xref: /linux/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn6_calcs_dchub.c (revision 2c3ed158087d2971cad00faab24e2143eef49944)
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 }