1 // SPDX-License-Identifier: MIT 2 // 3 // Copyright 2025 Advanced Micro Devices, Inc. 4 5 #include "dml2_core_dcn5_calcs_dchub.h" 6 #include "dml2_core_dcn6_calcs_dchub.h" 7 #include "dml_top_display_cfg_types.h" 8 #include "dml2_core_utils.h" 9 #include "dml_top_types.h" 10 11 unsigned int dcn6_calculate_max_vstartup( 12 bool ptoi_supported, 13 unsigned int vblank_nom_default_us, 14 const struct dml2_timing_cfg *timing, 15 enum dml2_uclk_pstate_change_strategy pstate_strategy, 16 double write_back_delay_us, 17 unsigned int svp_lines) 18 { 19 unsigned int vblank_size = 0; 20 unsigned int max_vstartup_lines = 0; 21 22 double line_time_us = (double)timing->h_total / ((double)timing->pixel_clock_khz / 1000); 23 unsigned int vblank_actual = timing->v_total - timing->v_active; 24 unsigned int vblank_nom_default_in_line = (unsigned int)math_floor2((double)vblank_nom_default_us / line_time_us, 1.0); 25 unsigned int vblank_avail = (timing->vblank_nom == 0) ? vblank_nom_default_in_line : (unsigned int)timing->vblank_nom; 26 27 vblank_size = (unsigned int)math_min2(vblank_actual, vblank_avail); 28 29 if (timing->interlaced && !ptoi_supported) 30 max_vstartup_lines = (unsigned int)(math_floor2((vblank_size - 1) / 2.0, 1.0)); 31 else 32 max_vstartup_lines = vblank_size - (unsigned int)math_max2(1.0, math_ceil2(write_back_delay_us / line_time_us, 1.0)); 33 34 if (pstate_strategy == dml2_uclk_pstate_change_strategy_force_alternate) 35 max_vstartup_lines = (unsigned int)math_min2(max_vstartup_lines, svp_lines); 36 37 max_vstartup_lines = (unsigned int)math_min2(max_vstartup_lines, __DML2_CALCS_MAX_VSTARTUP__); 38 39 DML_LOG_VERBOSE("DML::%s: VBlankNom = %lu\n", __func__, timing->vblank_nom); 40 DML_LOG_VERBOSE("DML::%s: vblank_nom_default_us = %u\n", __func__, vblank_nom_default_us); 41 DML_LOG_VERBOSE("DML::%s: line_time_us = %f\n", __func__, line_time_us); 42 DML_LOG_VERBOSE("DML::%s: vblank_actual = %u\n", __func__, vblank_actual); 43 DML_LOG_VERBOSE("DML::%s: vblank_avail = %u\n", __func__, vblank_avail); 44 DML_LOG_VERBOSE("DML::%s: max_vstartup_lines = %u\n", __func__, max_vstartup_lines); 45 return max_vstartup_lines; 46 } 47 48 void dcn6_calculate_alternate_svp_lines(struct dml2_core_calcs_calculate_alternate_svp_lines *p) 49 { 50 unsigned int i, j; 51 double line_time_us, max_line_time_us = 0, svp0_time_us, svp1_time_us, vratio, vratio_c, swath_time_us, swath_time_c_us; 52 double max_swath_time_all_planes_us = 0; 53 double pad_us = 0; 54 55 for (i = 0; i < p->display_cfg->num_streams; i++) { 56 line_time_us = ((double)p->display_cfg->stream_descriptors[i].timing.h_total * 1000 / p->display_cfg->stream_descriptors[i].timing.pixel_clock_khz); 57 for (j = 0; j < p->display_cfg->num_planes; j++) { 58 if (p->display_cfg->plane_descriptors[j].stream_index == i) { 59 vratio = p->display_cfg->plane_descriptors[j].composition.scaler_info.plane0.v_ratio; 60 vratio_c = p->display_cfg->plane_descriptors[j].composition.scaler_info.plane1.v_ratio; 61 /* For now swath_time calculated based only on vratio - can use hdl schedule later once calculated 62 * (though HDL scehdule may produce the same result as just calc from vratio) */ 63 swath_time_us = ((double)p->SwathHeightY[j] / vratio) * line_time_us; 64 swath_time_c_us = p->BytePerPixelInDETC[j] > 0 ? ((double)p->SwathHeightC[j] / vratio_c) * line_time_us : 0; 65 if (swath_time_us > max_swath_time_all_planes_us || swath_time_c_us > max_swath_time_all_planes_us) 66 max_swath_time_all_planes_us = swath_time_us > swath_time_c_us ? swath_time_us : swath_time_c_us; 67 } 68 } 69 if (line_time_us > max_line_time_us) 70 max_line_time_us = line_time_us; 71 } 72 pad_us = max_swath_time_all_planes_us + max_line_time_us; 73 svp0_time_us = p->dram_blackout_us + pad_us + max_swath_time_all_planes_us; 74 svp1_time_us = p->dram_blackout_us + pad_us; 75 76 for (i = 0; i < p->display_cfg->num_streams; i++) { 77 line_time_us = ((double)p->display_cfg->stream_descriptors[i].timing.h_total * 1000 / p->display_cfg->stream_descriptors[i].timing.pixel_clock_khz); 78 p->svp0_dst_lines[i] = (unsigned int)math_ceil(svp0_time_us / line_time_us); 79 p->svp1_dst_lines[i] = (unsigned int)math_ceil(svp1_time_us / line_time_us); 80 p->svp_req_limit[i] = (unsigned int)math_ceil((pad_us + max_swath_time_all_planes_us) / line_time_us); 81 } 82 DML_LOG_VERBOSE("DML::%s: svp0_time_us = %f\n", __func__, svp0_time_us); 83 DML_LOG_VERBOSE("DML::%s: svp1_time_us = %f\n", __func__, svp1_time_us); 84 DML_LOG_VERBOSE("DML::%s: max_swath_time_all_planes_us = %f\n", __func__, max_swath_time_all_planes_us); 85 DML_LOG_VERBOSE("DML::%s: pad_us = %f\n", __func__, pad_us); 86 } 87 88 struct plane_params { 89 unsigned int viewport_start; 90 unsigned int viewport_size; 91 unsigned int swath_height; 92 double prefetch_hdl_delta; 93 double recout_hdl_delta; 94 double vratio; 95 unsigned int vinit; 96 }; 97 98 /** 99 * ***************************************************************************************************************************** 100 * get_plane_params: Get plane related params for chroma vs. luma depending on the chroma flag 101 * ***************************************************************************************************************************** 102 */ 103 static void get_plane_params( 104 const struct dml2_core_calcs_calculate_alternate_params *p, 105 unsigned int plane_idx, 106 bool chroma, 107 struct plane_params *out) 108 { 109 const struct dml2_plane_parameters *plane = &p->display_cfg->plane_descriptors[plane_idx]; 110 bool vertical_access = p->display_cfg->plane_descriptors[plane_idx].composition.rotation_angle == dml2_rotation_90 || p->display_cfg->plane_descriptors[plane_idx].composition.rotation_angle == dml2_rotation_270; 111 112 if (!chroma) { 113 out->viewport_start = vertical_access ? plane->composition.viewport.plane0.x_start : plane->composition.viewport.plane0.y_start; 114 out->viewport_size = vertical_access ? plane->composition.viewport.plane0.width : plane->composition.viewport.plane0.height; 115 out->swath_height = p->SwathHeightY[plane_idx]; 116 out->prefetch_hdl_delta = p->prefetch_hdl_delta[plane_idx]; 117 out->recout_hdl_delta = p->recout_hdl_delta[plane_idx]; 118 out->vratio = p->display_cfg->plane_descriptors[plane_idx].composition.scaler_info.plane0.v_ratio; 119 out->vinit = p->VInitPrefillY[plane_idx]; 120 } else { 121 out->viewport_start = vertical_access ? plane->composition.viewport.plane1.x_start : plane->composition.viewport.plane1.y_start; 122 out->viewport_size = vertical_access ? plane->composition.viewport.plane1.width : plane->composition.viewport.plane1.height; 123 out->swath_height = p->SwathHeightC[plane_idx]; 124 out->prefetch_hdl_delta = p->prefetch_hdl_delta_c[plane_idx]; 125 out->recout_hdl_delta = p->recout_hdl_delta_c[plane_idx]; 126 out->vratio = p->display_cfg->plane_descriptors[plane_idx].composition.scaler_info.plane1.v_ratio; 127 out->vinit = p->VInitPrefillC[plane_idx]; 128 } 129 } 130 131 /** 132 * ***************************************************************************************************************************** 133 * compute_pre_rec_first_hdl: Computes the first hdl position of pre and rec swath given the input params 134 * ***************************************************************************************************************************** 135 */ 136 static void compute_pre_rec_first_hdl( 137 const struct dml2_core_calcs_calculate_alternate_params *p, 138 bool chroma, 139 unsigned int stream_idx, 140 unsigned int plane_idx, 141 double *pre_first_hdl_out, 142 double *rec_first_hdl_out) 143 { 144 unsigned long vtotal = p->display_cfg->stream_descriptors[stream_idx].timing.v_total; 145 unsigned int vblank_end = p->display_cfg->stream_descriptors[stream_idx].timing.v_blank_end; 146 bool access_direction = (p->display_cfg->plane_descriptors[plane_idx].composition.rotation_angle == dml2_rotation_90 && !p->display_cfg->plane_descriptors[plane_idx].composition.mirrored) || 147 (p->display_cfg->plane_descriptors[plane_idx].composition.rotation_angle == dml2_rotation_270 && p->display_cfg->plane_descriptors[plane_idx].composition.mirrored) || 148 (p->display_cfg->plane_descriptors[plane_idx].composition.rotation_angle == dml2_rotation_180); 149 double dst_y_prefetch = p->dst_y_prefetch[plane_idx]; 150 double dst_y_per_vm_vblank = p->dst_y_per_vm_vblank[plane_idx]; 151 double dst_y_per_row_vblank = p->dst_y_per_row_vblank[plane_idx]; 152 unsigned int dst_y_after_scaler = p->DSTYAfterScaler[plane_idx]; 153 int prefetch_end_line = (vblank_end - dst_y_after_scaler) % vtotal; 154 double prefetch_start_line = (prefetch_end_line > dst_y_prefetch) ? (prefetch_end_line - dst_y_prefetch) : (prefetch_end_line - dst_y_prefetch + vtotal); 155 double pre_first_hdl, rec_first_hdl; 156 struct plane_params in = { 0 }; 157 158 get_plane_params(p, plane_idx, chroma, &in); 159 160 pre_first_hdl = prefetch_start_line + dst_y_per_vm_vblank + 2.0 * dst_y_per_row_vblank + in.prefetch_hdl_delta; 161 rec_first_hdl = access_direction ? 162 (in.viewport_start + in.viewport_size - in.vinit - in.swath_height - math_floor2(in.viewport_start + in.viewport_size - in.vinit, in.swath_height)) / in.vratio + (vblank_end - dst_y_after_scaler + in.recout_hdl_delta) : 163 (math_floor2(in.viewport_start + in.vinit - 1, in.swath_height) - in.viewport_start - in.vinit) / in.vratio + (vblank_end - dst_y_after_scaler + in.recout_hdl_delta); 164 165 *pre_first_hdl_out = pre_first_hdl; 166 *rec_first_hdl_out = rec_first_hdl; 167 } 168 169 /** 170 * ************************************************************************************************************************************ 171 * calculate_copy_swaths: Calculates a tight upper bound for the swaths required for copy given swath params and svp0 + svp1 dst lines 172 * 173 * Given the first hdl position of pre and rec swaths, and the delta in dst lines between the hdls, this function calculates the 174 * number of swaths to be copied in the worst case given svp0 and svp1 dst lines. The upper bound is "tight" because this function 175 * assumes svp0 and svp1 cannot both overlap with prefetch (prefetch potentially has the most amount of swaths per dst line). 176 * 177 * ************************************************************************************************************************************ 178 */ 179 static unsigned int calculate_copy_swaths(double pre_first_hdl, 180 double rec_first_hdl, 181 double pre_hdl_delta, 182 double rec_hdl_delta, 183 unsigned int prefetch_swaths, 184 unsigned int total_swaths, 185 unsigned int svp0_dst_lines, 186 unsigned int svp1_dst_lines, 187 unsigned int vtotal) 188 { 189 unsigned int svp_dst_lines = svp0_dst_lines + svp1_dst_lines; 190 double prefetch_dst_lines = (prefetch_swaths - 1) * pre_hdl_delta + 1; 191 double lines_between_pre_rec_first_hdl = pre_first_hdl < rec_first_hdl ? rec_first_hdl - pre_first_hdl : rec_first_hdl - pre_first_hdl + vtotal; 192 double lines_for_rec_swaths = svp_dst_lines - lines_between_pre_rec_first_hdl; 193 unsigned int num_swaths; 194 195 if (lines_for_rec_swaths > 0) 196 num_swaths = prefetch_swaths + (unsigned int)math_ceil((lines_for_rec_swaths + rec_hdl_delta - 1) / rec_hdl_delta); 197 else 198 num_swaths = svp_dst_lines > prefetch_dst_lines ? prefetch_swaths + 1 : (unsigned int)math_ceil((svp_dst_lines + pre_hdl_delta - 1) / pre_hdl_delta); 199 200 if (num_swaths > total_swaths) 201 num_swaths = total_swaths; 202 203 return num_swaths; 204 } 205 206 /** 207 * ******************************************************************************************************************************************************* 208 * calculate_tile_aligned_size: Applies tiled-surface padding / alignment rules to an unaligned copy region 209 * 210 * Given the unaligned copy region dimensions (copy_width in pixels, copy_height in lines) and the plane's macro tile 211 * (swizzle block) dimensions, this returns the number of bytes reserved for the region following addrlib sizing rules: 212 * - The pitch is padded up to the macro tile width and the height is padded up to the macro tile height. 213 * size = alignedPitch * alignedHeight * bpp, which is inherently macro-tile (block) aligned 214 * - The final ceil2 to 256 is a harmless floor for degenerate tile sizes. 215 * 216 * ******************************************************************************************************************************************************* 217 */ 218 static unsigned int calculate_tile_aligned_size(unsigned int copy_width, unsigned int copy_height, unsigned int tile_width, unsigned int tile_height, unsigned int byte_per_pixel) 219 { 220 unsigned int mem_width = (unsigned int)math_ceil2(copy_width, tile_width); 221 unsigned int mem_height = (unsigned int)math_ceil2(copy_height, tile_height); 222 223 return (unsigned int)math_ceil2(mem_width * mem_height * byte_per_pixel, 256); 224 } 225 226 /** 227 * ******************************************************************************************************************************************************* 228 * calculate_max_mem_size_per_plane_per_dpp: Calculate (loose) upper bound for total number of bytes reserved in memory for the copy given number of swaths 229 * 230 * - The copy width / height is the min of the vp_width/height and maximum number of pixels that can fit across an ODM slice 231 * - This is to account for recout positions that cross the ODM seam but are "mostly" within the same ODM slice 232 * 233 * ******************************************************************************************************************************************************* 234 */ 235 static unsigned int calculate_max_mem_size_per_plane_per_dpp(const struct dml2_core_calcs_calculate_alternate_params *p, unsigned int plane_idx, unsigned int copy_swaths, bool chroma) 236 { 237 bool vertical_access = p->display_cfg->plane_descriptors[plane_idx].composition.rotation_angle == dml2_rotation_90 || p->display_cfg->plane_descriptors[plane_idx].composition.rotation_angle == dml2_rotation_270; 238 unsigned int h_active = p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[plane_idx].stream_index].timing.h_active; 239 double h_ratio = chroma ? p->display_cfg->plane_descriptors[plane_idx].composition.scaler_info.plane1.h_ratio : p->display_cfg->plane_descriptors[plane_idx].composition.scaler_info.plane0.h_ratio; 240 unsigned int copy_src_lines = copy_swaths * (chroma ? p->SwathHeightC[plane_idx] : p->SwathHeightY[plane_idx]); 241 unsigned int vp_width = chroma ? p->display_cfg->plane_descriptors[plane_idx].composition.viewport.plane1.width : p->display_cfg->plane_descriptors[plane_idx].composition.viewport.plane0.width; 242 unsigned int vp_height = chroma ? p->display_cfg->plane_descriptors[plane_idx].composition.viewport.plane1.height : p->display_cfg->plane_descriptors[plane_idx].composition.viewport.plane0.height; 243 unsigned int tile_width = chroma ? p->MacroTileWidthC[plane_idx] : p->MacroTileWidthY[plane_idx]; 244 unsigned int tile_height = chroma ? p->MacroTileHeightC[plane_idx] : p->MacroTileHeightY[plane_idx]; 245 unsigned int byte_per_pixel = chroma ? p->BytePerPixelC[plane_idx] : p->BytePerPixelY[plane_idx]; 246 unsigned int copy_width; 247 unsigned int copy_height; 248 unsigned int odm_combine_factor; 249 double odm_slice_pixels; 250 251 if (p->ODMMode[plane_idx] == dml2_odm_mode_combine_4to1) 252 odm_combine_factor = 4; 253 else if (p->ODMMode[plane_idx] == dml2_odm_mode_combine_3to1) 254 odm_combine_factor = 3; 255 else if (p->ODMMode[plane_idx] == dml2_odm_mode_combine_2to1) 256 odm_combine_factor = 2; 257 else 258 odm_combine_factor = 1; 259 260 odm_slice_pixels = (double)h_active / odm_combine_factor * h_ratio + (odm_combine_factor == 3 ? 2 : 0); 261 262 /* Unaligned copy region dimensions (in pixels / lines) prior to tile alignment. 263 * Also divide vp_widht/height by NoOfDPP for MPC combine scenarios (i.e., MPC split within an ODM slice). */ 264 copy_width = vertical_access ? copy_src_lines : (unsigned int)math_ceil(math_min2(odm_slice_pixels, vp_width / p->NoOfDPP[plane_idx])); 265 copy_height = vertical_access ? (unsigned int)math_ceil(math_min2(odm_slice_pixels, vp_height / p->NoOfDPP[plane_idx])) : copy_src_lines; 266 267 return calculate_tile_aligned_size(copy_width, copy_height, tile_width, tile_height, byte_per_pixel); 268 } 269 /** 270 * **************************************************************************************************************************************** 271 * calculate_ub_copy_size_per_plane_per_dpp: Calculate tight upper bound for total number of bytes required for the copy given number of swaths. 272 * 273 * - This function is intended to be used to calculate the total copy time, since we want to reduce the copy time upper bound as much as possible 274 * - For copy width assume two extra block widths (the copy itself does not need to be tiled aligned, only block aligned, so we don't add an extra 275 * tile to the copy width 276 * - For copy height assumes two extra block heights are required 277 * 278 * Note: This function could be optimized further (i.e., an even tighter upper bound) if we take into account 279 * vp_x_start and vp_y_start positions which will tell us if the start and end positions of the copy are already 280 * blocked aligned (then we would not need to add the extra block width/height). 281 * 282 * **************************************************************************************************************************************** 283 */ 284 static unsigned int calculate_ub_copy_size_per_plane_per_dpp(const struct dml2_core_calcs_calculate_alternate_params *p, unsigned int plane_idx, unsigned int copy_swaths, bool chroma) 285 { 286 bool vertical_access = p->display_cfg->plane_descriptors[plane_idx].composition.rotation_angle == dml2_rotation_90 || p->display_cfg->plane_descriptors[plane_idx].composition.rotation_angle == dml2_rotation_270; 287 unsigned int copy_src_lines = copy_swaths * (chroma ? p->SwathHeightC[plane_idx] : p->SwathHeightY[plane_idx]); 288 unsigned int vp_width = chroma ? p->display_cfg->plane_descriptors[plane_idx].composition.viewport.plane1.width : p->display_cfg->plane_descriptors[plane_idx].composition.viewport.plane0.width; 289 unsigned int vp_height = chroma ? p->display_cfg->plane_descriptors[plane_idx].composition.viewport.plane1.height : p->display_cfg->plane_descriptors[plane_idx].composition.viewport.plane0.height; 290 unsigned int block256_width = chroma ? p->Read256BlockWidthC[plane_idx] : p->Read256BlockWidthY[plane_idx]; 291 unsigned int block256_height = chroma ? p->Read256BlockHeightC[plane_idx] : p->Read256BlockHeightY[plane_idx]; 292 unsigned int copy_width = (vertical_access ? copy_src_lines : vp_width / p->NoOfDPP[plane_idx]) + 2 * block256_width; 293 unsigned int copy_height = (vertical_access ? vp_height / p->NoOfDPP[plane_idx] : copy_src_lines) + 2 * block256_height; 294 unsigned int byte_per_pixel = chroma ? p->BytePerPixelC[plane_idx] : p->BytePerPixelY[plane_idx]; 295 296 return (unsigned int)math_ceil2(copy_width * copy_height * byte_per_pixel, 256); 297 } 298 299 /** 300 * ***************************************************************************************************************************** 301 * calculate_alt_copy_time_us: Calculates a tight upper bound for the copy time over all planes and streams 302 * 303 * This function calculates a tight upper bound for the copy time over all planes and streams. This upper bound is "tight" 304 * because it does the calculation assuming SVP0 and SVP1 cannot both overlap with prefetch (which potentially has the "most" 305 * amount of bytes to copy per dst line). 306 * 307 * This function uses the exact NoOfDPP as calculated by DML (i.e., it does not use an input num_dpp param). This is because we 308 * want the copy time calculation to be precise in order to minimize FW latency / overhead. 309 * 310 * ***************************************************************************************************************************** 311 */ 312 static unsigned int calculate_alt_copy_time_us(const struct dml2_core_calcs_calculate_alternate_params *p) 313 { 314 unsigned int i, j; 315 double pre_first_hdl = 0.0, rec_first_hdl = 0.0; 316 double pre_first_hdl_c = 0.0, rec_first_hdl_c = 0.0; 317 double rec_hdl_delta, rec_hdl_delta_c; 318 double pre_hdl_delta, pre_hdl_delta_c; 319 unsigned int copy_swaths, copy_swaths_c; 320 unsigned int vtotal; 321 unsigned int copy_size_bytes = 0; 322 323 for (i = 0; i < p->display_cfg->num_streams; i++) { 324 vtotal = p->display_cfg->stream_descriptors[i].timing.v_total; 325 for (j = 0; j < p->display_cfg->num_planes; j++) { 326 if (p->display_cfg->plane_descriptors[j].stream_index != i) 327 continue; 328 compute_pre_rec_first_hdl(p, false, i, j, &pre_first_hdl, &rec_first_hdl); 329 rec_hdl_delta = p->recout_hdl_delta[j]; 330 pre_hdl_delta = p->prefetch_hdl_delta[j]; 331 copy_swaths = calculate_copy_swaths(pre_first_hdl, rec_first_hdl, pre_hdl_delta, rec_hdl_delta, p->prefetch_swaths[j], p->total_swaths[j], p->svp0_dst_lines[i], p->svp1_dst_lines[i], vtotal); 332 copy_size_bytes += calculate_ub_copy_size_per_plane_per_dpp(p, j, copy_swaths, false) * p->NoOfDPP[j]; 333 if (p->BytePerPixelInDETC[j] > 0) { 334 compute_pre_rec_first_hdl(p, true, i, j, &pre_first_hdl_c, &rec_first_hdl_c); 335 rec_hdl_delta_c = p->recout_hdl_delta_c[j]; 336 pre_hdl_delta_c = p->prefetch_hdl_delta_c[j]; 337 copy_swaths_c = calculate_copy_swaths(pre_first_hdl_c, rec_first_hdl_c, pre_hdl_delta_c, rec_hdl_delta_c, p->prefetch_swaths_c[j], p->total_swaths_c[j], p->svp0_dst_lines[i], p->svp1_dst_lines[i], vtotal); 338 copy_size_bytes += calculate_ub_copy_size_per_plane_per_dpp(p, j, copy_swaths_c, false) * p->NoOfDPP[j]; 339 } 340 } 341 } 342 return (unsigned int)math_ceil((double)copy_size_bytes * 1000 / *p->lsdma_bw_req_for_alt_kbps); 343 } 344 345 /** 346 * ***************************************************************************************************************************** 347 * calculate_ub_copy_size_per_plane_per_dpp_per_svp: Calculates the upper bound copy size in bytes for a given plane and svp_dst_lines 348 * 349 * @input: p - alternate related params (input only) 350 * svp_dst_lines - number of lines (in dst space) for the svp (one of svp0 or svp1 dst lines) 351 * plane_idx - plane index to calculate for 352 * chroma - flag to indicate if chroma or luma plane 353 * 354 * TODO: The check for total copy size versus total alt-channel aperture size can be moved directly into mode support (from 355 * optimize / admissibility check layer) 356 * 357 * Note 2: This function calculates a loose upper bound for the size required for the copy. The reason for this is because each 358 * SVP aperture needs enough space to hold the worst case copy size (i.e., prefetch + some recout swaths), so we calculate 359 * such that any SVP needs to consider the prefetch swaths in the size required. But in actuality only one of SVP0 or SVP1 360 * would have prefetch swaths required to be copied since there cannot be the case where both SVPs overlap with prefetch. 361 * Therefore the result of this function should not be used to calculate the total copy time required (as it would be too long). 362 * 363 * ***************************************************************************************************************************** 364 */ 365 static unsigned int calculate_ub_copy_size_per_plane_per_dpp_per_svp(const struct dml2_core_calcs_calculate_alternate_params *p, unsigned int svp_dst_lines, unsigned int plane_idx, bool chroma) 366 { 367 unsigned int svp_lines_for_va; 368 unsigned int copy_swaths; 369 unsigned int copy_size = 0; 370 371 if (chroma && p->BytePerPixelInDETC[plane_idx] > 0) { 372 /* chomra plane */ 373 svp_lines_for_va = svp_dst_lines - (unsigned int)((p->prefetch_swaths_c[plane_idx] - 1) * p->prefetch_hdl_delta_c[plane_idx]); 374 copy_swaths = p->prefetch_swaths_c[plane_idx] + (unsigned int)math_ceil(svp_lines_for_va / p->recout_hdl_delta_c[plane_idx]); 375 if (copy_swaths > p->total_swaths_c[plane_idx]) 376 copy_swaths = p->total_swaths_c[plane_idx]; 377 copy_size = calculate_max_mem_size_per_plane_per_dpp(p, plane_idx, copy_swaths, chroma); 378 } else if (!chroma) { 379 /* luma plane */ 380 svp_lines_for_va = svp_dst_lines - (unsigned int)((p->prefetch_swaths[plane_idx] - 1) * p->prefetch_hdl_delta[plane_idx]); 381 copy_swaths = p->prefetch_swaths[plane_idx] + (unsigned int)math_ceil(svp_lines_for_va / p->recout_hdl_delta[plane_idx]); 382 if (copy_swaths > p->total_swaths[plane_idx]) 383 copy_swaths = p->total_swaths[plane_idx]; 384 copy_size = calculate_max_mem_size_per_plane_per_dpp(p, plane_idx, copy_swaths, chroma); 385 } 386 387 return copy_size; 388 } 389 390 struct swath_params { 391 unsigned int prefetch_swaths; 392 unsigned int total_swaths; 393 double recout_hdl_delta; 394 double prefetch_hdl_delta; 395 }; 396 397 /** 398 * *********************************************************************************************************** 399 * calculate_swath_params: Function that calculates swath related params for alt-channel and returns the values 400 * 401 * This function calculates: 402 * - number of prefetch swaths 403 * - number of total swaths 404 * - recout_hdl_delta (number of dst lines between hdls in recout) 405 * - prefetch_hdl_delta (number of dst lines between hdls in prefetch) 406 * 407 * And returns it to the out parameter. 408 * 409 * *********************************************************************************************************** 410 */ 411 static void calculate_swath_params(const struct dml2_core_calcs_calculate_alternate_params *p, unsigned int plane_idx, bool chroma, struct swath_params *out) 412 { 413 bool vertical_access = p->display_cfg->plane_descriptors[plane_idx].composition.rotation_angle == dml2_rotation_90 || p->display_cfg->plane_descriptors[plane_idx].composition.rotation_angle == dml2_rotation_270; 414 bool access_direction = (p->display_cfg->plane_descriptors[plane_idx].composition.rotation_angle == dml2_rotation_90 && !p->display_cfg->plane_descriptors[plane_idx].composition.mirrored) || 415 (p->display_cfg->plane_descriptors[plane_idx].composition.rotation_angle == dml2_rotation_270 && p->display_cfg->plane_descriptors[plane_idx].composition.mirrored) || 416 (p->display_cfg->plane_descriptors[plane_idx].composition.rotation_angle == dml2_rotation_180); 417 unsigned int vp_x_start = chroma ? p->display_cfg->plane_descriptors[plane_idx].composition.viewport.plane1.x_start : p->display_cfg->plane_descriptors[plane_idx].composition.viewport.plane0.x_start; 418 unsigned int vp_y_start = chroma ? p->display_cfg->plane_descriptors[plane_idx].composition.viewport.plane1.y_start : p->display_cfg->plane_descriptors[plane_idx].composition.viewport.plane0.y_start; 419 unsigned int vp_height = chroma ? p->display_cfg->plane_descriptors[plane_idx].composition.viewport.plane1.height : p->display_cfg->plane_descriptors[plane_idx].composition.viewport.plane0.height; 420 unsigned int vp_width = chroma ? p->display_cfg->plane_descriptors[plane_idx].composition.viewport.plane1.width : p->display_cfg->plane_descriptors[plane_idx].composition.viewport.plane0.width; 421 double vratio = chroma ? p->display_cfg->plane_descriptors[plane_idx].composition.scaler_info.plane1.v_ratio : p->display_cfg->plane_descriptors[plane_idx].composition.scaler_info.plane0.v_ratio; 422 double vratio_pre = chroma ? p->VRatioPrefetchC[plane_idx] : p->VRatioPrefetchY[plane_idx]; 423 unsigned int swath_height = chroma ? p->SwathHeightC[plane_idx] : p->SwathHeightY[plane_idx]; 424 unsigned int vinit = chroma ? p->VInitPrefillC[plane_idx] : p->VInitPrefillY[plane_idx]; 425 unsigned int viewport_start = vertical_access ? vp_x_start : vp_y_start; 426 unsigned int viewport_size = vertical_access ? vp_width : vp_height; 427 unsigned int src_y_last_pref_sw_algn, src_y_first_sw_algn, src_y_last_va_sw_algn; 428 429 if (access_direction) { 430 src_y_first_sw_algn = (unsigned int)math_floor2(viewport_start + viewport_size - 1, swath_height); 431 src_y_last_pref_sw_algn = (unsigned int)math_floor2(viewport_start + viewport_size - vinit, swath_height); 432 src_y_last_va_sw_algn = (unsigned int)math_floor2(viewport_start, swath_height); 433 } else { 434 src_y_first_sw_algn = (unsigned int)math_floor2(viewport_start, swath_height); 435 src_y_last_pref_sw_algn = (unsigned int)math_floor2(viewport_start + vinit - 1, swath_height); 436 src_y_last_va_sw_algn = (unsigned int)math_floor2(viewport_start + viewport_size - 1, swath_height); 437 } 438 out->prefetch_swaths = (access_direction ? src_y_first_sw_algn - src_y_last_pref_sw_algn : src_y_last_pref_sw_algn - src_y_first_sw_algn) / swath_height + 1; 439 out->total_swaths = (access_direction ? src_y_first_sw_algn - src_y_last_va_sw_algn : src_y_last_va_sw_algn - src_y_first_sw_algn) / swath_height + 1; 440 out->recout_hdl_delta = (double)swath_height / vratio; 441 out->prefetch_hdl_delta = (double)swath_height / vratio_pre; 442 } 443 444 static unsigned int calc_svp_size_256kb_aligned(unsigned int total_size_bytes) 445 { 446 return ((total_size_bytes + 0x3FFFFu) >> 18) << 18; // Round up to nearest 256KB boundary 447 } 448 449 void dcn6_calculate_alternate_params(struct dml2_core_calcs_calculate_alternate_params *p) 450 { 451 unsigned int i, j, k; 452 double line_time_us = 0, prefetch_time_us, max_prefetch_time_us = 0; 453 unsigned int svp_max_bytes[2]; 454 unsigned int svp_max_bytes_per_dpp[2]; 455 unsigned int svp_dst_lines[2]; 456 double copy_time_us; 457 double svp_req_lim_us = 0; 458 unsigned int fw_delay; 459 struct swath_params swath_params; 460 461 /* the alternate channel outputs are only meaningful when the alternate channel is in use; 462 * otherwise zero all outputs and return early */ 463 if (!p->alt_chan_in_use) { 464 *p->svp0_max_bytes = 0; 465 *p->svp1_max_bytes = 0; 466 *p->lsdma_bw_req_for_alt_kbps = 0; 467 468 for (i = 0; i < p->display_cfg->num_planes; i++) { 469 p->svp0_max_bytes_per_dpp[i] = 0; 470 p->svp0_max_bytes_per_dpp_c[i] = 0; 471 p->svp1_max_bytes_per_dpp[i] = 0; 472 p->svp1_max_bytes_per_dpp_c[i] = 0; 473 p->total_swaths[i] = 0; 474 p->total_swaths_c[i] = 0; 475 p->prefetch_swaths[i] = 0; 476 p->prefetch_swaths_c[i] = 0; 477 p->prefetch_hdl_delta[i] = 0; 478 p->recout_hdl_delta[i] = 0; 479 p->prefetch_hdl_delta_c[i] = 0; 480 p->recout_hdl_delta_c[i] = 0; 481 } 482 483 for (i = 0; i < p->display_cfg->num_streams; i++) { 484 p->nom_req_limit_alt[i] = 0; 485 p->min_lead_dst_lines[i] = 0; 486 p->max_prefetch_in_lines[i] = 0; 487 } 488 489 return; 490 } 491 492 *p->svp0_max_bytes = 0; 493 *p->svp1_max_bytes = 0; 494 svp_max_bytes[0] = 0; 495 svp_max_bytes[1] = 0; 496 /* This initial loop calculates a few params that are used for calculations / assignments in later parts of the function: 497 * - max_prefetch_time_us 498 */ 499 for (i = 0; i < p->display_cfg->num_streams; i++) { 500 line_time_us = ((double)p->display_cfg->stream_descriptors[i].timing.h_total * 1000 / p->display_cfg->stream_descriptors[i].timing.pixel_clock_khz); 501 if (p->svp_req_limit[i] * line_time_us > svp_req_lim_us) 502 svp_req_lim_us = p->svp_req_limit[i] * line_time_us; 503 for (j = 0; j < p->display_cfg->num_planes; j++) { 504 prefetch_time_us = line_time_us * p->dst_y_prefetch[j]; 505 if (prefetch_time_us > max_prefetch_time_us) 506 max_prefetch_time_us = prefetch_time_us; 507 } 508 } 509 510 for (i = 0; i < p->display_cfg->num_streams; i++) { 511 svp_dst_lines[0] = p->svp0_dst_lines[i]; 512 svp_dst_lines[1] = p->svp1_dst_lines[i]; 513 line_time_us = ((double)p->display_cfg->stream_descriptors[i].timing.h_total * 1000 / p->display_cfg->stream_descriptors[i].timing.pixel_clock_khz); 514 p->max_prefetch_in_lines[i] = (unsigned int)math_ceil(max_prefetch_time_us / line_time_us); 515 for (j = 0; j < p->display_cfg->num_planes; j++) { 516 if (p->display_cfg->plane_descriptors[j].stream_index == i) { 517 calculate_swath_params(p, j, false, &swath_params); 518 p->prefetch_swaths[j] = swath_params.prefetch_swaths; 519 p->total_swaths[j] = swath_params.total_swaths; 520 p->recout_hdl_delta[j] = swath_params.recout_hdl_delta; 521 p->prefetch_hdl_delta[j] = swath_params.prefetch_hdl_delta; 522 for (k = 0; k < 2; k++) { 523 svp_max_bytes_per_dpp[k] = calculate_ub_copy_size_per_plane_per_dpp_per_svp(p, svp_dst_lines[k], j, false); 524 svp_max_bytes[k] += calc_svp_size_256kb_aligned(svp_max_bytes_per_dpp[k]) * p->NoOfDPP[j]; 525 } 526 p->svp0_max_bytes_per_dpp[j] = svp_max_bytes_per_dpp[0]; 527 p->svp1_max_bytes_per_dpp[j] = svp_max_bytes_per_dpp[1]; 528 529 if (p->BytePerPixelInDETC[j] > 0) { 530 calculate_swath_params(p, j, true, &swath_params); 531 p->prefetch_swaths_c[j] = swath_params.prefetch_swaths; 532 p->total_swaths_c[j] = swath_params.total_swaths; 533 p->recout_hdl_delta_c[j] = swath_params.recout_hdl_delta; 534 p->prefetch_hdl_delta_c[j] = swath_params.prefetch_hdl_delta; 535 536 for (k = 0; k < 2; k++) { 537 svp_max_bytes_per_dpp[k] = calculate_ub_copy_size_per_plane_per_dpp_per_svp(p, svp_dst_lines[k], j, true); 538 svp_max_bytes[k] += calc_svp_size_256kb_aligned(svp_max_bytes_per_dpp[k]) * p->NoOfDPP[j]; 539 } 540 p->svp0_max_bytes_per_dpp_c[j] = svp_max_bytes_per_dpp[0]; 541 p->svp1_max_bytes_per_dpp_c[j] = svp_max_bytes_per_dpp[1]; 542 } else { 543 p->svp0_max_bytes_per_dpp_c[j] = 0; 544 p->svp1_max_bytes_per_dpp_c[j] = 0; 545 } 546 } 547 } 548 } 549 550 *p->svp0_max_bytes = svp_max_bytes[0]; 551 *p->svp1_max_bytes = svp_max_bytes[1]; 552 *p->lsdma_bw_req_for_alt_kbps = math_min2(p->dcn_non_urgent_bandwidth_kbps, p->max_lsdma_bandwidth_kbps); 553 copy_time_us = p->display_cfg->overrides.hw.force_alt_chan_copy_time.enable ? p->display_cfg->overrides.hw.force_alt_chan_copy_time.copy_time_us : calculate_alt_copy_time_us(p); 554 fw_delay = p->display_cfg->overrides.hw.force_alt_chan_fw_delay.enable ? p->display_cfg->overrides.hw.force_alt_chan_fw_delay.fw_delay_us : p->alt_chan_fw_delay_us; 555 for (i = 0; i < p->display_cfg->num_streams; i++) { 556 line_time_us = ((double)p->display_cfg->stream_descriptors[i].timing.h_total * 1000 / p->display_cfg->stream_descriptors[i].timing.pixel_clock_khz); 557 /* If copy_time is very short then clamp nom_req_limit to be equal to svp_req_limit. This is to prevent underflow 558 * because a short nom_req_limit prevents DCN from being able to request ahead. */ 559 p->nom_req_limit_alt[i] = (unsigned int)math_max2(p->svp_req_limit[i], math_ceil((copy_time_us) / line_time_us)); 560 p->min_lead_dst_lines[i] = (unsigned int)math_ceil((copy_time_us + fw_delay + math_max2(svp_req_lim_us, max_prefetch_time_us)) / line_time_us); 561 } 562 } 563 564 void dcn6_calculate_flip_schedule( 565 struct dml2_core_internal_scratch *s, 566 bool iflip_enable, 567 bool ihostvm_enable, 568 bool iffbmm_enable, 569 double HostVMInefficiencyFactor, 570 double Tvm_trips_flip, 571 double Tr0_trips_flip, 572 double Tvm_trips_flip_rounded, 573 double Tr0_trips_flip_rounded, 574 bool GPUVMEnable, 575 double vm_bytes, // vm_bytes 576 double DPTEBytesPerRow, // dpte_row_bytes 577 enum dml2_source_format_class SourcePixelFormat, 578 double LineTime, 579 double VRatio, 580 double VRatioChroma, 581 double Tno_bw_flip, 582 unsigned int dpte_row_height, 583 unsigned int dpte_row_height_chroma, 584 unsigned int max_flip_time_us, 585 unsigned int max_flip_time_lines, 586 unsigned int meta_row_height, 587 unsigned int meta_row_height_chroma, 588 589 // Output 590 double *dst_y_per_vm_flip, 591 double *dst_y_per_row_flip, 592 double *final_flip_bw, 593 bool *ImmediateFlipSupportedForPipe) 594 { 595 (void)meta_row_height; 596 (void)meta_row_height_chroma; 597 struct dml2_core_shared_CalculateFlipSchedule_locals *l = &s->CalculateFlipSchedule_locals; 598 599 l->dual_plane = dml2_core_utils_is_420(SourcePixelFormat) || dml2_core_utils_is_422_planar(SourcePixelFormat) || SourcePixelFormat == dml2_rgbe_alpha; 600 l->dpte_row_bytes = DPTEBytesPerRow; 601 602 DML_LOG_VERBOSE("DML::%s: GPUVMEnable = %u\n", __func__, GPUVMEnable); 603 DML_LOG_VERBOSE("DML::%s: ip.max_flip_time_us = %d\n", __func__, max_flip_time_us); 604 DML_LOG_VERBOSE("DML::%s: ip.max_flip_time_lines = %d\n", __func__, max_flip_time_lines); 605 DML_LOG_VERBOSE("DML::%s: iflip_enable = %u\n", __func__, iflip_enable); 606 DML_LOG_VERBOSE("DML::%s: HostVMInefficiencyFactor = %f\n", __func__, HostVMInefficiencyFactor); 607 DML_LOG_VERBOSE("DML::%s: LineTime = %f\n", __func__, LineTime); 608 DML_LOG_VERBOSE("DML::%s: Tno_bw_flip = %f\n", __func__, Tno_bw_flip); 609 DML_LOG_VERBOSE("DML::%s: Tvm_trips_flip = %f\n", __func__, Tvm_trips_flip); 610 DML_LOG_VERBOSE("DML::%s: Tr0_trips_flip = %f\n", __func__, Tr0_trips_flip); 611 DML_LOG_VERBOSE("DML::%s: Tvm_trips_flip_rounded = %f\n", __func__, Tvm_trips_flip_rounded); 612 DML_LOG_VERBOSE("DML::%s: Tr0_trips_flip_rounded = %f\n", __func__, Tr0_trips_flip_rounded); 613 DML_LOG_VERBOSE("DML::%s: vm_bytes = %f\n", __func__, vm_bytes); 614 DML_LOG_VERBOSE("DML::%s: DPTEBytesPerRow = %f\n", __func__, DPTEBytesPerRow); 615 DML_LOG_VERBOSE("DML::%s: dpte_row_bytes = %f\n", __func__, l->dpte_row_bytes); 616 DML_LOG_VERBOSE("DML::%s: dpte_row_height = %d\n", __func__, dpte_row_height); 617 DML_LOG_VERBOSE("DML::%s: meta_row_height = %d\n", __func__, meta_row_height); 618 DML_LOG_VERBOSE("DML::%s: VRatio = %f\n", __func__, VRatio); 619 620 bool flip_enable = iflip_enable || (GPUVMEnable && (ihostvm_enable || iffbmm_enable)); 621 622 if (GPUVMEnable) { 623 if (l->dual_plane) { 624 l->min_row_height = dpte_row_height; 625 l->min_row_height_chroma = dpte_row_height_chroma; 626 l->min_row_time = math_min2(l->min_row_height * LineTime / VRatio, l->min_row_height_chroma * LineTime / VRatioChroma); 627 } else { 628 l->min_row_height = dpte_row_height; 629 l->min_row_time = l->min_row_height * LineTime / VRatio; 630 } 631 DML_LOG_VERBOSE("DML::%s: min_row_time = %f\n", __func__, l->min_row_time); 632 DML_ASSERT(l->min_row_time > 0); 633 634 // For mode check, calculation the flip bw requirement with worst case flip time 635 l->max_flip_time = math_min2(math_min2(l->min_row_time, (double)max_flip_time_lines * LineTime / VRatio), 636 math_max2(Tvm_trips_flip_rounded + 2 * Tr0_trips_flip_rounded, (double)max_flip_time_us)); 637 638 //The lower bound on flip bandwidth 639 // Note: The get_urgent_bandwidth_required already consider dpte_row_bw and meta_row_bw in bandwidth calculation, so leave final_flip_bw = 0 if iflip not required 640 l->lb_flip_bw = 0; 641 642 if (flip_enable) { 643 l->hvm_scaled_vm_bytes = vm_bytes * HostVMInefficiencyFactor; 644 l->num_rows = 2; 645 l->hvm_scaled_row_bytes = l->num_rows * l->dpte_row_bytes * HostVMInefficiencyFactor; 646 l->hvm_scaled_vm_row_bytes = l->hvm_scaled_vm_bytes + l->hvm_scaled_row_bytes; 647 l->lb_flip_bw = math_max3( 648 l->hvm_scaled_vm_row_bytes / (l->max_flip_time - Tno_bw_flip), 649 l->hvm_scaled_vm_bytes / (l->max_flip_time - Tno_bw_flip - 2 * Tr0_trips_flip_rounded), 650 l->hvm_scaled_row_bytes / (l->max_flip_time - Tvm_trips_flip_rounded)); 651 DML_LOG_VERBOSE("DML::%s: max_flip_time = %f\n", __func__, l->max_flip_time); 652 DML_LOG_VERBOSE("DML::%s: total vm bytes (hvm ineff scaled) = %f\n", __func__, l->hvm_scaled_vm_bytes); 653 DML_LOG_VERBOSE("DML::%s: total row bytes (%f row, hvm ineff scaled) = %f\n", __func__, l->num_rows, l->hvm_scaled_row_bytes); 654 DML_LOG_VERBOSE("DML::%s: total vm+row bytes (hvm ineff scaled) = %f\n", __func__, l->hvm_scaled_vm_row_bytes); 655 DML_LOG_VERBOSE("DML::%s: lb_flip_bw for vm and row = %f\n", __func__, l->hvm_scaled_vm_row_bytes / (l->max_flip_time - Tno_bw_flip)); 656 DML_LOG_VERBOSE("DML::%s: lb_flip_bw for vm = %f\n", __func__, l->hvm_scaled_vm_bytes / (l->max_flip_time - Tno_bw_flip - 2 * Tr0_trips_flip_rounded)); 657 DML_LOG_VERBOSE("DML::%s: lb_flip_bw for row = %f\n", __func__, l->hvm_scaled_row_bytes / (l->max_flip_time - Tvm_trips_flip_rounded)); 658 659 if (l->lb_flip_bw > 0) { 660 DML_LOG_VERBOSE("DML::%s: mode_support est Tvm_flip = %f (bw-based)\n", __func__, Tno_bw_flip + l->hvm_scaled_vm_bytes / l->lb_flip_bw); 661 DML_LOG_VERBOSE("DML::%s: mode_support est Tr0_flip = %f (bw-based)\n", __func__, l->hvm_scaled_row_bytes / l->lb_flip_bw / l->num_rows); 662 DML_LOG_VERBOSE("DML::%s: mode_support est dst_y_per_vm_flip = %f (bw-based)\n", __func__, Tno_bw_flip + l->hvm_scaled_vm_bytes / l->lb_flip_bw / LineTime); 663 DML_LOG_VERBOSE("DML::%s: mode_support est dst_y_per_row_flip = %f (bw-based)\n", __func__, l->hvm_scaled_row_bytes / l->lb_flip_bw / LineTime / l->num_rows); 664 DML_LOG_VERBOSE("DML::%s: Tvm_trips_flip_rounded + 2*Tr0_trips_flip_rounded = %f\n", __func__, (Tvm_trips_flip_rounded + 2 * Tr0_trips_flip_rounded)); 665 } 666 l->lb_flip_bw = math_max3(l->lb_flip_bw, 667 l->hvm_scaled_vm_bytes / ((31 * LineTime) - Tno_bw_flip), 668 l->dpte_row_bytes * HostVMInefficiencyFactor / (15 * LineTime)); 669 670 DML_LOG_VERBOSE("DML::%s: lb_flip_bw for vm reg limit = %f\n", __func__, l->hvm_scaled_vm_bytes / ((31 * LineTime) - Tno_bw_flip)); 671 } 672 673 *final_flip_bw = l->lb_flip_bw; 674 675 if (flip_enable) { 676 DML_LOG_VERBOSE("DML::%s: final_flip_bw = %f\n", __func__, *final_flip_bw); 677 if (*final_flip_bw == 0) { 678 l->Tvm_flip = 0; 679 l->Tr0_flip = 0; 680 } else { 681 l->Tvm_flip = math_max3(Tvm_trips_flip, 682 Tno_bw_flip + vm_bytes * HostVMInefficiencyFactor / *final_flip_bw, 683 LineTime / 4.0); 684 685 l->Tr0_flip = math_max3(Tr0_trips_flip, 686 l->dpte_row_bytes * HostVMInefficiencyFactor / *final_flip_bw, 687 LineTime / 4.0); 688 } 689 DML_LOG_VERBOSE("DML::%s: total vm bytes (hvm ineff scaled) = %f\n", __func__, vm_bytes * HostVMInefficiencyFactor); 690 DML_LOG_VERBOSE("DML::%s: Tvm_flip = %f (bw-based), Tvm_trips_flip = %f (latency-based)\n", __func__, Tno_bw_flip + vm_bytes * HostVMInefficiencyFactor / l->ImmediateFlipBW, Tvm_trips_flip); 691 *dst_y_per_vm_flip = math_ceil2(4.0 * (l->Tvm_flip / LineTime), 1.0) / 4.0; 692 *dst_y_per_row_flip = math_ceil2(4.0 * (l->Tr0_flip / LineTime), 1.0) / 4.0; 693 694 *final_flip_bw = math_max2(vm_bytes * HostVMInefficiencyFactor / (*dst_y_per_vm_flip * LineTime), 695 l->dpte_row_bytes * HostVMInefficiencyFactor / (*dst_y_per_row_flip * LineTime)); 696 697 if (*dst_y_per_vm_flip >= 32 || *dst_y_per_row_flip >= 16 || l->Tvm_flip + 2 * l->Tr0_flip > l->min_row_time) { 698 *ImmediateFlipSupportedForPipe = false; 699 } else { 700 *ImmediateFlipSupportedForPipe = flip_enable; 701 } 702 } else { 703 l->Tvm_flip = 0; 704 l->Tr0_flip = 0; 705 *dst_y_per_vm_flip = 0; 706 *dst_y_per_row_flip = 0; 707 *final_flip_bw = 0; 708 *ImmediateFlipSupportedForPipe = flip_enable; 709 } 710 } else { 711 l->Tvm_flip = 0; 712 l->Tr0_flip = 0; 713 *dst_y_per_vm_flip = 0; 714 *dst_y_per_row_flip = 0; 715 *final_flip_bw = 0; 716 *ImmediateFlipSupportedForPipe = flip_enable; 717 } 718 719 DML_LOG_VERBOSE("DML::%s: dst_y_per_vm_flip = %f (should be < 32)\n", __func__, *dst_y_per_vm_flip); 720 DML_LOG_VERBOSE("DML::%s: dst_y_per_row_flip = %f (should be < 16)\n", __func__, *dst_y_per_row_flip); 721 DML_LOG_VERBOSE("DML::%s: Tvm_flip = %f (final)\n", __func__, l->Tvm_flip); 722 DML_LOG_VERBOSE("DML::%s: Tr0_flip = %f (final)\n", __func__, l->Tr0_flip); 723 DML_LOG_VERBOSE("DML::%s: Tvm_flip + 2*Tr0_flip = %f (should be <= min_row_time=%f)\n", __func__, l->Tvm_flip + 2 * l->Tr0_flip, l->min_row_time); 724 DML_LOG_VERBOSE("DML::%s: final_flip_bw = %f\n", __func__, *final_flip_bw); 725 DML_LOG_VERBOSE("DML::%s: ImmediateFlipSupportedForPipe = %u\n", __func__, *ImmediateFlipSupportedForPipe); 726 } 727 728 static void dcn6_rq_dlg_get_dlg_reg( 729 struct dml2_core_internal_scratch *s, 730 struct dml2_display_dlg_regs *disp_dlg_regs, 731 struct dml2_display_ttu_regs *disp_ttu_regs, 732 const struct dml2_display_cfg *display_cfg, 733 const struct dml2_core_internal_display_mode_lib *mode_lib, 734 const unsigned int pipe_idx, 735 const struct dml2_utm_soc_bb *utm_soc_bb) 736 { 737 struct dml2_core_shared_rq_dlg_get_dlg_reg_locals *l = &s->rq_dlg_get_dlg_reg_locals; 738 739 memset(l, 0, sizeof(struct dml2_core_shared_rq_dlg_get_dlg_reg_locals)); 740 741 DML_LOG_VERBOSE("DML_DLG::%s: Calculation for pipe_idx=%d\n", __func__, pipe_idx); 742 743 l->plane_idx = mode_lib->mp.pipe_plane[pipe_idx]; 744 l->stream_idx = display_cfg->plane_descriptors[l->plane_idx].stream_index; 745 DML_ASSERT(l->plane_idx < DML2_MAX_PLANES); 746 747 l->source_format = dml2_444_8; 748 l->odm_mode = dml2_odm_mode_bypass; 749 l->dual_plane = false; 750 l->htotal = 0; 751 l->hactive = 0; 752 l->hblank_end = 0; 753 l->vblank_end = 0; 754 l->interlaced = false; 755 l->pclk_freq_in_mhz = 0.0; 756 l->refclk_freq_in_mhz = (display_cfg->overrides.hw.dlg_ref_clk_mhz > 0) ? (double)display_cfg->overrides.hw.dlg_ref_clk_mhz : utm_soc_bb->dchub_refclk_mhz; 757 l->ref_freq_to_pix_freq = 0.0; 758 759 if (l->plane_idx < DML2_MAX_PLANES) { 760 761 l->timing = &display_cfg->stream_descriptors[display_cfg->plane_descriptors[l->plane_idx].stream_index].timing; 762 l->source_format = display_cfg->plane_descriptors[l->plane_idx].pixel_format; 763 l->odm_mode = mode_lib->mp.ODMMode[l->plane_idx]; 764 765 l->dual_plane = dml2_core_utils_is_dual_plane(l->source_format); 766 767 l->htotal = l->timing->h_total; 768 l->hactive = l->timing->h_active; 769 l->hblank_end = l->timing->h_blank_end; 770 l->vblank_end = l->timing->v_blank_end; 771 l->interlaced = l->timing->interlaced; 772 l->pclk_freq_in_mhz = (double)l->timing->pixel_clock_khz / 1000; 773 l->ref_freq_to_pix_freq = l->refclk_freq_in_mhz / l->pclk_freq_in_mhz; 774 775 DML_LOG_VERBOSE("DML_DLG::%s: plane_idx = %d\n", __func__, l->plane_idx); 776 DML_LOG_VERBOSE("DML_DLG: %s: htotal = %d\n", __func__, l->htotal); 777 DML_LOG_VERBOSE("DML_DLG: %s: refclk_freq_in_mhz = %3.2f\n", __func__, l->refclk_freq_in_mhz); 778 DML_LOG_VERBOSE("DML_DLG: %s: dlg_ref_clk_mhz = %3.2f\n", __func__, display_cfg->overrides.hw.dlg_ref_clk_mhz); 779 DML_LOG_VERBOSE("DML_DLG: %s: soc.refclk_mhz = %u\n", __func__, utm_soc_bb->dchub_refclk_mhz); 780 DML_LOG_VERBOSE("DML_DLG: %s: pclk_freq_in_mhz = %3.2f\n", __func__, l->pclk_freq_in_mhz); 781 DML_LOG_VERBOSE("DML_DLG: %s: ref_freq_to_pix_freq = %3.2f\n", __func__, l->ref_freq_to_pix_freq); 782 DML_LOG_VERBOSE("DML_DLG: %s: interlaced = %d\n", __func__, l->interlaced); 783 784 DML_ASSERT(l->refclk_freq_in_mhz != 0); 785 DML_ASSERT(l->pclk_freq_in_mhz != 0); 786 DML_ASSERT(l->ref_freq_to_pix_freq < 4.0); 787 788 // Need to figure out which side of odm combine we're in 789 // Assume the pipe instance under the same plane is in order 790 791 if (l->odm_mode == dml2_odm_mode_bypass) { 792 disp_dlg_regs->refcyc_h_blank_end = (unsigned int)((double)l->hblank_end * l->ref_freq_to_pix_freq); 793 } else if (l->odm_mode == dml2_odm_mode_combine_2to1 || l->odm_mode == dml2_odm_mode_combine_3to1 || l->odm_mode == dml2_odm_mode_combine_4to1) { 794 // find out how many pipe are in this plane 795 l->num_active_pipes = mode_lib->mp.num_active_pipes; 796 l->first_pipe_idx_in_plane = DML2_MAX_PLANES; 797 l->pipe_idx_in_combine = 0; // pipe index within the plane 798 l->odm_combine_factor = 2; 799 800 if (l->odm_mode == dml2_odm_mode_combine_3to1) 801 l->odm_combine_factor = 3; 802 else if (l->odm_mode == dml2_odm_mode_combine_4to1) 803 l->odm_combine_factor = 4; 804 805 for (unsigned int i = 0; i < l->num_active_pipes; i++) { 806 if (mode_lib->mp.pipe_plane[i] == l->plane_idx) { 807 if (i < l->first_pipe_idx_in_plane) { 808 l->first_pipe_idx_in_plane = i; 809 } 810 } 811 } 812 l->pipe_idx_in_combine = pipe_idx - l->first_pipe_idx_in_plane; // DML assumes the pipes in the same plane will have continuous indexing (i.e. plane 0 use pipe 0, 1, and plane 1 uses pipe 2, 3, etc.) 813 814 disp_dlg_regs->refcyc_h_blank_end = (unsigned int)(((double)l->hblank_end + (double)l->pipe_idx_in_combine * (double)l->hactive / (double)l->odm_combine_factor) * l->ref_freq_to_pix_freq); 815 DML_LOG_VERBOSE("DML_DLG: %s: pipe_idx = %d\n", __func__, pipe_idx); 816 DML_LOG_VERBOSE("DML_DLG: %s: first_pipe_idx_in_plane = %d\n", __func__, l->first_pipe_idx_in_plane); 817 DML_LOG_VERBOSE("DML_DLG: %s: pipe_idx_in_combine = %d\n", __func__, l->pipe_idx_in_combine); 818 DML_LOG_VERBOSE("DML_DLG: %s: odm_combine_factor = %d\n", __func__, l->odm_combine_factor); 819 } 820 DML_LOG_VERBOSE("DML_DLG: %s: refcyc_h_blank_end = %d\n", __func__, disp_dlg_regs->refcyc_h_blank_end); 821 822 DML_ASSERT(disp_dlg_regs->refcyc_h_blank_end < (unsigned int)math_pow(2, 13)); 823 824 disp_dlg_regs->ref_freq_to_pix_freq = (unsigned int)(l->ref_freq_to_pix_freq * math_pow(2, 19)); 825 disp_dlg_regs->refcyc_per_htotal = (unsigned int)(l->ref_freq_to_pix_freq * (double)l->htotal * math_pow(2, 8)); 826 disp_dlg_regs->dlg_vblank_end = l->interlaced ? (l->vblank_end / 2) : l->vblank_end; // 15 bits 827 828 l->min_ttu_vblank = mode_lib->mp.MinTTUVBlank[mode_lib->mp.pipe_plane[pipe_idx]]; 829 l->min_dst_y_next_start = (unsigned int)(mode_lib->mp.MIN_DST_Y_NEXT_START[mode_lib->mp.pipe_plane[pipe_idx]]); 830 831 DML_LOG_VERBOSE("DML_DLG: %s: min_ttu_vblank (us) = %3.2f\n", __func__, l->min_ttu_vblank); 832 DML_LOG_VERBOSE("DML_DLG: %s: min_dst_y_next_start = %d\n", __func__, l->min_dst_y_next_start); 833 DML_LOG_VERBOSE("DML_DLG: %s: ref_freq_to_pix_freq = %3.2f\n", __func__, l->ref_freq_to_pix_freq); 834 835 l->vready_after_vcount0 = (unsigned int)(mode_lib->mp.VREADY_AT_OR_AFTER_VSYNC[mode_lib->mp.pipe_plane[pipe_idx]]); 836 disp_dlg_regs->vready_after_vcount0 = l->vready_after_vcount0; 837 838 DML_LOG_VERBOSE("DML_DLG: %s: vready_after_vcount0 = %d\n", __func__, disp_dlg_regs->vready_after_vcount0); 839 840 l->dst_x_after_scaler = (unsigned int)(mode_lib->mp.DSTXAfterScaler[mode_lib->mp.pipe_plane[pipe_idx]]); 841 l->dst_y_after_scaler = (unsigned int)(mode_lib->mp.DSTYAfterScaler[mode_lib->mp.pipe_plane[pipe_idx]]); 842 843 DML_LOG_VERBOSE("DML_DLG: %s: dst_x_after_scaler = %d\n", __func__, l->dst_x_after_scaler); 844 DML_LOG_VERBOSE("DML_DLG: %s: dst_y_after_scaler = %d\n", __func__, l->dst_y_after_scaler); 845 846 l->dst_y_prefetch = mode_lib->mp.dst_y_prefetch[mode_lib->mp.pipe_plane[pipe_idx]]; 847 l->dst_y_per_vm_vblank = mode_lib->mp.dst_y_per_vm_vblank[mode_lib->mp.pipe_plane[pipe_idx]]; 848 l->dst_y_per_row_vblank = mode_lib->mp.dst_y_per_row_vblank[mode_lib->mp.pipe_plane[pipe_idx]]; 849 l->dst_y_per_vm_flip = mode_lib->mp.dst_y_per_vm_flip[mode_lib->mp.pipe_plane[pipe_idx]]; 850 l->dst_y_per_row_flip = mode_lib->mp.dst_y_per_row_flip[mode_lib->mp.pipe_plane[pipe_idx]]; 851 852 DML_LOG_VERBOSE("DML_DLG: %s: dst_y_prefetch (after rnd) = %3.2f\n", __func__, l->dst_y_prefetch); 853 DML_LOG_VERBOSE("DML_DLG: %s: dst_y_per_vm_flip = %3.2f\n", __func__, l->dst_y_per_vm_flip); 854 DML_LOG_VERBOSE("DML_DLG: %s: dst_y_per_row_flip = %3.2f\n", __func__, l->dst_y_per_row_flip); 855 DML_LOG_VERBOSE("DML_DLG: %s: dst_y_per_vm_vblank = %3.2f\n", __func__, l->dst_y_per_vm_vblank); 856 DML_LOG_VERBOSE("DML_DLG: %s: dst_y_per_row_vblank = %3.2f\n", __func__, l->dst_y_per_row_vblank); 857 858 if (l->dst_y_prefetch > 0 && l->dst_y_per_vm_vblank > 0 && l->dst_y_per_row_vblank > 0) { 859 DML_ASSERT(l->dst_y_prefetch > (l->dst_y_per_vm_vblank + l->dst_y_per_row_vblank)); 860 } 861 862 l->vratio_pre_l = mode_lib->mp.VRatioPrefetchY[mode_lib->mp.pipe_plane[pipe_idx]]; 863 l->vratio_pre_c = mode_lib->mp.VRatioPrefetchC[mode_lib->mp.pipe_plane[pipe_idx]]; 864 865 DML_LOG_VERBOSE("DML_DLG: %s: vratio_pre_l = %3.2f\n", __func__, l->vratio_pre_l); 866 DML_LOG_VERBOSE("DML_DLG: %s: vratio_pre_c = %3.2f\n", __func__, l->vratio_pre_c); 867 868 // Active 869 l->refcyc_per_line_delivery_pre_l = mode_lib->mp.DisplayPipeLineDeliveryTimeLumaPrefetch[mode_lib->mp.pipe_plane[pipe_idx]] * l->refclk_freq_in_mhz; 870 l->refcyc_per_line_delivery_l = mode_lib->mp.DisplayPipeLineDeliveryTimeLuma[mode_lib->mp.pipe_plane[pipe_idx]] * l->refclk_freq_in_mhz; 871 872 DML_LOG_VERBOSE("DML_DLG: %s: refcyc_per_line_delivery_pre_l = %3.2f\n", __func__, l->refcyc_per_line_delivery_pre_l); 873 DML_LOG_VERBOSE("DML_DLG: %s: refcyc_per_line_delivery_l = %3.2f\n", __func__, l->refcyc_per_line_delivery_l); 874 875 l->refcyc_per_line_delivery_pre_c = 0.0; 876 l->refcyc_per_line_delivery_c = 0.0; 877 878 if (l->dual_plane) { 879 l->refcyc_per_line_delivery_pre_c = mode_lib->mp.DisplayPipeLineDeliveryTimeChromaPrefetch[mode_lib->mp.pipe_plane[pipe_idx]] * l->refclk_freq_in_mhz; 880 l->refcyc_per_line_delivery_c = mode_lib->mp.DisplayPipeLineDeliveryTimeChroma[mode_lib->mp.pipe_plane[pipe_idx]] * l->refclk_freq_in_mhz; 881 882 DML_LOG_VERBOSE("DML_DLG: %s: refcyc_per_line_delivery_pre_c = %3.2f\n", __func__, l->refcyc_per_line_delivery_pre_c); 883 DML_LOG_VERBOSE("DML_DLG: %s: refcyc_per_line_delivery_c = %3.2f\n", __func__, l->refcyc_per_line_delivery_c); 884 } 885 886 disp_dlg_regs->refcyc_per_vm_dmdata = (unsigned int)(mode_lib->mp.Tdmdl_vm[mode_lib->mp.pipe_plane[pipe_idx]] * l->refclk_freq_in_mhz); 887 disp_dlg_regs->dmdata_dl_delta = (unsigned int)(mode_lib->mp.Tdmdl[mode_lib->mp.pipe_plane[pipe_idx]] * l->refclk_freq_in_mhz); 888 889 l->refcyc_per_req_delivery_pre_l = mode_lib->mp.DisplayPipeRequestDeliveryTimeLumaPrefetch[mode_lib->mp.pipe_plane[pipe_idx]] * l->refclk_freq_in_mhz; 890 l->refcyc_per_req_delivery_l = mode_lib->mp.DisplayPipeRequestDeliveryTimeLuma[mode_lib->mp.pipe_plane[pipe_idx]] * l->refclk_freq_in_mhz; 891 892 DML_LOG_VERBOSE("DML_DLG: %s: refcyc_per_req_delivery_pre_l = %3.2f\n", __func__, l->refcyc_per_req_delivery_pre_l); 893 DML_LOG_VERBOSE("DML_DLG: %s: refcyc_per_req_delivery_l = %3.2f\n", __func__, l->refcyc_per_req_delivery_l); 894 895 l->refcyc_per_req_delivery_pre_c = 0.0; 896 l->refcyc_per_req_delivery_c = 0.0; 897 if (l->dual_plane) { 898 l->refcyc_per_req_delivery_pre_c = mode_lib->mp.DisplayPipeRequestDeliveryTimeChromaPrefetch[mode_lib->mp.pipe_plane[pipe_idx]] * l->refclk_freq_in_mhz; 899 l->refcyc_per_req_delivery_c = mode_lib->mp.DisplayPipeRequestDeliveryTimeChroma[mode_lib->mp.pipe_plane[pipe_idx]] * l->refclk_freq_in_mhz; 900 901 DML_LOG_VERBOSE("DML_DLG: %s: refcyc_per_req_delivery_pre_c = %3.2f\n", __func__, l->refcyc_per_req_delivery_pre_c); 902 DML_LOG_VERBOSE("DML_DLG: %s: refcyc_per_req_delivery_c = %3.2f\n", __func__, l->refcyc_per_req_delivery_c); 903 } 904 905 // TTU - Cursor 906 DML_ASSERT(display_cfg->plane_descriptors[l->plane_idx].cursor.num_cursors <= 1); 907 908 // Assign to register structures 909 disp_dlg_regs->min_dst_y_next_start = (unsigned int)((double)l->min_dst_y_next_start * math_pow(2, 2)); 910 DML_ASSERT(disp_dlg_regs->min_dst_y_next_start < (unsigned int)math_pow(2, 18)); 911 912 disp_dlg_regs->dst_y_after_scaler = l->dst_y_after_scaler; // in terms of line 913 disp_dlg_regs->refcyc_x_after_scaler = (unsigned int)((double)l->dst_x_after_scaler * l->ref_freq_to_pix_freq); // in terms of refclk 914 disp_dlg_regs->dst_y_prefetch = (unsigned int)(l->dst_y_prefetch * math_pow(2, 2)); 915 disp_dlg_regs->dst_y_per_vm_vblank = (unsigned int)(l->dst_y_per_vm_vblank * math_pow(2, 2)); 916 disp_dlg_regs->dst_y_per_row_vblank = (unsigned int)(l->dst_y_per_row_vblank * math_pow(2, 2)); 917 disp_dlg_regs->dst_y_per_vm_flip = (unsigned int)(l->dst_y_per_vm_flip * math_pow(2, 2)); 918 disp_dlg_regs->dst_y_per_row_flip = (unsigned int)(l->dst_y_per_row_flip * math_pow(2, 2)); 919 920 disp_dlg_regs->vratio_prefetch = (unsigned int)(l->vratio_pre_l * math_pow(2, 19)); 921 disp_dlg_regs->vratio_prefetch_c = (unsigned int)(l->vratio_pre_c * math_pow(2, 19)); 922 923 DML_LOG_VERBOSE("DML_DLG: %s: disp_dlg_regs->dst_y_per_vm_vblank = 0x%x\n", __func__, disp_dlg_regs->dst_y_per_vm_vblank); 924 DML_LOG_VERBOSE("DML_DLG: %s: disp_dlg_regs->dst_y_per_row_vblank = 0x%x\n", __func__, disp_dlg_regs->dst_y_per_row_vblank); 925 DML_LOG_VERBOSE("DML_DLG: %s: disp_dlg_regs->dst_y_per_vm_flip = 0x%x\n", __func__, disp_dlg_regs->dst_y_per_vm_flip); 926 DML_LOG_VERBOSE("DML_DLG: %s: disp_dlg_regs->dst_y_per_row_flip = 0x%x\n", __func__, disp_dlg_regs->dst_y_per_row_flip); 927 928 disp_dlg_regs->refcyc_per_vm_group_vblank = (unsigned int)(mode_lib->mp.TimePerVMGroupVBlank[mode_lib->mp.pipe_plane[pipe_idx]] * l->refclk_freq_in_mhz); 929 disp_dlg_regs->refcyc_per_vm_group_flip = (unsigned int)(mode_lib->mp.TimePerVMGroupFlip[mode_lib->mp.pipe_plane[pipe_idx]] * l->refclk_freq_in_mhz); 930 disp_dlg_regs->refcyc_per_vm_req_vblank = (unsigned int)(mode_lib->mp.TimePerVMRequestVBlank[mode_lib->mp.pipe_plane[pipe_idx]] * l->refclk_freq_in_mhz * math_pow(2, 10)); 931 disp_dlg_regs->refcyc_per_vm_req_flip = (unsigned int)(mode_lib->mp.TimePerVMRequestFlip[mode_lib->mp.pipe_plane[pipe_idx]] * l->refclk_freq_in_mhz * math_pow(2, 10)); 932 933 l->dst_y_per_pte_row_nom_l = mode_lib->mp.DST_Y_PER_PTE_ROW_NOM_L[mode_lib->mp.pipe_plane[pipe_idx]]; 934 l->dst_y_per_pte_row_nom_c = mode_lib->mp.DST_Y_PER_PTE_ROW_NOM_C[mode_lib->mp.pipe_plane[pipe_idx]]; 935 l->refcyc_per_pte_group_nom_l = mode_lib->mp.time_per_pte_group_nom_luma[mode_lib->mp.pipe_plane[pipe_idx]] * l->refclk_freq_in_mhz; 936 l->refcyc_per_pte_group_nom_c = mode_lib->mp.time_per_pte_group_nom_chroma[mode_lib->mp.pipe_plane[pipe_idx]] * l->refclk_freq_in_mhz; 937 l->refcyc_per_pte_group_vblank_l = mode_lib->mp.time_per_pte_group_vblank_luma[mode_lib->mp.pipe_plane[pipe_idx]] * l->refclk_freq_in_mhz; 938 l->refcyc_per_pte_group_vblank_c = mode_lib->mp.time_per_pte_group_vblank_chroma[mode_lib->mp.pipe_plane[pipe_idx]] * l->refclk_freq_in_mhz; 939 l->refcyc_per_pte_group_flip_l = mode_lib->mp.time_per_pte_group_flip_luma[mode_lib->mp.pipe_plane[pipe_idx]] * l->refclk_freq_in_mhz; 940 l->refcyc_per_pte_group_flip_c = mode_lib->mp.time_per_pte_group_flip_chroma[mode_lib->mp.pipe_plane[pipe_idx]] * l->refclk_freq_in_mhz; 941 l->refcyc_per_tdlut_group = mode_lib->mp.time_per_tdlut_group[mode_lib->mp.pipe_plane[pipe_idx]] * l->refclk_freq_in_mhz; 942 943 disp_dlg_regs->dst_y_per_pte_row_nom_l = (unsigned int)(l->dst_y_per_pte_row_nom_l * math_pow(2, 2)); 944 disp_dlg_regs->dst_y_per_pte_row_nom_c = (unsigned int)(l->dst_y_per_pte_row_nom_c * math_pow(2, 2)); 945 946 disp_dlg_regs->refcyc_per_pte_group_nom_l = (unsigned int)(l->refcyc_per_pte_group_nom_l); 947 disp_dlg_regs->refcyc_per_pte_group_nom_c = (unsigned int)(l->refcyc_per_pte_group_nom_c); 948 disp_dlg_regs->refcyc_per_pte_group_vblank_l = (unsigned int)(l->refcyc_per_pte_group_vblank_l); 949 disp_dlg_regs->refcyc_per_pte_group_vblank_c = (unsigned int)(l->refcyc_per_pte_group_vblank_c); 950 disp_dlg_regs->refcyc_per_pte_group_flip_l = (unsigned int)(l->refcyc_per_pte_group_flip_l); 951 disp_dlg_regs->refcyc_per_pte_group_flip_c = (unsigned int)(l->refcyc_per_pte_group_flip_c); 952 disp_dlg_regs->refcyc_per_line_delivery_pre_l = (unsigned int)math_floor2(l->refcyc_per_line_delivery_pre_l, 1); 953 disp_dlg_regs->refcyc_per_line_delivery_l = (unsigned int)math_floor2(l->refcyc_per_line_delivery_l, 1); 954 disp_dlg_regs->refcyc_per_line_delivery_pre_c = (unsigned int)math_floor2(l->refcyc_per_line_delivery_pre_c, 1); 955 disp_dlg_regs->refcyc_per_line_delivery_c = (unsigned int)math_floor2(l->refcyc_per_line_delivery_c, 1); 956 957 l->dst_y_per_meta_row_nom_l = mode_lib->mp.DST_Y_PER_META_ROW_NOM_L[mode_lib->mp.pipe_plane[pipe_idx]]; 958 l->dst_y_per_meta_row_nom_c = mode_lib->mp.DST_Y_PER_META_ROW_NOM_C[mode_lib->mp.pipe_plane[pipe_idx]]; 959 l->refcyc_per_meta_chunk_nom_l = mode_lib->mp.TimePerMetaChunkNominal[mode_lib->mp.pipe_plane[pipe_idx]] * l->refclk_freq_in_mhz; 960 l->refcyc_per_meta_chunk_nom_c = mode_lib->mp.TimePerChromaMetaChunkNominal[mode_lib->mp.pipe_plane[pipe_idx]] * l->refclk_freq_in_mhz; 961 l->refcyc_per_meta_chunk_vblank_l = mode_lib->mp.TimePerMetaChunkVBlank[mode_lib->mp.pipe_plane[pipe_idx]] * l->refclk_freq_in_mhz; 962 l->refcyc_per_meta_chunk_vblank_c = mode_lib->mp.TimePerChromaMetaChunkVBlank[mode_lib->mp.pipe_plane[pipe_idx]] * l->refclk_freq_in_mhz; 963 l->refcyc_per_meta_chunk_flip_l = mode_lib->mp.TimePerMetaChunkFlip[mode_lib->mp.pipe_plane[pipe_idx]] * l->refclk_freq_in_mhz; 964 l->refcyc_per_meta_chunk_flip_c = mode_lib->mp.TimePerChromaMetaChunkFlip[mode_lib->mp.pipe_plane[pipe_idx]] * l->refclk_freq_in_mhz; 965 966 disp_dlg_regs->dst_y_per_meta_row_nom_l = (unsigned int)(l->dst_y_per_meta_row_nom_l * math_pow(2, 2)); 967 disp_dlg_regs->dst_y_per_meta_row_nom_c = (unsigned int)(l->dst_y_per_meta_row_nom_c * math_pow(2, 2)); 968 disp_dlg_regs->refcyc_per_meta_chunk_nom_l = (unsigned int)(l->refcyc_per_meta_chunk_nom_l); 969 disp_dlg_regs->refcyc_per_meta_chunk_nom_c = (unsigned int)(l->refcyc_per_meta_chunk_nom_c); 970 disp_dlg_regs->refcyc_per_meta_chunk_vblank_l = (unsigned int)(l->refcyc_per_meta_chunk_vblank_l); 971 disp_dlg_regs->refcyc_per_meta_chunk_vblank_c = (unsigned int)(l->refcyc_per_meta_chunk_vblank_c); 972 disp_dlg_regs->refcyc_per_meta_chunk_flip_l = (unsigned int)(l->refcyc_per_meta_chunk_flip_l); 973 disp_dlg_regs->refcyc_per_meta_chunk_flip_c = (unsigned int)(l->refcyc_per_meta_chunk_flip_c); 974 975 disp_dlg_regs->refcyc_per_tdlut_group = (unsigned int)(l->refcyc_per_tdlut_group); 976 977 /* Assign drq limit based on alt-channel enabled or not */ 978 if (display_cfg->plane_descriptors[l->plane_idx].overrides.uclk_pstate_change_strategy == dml2_uclk_pstate_change_strategy_force_alternate) { 979 disp_dlg_regs->dst_y_delta_drq_limit = mode_lib->mp.nom_req_limit_alt[l->stream_idx]; 980 disp_dlg_regs->dst_y_svp_drq_limit = mode_lib->mp.svp_req_limit[l->stream_idx]; 981 disp_dlg_regs->force_prefetch_to_vblank = 1; // For alt-channel, always force disp prefetch to vblank 982 disp_dlg_regs->force_cursor_to_disp_pref = 1; // For alt-channel, always force cursor to disp prefetch 983 } else { 984 disp_dlg_regs->dst_y_delta_drq_limit = 0x7fff; // off 985 disp_dlg_regs->dst_y_svp_drq_limit = 0x7fff; // off 986 disp_dlg_regs->force_prefetch_to_vblank = 0; // off 987 disp_dlg_regs->force_cursor_to_disp_pref = 0; // off 988 } 989 990 disp_ttu_regs->refcyc_per_req_delivery_pre_l = (unsigned int)(l->refcyc_per_req_delivery_pre_l * math_pow(2, 10)); 991 disp_ttu_regs->refcyc_per_req_delivery_l = (unsigned int)(l->refcyc_per_req_delivery_l * math_pow(2, 10)); 992 disp_ttu_regs->refcyc_per_req_delivery_pre_c = (unsigned int)(l->refcyc_per_req_delivery_pre_c * math_pow(2, 10)); 993 disp_ttu_regs->refcyc_per_req_delivery_c = (unsigned int)(l->refcyc_per_req_delivery_c * math_pow(2, 10)); 994 disp_ttu_regs->qos_level_low_wm = 0; 995 996 disp_ttu_regs->qos_level_high_wm = (unsigned int)(4.0 * (double)l->htotal * l->ref_freq_to_pix_freq); 997 998 disp_ttu_regs->qos_level_flip = 14; 999 disp_ttu_regs->qos_level_fixed_l = 8; 1000 disp_ttu_regs->qos_level_fixed_c = 8; 1001 disp_ttu_regs->qos_ramp_disable_l = 0; 1002 disp_ttu_regs->qos_ramp_disable_c = 0; 1003 disp_ttu_regs->min_ttu_vblank = (unsigned int)(l->min_ttu_vblank * l->refclk_freq_in_mhz); 1004 1005 // CHECK for HW registers' range, DML_ASSERT or clamp 1006 DML_ASSERT(l->refcyc_per_req_delivery_pre_l < math_pow(2, 13)); 1007 DML_ASSERT(l->refcyc_per_req_delivery_l < math_pow(2, 13)); 1008 DML_ASSERT(l->refcyc_per_req_delivery_pre_c < math_pow(2, 13)); 1009 DML_ASSERT(l->refcyc_per_req_delivery_c < math_pow(2, 13)); 1010 if (disp_dlg_regs->refcyc_per_vm_group_vblank >= (unsigned int)math_pow(2, 23)) 1011 disp_dlg_regs->refcyc_per_vm_group_vblank = (unsigned int)(math_pow(2, 23) - 1); 1012 1013 if (disp_dlg_regs->refcyc_per_vm_group_flip >= (unsigned int)math_pow(2, 23)) 1014 disp_dlg_regs->refcyc_per_vm_group_flip = (unsigned int)(math_pow(2, 23) - 1); 1015 1016 if (disp_dlg_regs->refcyc_per_vm_req_vblank >= (unsigned int)math_pow(2, 23)) 1017 disp_dlg_regs->refcyc_per_vm_req_vblank = (unsigned int)(math_pow(2, 23) - 1); 1018 1019 if (disp_dlg_regs->refcyc_per_vm_req_flip >= (unsigned int)math_pow(2, 23)) 1020 disp_dlg_regs->refcyc_per_vm_req_flip = (unsigned int)(math_pow(2, 23) - 1); 1021 1022 1023 DML_ASSERT(disp_dlg_regs->dst_y_after_scaler < (unsigned int)8); 1024 DML_ASSERT(disp_dlg_regs->refcyc_x_after_scaler < (unsigned int)math_pow(2, 13)); 1025 1026 if (disp_dlg_regs->dst_y_per_pte_row_nom_l >= (unsigned int)math_pow(2, 17)) { 1027 DML_LOG_VERBOSE("DML_DLG: %s: Warning DST_Y_PER_PTE_ROW_NOM_L %u > register max U15.2 %u, clamp to max\n", __func__, disp_dlg_regs->dst_y_per_pte_row_nom_l, (unsigned int)math_pow(2, 17) - 1); 1028 l->dst_y_per_pte_row_nom_l = (unsigned int)math_pow(2, 17) - 1; 1029 } 1030 if (l->dual_plane) { 1031 if (disp_dlg_regs->dst_y_per_pte_row_nom_c >= (unsigned int)math_pow(2, 17)) { 1032 DML_LOG_VERBOSE("DML_DLG: %s: Warning DST_Y_PER_PTE_ROW_NOM_C %u > register max U15.2 %u, clamp to max\n", __func__, disp_dlg_regs->dst_y_per_pte_row_nom_c, (unsigned int)math_pow(2, 17) - 1); 1033 l->dst_y_per_pte_row_nom_c = (unsigned int)math_pow(2, 17) - 1; 1034 } 1035 } 1036 1037 if (disp_dlg_regs->refcyc_per_pte_group_nom_l >= (unsigned int)math_pow(2, 23)) 1038 disp_dlg_regs->refcyc_per_pte_group_nom_l = (unsigned int)(math_pow(2, 23) - 1); 1039 if (l->dual_plane) { 1040 if (disp_dlg_regs->refcyc_per_pte_group_nom_c >= (unsigned int)math_pow(2, 23)) 1041 disp_dlg_regs->refcyc_per_pte_group_nom_c = (unsigned int)(math_pow(2, 23) - 1); 1042 } 1043 DML_ASSERT(disp_dlg_regs->refcyc_per_pte_group_vblank_l < (unsigned int)math_pow(2, 13)); 1044 if (l->dual_plane) { 1045 DML_ASSERT(disp_dlg_regs->refcyc_per_pte_group_vblank_c < (unsigned int)math_pow(2, 13)); 1046 } 1047 1048 DML_ASSERT(disp_dlg_regs->refcyc_per_line_delivery_pre_l < (unsigned int)math_pow(2, 13)); 1049 DML_ASSERT(disp_dlg_regs->refcyc_per_line_delivery_l < (unsigned int)math_pow(2, 13)); 1050 DML_ASSERT(disp_dlg_regs->refcyc_per_line_delivery_pre_c < (unsigned int)math_pow(2, 13)); 1051 DML_ASSERT(disp_dlg_regs->refcyc_per_line_delivery_c < (unsigned int)math_pow(2, 13)); 1052 DML_ASSERT(disp_ttu_regs->qos_level_low_wm < (unsigned int)math_pow(2, 14)); 1053 DML_ASSERT(disp_ttu_regs->qos_level_high_wm < (unsigned int)math_pow(2, 14)); 1054 DML_ASSERT(disp_ttu_regs->min_ttu_vblank < (unsigned int)math_pow(2, 24)); 1055 DML_LOG_VERBOSE("DML_DLG::%s: Calculation for pipe[%d] done\n", __func__, pipe_idx); 1056 } 1057 } 1058 1059 static void dcn6_rq_dlg_get_wm_regs(const struct dml2_display_cfg *display_cfg, const struct dml2_core_internal_display_mode_lib *mode_lib, const struct dml2_utm_soc_bb *utm_soc_bb, struct dml2_dchub_watermark_regs *wm_regs) 1060 { 1061 double refclk_freq_in_mhz = (display_cfg->overrides.hw.dlg_ref_clk_mhz > 0) ? (double)display_cfg->overrides.hw.dlg_ref_clk_mhz : utm_soc_bb->dchub_refclk_mhz; 1062 1063 wm_regs->fclk_pstate = (int unsigned)(mode_lib->mp.Watermark.FCLKChangeWatermark * refclk_freq_in_mhz); 1064 wm_regs->sr_enter = (int unsigned)(mode_lib->mp.Watermark.StutterEnterPlusExitWatermark * refclk_freq_in_mhz); 1065 wm_regs->sr_exit = (int unsigned)(mode_lib->mp.Watermark.StutterExitWatermark * refclk_freq_in_mhz); 1066 wm_regs->sr_enter_z8 = (int unsigned)(mode_lib->mp.Watermark.Z8StutterEnterPlusExitWatermark * refclk_freq_in_mhz); 1067 wm_regs->sr_exit_z8 = (int unsigned)(mode_lib->mp.Watermark.Z8StutterExitWatermark * refclk_freq_in_mhz); 1068 wm_regs->sr_enter_low_power = (int unsigned)(mode_lib->mp.Watermark.LowPowerStutterEnterPlusExitWatermark * refclk_freq_in_mhz); 1069 wm_regs->sr_exit_low_power = (int unsigned)(mode_lib->mp.Watermark.LowPowerStutterExitWatermark * refclk_freq_in_mhz); 1070 wm_regs->temp_read_or_ppt = (int unsigned)(mode_lib->mp.Watermark.temp_read_or_ppt_watermark_us * refclk_freq_in_mhz); 1071 wm_regs->ppt = (int unsigned)(mode_lib->mp.Watermark.temp_read_or_ppt_watermark_us * refclk_freq_in_mhz); 1072 wm_regs->uclk_pstate = (int unsigned)(mode_lib->mp.Watermark.DRAMClockChangeWatermark * refclk_freq_in_mhz); 1073 wm_regs->urgent = (int unsigned)(mode_lib->mp.Watermark.UrgentWatermark * refclk_freq_in_mhz); 1074 wm_regs->usr = (int unsigned)(mode_lib->mp.Watermark.USRRetrainingWatermark * refclk_freq_in_mhz); 1075 wm_regs->refcyc_per_trip_to_mem = (unsigned int)(mode_lib->mp.UrgentLatency * refclk_freq_in_mhz); 1076 wm_regs->refcyc_per_meta_trip_to_mem = (unsigned int)(mode_lib->mp.MetaTripToMemory * refclk_freq_in_mhz); 1077 wm_regs->frac_urg_bw_flip = (unsigned int)(mode_lib->mp.FractionOfUrgentBandwidthImmediateFlip * 1000); 1078 wm_regs->frac_urg_bw_nom = (unsigned int)(mode_lib->mp.FractionOfUrgentBandwidth * 1000); 1079 } 1080 1081 void dcn6_get_pipe_regs(const struct dml2_display_cfg *display_cfg, 1082 const struct dml2_core_internal_display_mode_lib *mode_lib, 1083 struct dml2_dchub_per_pipe_register_set *out, int pipe_index, 1084 const struct dml2_utm_soc_bb *utm_soc_bb, 1085 struct dml2_core_internal_scratch *s) 1086 { 1087 dcn5_rq_dlg_get_rq_reg(&out->rq_regs, display_cfg, mode_lib, pipe_index); 1088 dcn6_rq_dlg_get_dlg_reg(s, &out->dlg_regs, &out->ttu_regs, display_cfg, mode_lib, pipe_index, utm_soc_bb); 1089 out->det_size = mode_lib->mp.DETBufferSizeInKByte[mode_lib->mp.pipe_plane[pipe_index]] / mode_lib->ip.config_return_buffer_segment_size_in_kbytes; 1090 } 1091 1092 static bool dcn6_calculate_pstate_support_method( 1093 enum dml2_pstate_method method, 1094 double peak_vactive_p_vblank_latency_hiding_margin_us, 1095 double vactive_margin_us, 1096 double reserved_vblank_us, 1097 double blackout_us, 1098 bool all_streams_blanked, 1099 /* output */ 1100 enum dml2_pstate_change_support *surface_pstate_change_support) 1101 { 1102 *surface_pstate_change_support = dml2_pstate_change_unsupported; 1103 if (method == dml2_pstate_method_na) { 1104 /* automatic */ 1105 if (all_streams_blanked || 1106 (vactive_margin_us > 0 && reserved_vblank_us >= blackout_us)) 1107 *surface_pstate_change_support = dml2_pstate_change_vblank_and_vactive; 1108 else if (vactive_margin_us > 0) 1109 *surface_pstate_change_support = dml2_pstate_change_vactive; 1110 else if (reserved_vblank_us >= blackout_us) 1111 *surface_pstate_change_support = dml2_pstate_change_vblank; 1112 } else if (method == dml2_pstate_method_vactive || method == dml2_pstate_method_fw_vactive_drr) { 1113 /* vactive */ 1114 if (all_streams_blanked || 1115 (vactive_margin_us > 0 && reserved_vblank_us >= blackout_us)) 1116 *surface_pstate_change_support = dml2_pstate_change_vblank_and_vactive; 1117 else if (vactive_margin_us > 0 || peak_vactive_p_vblank_latency_hiding_margin_us > 0) 1118 *surface_pstate_change_support = dml2_pstate_change_vactive; 1119 } else if ((method == dml2_pstate_method_vblank || method == dml2_pstate_method_fw_vblank_drr) && 1120 reserved_vblank_us >= blackout_us) { 1121 /* vblank */ 1122 *surface_pstate_change_support = dml2_pstate_change_vblank; 1123 } else if (method == dml2_pstate_method_fw_drr) { 1124 /* drr */ 1125 *surface_pstate_change_support = dml2_pstate_change_drr; 1126 } else if (method == dml2_pstate_method_alternate) { 1127 /* TODO - alternate */ 1128 *surface_pstate_change_support = dml2_pstate_change_mall_svp; 1129 } 1130 1131 return *surface_pstate_change_support != dml2_pstate_change_unsupported; 1132 } 1133 1134 void dcn6_calculate_watermarks_and_dram_speed_change_support( 1135 struct dml2_core_internal_scratch *scratch, 1136 struct dml2_core_calcs_CalculateWatermarksMALLUseAndDRAMSpeedChangeSupport_params *p) 1137 { 1138 struct dml2_core_calcs_CalculateWatermarksMALLUseAndDRAMSpeedChangeSupport_locals *s = &scratch->CalculateWatermarksMALLUseAndDRAMSpeedChangeSupport_locals; 1139 1140 double reserved_vblank_time_us; 1141 bool FoundCriticalSurface = false; 1142 1143 s->TotalActiveWriteback = 0; 1144 p->Watermark->UrgentWatermark = p->mmSOCParameters.UrgentLatency + p->mmSOCParameters.ExtraLatency; 1145 1146 DML_LOG_VERBOSE("DML::%s: UrgentLatency = %f\n", __func__, p->mmSOCParameters.UrgentLatency); 1147 DML_LOG_VERBOSE("DML::%s: ExtraLatency = %f\n", __func__, p->mmSOCParameters.ExtraLatency); 1148 DML_LOG_VERBOSE("DML::%s: UrgentWatermark = %f\n", __func__, p->Watermark->UrgentWatermark); 1149 1150 p->Watermark->USRRetrainingWatermark = p->mmSOCParameters.UrgentLatency + p->mmSOCParameters.ExtraLatency + p->mmSOCParameters.USRRetrainingLatency + p->mmSOCParameters.SMNLatency; 1151 p->Watermark->DRAMClockChangeWatermark = p->mmSOCParameters.DRAMClockChangeLatency + p->Watermark->UrgentWatermark; 1152 p->Watermark->FCLKChangeWatermark = p->mmSOCParameters.FCLKChangeLatency + p->Watermark->UrgentWatermark; 1153 p->Watermark->StutterExitWatermark = p->mmSOCParameters.SRExitTime + p->mmSOCParameters.ExtraLatency_sr + 10 / p->DCFClkDeepSleep; 1154 p->Watermark->StutterEnterPlusExitWatermark = p->mmSOCParameters.SREnterPlusExitTime + p->mmSOCParameters.ExtraLatency_sr + 10 / p->DCFClkDeepSleep; 1155 p->Watermark->LowPowerStutterExitWatermark = p->mmSOCParameters.SRExitTimeLowPower + p->mmSOCParameters.ExtraLatency_sr + 10 / p->DCFClkDeepSleep; 1156 p->Watermark->LowPowerStutterEnterPlusExitWatermark = p->mmSOCParameters.SREnterPlusExitTimeLowPower + p->mmSOCParameters.ExtraLatency_sr + 10 / p->DCFClkDeepSleep; 1157 p->Watermark->Z8StutterExitWatermark = p->mmSOCParameters.SRExitZ8Time + p->mmSOCParameters.ExtraLatency_sr + 10 / p->DCFClkDeepSleep; 1158 p->Watermark->Z8StutterEnterPlusExitWatermark = p->mmSOCParameters.SREnterPlusExitZ8Time + p->mmSOCParameters.ExtraLatency_sr + 10 / p->DCFClkDeepSleep; 1159 if (p->mmSOCParameters.qos_type == dml2_qos_param_type_dcn4x) { 1160 p->Watermark->StutterExitWatermark += p->mmSOCParameters.max_urgent_latency_us + p->mmSOCParameters.df_response_time_us; 1161 p->Watermark->StutterEnterPlusExitWatermark += p->mmSOCParameters.max_urgent_latency_us + p->mmSOCParameters.df_response_time_us; 1162 p->Watermark->LowPowerStutterExitWatermark += p->mmSOCParameters.max_urgent_latency_us + p->mmSOCParameters.df_response_time_us; 1163 p->Watermark->LowPowerStutterEnterPlusExitWatermark += p->mmSOCParameters.max_urgent_latency_us + p->mmSOCParameters.df_response_time_us; 1164 p->Watermark->Z8StutterExitWatermark += p->mmSOCParameters.max_urgent_latency_us + p->mmSOCParameters.df_response_time_us; 1165 p->Watermark->Z8StutterEnterPlusExitWatermark += p->mmSOCParameters.max_urgent_latency_us + p->mmSOCParameters.df_response_time_us; 1166 } 1167 p->Watermark->temp_read_or_ppt_watermark_us = p->mmSOCParameters.temp_read_or_ppt_blackout_us + p->Watermark->UrgentWatermark; 1168 1169 DML_LOG_VERBOSE("DML::%s: UrgentLatency = %f\n", __func__, p->mmSOCParameters.UrgentLatency); 1170 DML_LOG_VERBOSE("DML::%s: ExtraLatency = %f\n", __func__, p->mmSOCParameters.ExtraLatency); 1171 DML_LOG_VERBOSE("DML::%s: DRAMClockChangeLatency = %f\n", __func__, p->mmSOCParameters.DRAMClockChangeLatency); 1172 DML_LOG_VERBOSE("DML::%s: SREnterPlusExitZ8Time = %f\n", __func__, p->mmSOCParameters.SREnterPlusExitZ8Time); 1173 DML_LOG_VERBOSE("DML::%s: SREnterPlusExitTime = %f\n", __func__, p->mmSOCParameters.SREnterPlusExitTime); 1174 DML_LOG_VERBOSE("DML::%s: UrgentWatermark = %f\n", __func__, p->Watermark->UrgentWatermark); 1175 DML_LOG_VERBOSE("DML::%s: USRRetrainingWatermark = %f\n", __func__, p->Watermark->USRRetrainingWatermark); 1176 DML_LOG_VERBOSE("DML::%s: DRAMClockChangeWatermark = %f\n", __func__, p->Watermark->DRAMClockChangeWatermark); 1177 DML_LOG_VERBOSE("DML::%s: FCLKChangeWatermark = %f\n", __func__, p->Watermark->FCLKChangeWatermark); 1178 DML_LOG_VERBOSE("DML::%s: StutterExitWatermark = %f\n", __func__, p->Watermark->StutterExitWatermark); 1179 DML_LOG_VERBOSE("DML::%s: StutterEnterPlusExitWatermark = %f\n", __func__, p->Watermark->StutterEnterPlusExitWatermark); 1180 DML_LOG_VERBOSE("DML::%s: Z8StutterExitWatermark = %f\n", __func__, p->Watermark->Z8StutterExitWatermark); 1181 DML_LOG_VERBOSE("DML::%s: Z8StutterEnterPlusExitWatermark = %f\n", __func__, p->Watermark->Z8StutterEnterPlusExitWatermark); 1182 DML_LOG_VERBOSE("DML::%s: temp_read_or_ppt_watermark_us = %f\n", __func__, p->Watermark->temp_read_or_ppt_watermark_us); 1183 1184 s->TotalActiveWriteback = 0; 1185 for (unsigned int k = 0; k < p->NumberOfActiveSurfaces; ++k) 1186 for (unsigned int j = 0; j < p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].writeback.active_writebacks_per_stream; ++j) 1187 s->TotalActiveWriteback = s->TotalActiveWriteback + 1; 1188 1189 if (s->TotalActiveWriteback <= 1) { 1190 p->Watermark->WritebackUrgentWatermark = p->mmSOCParameters.WritebackLatency; 1191 } else { 1192 p->Watermark->WritebackUrgentWatermark = p->mmSOCParameters.WritebackLatency + p->WritebackChunkSize * 1024.0 / 32.0 / p->SOCCLK; 1193 } 1194 if (p->USRRetrainingRequired) 1195 p->Watermark->WritebackUrgentWatermark = p->Watermark->WritebackUrgentWatermark + p->mmSOCParameters.USRRetrainingLatency; 1196 1197 if (s->TotalActiveWriteback <= 1) { 1198 p->Watermark->WritebackDRAMClockChangeWatermark = p->mmSOCParameters.DRAMClockChangeLatency + p->mmSOCParameters.WritebackLatency; 1199 p->Watermark->WritebackFCLKChangeWatermark = p->mmSOCParameters.FCLKChangeLatency + p->mmSOCParameters.WritebackLatency; 1200 } else { 1201 p->Watermark->WritebackDRAMClockChangeWatermark = p->mmSOCParameters.DRAMClockChangeLatency + p->mmSOCParameters.WritebackLatency + p->WritebackChunkSize * 1024.0 / 32.0 / p->SOCCLK; 1202 p->Watermark->WritebackFCLKChangeWatermark = p->mmSOCParameters.FCLKChangeLatency + p->mmSOCParameters.WritebackLatency + p->WritebackChunkSize * 1024 / 32 / p->SOCCLK; 1203 } 1204 1205 if (p->USRRetrainingRequired) 1206 p->Watermark->WritebackDRAMClockChangeWatermark = p->Watermark->WritebackDRAMClockChangeWatermark + p->mmSOCParameters.USRRetrainingLatency; 1207 1208 if (p->USRRetrainingRequired) 1209 p->Watermark->WritebackFCLKChangeWatermark = p->Watermark->WritebackFCLKChangeWatermark + p->mmSOCParameters.USRRetrainingLatency; 1210 1211 DML_LOG_VERBOSE("DML::%s: WritebackDRAMClockChangeWatermark = %f\n", __func__, p->Watermark->WritebackDRAMClockChangeWatermark); 1212 DML_LOG_VERBOSE("DML::%s: WritebackFCLKChangeWatermark = %f\n", __func__, p->Watermark->WritebackFCLKChangeWatermark); 1213 DML_LOG_VERBOSE("DML::%s: WritebackUrgentWatermark = %f\n", __func__, p->Watermark->WritebackUrgentWatermark); 1214 DML_LOG_VERBOSE("DML::%s: USRRetrainingRequired = %u\n", __func__, p->USRRetrainingRequired); 1215 DML_LOG_VERBOSE("DML::%s: USRRetrainingLatency = %f\n", __func__, p->mmSOCParameters.USRRetrainingLatency); 1216 1217 s->TotalPixelBW = 0.0; 1218 for (unsigned int k = 0; k < p->NumberOfActiveSurfaces; ++k) { 1219 double h_total = (double)p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].timing.h_total; 1220 double pixel_clock_mhz = p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].timing.pixel_clock_khz / 1000.0; 1221 double v_ratio = p->display_cfg->plane_descriptors[k].composition.scaler_info.plane0.v_ratio; 1222 double v_ratio_c = p->display_cfg->plane_descriptors[k].composition.scaler_info.plane1.v_ratio; 1223 s->TotalPixelBW = s->TotalPixelBW + p->DPPPerSurface[k] 1224 * (p->SwathWidthY[k] * p->BytePerPixelDETY[k] * v_ratio + p->SwathWidthC[k] * p->BytePerPixelDETC[k] * v_ratio_c) / (h_total / pixel_clock_mhz); 1225 } 1226 1227 *p->global_fclk_change_supported = true; 1228 *p->global_dram_clock_change_supported = true; 1229 *p->global_temp_read_or_ppt_supported = true; 1230 1231 for (unsigned int k = 0; k < p->NumberOfActiveSurfaces; ++k) { 1232 double h_total = (double)p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].timing.h_total; 1233 double pixel_clock_mhz = p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].timing.pixel_clock_khz / 1000.0; 1234 double v_ratio = p->display_cfg->plane_descriptors[k].composition.scaler_info.plane0.v_ratio; 1235 double v_ratio_c = p->display_cfg->plane_descriptors[k].composition.scaler_info.plane1.v_ratio; 1236 double v_taps = p->display_cfg->plane_descriptors[k].composition.scaler_info.plane0.v_taps; 1237 double v_taps_c = p->display_cfg->plane_descriptors[k].composition.scaler_info.plane1.v_taps; 1238 double h_ratio = p->display_cfg->plane_descriptors[k].composition.scaler_info.plane0.h_ratio; 1239 double h_ratio_c = p->display_cfg->plane_descriptors[k].composition.scaler_info.plane1.h_ratio; 1240 double LBBitPerPixel = 57; 1241 1242 s->LBLatencyHidingSourceLinesY[k] = (unsigned int)(math_min2((double)p->MaxLineBufferLines, math_floor2((double)p->LineBufferSize / LBBitPerPixel / ((double)p->SwathWidthY[k] / math_max2(h_ratio, 1.0)), 1)) - (v_taps - 1)); 1243 s->LBLatencyHidingSourceLinesC[k] = (unsigned int)(math_min2((double)p->MaxLineBufferLines, math_floor2((double)p->LineBufferSize / LBBitPerPixel / ((double)p->SwathWidthC[k] / math_max2(h_ratio_c, 1.0)), 1)) - (v_taps_c - 1)); 1244 1245 DML_LOG_VERBOSE("DML::%s: k=%u, MaxLineBufferLines= %u\n", __func__, k, p->MaxLineBufferLines); 1246 DML_LOG_VERBOSE("DML::%s: k=%u, LineBufferSize = %u\n", __func__, k, p->LineBufferSize); 1247 DML_LOG_VERBOSE("DML::%s: k=%u, LBBitPerPixel = %f\n", __func__, k, LBBitPerPixel); 1248 DML_LOG_VERBOSE("DML::%s: k=%u, HRatio = %f\n", __func__, k, h_ratio); 1249 DML_LOG_VERBOSE("DML::%s: k=%u, VTaps = %f\n", __func__, k, v_taps); 1250 1251 s->EffectiveLBLatencyHidingY = s->LBLatencyHidingSourceLinesY[k] / v_ratio * (h_total / pixel_clock_mhz); 1252 s->EffectiveLBLatencyHidingC = s->LBLatencyHidingSourceLinesC[k] / v_ratio_c * (h_total / pixel_clock_mhz); 1253 1254 s->EffectiveDETBufferSizeY = p->DETBufferSizeY[k]; 1255 if (p->UnboundedRequestEnabled) { 1256 s->EffectiveDETBufferSizeY = s->EffectiveDETBufferSizeY + p->CompressedBufferSizeInkByte * 1024 * (p->SwathWidthY[k] * p->BytePerPixelDETY[k] * v_ratio) / (h_total / pixel_clock_mhz) / s->TotalPixelBW; 1257 } 1258 1259 s->LinesInDETY[k] = (double)s->EffectiveDETBufferSizeY / p->BytePerPixelDETY[k] / p->SwathWidthY[k]; 1260 s->LinesInDETYRoundedDownToSwath[k] = (unsigned int)(math_floor2(s->LinesInDETY[k], p->SwathHeightY[k])); 1261 s->FullDETBufferingTimeY = s->LinesInDETYRoundedDownToSwath[k] * (h_total / pixel_clock_mhz) / v_ratio; 1262 1263 s->ActiveClockChangeLatencyHidingY = s->EffectiveLBLatencyHidingY + s->FullDETBufferingTimeY - ((double)p->DSTXAfterScaler[k] / h_total + (double)p->DSTYAfterScaler[k]) * h_total / pixel_clock_mhz; 1264 1265 if (p->NumberOfActiveSurfaces > 1) { 1266 s->ActiveClockChangeLatencyHidingY = s->ActiveClockChangeLatencyHidingY - (1.0 - 1.0 / (double)p->NumberOfActiveSurfaces) * (double)p->SwathHeightY[k] * (double)h_total / pixel_clock_mhz / v_ratio; 1267 } 1268 1269 if (p->BytePerPixelDETC[k] > 0) { 1270 s->LinesInDETC[k] = p->DETBufferSizeC[k] / p->BytePerPixelDETC[k] / p->SwathWidthC[k]; 1271 s->LinesInDETCRoundedDownToSwath[k] = (unsigned int)(math_floor2(s->LinesInDETC[k], p->SwathHeightC[k])); 1272 s->FullDETBufferingTimeC = s->LinesInDETCRoundedDownToSwath[k] * (h_total / pixel_clock_mhz) / v_ratio_c; 1273 s->ActiveClockChangeLatencyHidingC = s->EffectiveLBLatencyHidingC + s->FullDETBufferingTimeC - ((double)p->DSTXAfterScaler[k] / (double)h_total + (double)p->DSTYAfterScaler[k]) * (double)h_total / pixel_clock_mhz; 1274 if (p->NumberOfActiveSurfaces > 1) { 1275 s->ActiveClockChangeLatencyHidingC = s->ActiveClockChangeLatencyHidingC - (1.0 - 1.0 / (double)p->NumberOfActiveSurfaces) * (double)p->SwathHeightC[k] * (double)h_total / pixel_clock_mhz / v_ratio_c; 1276 } 1277 s->ActiveClockChangeLatencyHiding = math_min2(s->ActiveClockChangeLatencyHidingY, s->ActiveClockChangeLatencyHidingC); 1278 } else { 1279 s->ActiveClockChangeLatencyHiding = s->ActiveClockChangeLatencyHidingY; 1280 } 1281 1282 DML_LOG_VERBOSE("DML::%s: ActiveClockChangeLatencyHidingY = %f\n", __func__, s->ActiveClockChangeLatencyHidingY); 1283 DML_LOG_VERBOSE("DML::%s: ActiveClockChangeLatencyHidingC = %f\n", __func__, s->ActiveClockChangeLatencyHidingC); 1284 DML_LOG_VERBOSE("DML::%s: ActiveClockChangeLatencyHiding = %f\n", __func__, s->ActiveClockChangeLatencyHiding); 1285 1286 reserved_vblank_time_us = (double)p->display_cfg->plane_descriptors[k].overrides.reserved_vblank_time_ns / 1000; 1287 1288 s->ActiveDRAMClockChangeLatencyMargin[k] = s->ActiveClockChangeLatencyHiding - p->Watermark->DRAMClockChangeWatermark; 1289 s->ActiveFCLKChangeLatencyMargin[k] = s->ActiveClockChangeLatencyHiding - p->Watermark->FCLKChangeWatermark; 1290 s->USRRetrainingLatencyMargin[k] = s->ActiveClockChangeLatencyHiding - p->Watermark->USRRetrainingWatermark; 1291 s->temp_read_or_ppt_latency_margin[k] = s->ActiveClockChangeLatencyHiding - p->Watermark->temp_read_or_ppt_watermark_us; 1292 s->peak_vactive_p_vblank_latency_hiding_us = s->ActiveClockChangeLatencyHiding + reserved_vblank_time_us; 1293 1294 DML_LOG_VERBOSE("DML::%s: k=%u, ActiveFCLKChangeLatencyMargin = %f\n", __func__, k, s->ActiveFCLKChangeLatencyMargin[k]); 1295 DML_LOG_VERBOSE("DML::%s: k=%u, ActiveDRAMClockChangeLatencyMargin = %f\n", __func__, k, s->ActiveDRAMClockChangeLatencyMargin[k]); 1296 1297 if (p->VActiveLatencyHidingMargin) { 1298 p->VActiveLatencyHidingMargin[k] = s->ActiveDRAMClockChangeLatencyMargin[k]; 1299 DML_LOG_VERBOSE("DML::%s: k=%u, VActiveLatencyHidingMargin = %f\n", __func__, k, p->VActiveLatencyHidingMargin[k]); 1300 } 1301 1302 if (p->VActiveLatencyHidingUs) { 1303 p->VActiveLatencyHidingUs[k] = s->ActiveClockChangeLatencyHiding; 1304 DML_LOG_VERBOSE("DML::%s: k=%u, VActiveLatencyHidingUs = %f\n", __func__, k, p->VActiveLatencyHidingUs[k]); 1305 } 1306 1307 for (unsigned int j = 0; j < p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].writeback.active_writebacks_per_stream; ++j) { 1308 double byte_per_pixel_luma_in_buffer = 1.0; 1309 double buffer_for_luma = (double)p->WritebackInterfaceBufferSize * 1024.0 / 2.0; 1310 if (p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].writeback.writeback_stream[j].pixel_format == dml2_444_64) { 1311 byte_per_pixel_luma_in_buffer = 8.0; 1312 buffer_for_luma = (double)p->WritebackInterfaceBufferSize * 1024.0; 1313 } else if (p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].writeback.writeback_stream[j].pixel_format == dml2_444_32) { 1314 byte_per_pixel_luma_in_buffer = 4.0; 1315 buffer_for_luma = (double)p->WritebackInterfaceBufferSize * 1024.0; 1316 } else if (p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].writeback.writeback_stream[j].pixel_format == dml2_422_packed_8 1317 || p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].writeback.writeback_stream[j].pixel_format == dml2_420_8) { 1318 byte_per_pixel_luma_in_buffer = 1.0; 1319 buffer_for_luma = (double)p->WritebackInterfaceBufferSize * 1024.0 / 2.0; 1320 } else if (p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].writeback.writeback_stream[j].pixel_format == dml2_422_packed_10 1321 || p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].writeback.writeback_stream[j].pixel_format == dml2_420_10) { 1322 byte_per_pixel_luma_in_buffer = 10.0 / 8.0; 1323 buffer_for_luma = (double)p->WritebackInterfaceBufferSize * 1024.0 / 2.0; 1324 } 1325 1326 s->WritebackLatencyHiding = buffer_for_luma 1327 / ((double)p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].writeback.writeback_stream[j].output_height 1328 * (double)p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].writeback.writeback_stream[j].output_width 1329 / ((double)p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].writeback.writeback_stream[j].input_height 1330 * (double)h_total / pixel_clock_mhz)) / byte_per_pixel_luma_in_buffer; 1331 1332 s->peak_vactive_p_vblank_latency_hiding_us = 0.0; /* not supported with writeback */ 1333 s->WritebackDRAMClockChangeLatencyMargin = s->WritebackLatencyHiding - p->Watermark->WritebackDRAMClockChangeWatermark; 1334 s->WritebackFCLKChangeLatencyMargin = s->WritebackLatencyHiding - p->Watermark->WritebackFCLKChangeWatermark; 1335 s->ActiveDRAMClockChangeLatencyMargin[k] = math_min2(s->ActiveDRAMClockChangeLatencyMargin[k], s->WritebackDRAMClockChangeLatencyMargin); 1336 s->ActiveFCLKChangeLatencyMargin[k] = math_min2(s->ActiveFCLKChangeLatencyMargin[k], s->WritebackFCLKChangeLatencyMargin); 1337 DML_LOG_VERBOSE("DML::%s: k=%u, ActiveFCLKChangeLatencyMargin = %f (WB)\n", __func__, k, s->ActiveFCLKChangeLatencyMargin[k]); 1338 } 1339 1340 p->MaxActiveDRAMClockChangeLatencySupported[k] = s->ActiveDRAMClockChangeLatencyMargin[k] + p->mmSOCParameters.DRAMClockChangeLatency; 1341 1342 *p->global_fclk_change_supported &= dcn6_calculate_pstate_support_method( 1343 dml2_pstate_method_vactive, 1344 s->peak_vactive_p_vblank_latency_hiding_us - p->mmSOCParameters.FCLKChangeLatency, 1345 s->ActiveFCLKChangeLatencyMargin[k], 1346 reserved_vblank_time_us, 1347 p->mmSOCParameters.FCLKChangeLatency, 1348 p->display_cfg->overrides.all_streams_blanked, 1349 /* output */ 1350 &p->FCLKChangeSupport[k]); 1351 1352 *p->global_temp_read_or_ppt_supported &= dcn6_calculate_pstate_support_method( 1353 dml2_pstate_method_vactive, 1354 s->peak_vactive_p_vblank_latency_hiding_us - p->mmSOCParameters.temp_read_or_ppt_blackout_us, 1355 s->temp_read_or_ppt_latency_margin[k], 1356 reserved_vblank_time_us, 1357 p->mmSOCParameters.temp_read_or_ppt_blackout_us, 1358 p->display_cfg->overrides.all_streams_blanked, 1359 /* output */ 1360 &p->temp_read_or_ppt_support[k]); 1361 1362 *p->global_dram_clock_change_support_required |= p->uclk_pstate_switch_modes[k] != dml2_pstate_method_na; 1363 *p->global_dram_clock_change_supported &= dcn6_calculate_pstate_support_method( 1364 p->uclk_pstate_switch_modes[k], 1365 s->peak_vactive_p_vblank_latency_hiding_us - p->mmSOCParameters.DRAMClockChangeLatency, 1366 s->ActiveDRAMClockChangeLatencyMargin[k], 1367 reserved_vblank_time_us, 1368 p->mmSOCParameters.DRAMClockChangeLatency, 1369 p->display_cfg->overrides.all_streams_blanked, 1370 /* output */ 1371 &p->DRAMClockChangeSupport[k]); 1372 1373 s->dst_y_pstate = (unsigned int)(math_ceil2((p->mmSOCParameters.DRAMClockChangeLatency + p->mmSOCParameters.UrgentLatency) / (h_total / pixel_clock_mhz), 1)); 1374 s->src_y_pstate_l = (unsigned int)(math_ceil2(s->dst_y_pstate * v_ratio, p->SwathHeightY[k])); 1375 s->src_y_ahead_l = (unsigned int)(math_floor2(p->DETBufferSizeY[k] / p->BytePerPixelDETY[k] / p->SwathWidthY[k], p->SwathHeightY[k]) + s->LBLatencyHidingSourceLinesY[k]); 1376 1377 DML_LOG_VERBOSE("DML::%s: k=%u, DETBufferSizeY = %u\n", __func__, k, p->DETBufferSizeY[k]); 1378 DML_LOG_VERBOSE("DML::%s: k=%u, BytePerPixelDETY = %f\n", __func__, k, p->BytePerPixelDETY[k]); 1379 DML_LOG_VERBOSE("DML::%s: k=%u, SwathWidthY = %u\n", __func__, k, p->SwathWidthY[k]); 1380 DML_LOG_VERBOSE("DML::%s: k=%u, SwathHeightY = %u\n", __func__, k, p->SwathHeightY[k]); 1381 DML_LOG_VERBOSE("DML::%s: k=%u, LBLatencyHidingSourceLinesY = %u\n", __func__, k, s->LBLatencyHidingSourceLinesY[k]); 1382 DML_LOG_VERBOSE("DML::%s: k=%u, dst_y_pstate = %u\n", __func__, k, s->dst_y_pstate); 1383 DML_LOG_VERBOSE("DML::%s: k=%u, src_y_pstate_l = %u\n", __func__, k, s->src_y_pstate_l); 1384 DML_LOG_VERBOSE("DML::%s: k=%u, src_y_ahead_l = %u\n", __func__, k, s->src_y_ahead_l); 1385 DML_LOG_VERBOSE("DML::%s: k=%u, meta_row_height_l = %u\n", __func__, k, p->meta_row_height_l[k]); 1386 1387 if (p->BytePerPixelDETC[k] > 0) { 1388 s->src_y_pstate_c = (unsigned int)(math_ceil2(s->dst_y_pstate * v_ratio_c, p->SwathHeightC[k])); 1389 s->src_y_ahead_c = (unsigned int)(math_floor2(p->DETBufferSizeC[k] / p->BytePerPixelDETC[k] / p->SwathWidthC[k], p->SwathHeightC[k]) + s->LBLatencyHidingSourceLinesC[k]); 1390 1391 DML_LOG_VERBOSE("DML::%s: k=%u, meta_row_height_c = %u\n", __func__, k, p->meta_row_height_c[k]); 1392 DML_LOG_VERBOSE("DML::%s: k=%u, src_y_pstate_c = %u\n", __func__, k, s->src_y_pstate_c); 1393 DML_LOG_VERBOSE("DML::%s: k=%u, src_y_ahead_c = %u\n", __func__, k, s->src_y_ahead_c); 1394 DML_LOG_VERBOSE("DML::%s: k=%u, sub_vp_lines_c = %u\n", __func__, k, s->sub_vp_lines_c); 1395 } 1396 } 1397 1398 for (unsigned int k = 0; k < p->NumberOfActiveSurfaces; ++k) { 1399 DML_LOG_VERBOSE("DML::%s: k=%u, ActiveFCLKChangeLatencyMargin=%f\n", __func__, k, s->ActiveFCLKChangeLatencyMargin[k]); 1400 if (((!FoundCriticalSurface) || ((s->ActiveFCLKChangeLatencyMargin[k] + p->mmSOCParameters.FCLKChangeLatency) < *p->MaxActiveFCLKChangeLatencySupported))) { 1401 FoundCriticalSurface = true; 1402 *p->MaxActiveFCLKChangeLatencySupported = s->ActiveFCLKChangeLatencyMargin[k] + p->mmSOCParameters.FCLKChangeLatency; 1403 } 1404 } 1405 1406 DML_LOG_VERBOSE("DML::%s: DRAMClockChangeSupport = %u\n", __func__, *p->global_dram_clock_change_supported); 1407 DML_LOG_VERBOSE("DML::%s: FCLKChangeSupport = %u\n", __func__, *p->global_fclk_change_supported); 1408 DML_LOG_VERBOSE("DML::%s: MaxActiveFCLKChangeLatencySupported = %f\n", __func__, *p->MaxActiveFCLKChangeLatencySupported); 1409 DML_LOG_VERBOSE("DML::%s: USRRetrainingSupport = %u\n", __func__, *p->USRRetrainingSupport); 1410 } 1411 1412 void dcn6_calculate_stutter_efficiency(struct dml2_core_internal_scratch *scratch, 1413 struct dml2_core_calcs_CalculateStutterEfficiency_params *p) 1414 { 1415 struct dml2_core_calcs_CalculateStutterEfficiency_locals *l = &scratch->CalculateStutterEfficiency_locals; 1416 1417 unsigned int TotalNumberOfActiveOTG = 0; 1418 double SinglePixelClock = 0; 1419 unsigned int SingleHTotal = 0; 1420 unsigned int SingleVTotal = 0; 1421 bool SameTiming = true; 1422 bool at_least_one_single_pipe_single_plane_surface = false; 1423 bool FoundCriticalSurface = false; 1424 1425 memset(l, 0, sizeof(struct dml2_core_calcs_CalculateStutterEfficiency_locals)); 1426 1427 for (unsigned int k = 0; k < p->NumberOfActiveSurfaces; ++k) { 1428 if (p->display_cfg->plane_descriptors[k].surface.dcc.enable == true) { 1429 if ((dml2_core_utils_is_vertical_rotation(p->display_cfg->plane_descriptors[k].composition.rotation_angle) && p->BlockWidth256BytesY[k] > p->SwathHeightY[k]) || (!dml2_core_utils_is_vertical_rotation(p->display_cfg->plane_descriptors[k].composition.rotation_angle) && p->BlockHeight256BytesY[k] > p->SwathHeightY[k]) || p->DCCYMaxUncompressedBlock[k] < 256) { 1430 l->MaximumEffectiveCompressionLuma = 2; 1431 } else { 1432 l->MaximumEffectiveCompressionLuma = 4; 1433 } 1434 l->TotalCompressedReadBandwidth = l->TotalCompressedReadBandwidth + p->ReadBandwidthSurfaceLuma[k] / math_min2(p->display_cfg->plane_descriptors[k].surface.dcc.informative.dcc_rate_plane0, l->MaximumEffectiveCompressionLuma); 1435 DML_LOG_VERBOSE("DML::%s: k=%u, ReadBandwidthSurfaceLuma = %f\n", __func__, k, p->ReadBandwidthSurfaceLuma[k]); 1436 DML_LOG_VERBOSE("DML::%s: k=%u, NetDCCRateLuma = %f\n", __func__, k, p->display_cfg->plane_descriptors[k].surface.dcc.informative.dcc_rate_plane0); 1437 DML_LOG_VERBOSE("DML::%s: k=%u, MaximumEffectiveCompressionLuma = %f\n", __func__, k, l->MaximumEffectiveCompressionLuma); 1438 l->TotalZeroSizeRequestReadBandwidth = l->TotalZeroSizeRequestReadBandwidth + p->ReadBandwidthSurfaceLuma[k] * p->display_cfg->plane_descriptors[k].surface.dcc.informative.fraction_of_zero_size_request_plane0; 1439 l->TotalZeroSizeCompressedReadBandwidth = l->TotalZeroSizeCompressedReadBandwidth + p->ReadBandwidthSurfaceLuma[k] * p->display_cfg->plane_descriptors[k].surface.dcc.informative.fraction_of_zero_size_request_plane0 / l->MaximumEffectiveCompressionLuma; 1440 1441 if (p->ReadBandwidthSurfaceChroma[k] > 0) { 1442 if ((dml2_core_utils_is_vertical_rotation(p->display_cfg->plane_descriptors[k].composition.rotation_angle) && p->BlockWidth256BytesC[k] > p->SwathHeightC[k]) || (!dml2_core_utils_is_vertical_rotation(p->display_cfg->plane_descriptors[k].composition.rotation_angle) && p->BlockHeight256BytesC[k] > p->SwathHeightC[k]) || p->DCCCMaxUncompressedBlock[k] < 256) { 1443 l->MaximumEffectiveCompressionChroma = 2; 1444 } else { 1445 l->MaximumEffectiveCompressionChroma = 4; 1446 } 1447 l->TotalCompressedReadBandwidth = l->TotalCompressedReadBandwidth + p->ReadBandwidthSurfaceChroma[k] / math_min2(p->display_cfg->plane_descriptors[k].surface.dcc.informative.dcc_rate_plane1, l->MaximumEffectiveCompressionChroma); 1448 DML_LOG_VERBOSE("DML::%s: k=%u, ReadBandwidthSurfaceChroma = %f\n", __func__, k, p->ReadBandwidthSurfaceChroma[k]); 1449 DML_LOG_VERBOSE("DML::%s: k=%u, NetDCCRateChroma = %f\n", __func__, k, p->display_cfg->plane_descriptors[k].surface.dcc.informative.dcc_rate_plane1); 1450 DML_LOG_VERBOSE("DML::%s: k=%u, MaximumEffectiveCompressionChroma = %f\n", __func__, k, l->MaximumEffectiveCompressionChroma); 1451 l->TotalZeroSizeRequestReadBandwidth = l->TotalZeroSizeRequestReadBandwidth + p->ReadBandwidthSurfaceChroma[k] * p->display_cfg->plane_descriptors[k].surface.dcc.informative.fraction_of_zero_size_request_plane1; 1452 l->TotalZeroSizeCompressedReadBandwidth = l->TotalZeroSizeCompressedReadBandwidth + p->ReadBandwidthSurfaceChroma[k] * p->display_cfg->plane_descriptors[k].surface.dcc.informative.fraction_of_zero_size_request_plane1 / l->MaximumEffectiveCompressionChroma; 1453 } 1454 } else { 1455 l->TotalCompressedReadBandwidth = l->TotalCompressedReadBandwidth + p->ReadBandwidthSurfaceLuma[k] + p->ReadBandwidthSurfaceChroma[k]; 1456 } 1457 l->TotalRowReadBandwidth = l->TotalRowReadBandwidth + p->DPPPerSurface[k] * (p->meta_row_bw[k] + p->dpte_row_bw[k]); 1458 } 1459 1460 l->AverageDCCCompressionRate = p->TotalDataReadBandwidth / l->TotalCompressedReadBandwidth; 1461 l->AverageDCCZeroSizeFraction = l->TotalZeroSizeRequestReadBandwidth / p->TotalDataReadBandwidth; 1462 1463 DML_LOG_VERBOSE("DML::%s: UnboundedRequestEnabled = %u\n", __func__, p->UnboundedRequestEnabled); 1464 DML_LOG_VERBOSE("DML::%s: TotalCompressedReadBandwidth = %f\n", __func__, l->TotalCompressedReadBandwidth); 1465 DML_LOG_VERBOSE("DML::%s: TotalZeroSizeRequestReadBandwidth = %f\n", __func__, l->TotalZeroSizeRequestReadBandwidth); 1466 DML_LOG_VERBOSE("DML::%s: TotalZeroSizeCompressedReadBandwidth = %f\n", __func__, l->TotalZeroSizeCompressedReadBandwidth); 1467 DML_LOG_VERBOSE("DML::%s: MaximumEffectiveCompressionLuma = %f\n", __func__, l->MaximumEffectiveCompressionLuma); 1468 DML_LOG_VERBOSE("DML::%s: MaximumEffectiveCompressionChroma = %f\n", __func__, l->MaximumEffectiveCompressionChroma); 1469 DML_LOG_VERBOSE("DML::%s: AverageDCCCompressionRate = %f\n", __func__, l->AverageDCCCompressionRate); 1470 DML_LOG_VERBOSE("DML::%s: AverageDCCZeroSizeFraction = %f\n", __func__, l->AverageDCCZeroSizeFraction); 1471 1472 DML_LOG_VERBOSE("DML::%s: CompbufReservedSpace64B = %u (%f kbytes)\n", __func__, p->CompbufReservedSpace64B, p->CompbufReservedSpace64B * 64 / 1024.0); 1473 DML_LOG_VERBOSE("DML::%s: CompbufReservedSpaceZs = %u\n", __func__, p->CompbufReservedSpaceZs); 1474 DML_LOG_VERBOSE("DML::%s: CompressedBufferSizeInkByte = %u kbytes\n", __func__, p->CompressedBufferSizeInkByte); 1475 DML_LOG_VERBOSE("DML::%s: ROBBufferSizeInKByte = %u kbytes\n", __func__, p->ROBBufferSizeInKByte); 1476 if (l->AverageDCCZeroSizeFraction == 1) { 1477 l->AverageZeroSizeCompressionRate = l->TotalZeroSizeRequestReadBandwidth / l->TotalZeroSizeCompressedReadBandwidth; 1478 l->EffectiveCompressedBufferSize = (double)p->MetaFIFOSizeInKEntries * 1024 * 64 * l->AverageZeroSizeCompressionRate + ((double)p->ZeroSizeBufferEntries - p->CompbufReservedSpaceZs) * 64 * l->AverageZeroSizeCompressionRate; 1479 1480 1481 } else if (l->AverageDCCZeroSizeFraction > 0) { 1482 l->AverageZeroSizeCompressionRate = l->TotalZeroSizeRequestReadBandwidth / l->TotalZeroSizeCompressedReadBandwidth; 1483 l->EffectiveCompressedBufferSize = math_min2((double)p->CompressedBufferSizeInkByte * 1024 * l->AverageDCCCompressionRate, 1484 (double)p->MetaFIFOSizeInKEntries * 1024 * 64 / (l->AverageDCCZeroSizeFraction / l->AverageZeroSizeCompressionRate + 1 / l->AverageDCCCompressionRate)) + 1485 (p->rob_alloc_compressed ? math_min2(((double)p->ROBBufferSizeInKByte * 1024 - p->CompbufReservedSpace64B * 64) * l->AverageDCCCompressionRate, 1486 ((double)p->ZeroSizeBufferEntries - p->CompbufReservedSpaceZs) * 64 / (l->AverageDCCZeroSizeFraction / l->AverageZeroSizeCompressionRate)) 1487 : ((double)p->ROBBufferSizeInKByte * 1024 - p->CompbufReservedSpace64B * 64)); 1488 1489 1490 DML_LOG_VERBOSE("DML::%s: min 1 = %f\n", __func__, p->CompressedBufferSizeInkByte * 1024 * l->AverageDCCCompressionRate); 1491 DML_LOG_VERBOSE("DML::%s: min 2 = %f\n", __func__, p->MetaFIFOSizeInKEntries * 1024 * 64 / (l->AverageDCCZeroSizeFraction / l->AverageZeroSizeCompressionRate + 1 / l->AverageDCCCompressionRate)); 1492 DML_LOG_VERBOSE("DML::%s: min 3 = %d\n", __func__, (p->ROBBufferSizeInKByte * 1024 - p->CompbufReservedSpace64B * 64)); 1493 DML_LOG_VERBOSE("DML::%s: min 4 = %f\n", __func__, (p->ZeroSizeBufferEntries - p->CompbufReservedSpaceZs) * 64 / (l->AverageDCCZeroSizeFraction / l->AverageZeroSizeCompressionRate)); 1494 } else { 1495 l->EffectiveCompressedBufferSize = math_min2((double)p->CompressedBufferSizeInkByte * 1024 * l->AverageDCCCompressionRate, 1496 (double)p->MetaFIFOSizeInKEntries * 1024 * 64 * l->AverageDCCCompressionRate) + 1497 ((double)p->ROBBufferSizeInKByte * 1024 - p->CompbufReservedSpace64B * 64) * (p->rob_alloc_compressed ? l->AverageDCCCompressionRate : 1.0); 1498 1499 DML_LOG_VERBOSE("DML::%s: min 1 = %f\n", __func__, p->CompressedBufferSizeInkByte * 1024 * l->AverageDCCCompressionRate); 1500 DML_LOG_VERBOSE("DML::%s: min 2 = %f\n", __func__, p->MetaFIFOSizeInKEntries * 1024 * 64 * l->AverageDCCCompressionRate); 1501 } 1502 1503 DML_LOG_VERBOSE("DML::%s: MetaFIFOSizeInKEntries = %u\n", __func__, p->MetaFIFOSizeInKEntries); 1504 DML_LOG_VERBOSE("DML::%s: ZeroSizeBufferEntries = %u\n", __func__, p->ZeroSizeBufferEntries); 1505 DML_LOG_VERBOSE("DML::%s: AverageZeroSizeCompressionRate = %f\n", __func__, l->AverageZeroSizeCompressionRate); 1506 DML_LOG_VERBOSE("DML::%s: EffectiveCompressedBufferSize = %f (%f kbytes)\n", __func__, l->EffectiveCompressedBufferSize, l->EffectiveCompressedBufferSize / 1024.0); 1507 1508 *p->StutterPeriod = 0; 1509 1510 for (unsigned int k = 0; k < p->NumberOfActiveSurfaces; ++k) { 1511 l->LinesInDETY = ((double)p->DETBufferSizeY[k] + (p->UnboundedRequestEnabled == true ? l->EffectiveCompressedBufferSize : 0) * p->ReadBandwidthSurfaceLuma[k] / p->TotalDataReadBandwidth) / p->BytePerPixelDETY[k] / p->SwathWidthY[k]; 1512 l->LinesInDETYRoundedDownToSwath = math_floor2(l->LinesInDETY, p->SwathHeightY[k]); 1513 l->DETBufferingTimeY = l->LinesInDETYRoundedDownToSwath * ((double)p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].timing.h_total / ((double)p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].timing.pixel_clock_khz / 1000)) / p->display_cfg->plane_descriptors[k].composition.scaler_info.plane0.v_ratio; 1514 at_least_one_single_pipe_single_plane_surface |= (p->DPPPerSurface[k] == 1) && (p->ReadBandwidthSurfaceChroma[k] == 0); 1515 DML_LOG_VERBOSE("DML::%s: k=%u, DETBufferSizeY = %u (%u kbytes)\n", __func__, k, p->DETBufferSizeY[k], p->DETBufferSizeY[k] / 1024); 1516 DML_LOG_VERBOSE("DML::%s: k=%u, BytePerPixelDETY = %f\n", __func__, k, p->BytePerPixelDETY[k]); 1517 DML_LOG_VERBOSE("DML::%s: k=%u, SwathWidthY = %u\n", __func__, k, p->SwathWidthY[k]); 1518 DML_LOG_VERBOSE("DML::%s: k=%u, ReadBandwidthSurfaceLuma = %f\n", __func__, k, p->ReadBandwidthSurfaceLuma[k]); 1519 DML_LOG_VERBOSE("DML::%s: k=%u, TotalDataReadBandwidth = %f\n", __func__, k, p->TotalDataReadBandwidth); 1520 DML_LOG_VERBOSE("DML::%s: k=%u, LinesInDETY = %f\n", __func__, k, l->LinesInDETY); 1521 DML_LOG_VERBOSE("DML::%s: k=%u, LinesInDETYRoundedDownToSwath = %f\n", __func__, k, l->LinesInDETYRoundedDownToSwath); 1522 DML_LOG_VERBOSE("DML::%s: k=%u, VRatio = %f\n", __func__, k, p->display_cfg->plane_descriptors[k].composition.scaler_info.plane0.v_ratio); 1523 DML_LOG_VERBOSE("DML::%s: k=%u, DETBufferingTimeY = %f\n", __func__, k, l->DETBufferingTimeY); 1524 1525 if (!FoundCriticalSurface || l->DETBufferingTimeY < *p->StutterPeriod) { 1526 bool isInterlaceTiming = p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].timing.interlaced && !p->ProgressiveToInterlaceUnitInOPP; 1527 1528 FoundCriticalSurface = true; 1529 *p->StutterPeriod = l->DETBufferingTimeY; 1530 l->FrameTimeCriticalSurface = (isInterlaceTiming ? math_floor2((double)p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].timing.v_total / 2.0, 1.0) : p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].timing.v_total) * (double)p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].timing.h_total / ((double)p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].timing.pixel_clock_khz / 1000); 1531 l->VActiveTimeCriticalSurface = (isInterlaceTiming ? math_floor2((double)p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].timing.v_active / 2.0, 1.0) : p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].timing.v_active) * (double)p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].timing.h_total / ((double)p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].timing.pixel_clock_khz / 1000); 1532 l->BytePerPixelYCriticalSurface = p->BytePerPixelY[k]; 1533 l->SwathWidthYCriticalSurface = p->SwathWidthY[k]; 1534 l->SwathHeightYCriticalSurface = p->SwathHeightY[k]; 1535 l->BlockWidth256BytesYCriticalSurface = p->BlockWidth256BytesY[k]; 1536 l->DETBufferSizeYCriticalSurface = p->DETBufferSizeY[k]; 1537 l->MinTTUVBlankCriticalSurface = p->MinTTUVBlank[k]; 1538 l->SinglePlaneCriticalSurface = (p->ReadBandwidthSurfaceChroma[k] == 0); 1539 l->SinglePipeCriticalSurface = (p->DPPPerSurface[k] == 1); 1540 1541 DML_LOG_VERBOSE("DML::%s: k=%u, FoundCriticalSurface = %u\n", __func__, k, FoundCriticalSurface); 1542 DML_LOG_VERBOSE("DML::%s: k=%u, StutterPeriod = %f\n", __func__, k, *p->StutterPeriod); 1543 DML_LOG_VERBOSE("DML::%s: k=%u, MinTTUVBlankCriticalSurface = %f\n", __func__, k, l->MinTTUVBlankCriticalSurface); 1544 DML_LOG_VERBOSE("DML::%s: k=%u, FrameTimeCriticalSurface= %f\n", __func__, k, l->FrameTimeCriticalSurface); 1545 DML_LOG_VERBOSE("DML::%s: k=%u, VActiveTimeCriticalSurface = %f\n", __func__, k, l->VActiveTimeCriticalSurface); 1546 DML_LOG_VERBOSE("DML::%s: k=%u, BytePerPixelYCriticalSurface = %u\n", __func__, k, l->BytePerPixelYCriticalSurface); 1547 DML_LOG_VERBOSE("DML::%s: k=%u, SwathWidthYCriticalSurface = %f\n", __func__, k, l->SwathWidthYCriticalSurface); 1548 DML_LOG_VERBOSE("DML::%s: k=%u, SwathHeightYCriticalSurface = %f\n", __func__, k, l->SwathHeightYCriticalSurface); 1549 DML_LOG_VERBOSE("DML::%s: k=%u, BlockWidth256BytesYCriticalSurface = %u\n", __func__, k, l->BlockWidth256BytesYCriticalSurface); 1550 DML_LOG_VERBOSE("DML::%s: k=%u, SinglePlaneCriticalSurface = %u\n", __func__, k, l->SinglePlaneCriticalSurface); 1551 DML_LOG_VERBOSE("DML::%s: k=%u, SinglePipeCriticalSurface = %u\n", __func__, k, l->SinglePipeCriticalSurface); 1552 } 1553 } 1554 1555 // for bounded req, the stutter period is calculated only based on DET size, but during burst there can be some return inside ROB/compressed buffer 1556 // stutter period is calculated only on the det sizing 1557 // if (cdb + rob >= det) the stutter burst will be absorbed by the cdb + rob which is before decompress 1558 // else 1559 // the cdb + rob part will be in compressed rate with urg bw (idea bw) 1560 // the det part will be return at uncompressed rate with 64B/dcfclk 1561 // 1562 // for unbounded req, the stutter period should be calculated as total of CDB+ROB+DET, so the term "PartOfUncompressedPixelBurstThatFitsInROBAndCompressedBuffer" 1563 // should be == EffectiveCompressedBufferSize which will returned a compressed rate, the rest of stutter period is from the DET will be returned at uncompressed rate with 64B/dcfclk 1564 1565 l->PartOfUncompressedPixelBurstThatFitsInROBAndCompressedBuffer = math_min2(*p->StutterPeriod * p->TotalDataReadBandwidth, l->EffectiveCompressedBufferSize); 1566 DML_LOG_VERBOSE("DML::%s: AverageDCCCompressionRate = %f\n", __func__, l->AverageDCCCompressionRate); 1567 DML_LOG_VERBOSE("DML::%s: StutterPeriod*TotalDataReadBandwidth = %f (%f kbytes)\n", __func__, *p->StutterPeriod * p->TotalDataReadBandwidth, (*p->StutterPeriod * p->TotalDataReadBandwidth) / 1024.0); 1568 DML_LOG_VERBOSE("DML::%s: EffectiveCompressedBufferSize = %f (%f kbytes)\n", __func__, l->EffectiveCompressedBufferSize, l->EffectiveCompressedBufferSize / 1024.0); 1569 DML_LOG_VERBOSE("DML::%s: PartOfUncompressedPixelBurstThatFitsInROBAndCompressedBuffer = %f (%f kbytes)\n", __func__, l->PartOfUncompressedPixelBurstThatFitsInROBAndCompressedBuffer, l->PartOfUncompressedPixelBurstThatFitsInROBAndCompressedBuffer / 1024); 1570 DML_LOG_VERBOSE("DML::%s: ReturnBW = %f\n", __func__, p->ReturnBW); 1571 DML_LOG_VERBOSE("DML::%s: TotalDataReadBandwidth = %f\n", __func__, p->TotalDataReadBandwidth); 1572 DML_LOG_VERBOSE("DML::%s: TotalRowReadBandwidth = %f\n", __func__, l->TotalRowReadBandwidth); 1573 DML_LOG_VERBOSE("DML::%s: DCFCLK = %f\n", __func__, p->DCFCLK); 1574 1575 l->StutterBurstTime = l->PartOfUncompressedPixelBurstThatFitsInROBAndCompressedBuffer 1576 / (p->ReturnBW * (p->hw_debug5 ? 1 : l->AverageDCCCompressionRate)) + 1577 (*p->StutterPeriod * p->TotalDataReadBandwidth - l->PartOfUncompressedPixelBurstThatFitsInROBAndCompressedBuffer) 1578 / math_min2(p->DCFCLK * 64, p->ReturnBW * (p->hw_debug5 ? 1 : l->AverageDCCCompressionRate)) + 1579 *p->StutterPeriod * l->TotalRowReadBandwidth / p->ReturnBW; 1580 DML_LOG_VERBOSE("DML::%s: Part 1 = %f\n", __func__, l->PartOfUncompressedPixelBurstThatFitsInROBAndCompressedBuffer / p->ReturnBW / (p->hw_debug5 ? 1 : l->AverageDCCCompressionRate)); 1581 DML_LOG_VERBOSE("DML::%s: Part 2 = %f\n", __func__, (*p->StutterPeriod * p->TotalDataReadBandwidth - l->PartOfUncompressedPixelBurstThatFitsInROBAndCompressedBuffer) / (p->DCFCLK * 64)); 1582 DML_LOG_VERBOSE("DML::%s: Part 3 = %f\n", __func__, *p->StutterPeriod * l->TotalRowReadBandwidth / p->ReturnBW); 1583 DML_LOG_VERBOSE("DML::%s: StutterBurstTime = %f\n", __func__, l->StutterBurstTime); 1584 l->TotalActiveWriteback = 0; 1585 memset(l->stream_visited, 0, DML2_MAX_PLANES * sizeof(bool)); 1586 1587 for (unsigned int k = 0; k < p->NumberOfActiveSurfaces; ++k) { 1588 if (!l->stream_visited[p->display_cfg->plane_descriptors[k].stream_index]) { 1589 1590 for (unsigned int j = 0; j < p->display_cfg->stream_descriptors[k].writeback.active_writebacks_per_stream; j++) 1591 l->TotalActiveWriteback = l->TotalActiveWriteback + 1; 1592 1593 if (TotalNumberOfActiveOTG == 0) { // first otg 1594 SinglePixelClock = ((double)p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].timing.pixel_clock_khz / 1000); 1595 SingleHTotal = p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].timing.h_total; 1596 SingleVTotal = p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].timing.v_total; 1597 } else if (SinglePixelClock != ((double)p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].timing.pixel_clock_khz / 1000) || 1598 SingleHTotal != p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].timing.h_total || 1599 SingleVTotal != p->display_cfg->stream_descriptors[p->display_cfg->plane_descriptors[k].stream_index].timing.v_total) { 1600 SameTiming = false; 1601 } 1602 TotalNumberOfActiveOTG = TotalNumberOfActiveOTG + 1; 1603 l->stream_visited[p->display_cfg->plane_descriptors[k].stream_index] = 1; 1604 } 1605 } 1606 1607 if (l->TotalActiveWriteback == 0) { 1608 DML_LOG_VERBOSE("DML::%s: SRExitTime = %f\n", __func__, p->SRExitTime); 1609 DML_LOG_VERBOSE("DML::%s: SRExitZ8Time = %f\n", __func__, p->SRExitZ8Time); 1610 DML_LOG_VERBOSE("DML::%s: SRExitTimeLowPower = %f\n", __func__, p->SRExitTime); 1611 DML_LOG_VERBOSE("DML::%s: StutterPeriod = %f\n", __func__, *p->StutterPeriod); 1612 *p->StutterEfficiencyNotIncludingVBlank = math_max2(0., 1 - (p->SRExitTime + l->StutterBurstTime) / *p->StutterPeriod) * 100; 1613 *p->Z8StutterEfficiencyNotIncludingVBlank = math_max2(0., 1 - (p->SRExitZ8Time + l->StutterBurstTime) / *p->StutterPeriod) * 100; 1614 *p->LowPowerStutterEfficiencyNotIncludingVBlank = math_max2(0., 1 - (p->SRExitTimeLowPower + l->StutterBurstTime) / *p->StutterPeriod) * 100; 1615 *p->NumberOfStutterBurstsPerFrame = (*p->StutterEfficiencyNotIncludingVBlank > 0 ? (unsigned int)(math_ceil2(l->VActiveTimeCriticalSurface / *p->StutterPeriod, 1)) : 0); 1616 *p->Z8NumberOfStutterBurstsPerFrame = (*p->Z8StutterEfficiencyNotIncludingVBlank > 0 ? (unsigned int)(math_ceil2(l->VActiveTimeCriticalSurface / *p->StutterPeriod, 1)) : 0); 1617 *p->LowPowerNumberOfStutterBurstsPerFrame = (*p->LowPowerStutterEfficiencyNotIncludingVBlank > 0 ? (unsigned int)(math_ceil2(l->VActiveTimeCriticalSurface / *p->StutterPeriod, 1)) : 0); 1618 1619 } else { 1620 *p->StutterEfficiencyNotIncludingVBlank = 0.0; 1621 *p->Z8StutterEfficiencyNotIncludingVBlank = 0.0; 1622 *p->LowPowerStutterEfficiencyNotIncludingVBlank = 0.0; 1623 *p->NumberOfStutterBurstsPerFrame = 0; 1624 *p->Z8NumberOfStutterBurstsPerFrame = 0; 1625 *p->LowPowerNumberOfStutterBurstsPerFrame = 0; 1626 } 1627 DML_LOG_VERBOSE("DML::%s: VActiveTimeCriticalSurface = %f\n", __func__, l->VActiveTimeCriticalSurface); 1628 DML_LOG_VERBOSE("DML::%s: StutterEfficiencyNotIncludingVBlank = %f\n", __func__, *p->StutterEfficiencyNotIncludingVBlank); 1629 DML_LOG_VERBOSE("DML::%s: Z8StutterEfficiencyNotIncludingVBlank = %f\n", __func__, *p->Z8StutterEfficiencyNotIncludingVBlank); 1630 DML_LOG_VERBOSE("DML::%s: LowPowerStutterEfficiencyNotIncludingVBlank = %f\n", __func__, *p->LowPowerStutterEfficiencyNotIncludingVBlank); 1631 DML_LOG_VERBOSE("DML::%s: NumberOfStutterBurstsPerFrame = %u\n", __func__, *p->NumberOfStutterBurstsPerFrame); 1632 DML_LOG_VERBOSE("DML::%s: Z8NumberOfStutterBurstsPerFrame = %u\n", __func__, *p->Z8NumberOfStutterBurstsPerFrame); 1633 DML_LOG_VERBOSE("DML::%s: LowPowerNumberOfStutterBurstsPerFrame = %u\n", __func__, *p->LowPowerNumberOfStutterBurstsPerFrame); 1634 1635 if (*p->StutterEfficiencyNotIncludingVBlank > 0) { 1636 if (!((p->SynchronizeTimings || TotalNumberOfActiveOTG == 1) && SameTiming)) { 1637 *p->StutterEfficiency = *p->StutterEfficiencyNotIncludingVBlank; 1638 } else { 1639 *p->StutterEfficiency = (1 - (*p->NumberOfStutterBurstsPerFrame * p->SRExitTime + l->StutterBurstTime * l->VActiveTimeCriticalSurface / *p->StutterPeriod) / l->FrameTimeCriticalSurface) * 100; 1640 } 1641 } else { 1642 *p->StutterEfficiency = 0; 1643 *p->NumberOfStutterBurstsPerFrame = 0; 1644 } 1645 1646 if (*p->Z8StutterEfficiencyNotIncludingVBlank > 0) { 1647 if (!((p->SynchronizeTimings || TotalNumberOfActiveOTG == 1) && SameTiming)) { 1648 *p->Z8StutterEfficiency = *p->Z8StutterEfficiencyNotIncludingVBlank; 1649 } else { 1650 *p->Z8StutterEfficiency = (1 - (*p->Z8NumberOfStutterBurstsPerFrame * p->SRExitZ8Time + l->StutterBurstTime * l->VActiveTimeCriticalSurface / *p->StutterPeriod) / l->FrameTimeCriticalSurface) * 100; 1651 } 1652 } else { 1653 *p->Z8StutterEfficiency = 0.; 1654 *p->Z8NumberOfStutterBurstsPerFrame = 0; 1655 } 1656 1657 if (*p->LowPowerStutterEfficiencyNotIncludingVBlank > 0) { 1658 if (!((p->SynchronizeTimings || TotalNumberOfActiveOTG == 1) && SameTiming)) { 1659 *p->LowPowerStutterEfficiency = *p->LowPowerStutterEfficiencyNotIncludingVBlank; 1660 } else { 1661 *p->LowPowerStutterEfficiency = (1 - (*p->LowPowerNumberOfStutterBurstsPerFrame * p->SRExitTimeLowPower + l->StutterBurstTime * l->VActiveTimeCriticalSurface / *p->StutterPeriod) / l->FrameTimeCriticalSurface) * 100; 1662 } 1663 } else { 1664 *p->LowPowerStutterEfficiency = 0; 1665 *p->LowPowerNumberOfStutterBurstsPerFrame = 0; 1666 } 1667 1668 DML_LOG_VERBOSE("DML::%s: TotalNumberOfActiveOTG = %u\n", __func__, TotalNumberOfActiveOTG); 1669 DML_LOG_VERBOSE("DML::%s: SameTiming = %u\n", __func__, SameTiming); 1670 DML_LOG_VERBOSE("DML::%s: SynchronizeTimings = %u\n", __func__, p->SynchronizeTimings); 1671 DML_LOG_VERBOSE("DML::%s: LastZ8StutterPeriod = %f\n", __func__, *p->Z8StutterEfficiencyNotIncludingVBlank > 0 ? l->VActiveTimeCriticalSurface - (*p->Z8NumberOfStutterBurstsPerFrame - 1) * *p->StutterPeriod : 0); 1672 DML_LOG_VERBOSE("DML::%s: Z8StutterEnterPlusExitWatermark = %f\n", __func__, p->Z8StutterEnterPlusExitWatermark); 1673 DML_LOG_VERBOSE("DML::%s: StutterBurstTime = %f\n", __func__, l->StutterBurstTime); 1674 DML_LOG_VERBOSE("DML::%s: StutterPeriod = %f\n", __func__, *p->StutterPeriod); 1675 DML_LOG_VERBOSE("DML::%s: StutterEfficiency = %f\n", __func__, *p->StutterEfficiency); 1676 DML_LOG_VERBOSE("DML::%s: Z8StutterEfficiency = %f\n", __func__, *p->Z8StutterEfficiency); 1677 DML_LOG_VERBOSE("DML::%s: StutterEfficiencyNotIncludingVBlank = %f\n", __func__, *p->StutterEfficiencyNotIncludingVBlank); 1678 DML_LOG_VERBOSE("DML::%s: LowPowerStutterEfficiency = %f\n", __func__, *p->LowPowerStutterEfficiency); 1679 DML_LOG_VERBOSE("DML::%s: Z8NumberOfStutterBurstsPerFrame = %u\n", __func__, *p->Z8NumberOfStutterBurstsPerFrame); 1680 1681 *p->DCHUBBUB_ARB_CSTATE_MAX_CAP_MODE = !(!p->UnboundedRequestEnabled && (TotalNumberOfActiveOTG == 1) && at_least_one_single_pipe_single_plane_surface); 1682 1683 DML_LOG_VERBOSE("DML::%s: DETBufferSizeYCriticalSurface = %u\n", __func__, l->DETBufferSizeYCriticalSurface); 1684 DML_LOG_VERBOSE("DML::%s: PixelChunkSizeInKByte = %u\n", __func__, p->PixelChunkSizeInKByte); 1685 DML_LOG_VERBOSE("DML::%s: DCHUBBUB_ARB_CSTATE_MAX_CAP_MODE = %u\n", __func__, *p->DCHUBBUB_ARB_CSTATE_MAX_CAP_MODE); 1686 } 1687 1688 void dcn6_get_watermarks(const struct dml2_display_cfg *display_cfg, const struct dml2_core_internal_display_mode_lib *mode_lib, const struct dml2_utm_soc_bb *utm_soc_bb, struct dml2_dchub_watermark_regs *out) 1689 { 1690 dcn6_rq_dlg_get_wm_regs(display_cfg, mode_lib, utm_soc_bb, out); 1691 } 1692 1693 void dcn6_calculate_excess_vactive_bandwidth_required( 1694 const struct dml2_display_cfg *display_cfg, 1695 unsigned int bytes_required_l[dml2_pstate_type_count][DML2_MAX_PLANES], 1696 unsigned int bytes_required_c[dml2_pstate_type_count][DML2_MAX_PLANES], 1697 /* outputs */ 1698 double excess_vactive_fill_bw_l[], 1699 double excess_vactive_fill_bw_c[]) 1700 { 1701 unsigned int plane_index; 1702 enum dml2_pstate_type pstate_type; 1703 1704 for (plane_index = 0; plane_index < display_cfg->num_planes; plane_index++) { 1705 excess_vactive_fill_bw_l[plane_index] = 0.0; 1706 excess_vactive_fill_bw_c[plane_index] = 0.0; 1707 1708 for (pstate_type = 0; pstate_type < dml2_pstate_type_count; pstate_type++) { 1709 if (display_cfg->plane_descriptors[plane_index].overrides.max_vactive_det_fill_delay_us[pstate_type] > 0) { 1710 excess_vactive_fill_bw_l[plane_index] = math_max2( 1711 (double)bytes_required_l[pstate_type][plane_index] / 1712 (double)display_cfg->plane_descriptors[plane_index].overrides.max_vactive_det_fill_delay_us[pstate_type], 1713 excess_vactive_fill_bw_l[plane_index]); 1714 excess_vactive_fill_bw_c[plane_index] = math_max2( 1715 (double)bytes_required_c[pstate_type][plane_index] / 1716 (double)display_cfg->plane_descriptors[plane_index].overrides.max_vactive_det_fill_delay_us[pstate_type], 1717 excess_vactive_fill_bw_c[plane_index]); 1718 } 1719 } 1720 } 1721 } 1722 1723 void dcn6_calculate_pstate_schedule_windows( 1724 int num_active_planes, 1725 const unsigned int v_blank_start[DML2_MAX_PLANES], 1726 const unsigned int v_blank_end[DML2_MAX_PLANES], 1727 const double otg_vline_time_us[DML2_MAX_PLANES], 1728 const double det_fill_delay_us[DML2_MAX_PLANES], 1729 const double reserved_vblank_us[DML2_MAX_PLANES], 1730 const double blackout_us, 1731 // Outputs 1732 double allow_start_us[DML2_MAX_PLANES], 1733 double allow_end_us[DML2_MAX_PLANES]) 1734 { 1735 int k; 1736 int allow_start_otg_vlines, allow_end_otg_vlines; 1737 int det_fill_delay_otg_vlines; 1738 int blackout_otg_vlines; 1739 int reserved_vblank_otg_vlines; 1740 1741 /** 1742 * Calculate allow start and end for pstate in vactive: 1743 * 1744 * |vblank end vblank start| 1745 * |<------------------------ vactive ---------------------------->| 1746 * |<-- det fill delay ->|<----- allow window ----->|<----------- blackout ------------>| 1747 * | |allow start allow end| |<- reserved blank ->| 1748 */ 1749 for (k = 0; k < num_active_planes; k++) { 1750 /* Calculate the allow window in units of vlines */ 1751 blackout_otg_vlines = (int)(math_ceil(blackout_us / otg_vline_time_us[k])); 1752 det_fill_delay_otg_vlines = (int)(math_ceil(det_fill_delay_us[k] / otg_vline_time_us[k])); 1753 reserved_vblank_otg_vlines = (int)(math_ceil(reserved_vblank_us[k] / otg_vline_time_us[k])); 1754 1755 allow_start_otg_vlines = v_blank_end[k] + det_fill_delay_otg_vlines; 1756 allow_end_otg_vlines = v_blank_start[k] - (blackout_otg_vlines - reserved_vblank_otg_vlines); 1757 1758 /* Convert them back to time since the start of a frame */ 1759 allow_start_us[k] = allow_start_otg_vlines * otg_vline_time_us[k]; 1760 allow_end_us[k] = allow_end_otg_vlines * otg_vline_time_us[k]; 1761 } 1762 } 1763 1764 void dcn6_calculate_pstate_schedule_admissibility( 1765 uint32_t num_active_planes, 1766 double max_allow_delay_us, 1767 double min_allow_width_us, 1768 const uint32_t timing_group_id[DML2_MAX_PLANES], 1769 uint32_t timing_group_count, 1770 const double frame_time_us[DML2_MAX_PLANES], 1771 const double allow_start_us[DML2_MAX_PLANES], 1772 const double allow_end_us[DML2_MAX_PLANES], 1773 const enum dml2_pstate_method pstate_method[DML2_MAX_PLANES], 1774 const bool is_drr[DML2_MAX_DCN_PIPES], 1775 // Output 1776 double allow_window_us[DML2_MAX_DCN_PIPES], 1777 double disallow_window_us[DML2_MAX_DCN_PIPES], 1778 bool *pstate_admissible) 1779 { 1780 unsigned int cur_id = 0, other_id = 0; 1781 unsigned int k = 0, i = 0; 1782 unsigned int sorted[DML2_MAX_DCN_PIPES]; // group IDs sorted by disallow window size, from highest to lowest 1783 double sum_of_disallow_windows_us = 0.0; 1784 double sum_of_allow_windows_us = 0.0; 1785 1786 /* Initialize as not admissible first */ 1787 *pstate_admissible = false; 1788 1789 /** 1790 * Calculate the allow and disallow window for each timing group. 1791 * A timing group may contain multiple planes rendered under a synchronized and identical timing framework. 1792 * Each plane has its own allow window slack described by allow_start_us and allow_end_us. 1793 * The goal is to find the intersection of allow windows across all planes in a timing group. This is used as 1794 * a key data point to determine the p-state admissibility result. 1795 * Here is an example of 3 planes in the same timing group and how the allow window is calculated: 1796 * |----------------------------frame_time_us-----------------------------| 1797 * plane0 |XXXXXXXXXXXXXX|----------- allow window 0 ------------------|XXXXXXXXX| 1798 * plane1 |XXXX|--------------------- allow window 1 -------------|XXXXXXXXXXXXXX| 1799 * plane2 |XXXXXXXX|----------------- allow window 2 -----------|XXXXXXXXXXXXXXXX| 1800 * group |XXXXXXXXXXXXXX|----------- allow window (group)------|XXXXXXXXXXXXXXXX| 1801 */ 1802 memset(allow_window_us, 0, sizeof(double) * DML2_MAX_DCN_PIPES); 1803 memset(disallow_window_us, 0, sizeof(double) * DML2_MAX_DCN_PIPES); 1804 for (cur_id = 0; cur_id < timing_group_count; cur_id++) { 1805 double group_allow_start_us = 0.0; 1806 double group_allow_end_us = 0.0; 1807 double group_frame_time_us = 0.0; 1808 bool first = true; 1809 1810 for (k = 0; k < num_active_planes; k++) { 1811 /* Skip planes that are not part of the current timing group */ 1812 if (timing_group_id[k] != cur_id) 1813 continue; 1814 if (first) { 1815 group_frame_time_us = frame_time_us[k]; 1816 group_allow_start_us = allow_start_us[k]; 1817 group_allow_end_us = allow_end_us[k]; 1818 first = false; 1819 } else { 1820 group_allow_start_us = math_max2(group_allow_start_us, allow_start_us[k]); 1821 group_allow_end_us = math_min2(group_allow_end_us, allow_end_us[k]); 1822 } 1823 } 1824 1825 allow_window_us[cur_id] = group_allow_end_us - group_allow_start_us; 1826 if (allow_window_us[cur_id] > group_frame_time_us) 1827 /* Clamp allow window to frame time */ 1828 allow_window_us[cur_id] = group_frame_time_us; 1829 disallow_window_us[cur_id] = group_frame_time_us - allow_window_us[cur_id]; 1830 } 1831 1832 /* Calculate the total sum of all allow and disallow windows */ 1833 for (cur_id = 0; cur_id < timing_group_count; cur_id++) { 1834 sum_of_disallow_windows_us += disallow_window_us[cur_id]; 1835 sum_of_allow_windows_us += allow_window_us[cur_id]; 1836 } 1837 1838 /** 1839 * Check 1 - Every group has a positive allow window greater than or equal to the minimum allow width. 1840 */ 1841 for (cur_id = 0; cur_id < timing_group_count; cur_id++) 1842 if (allow_window_us[cur_id] <= 0 1843 || allow_window_us[cur_id] < min_allow_width_us) 1844 return; 1845 1846 /** 1847 * Check 2 - Every group has a disallow window within the FAMS maximum scheduling latency budget. 1848 */ 1849 for (cur_id = 0; cur_id < timing_group_count; cur_id++) 1850 if (disallow_window_us[cur_id] > max_allow_delay_us) 1851 return; 1852 1853 /** 1854 * Schedulable Case 1 - Single group 1855 */ 1856 if (timing_group_count == 1) { 1857 *pstate_admissible = true; 1858 return; 1859 } 1860 1861 /** 1862 * Schedulable Case 2 - Positive allow fragment after recursive slice halving. 1863 * Passing Conditions: 1864 * 1. Total sum of disallow windows across all groups is less than the FAMS maximum scheduling latency budget. 1865 * 2. Every group's remaining allow fragment is still positive after recursive slicing and halving. 1866 */ 1867 1868 if (sum_of_disallow_windows_us < max_allow_delay_us) { 1869 *pstate_admissible = true; 1870 /* Bubble sort group IDs by disallow window size, from highest to lowest */ 1871 for (cur_id = 0; cur_id < timing_group_count; cur_id++) 1872 sorted[cur_id] = cur_id; 1873 for (cur_id = 0; cur_id < timing_group_count; cur_id++) 1874 for (other_id = cur_id + 1; other_id < timing_group_count; other_id++) 1875 if (disallow_window_us[sorted[cur_id]] < disallow_window_us[sorted[other_id]]) 1876 swap(sorted[cur_id], sorted[other_id]); 1877 /* Continuously slice each group's allow fragment */ 1878 for (cur_id = 0; cur_id < timing_group_count; cur_id++) { 1879 double allow_fragment_us = allow_window_us[cur_id]; 1880 1881 for (i = 0; i < timing_group_count; i++) { 1882 other_id = sorted[i]; 1883 1884 if (cur_id == other_id || disallow_window_us[other_id] <= 0.0) 1885 continue; 1886 1887 // slicing 1888 allow_fragment_us -= disallow_window_us[other_id]; 1889 // halving 1890 allow_fragment_us /= 2; 1891 if (allow_window_us[other_id] < allow_fragment_us) 1892 allow_fragment_us = allow_window_us[other_id]; 1893 } 1894 1895 if (allow_fragment_us <= 0.0) { 1896 *pstate_admissible = false; 1897 break; 1898 } 1899 } 1900 1901 if (*pstate_admissible) 1902 return; 1903 } 1904 1905 /** 1906 * Schedulable Case 3 - Nesting frame times. 1907 * Passing Conditions: 1908 * 1. Total sum of disallow windows across all groups is less than the FAMS maximum scheduling latency budget. 1909 * 2. Every group's frame time can be fully contained by another group's allow window recursively, like nesting dolls. 1910 * 3. The nested groups must not have DRR enabled and active. 1911 */ 1912 if (sum_of_disallow_windows_us < max_allow_delay_us) { 1913 *pstate_admissible = true; 1914 /* Bubble sort group IDs by frame time, from highest to lowest */ 1915 for (cur_id = 0; cur_id < timing_group_count; cur_id++) 1916 sorted[cur_id] = cur_id; 1917 for (cur_id = 0; cur_id < timing_group_count; cur_id++) { 1918 double cur_frame_time_us = allow_window_us[cur_id] + disallow_window_us[cur_id]; 1919 for (other_id = cur_id + 1; other_id < timing_group_count; other_id++) { 1920 double other_frame_time_us = allow_window_us[other_id] + disallow_window_us[other_id]; 1921 if (cur_frame_time_us < other_frame_time_us) 1922 swap(sorted[cur_id], sorted[other_id]); 1923 } 1924 } 1925 /* Check nesting */ 1926 for (cur_id = 0; cur_id < timing_group_count - 1; cur_id++) { 1927 other_id = cur_id + 1; 1928 if (allow_window_us[sorted[cur_id]] < allow_window_us[sorted[other_id]] + disallow_window_us[sorted[other_id]]) { 1929 *pstate_admissible = false; 1930 break; 1931 } 1932 } 1933 1934 /* Starting from the first nested group, check DRR support */ 1935 for (cur_id = 1; cur_id < timing_group_count; cur_id++) 1936 if (is_drr[sorted[cur_id]]) { 1937 *pstate_admissible = false; 1938 break; 1939 } 1940 1941 if (*pstate_admissible) 1942 return; 1943 } 1944 1945 /** 1946 * Schedulable Case 4 - Non-harmonic phase drifting. 1947 * Passing Conditions: 1948 * 1. Applicable only for 2 timing groups. 1949 * 2. The small frame time does not perfectly align with the large frame time, so the allow and disallow 1950 * windows drift in and out of phase across frames, providing opportunities for p-state changes. 1951 * 3. The delay to recover from a worst-case phase shift to a common allow window is less than the FAMS 1952 * maximum scheduling latency budget. 1953 * 4. The drift per frame is smaller than the combined allow window (p-state can complete within the window 1954 * as it drifts through). 1955 */ 1956 if (timing_group_count == 2 1957 && !((1 << pstate_method[0] | 1 << pstate_method[1]) & PMO_FW_STRATEGY_MASK)) { // neither is FW strategy 1958 int small_group_id = 0; 1959 int large_group_id = 1; 1960 double shift_per_frame = 0.0; 1961 double max_shift_us = 0.0; 1962 double max_disallow_window_us = 0.0; 1963 1964 *pstate_admissible = true; 1965 if (allow_window_us[small_group_id] + disallow_window_us[small_group_id] 1966 > allow_window_us[large_group_id] + disallow_window_us[large_group_id]) 1967 swap(small_group_id, large_group_id); 1968 1969 shift_per_frame = math_mod((allow_window_us[large_group_id] + disallow_window_us[large_group_id]), 1970 (allow_window_us[small_group_id] + disallow_window_us[small_group_id])); 1971 1972 max_shift_us = disallow_window_us[large_group_id] - allow_window_us[small_group_id]; 1973 max_disallow_window_us = max_shift_us / shift_per_frame * (allow_window_us[large_group_id] + disallow_window_us[large_group_id]); 1974 1975 if (shift_per_frame == 0.0) 1976 /* Perfectly aligned, no drifting */ 1977 *pstate_admissible = false; 1978 if (shift_per_frame >= sum_of_allow_windows_us) 1979 /* Drifting, but the shift per frame exceeds the total allow window; no opportunity for p-state change */ 1980 *pstate_admissible = false; 1981 1982 if (max_disallow_window_us >= max_allow_delay_us) 1983 /** 1984 * The delay to recover from a worst-case phase shift to a common allow window exceeds the FAMS 1985 * maximum scheduling latency budget. 1986 */ 1987 *pstate_admissible = false; 1988 1989 if (*pstate_admissible) 1990 return; 1991 } 1992 1993 return; 1994 }