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 }