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