xref: /linux/drivers/gpu/drm/amd/display/dc/dml2/dml2_mall_phantom.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
1 /* SPDX-License-Identifier: MIT */
2 /*
3  * Copyright 2023 Advanced Micro Devices, Inc.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21  * OTHER DEALINGS IN THE SOFTWARE.
22  *
23  * Authors: AMD
24  *
25  */
26 
27 #include "dml2_dc_types.h"
28 #include "dml2_internal_types.h"
29 #include "dml2_utils.h"
30 #include "dml2_mall_phantom.h"
31 
dml2_helper_calculate_num_ways_for_subvp(struct dml2_context * ctx,struct dc_state * context)32 unsigned int dml2_helper_calculate_num_ways_for_subvp(struct dml2_context *ctx, struct dc_state *context)
33 {
34 	uint32_t num_ways = 0;
35 	uint32_t bytes_per_pixel = 0;
36 	uint32_t cache_lines_used = 0;
37 	uint32_t lines_per_way = 0;
38 	uint32_t total_cache_lines = 0;
39 	uint32_t bytes_in_mall = 0;
40 	uint32_t num_mblks = 0;
41 	uint32_t cache_lines_per_plane = 0;
42 	uint32_t i = 0;
43 	uint32_t mblk_width = 0;
44 	uint32_t mblk_height = 0;
45 	uint32_t full_vp_width_blk_aligned = 0;
46 	uint32_t mall_alloc_width_blk_aligned = 0;
47 	uint32_t mall_alloc_height_blk_aligned = 0;
48 
49 	for (i = 0; i < ctx->config.dcn_pipe_count; i++) {
50 		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
51 
52 		// Find the phantom pipes
53 		if (pipe->stream && pipe->plane_state && !pipe->top_pipe && !pipe->prev_odm_pipe &&
54 				ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) {
55 			bytes_per_pixel = pipe->plane_state->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 ? 8 : 4;
56 			mblk_width = ctx->config.mall_cfg.mblk_width_pixels;
57 			mblk_height = bytes_per_pixel == 4 ? mblk_width = ctx->config.mall_cfg.mblk_height_4bpe_pixels : ctx->config.mall_cfg.mblk_height_8bpe_pixels;
58 
59 			/* full_vp_width_blk_aligned = FLOOR(vp_x_start + full_vp_width + blk_width - 1, blk_width) -
60 			 * FLOOR(vp_x_start, blk_width)
61 			 */
62 			full_vp_width_blk_aligned = ((pipe->plane_res.scl_data.viewport.x +
63 					pipe->plane_res.scl_data.viewport.width + mblk_width - 1) / mblk_width * mblk_width) +
64 					(pipe->plane_res.scl_data.viewport.x / mblk_width * mblk_width);
65 
66 			/* mall_alloc_width_blk_aligned_l/c = full_vp_width_blk_aligned_l/c */
67 			mall_alloc_width_blk_aligned = full_vp_width_blk_aligned;
68 
69 			/* mall_alloc_height_blk_aligned_l/c = CEILING(sub_vp_height_l/c - 1, blk_height_l/c) + blk_height_l/c */
70 			mall_alloc_height_blk_aligned = (pipe->stream->timing.v_addressable - 1 + mblk_height - 1) /
71 					mblk_height * mblk_height + mblk_height;
72 
73 			/* full_mblk_width_ub_l/c = malldml2_mall_phantom.c_alloc_width_blk_aligned_l/c;
74 			 * full_mblk_height_ub_l/c = mall_alloc_height_blk_aligned_l/c;
75 			 * num_mblk_l/c = (full_mblk_width_ub_l/c / mblk_width_l/c) * (full_mblk_height_ub_l/c / mblk_height_l/c);
76 			 * (Should be divisible, but round up if not)
77 			 */
78 			num_mblks = ((mall_alloc_width_blk_aligned + mblk_width - 1) / mblk_width) *
79 					((mall_alloc_height_blk_aligned + mblk_height - 1) / mblk_height);
80 			bytes_in_mall = num_mblks * ctx->config.mall_cfg.mblk_size_bytes;
81 			// cache lines used is total bytes / cache_line size. Add +2 for worst case alignment
82 			// (MALL is 64-byte aligned)
83 			cache_lines_per_plane = bytes_in_mall / ctx->config.mall_cfg.cache_line_size_bytes + 2;
84 
85 			// For DCC we must cache the meat surface, so double cache lines required
86 			if (pipe->plane_state->dcc.enable)
87 				cache_lines_per_plane *= 2;
88 			cache_lines_used += cache_lines_per_plane;
89 		}
90 	}
91 
92 	total_cache_lines = ctx->config.mall_cfg.max_cab_allocation_bytes / ctx->config.mall_cfg.cache_line_size_bytes;
93 	lines_per_way = total_cache_lines / ctx->config.mall_cfg.cache_num_ways;
94 	num_ways = cache_lines_used / lines_per_way;
95 	if (cache_lines_used % lines_per_way > 0)
96 		num_ways++;
97 
98 	return num_ways;
99 }
100 
merge_pipes_for_subvp(struct dml2_context * ctx,struct dc_state * context)101 static void merge_pipes_for_subvp(struct dml2_context *ctx, struct dc_state *context)
102 {
103 	int i;
104 
105 	/* merge pipes if necessary */
106 	for (i = 0; i < ctx->config.dcn_pipe_count; i++) {
107 		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
108 
109 		// For now merge all pipes for SubVP since pipe split case isn't supported yet
110 
111 		/* if ODM merge we ignore mpc tree, mpo pipes will have their own flags */
112 		if (pipe->prev_odm_pipe) {
113 			/*split off odm pipe*/
114 			pipe->prev_odm_pipe->next_odm_pipe = pipe->next_odm_pipe;
115 			if (pipe->next_odm_pipe)
116 				pipe->next_odm_pipe->prev_odm_pipe = pipe->prev_odm_pipe;
117 
118 			pipe->bottom_pipe = NULL;
119 			pipe->next_odm_pipe = NULL;
120 			pipe->plane_state = NULL;
121 			pipe->stream = NULL;
122 			pipe->top_pipe = NULL;
123 			pipe->prev_odm_pipe = NULL;
124 			if (pipe->stream_res.dsc)
125 				ctx->config.svp_pstate.callbacks.release_dsc(&context->res_ctx, ctx->config.svp_pstate.callbacks.dc->res_pool, &pipe->stream_res.dsc);
126 			memset(&pipe->plane_res, 0, sizeof(pipe->plane_res));
127 			memset(&pipe->stream_res, 0, sizeof(pipe->stream_res));
128 		} else if (pipe->top_pipe && pipe->top_pipe->plane_state == pipe->plane_state) {
129 			struct pipe_ctx *top_pipe = pipe->top_pipe;
130 			struct pipe_ctx *bottom_pipe = pipe->bottom_pipe;
131 
132 			top_pipe->bottom_pipe = bottom_pipe;
133 			if (bottom_pipe)
134 				bottom_pipe->top_pipe = top_pipe;
135 
136 			pipe->top_pipe = NULL;
137 			pipe->bottom_pipe = NULL;
138 			pipe->plane_state = NULL;
139 			pipe->stream = NULL;
140 			memset(&pipe->plane_res, 0, sizeof(pipe->plane_res));
141 			memset(&pipe->stream_res, 0, sizeof(pipe->stream_res));
142 		}
143 	}
144 }
145 
all_pipes_have_stream_and_plane(struct dml2_context * ctx,const struct dc_state * context)146 static bool all_pipes_have_stream_and_plane(struct dml2_context *ctx, const struct dc_state *context)
147 {
148 	int i;
149 
150 	for (i = 0; i < ctx->config.dcn_pipe_count; i++) {
151 		const struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
152 
153 		if (!pipe->stream)
154 			continue;
155 
156 		if (!pipe->plane_state)
157 			return false;
158 	}
159 	return true;
160 }
161 
mpo_in_use(const struct dc_state * context)162 static bool mpo_in_use(const struct dc_state *context)
163 {
164 	int i;
165 
166 	for (i = 0; i < context->stream_count; i++) {
167 		if (context->stream_status[i].plane_count > 1)
168 			return true;
169 	}
170 	return false;
171 }
172 
173 /*
174  * dcn32_get_num_free_pipes: Calculate number of free pipes
175  *
176  * This function assumes that a "used" pipe is a pipe that has
177  * both a stream and a plane assigned to it.
178  *
179  * @dc: current dc state
180  * @context: new dc state
181  *
182  * Return:
183  * Number of free pipes available in the context
184  */
get_num_free_pipes(struct dml2_context * ctx,struct dc_state * state)185 static unsigned int get_num_free_pipes(struct dml2_context *ctx, struct dc_state *state)
186 {
187 	unsigned int i;
188 	unsigned int free_pipes = 0;
189 	unsigned int num_pipes = 0;
190 
191 	for (i = 0; i < ctx->config.dcn_pipe_count; i++) {
192 		struct pipe_ctx *pipe = &state->res_ctx.pipe_ctx[i];
193 
194 		if (pipe->stream && !pipe->top_pipe) {
195 			while (pipe) {
196 				num_pipes++;
197 				pipe = pipe->bottom_pipe;
198 			}
199 		}
200 	}
201 
202 	free_pipes = ctx->config.dcn_pipe_count - num_pipes;
203 	return free_pipes;
204 }
205 
206 /*
207  * dcn32_assign_subvp_pipe: Function to decide which pipe will use Sub-VP.
208  *
209  * We enter this function if we are Sub-VP capable (i.e. enough pipes available)
210  * and regular P-State switching (i.e. VACTIVE/VBLANK) is not supported, or if
211  * we are forcing SubVP P-State switching on the current config.
212  *
213  * The number of pipes used for the chosen surface must be less than or equal to the
214  * number of free pipes available.
215  *
216  * In general we choose surfaces with the longest frame time first (better for SubVP + VBLANK).
217  * For multi-display cases the ActiveDRAMClockChangeMargin doesn't provide enough info on its own
218  * for determining which should be the SubVP pipe (need a way to determine if a pipe / plane doesn't
219  * support MCLK switching naturally [i.e. ACTIVE or VBLANK]).
220  *
221  * @param dc: current dc state
222  * @param context: new dc state
223  * @param index: [out] dc pipe index for the pipe chosen to have phantom pipes assigned
224  *
225  * Return:
226  * True if a valid pipe assignment was found for Sub-VP. Otherwise false.
227  */
assign_subvp_pipe(struct dml2_context * ctx,struct dc_state * context,unsigned int * index)228 static bool assign_subvp_pipe(struct dml2_context *ctx, struct dc_state *context, unsigned int *index)
229 {
230 	unsigned int i, pipe_idx;
231 	unsigned int max_frame_time = 0;
232 	bool valid_assignment_found = false;
233 	unsigned int free_pipes = 2; //dcn32_get_num_free_pipes(dc, context);
234 	bool current_assignment_freesync = false;
235 	struct vba_vars_st *vba = &context->bw_ctx.dml.vba;
236 
237 	for (i = 0, pipe_idx = 0; i < ctx->config.dcn_pipe_count; i++) {
238 		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
239 		unsigned int num_pipes = 0;
240 		unsigned int refresh_rate = 0;
241 
242 		if (!pipe->stream)
243 			continue;
244 
245 		// Round up
246 		refresh_rate = (pipe->stream->timing.pix_clk_100hz * 100 +
247 				pipe->stream->timing.v_total * pipe->stream->timing.h_total - 1)
248 				/ (double)(pipe->stream->timing.v_total * pipe->stream->timing.h_total);
249 		/* SubVP pipe candidate requirements:
250 		 * - Refresh rate < 120hz
251 		 * - Not able to switch in vactive naturally (switching in active means the
252 		 *   DET provides enough buffer to hide the P-State switch latency -- trying
253 		 *   to combine this with SubVP can cause issues with the scheduling).
254 		 */
255 		if (pipe->plane_state && !pipe->top_pipe &&
256 				ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe) == SUBVP_NONE && refresh_rate < 120 &&
257 				vba->ActiveDRAMClockChangeLatencyMarginPerState[vba->VoltageLevel][vba->maxMpcComb][vba->pipe_plane[pipe_idx]] <= 0) {
258 			while (pipe) {
259 				num_pipes++;
260 				pipe = pipe->bottom_pipe;
261 			}
262 
263 			pipe = &context->res_ctx.pipe_ctx[i];
264 			if (num_pipes <= free_pipes) {
265 				struct dc_stream_state *stream = pipe->stream;
266 				unsigned int frame_us = (stream->timing.v_total * stream->timing.h_total /
267 						(double)(stream->timing.pix_clk_100hz * 100)) * 1000000;
268 				if (frame_us > max_frame_time && !stream->ignore_msa_timing_param) {
269 					*index = i;
270 					max_frame_time = frame_us;
271 					valid_assignment_found = true;
272 					current_assignment_freesync = false;
273 				/* For the 2-Freesync display case, still choose the one with the
274 			     * longest frame time
275 			     */
276 				} else if (stream->ignore_msa_timing_param && (!valid_assignment_found ||
277 						(current_assignment_freesync && frame_us > max_frame_time))) {
278 					*index = i;
279 					valid_assignment_found = true;
280 					current_assignment_freesync = true;
281 				}
282 			}
283 		}
284 		pipe_idx++;
285 	}
286 	return valid_assignment_found;
287 }
288 
289 /*
290  * enough_pipes_for_subvp: Function to check if there are "enough" pipes for SubVP.
291  *
292  * This function returns true if there are enough free pipes
293  * to create the required phantom pipes for any given stream
294  * (that does not already have phantom pipe assigned).
295  *
296  * e.g. For a 2 stream config where the first stream uses one
297  * pipe and the second stream uses 2 pipes (i.e. pipe split),
298  * this function will return true because there is 1 remaining
299  * pipe which can be used as the phantom pipe for the non pipe
300  * split pipe.
301  *
302  * @dc: current dc state
303  * @context: new dc state
304  *
305  * Return:
306  * True if there are enough free pipes to assign phantom pipes to at least one
307  * stream that does not already have phantom pipes assigned. Otherwise false.
308  */
enough_pipes_for_subvp(struct dml2_context * ctx,struct dc_state * state)309 static bool enough_pipes_for_subvp(struct dml2_context *ctx, struct dc_state *state)
310 {
311 	unsigned int i, split_cnt, free_pipes;
312 	unsigned int min_pipe_split = ctx->config.dcn_pipe_count + 1; // init as max number of pipes + 1
313 	bool subvp_possible = false;
314 
315 	for (i = 0; i < ctx->config.dcn_pipe_count; i++) {
316 		struct pipe_ctx *pipe = &state->res_ctx.pipe_ctx[i];
317 
318 		// Find the minimum pipe split count for non SubVP pipes
319 		if (pipe->stream && !pipe->top_pipe &&
320 				ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(state, pipe) == SUBVP_NONE) {
321 			split_cnt = 0;
322 			while (pipe) {
323 				split_cnt++;
324 				pipe = pipe->bottom_pipe;
325 			}
326 
327 			if (split_cnt < min_pipe_split)
328 				min_pipe_split = split_cnt;
329 		}
330 	}
331 
332 	free_pipes = get_num_free_pipes(ctx, state);
333 
334 	// SubVP only possible if at least one pipe is being used (i.e. free_pipes
335 	// should not equal to the pipe_count)
336 	if (free_pipes >= min_pipe_split && free_pipes < ctx->config.dcn_pipe_count)
337 		subvp_possible = true;
338 
339 	return subvp_possible;
340 }
341 
342 /*
343  * subvp_subvp_schedulable: Determine if SubVP + SubVP config is schedulable
344  *
345  * High level algorithm:
346  * 1. Find longest microschedule length (in us) between the two SubVP pipes
347  * 2. Check if the worst case overlap (VBLANK in middle of ACTIVE) for both
348  * pipes still allows for the maximum microschedule to fit in the active
349  * region for both pipes.
350  *
351  * @dc: current dc state
352  * @context: new dc state
353  *
354  * Return:
355  * bool - True if the SubVP + SubVP config is schedulable, false otherwise
356  */
subvp_subvp_schedulable(struct dml2_context * ctx,struct dc_state * context)357 static bool subvp_subvp_schedulable(struct dml2_context *ctx, struct dc_state *context)
358 {
359 	struct pipe_ctx *subvp_pipes[2];
360 	struct dc_stream_state *phantom = NULL;
361 	uint32_t microschedule_lines = 0;
362 	uint32_t index = 0;
363 	uint32_t i;
364 	uint32_t max_microschedule_us = 0;
365 	int32_t vactive1_us, vactive2_us, vblank1_us, vblank2_us;
366 
367 	for (i = 0; i < ctx->config.dcn_pipe_count; i++) {
368 		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
369 		uint32_t time_us = 0;
370 
371 		/* Loop to calculate the maximum microschedule time between the two SubVP pipes,
372 		 * and also to store the two main SubVP pipe pointers in subvp_pipes[2].
373 		 */
374 		if (pipe->stream && pipe->plane_state && !pipe->top_pipe &&
375 				ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe) == SUBVP_MAIN) {
376 			phantom = ctx->config.svp_pstate.callbacks.get_paired_subvp_stream(context, pipe->stream);
377 			microschedule_lines = (phantom->timing.v_total - phantom->timing.v_front_porch) +
378 					phantom->timing.v_addressable;
379 
380 			// Round up when calculating microschedule time (+ 1 at the end)
381 			time_us = (microschedule_lines * phantom->timing.h_total) /
382 					(double)(phantom->timing.pix_clk_100hz * 100) * 1000000 +
383 					ctx->config.svp_pstate.subvp_prefetch_end_to_mall_start_us +
384 					ctx->config.svp_pstate.subvp_fw_processing_delay_us + 1;
385 			if (time_us > max_microschedule_us)
386 				max_microschedule_us = time_us;
387 
388 			subvp_pipes[index] = pipe;
389 			index++;
390 
391 			// Maximum 2 SubVP pipes
392 			if (index == 2)
393 				break;
394 		}
395 	}
396 	vactive1_us = ((subvp_pipes[0]->stream->timing.v_addressable * subvp_pipes[0]->stream->timing.h_total) /
397 			(double)(subvp_pipes[0]->stream->timing.pix_clk_100hz * 100)) * 1000000;
398 	vactive2_us = ((subvp_pipes[1]->stream->timing.v_addressable * subvp_pipes[1]->stream->timing.h_total) /
399 				(double)(subvp_pipes[1]->stream->timing.pix_clk_100hz * 100)) * 1000000;
400 	vblank1_us = (((subvp_pipes[0]->stream->timing.v_total - subvp_pipes[0]->stream->timing.v_addressable) *
401 			subvp_pipes[0]->stream->timing.h_total) /
402 			(double)(subvp_pipes[0]->stream->timing.pix_clk_100hz * 100)) * 1000000;
403 	vblank2_us = (((subvp_pipes[1]->stream->timing.v_total - subvp_pipes[1]->stream->timing.v_addressable) *
404 			subvp_pipes[1]->stream->timing.h_total) /
405 			(double)(subvp_pipes[1]->stream->timing.pix_clk_100hz * 100)) * 1000000;
406 
407 	if ((vactive1_us - vblank2_us) / 2 > max_microschedule_us &&
408 	    (vactive2_us - vblank1_us) / 2 > max_microschedule_us)
409 		return true;
410 
411 	return false;
412 }
413 
414 /*
415  * dml2_svp_drr_schedulable: Determine if SubVP + DRR config is schedulable
416  *
417  * High level algorithm:
418  * 1. Get timing for SubVP pipe, phantom pipe, and DRR pipe
419  * 2. Determine the frame time for the DRR display when adding required margin for MCLK switching
420  * (the margin is equal to the MALL region + DRR margin (500us))
421  * 3.If (SubVP Active - Prefetch > Stretched DRR frame + max(MALL region, Stretched DRR frame))
422  * then report the configuration as supported
423  *
424  * @dc: current dc state
425  * @context: new dc state
426  * @drr_pipe: DRR pipe_ctx for the SubVP + DRR config
427  *
428  * Return:
429  * bool - True if the SubVP + DRR config is schedulable, false otherwise
430  */
dml2_svp_drr_schedulable(struct dml2_context * ctx,struct dc_state * context,struct dc_crtc_timing * drr_timing)431 bool dml2_svp_drr_schedulable(struct dml2_context *ctx, struct dc_state *context, struct dc_crtc_timing *drr_timing)
432 {
433 	bool schedulable = false;
434 	uint32_t i;
435 	struct pipe_ctx *pipe = NULL;
436 	struct dc_crtc_timing *main_timing = NULL;
437 	struct dc_crtc_timing *phantom_timing = NULL;
438 	struct dc_stream_state *phantom_stream;
439 	int16_t prefetch_us = 0;
440 	int16_t mall_region_us = 0;
441 	int16_t drr_frame_us = 0;	// nominal frame time
442 	int16_t subvp_active_us = 0;
443 	int16_t stretched_drr_us = 0;
444 	int16_t drr_stretched_vblank_us = 0;
445 	int16_t max_vblank_mallregion = 0;
446 
447 	// Find SubVP pipe
448 	for (i = 0; i < ctx->config.dcn_pipe_count; i++) {
449 		pipe = &context->res_ctx.pipe_ctx[i];
450 
451 		// We check for master pipe, but it shouldn't matter since we only need
452 		// the pipe for timing info (stream should be same for any pipe splits)
453 		if (!pipe->stream || !pipe->plane_state || pipe->top_pipe || pipe->prev_odm_pipe)
454 			continue;
455 
456 		// Find the SubVP pipe
457 		if (ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe) == SUBVP_MAIN)
458 			break;
459 	}
460 
461 	phantom_stream = ctx->config.svp_pstate.callbacks.get_paired_subvp_stream(context, pipe->stream);
462 	main_timing = &pipe->stream->timing;
463 	phantom_timing = &phantom_stream->timing;
464 	prefetch_us = (phantom_timing->v_total - phantom_timing->v_front_porch) * phantom_timing->h_total /
465 			(double)(phantom_timing->pix_clk_100hz * 100) * 1000000 +
466 			ctx->config.svp_pstate.subvp_prefetch_end_to_mall_start_us;
467 	subvp_active_us = main_timing->v_addressable * main_timing->h_total /
468 			(double)(main_timing->pix_clk_100hz * 100) * 1000000;
469 	drr_frame_us = drr_timing->v_total * drr_timing->h_total /
470 			(double)(drr_timing->pix_clk_100hz * 100) * 1000000;
471 	// P-State allow width and FW delays already included phantom_timing->v_addressable
472 	mall_region_us = phantom_timing->v_addressable * phantom_timing->h_total /
473 			(double)(phantom_timing->pix_clk_100hz * 100) * 1000000;
474 	stretched_drr_us = drr_frame_us + mall_region_us + SUBVP_DRR_MARGIN_US;
475 	drr_stretched_vblank_us = (drr_timing->v_total - drr_timing->v_addressable) * drr_timing->h_total /
476 			(double)(drr_timing->pix_clk_100hz * 100) * 1000000 + (stretched_drr_us - drr_frame_us);
477 	max_vblank_mallregion = drr_stretched_vblank_us > mall_region_us ? drr_stretched_vblank_us : mall_region_us;
478 
479 	/* We consider SubVP + DRR schedulable if the stretched frame duration of the DRR display (i.e. the
480 	 * highest refresh rate + margin that can support UCLK P-State switch) passes the static analysis
481 	 * for VBLANK: (VACTIVE region of the SubVP pipe can fit the MALL prefetch, VBLANK frame time,
482 	 * and the max of (VBLANK blanking time, MALL region)).
483 	 */
484 	if (stretched_drr_us < (1 / (double)drr_timing->min_refresh_in_uhz) * 1000000 * 1000000 &&
485 			subvp_active_us - prefetch_us - stretched_drr_us - max_vblank_mallregion > 0)
486 		schedulable = true;
487 
488 	return schedulable;
489 }
490 
491 
492 /*
493  * subvp_vblank_schedulable: Determine if SubVP + VBLANK config is schedulable
494  *
495  * High level algorithm:
496  * 1. Get timing for SubVP pipe, phantom pipe, and VBLANK pipe
497  * 2. If (SubVP Active - Prefetch > Vblank Frame Time + max(MALL region, Vblank blanking time))
498  * then report the configuration as supported
499  * 3. If the VBLANK display is DRR, then take the DRR static schedulability path
500  *
501  * @dc: current dc state
502  * @context: new dc state
503  *
504  * Return:
505  * bool - True if the SubVP + VBLANK/DRR config is schedulable, false otherwise
506  */
subvp_vblank_schedulable(struct dml2_context * ctx,struct dc_state * context)507 static bool subvp_vblank_schedulable(struct dml2_context *ctx, struct dc_state *context)
508 {
509 	struct pipe_ctx *pipe = NULL;
510 	struct pipe_ctx *subvp_pipe = NULL;
511 	bool found = false;
512 	bool schedulable = false;
513 	uint32_t i = 0;
514 	uint8_t vblank_index = 0;
515 	uint16_t prefetch_us = 0;
516 	uint16_t mall_region_us = 0;
517 	uint16_t vblank_frame_us = 0;
518 	uint16_t subvp_active_us = 0;
519 	uint16_t vblank_blank_us = 0;
520 	uint16_t max_vblank_mallregion = 0;
521 	struct dc_crtc_timing *main_timing = NULL;
522 	struct dc_crtc_timing *phantom_timing = NULL;
523 	struct dc_crtc_timing *vblank_timing = NULL;
524 	struct dc_stream_state *phantom_stream;
525 	enum mall_stream_type pipe_mall_type;
526 
527 	/* For SubVP + VBLANK/DRR cases, we assume there can only be
528 	 * a single VBLANK/DRR display. If DML outputs SubVP + VBLANK
529 	 * is supported, it is either a single VBLANK case or two VBLANK
530 	 * displays which are synchronized (in which case they have identical
531 	 * timings).
532 	 */
533 	for (i = 0; i < ctx->config.dcn_pipe_count; i++) {
534 		pipe = &context->res_ctx.pipe_ctx[i];
535 		pipe_mall_type = ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe);
536 
537 		// We check for master pipe, but it shouldn't matter since we only need
538 		// the pipe for timing info (stream should be same for any pipe splits)
539 		if (!pipe->stream || !pipe->plane_state || pipe->top_pipe || pipe->prev_odm_pipe)
540 			continue;
541 
542 		if (!found && pipe_mall_type == SUBVP_NONE) {
543 			// Found pipe which is not SubVP or Phantom (i.e. the VBLANK pipe).
544 			vblank_index = i;
545 			found = true;
546 		}
547 
548 		if (!subvp_pipe && pipe_mall_type == SUBVP_MAIN)
549 			subvp_pipe = pipe;
550 	}
551 	// Use ignore_msa_timing_param flag to identify as DRR
552 	if (found && context->res_ctx.pipe_ctx[vblank_index].stream->ignore_msa_timing_param) {
553 		// SUBVP + DRR case
554 		schedulable = dml2_svp_drr_schedulable(ctx, context, &context->res_ctx.pipe_ctx[vblank_index].stream->timing);
555 	} else if (found) {
556 		phantom_stream = ctx->config.svp_pstate.callbacks.get_paired_subvp_stream(context, subvp_pipe->stream);
557 		main_timing = &subvp_pipe->stream->timing;
558 		phantom_timing = &phantom_stream->timing;
559 		vblank_timing = &context->res_ctx.pipe_ctx[vblank_index].stream->timing;
560 		// Prefetch time is equal to VACTIVE + BP + VSYNC of the phantom pipe
561 		// Also include the prefetch end to mallstart delay time
562 		prefetch_us = (phantom_timing->v_total - phantom_timing->v_front_porch) * phantom_timing->h_total /
563 				(double)(phantom_timing->pix_clk_100hz * 100) * 1000000 +
564 				ctx->config.svp_pstate.subvp_prefetch_end_to_mall_start_us;
565 		// P-State allow width and FW delays already included phantom_timing->v_addressable
566 		mall_region_us = phantom_timing->v_addressable * phantom_timing->h_total /
567 				(double)(phantom_timing->pix_clk_100hz * 100) * 1000000;
568 		vblank_frame_us = vblank_timing->v_total * vblank_timing->h_total /
569 				(double)(vblank_timing->pix_clk_100hz * 100) * 1000000;
570 		vblank_blank_us =  (vblank_timing->v_total - vblank_timing->v_addressable) * vblank_timing->h_total /
571 				(double)(vblank_timing->pix_clk_100hz * 100) * 1000000;
572 		subvp_active_us = main_timing->v_addressable * main_timing->h_total /
573 				(double)(main_timing->pix_clk_100hz * 100) * 1000000;
574 		max_vblank_mallregion = vblank_blank_us > mall_region_us ? vblank_blank_us : mall_region_us;
575 
576 		// Schedulable if VACTIVE region of the SubVP pipe can fit the MALL prefetch, VBLANK frame time,
577 		// and the max of (VBLANK blanking time, MALL region)
578 		// TODO: Possibly add some margin (i.e. the below conditions should be [...] > X instead of [...] > 0)
579 		if (subvp_active_us - prefetch_us - vblank_frame_us - max_vblank_mallregion > 0)
580 			schedulable = true;
581 	}
582 	return schedulable;
583 }
584 
585 /*
586  * subvp_validate_static_schedulability: Check which SubVP case is calculated and handle
587  * static analysis based on the case.
588  *
589  * Three cases:
590  * 1. SubVP + SubVP
591  * 2. SubVP + VBLANK (DRR checked internally)
592  * 3. SubVP + VACTIVE (currently unsupported)
593  *
594  * @dc: current dc state
595  * @context: new dc state
596  * @vlevel: Voltage level calculated by DML
597  *
598  * Return:
599  * bool - True if statically schedulable, false otherwise
600  */
dml2_svp_validate_static_schedulability(struct dml2_context * ctx,struct dc_state * context,enum dml_dram_clock_change_support pstate_change_type)601 bool dml2_svp_validate_static_schedulability(struct dml2_context *ctx, struct dc_state *context, enum dml_dram_clock_change_support pstate_change_type)
602 {
603 	bool schedulable = true;	// true by default for single display case
604 	struct vba_vars_st *vba = &context->bw_ctx.dml.vba;
605 	uint32_t i, pipe_idx;
606 	uint8_t subvp_count = 0;
607 	uint8_t vactive_count = 0;
608 
609 	for (i = 0, pipe_idx = 0; i < ctx->config.dcn_pipe_count; i++) {
610 		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
611 		enum mall_stream_type pipe_mall_type = ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe);
612 
613 		if (!pipe->stream)
614 			continue;
615 
616 		if (pipe->plane_state && !pipe->top_pipe &&
617 				pipe_mall_type == SUBVP_MAIN)
618 			subvp_count++;
619 
620 		// Count how many planes that aren't SubVP/phantom are capable of VACTIVE
621 		// switching (SubVP + VACTIVE unsupported). In situations where we force
622 		// SubVP for a VACTIVE plane, we don't want to increment the vactive_count.
623 		if (vba->ActiveDRAMClockChangeLatencyMargin[vba->pipe_plane[pipe_idx]] > 0 &&
624 		    pipe_mall_type == SUBVP_NONE) {
625 			vactive_count++;
626 		}
627 		pipe_idx++;
628 	}
629 
630 	if (subvp_count == 2) {
631 		// Static schedulability check for SubVP + SubVP case
632 		schedulable = subvp_subvp_schedulable(ctx, context);
633 	} else if (pstate_change_type == dml_dram_clock_change_vblank_w_mall_sub_vp) {
634 		// Static schedulability check for SubVP + VBLANK case. Also handle the case where
635 		// DML outputs SubVP + VBLANK + VACTIVE (DML will report as SubVP + VBLANK)
636 		if (vactive_count > 0)
637 			schedulable = false;
638 		else
639 			schedulable = subvp_vblank_schedulable(ctx, context);
640 	} else if (pstate_change_type == dml_dram_clock_change_vactive_w_mall_sub_vp &&
641 			vactive_count > 0) {
642 		// For single display SubVP cases, DML will output dm_dram_clock_change_vactive_w_mall_sub_vp by default.
643 		// We tell the difference between SubVP vs. SubVP + VACTIVE by checking the vactive_count.
644 		// SubVP + VACTIVE currently unsupported
645 		schedulable = false;
646 	}
647 	return schedulable;
648 }
649 
set_phantom_stream_timing(struct dml2_context * ctx,struct dc_state * state,struct pipe_ctx * ref_pipe,struct dc_stream_state * phantom_stream,unsigned int dc_pipe_idx,unsigned int svp_height,unsigned int svp_vstartup)650 static void set_phantom_stream_timing(struct dml2_context *ctx, struct dc_state *state,
651 				     struct pipe_ctx *ref_pipe,
652 				     struct dc_stream_state *phantom_stream,
653 				     unsigned int dc_pipe_idx,
654 				     unsigned int svp_height,
655 				     unsigned int svp_vstartup)
656 {
657 	unsigned int i, pipe_idx;
658 	double line_time, fp_and_sync_width_time;
659 	struct pipe_ctx *pipe;
660 	uint32_t phantom_vactive, phantom_bp, pstate_width_fw_delay_lines;
661 	static const double cvt_rb_vblank_max = ((double) 460 / (1000 * 1000));
662 
663 	// Find DML pipe index (pipe_idx) using dc_pipe_idx
664 	for (i = 0, pipe_idx = 0; i < ctx->config.dcn_pipe_count; i++) {
665 		pipe = &state->res_ctx.pipe_ctx[i];
666 
667 		if (!pipe->stream)
668 			continue;
669 
670 		if (i == dc_pipe_idx)
671 			break;
672 
673 		pipe_idx++;
674 	}
675 
676 	// Calculate lines required for pstate allow width and FW processing delays
677 	pstate_width_fw_delay_lines = ((double)(ctx->config.svp_pstate.subvp_fw_processing_delay_us +
678 			ctx->config.svp_pstate.subvp_pstate_allow_width_us) / 1000000) *
679 			(ref_pipe->stream->timing.pix_clk_100hz * 100) /
680 			(double)ref_pipe->stream->timing.h_total;
681 
682 	// DML calculation for MALL region doesn't take into account FW delay
683 	// and required pstate allow width for multi-display cases
684 	/* Add 16 lines margin to the MALL REGION because SUB_VP_START_LINE must be aligned
685 	 * to 2 swaths (i.e. 16 lines)
686 	 */
687 	phantom_vactive = svp_height + pstate_width_fw_delay_lines + ctx->config.svp_pstate.subvp_swath_height_margin_lines;
688 
689 	phantom_stream->timing.v_front_porch = 1;
690 
691 	line_time = phantom_stream->timing.h_total / ((double)phantom_stream->timing.pix_clk_100hz * 100);
692 	fp_and_sync_width_time = (phantom_stream->timing.v_front_porch + phantom_stream->timing.v_sync_width) * line_time;
693 
694 	if ((svp_vstartup * line_time) + fp_and_sync_width_time > cvt_rb_vblank_max) {
695 		svp_vstartup = (cvt_rb_vblank_max - fp_and_sync_width_time) / line_time;
696 	}
697 
698 	// For backporch of phantom pipe, use vstartup of the main pipe
699 	phantom_bp = svp_vstartup;
700 
701 	phantom_stream->dst.y = 0;
702 	phantom_stream->dst.height = phantom_vactive;
703 	phantom_stream->src.y = 0;
704 	phantom_stream->src.height = phantom_vactive;
705 
706 	phantom_stream->timing.v_addressable = phantom_vactive;
707 
708 	phantom_stream->timing.v_total = phantom_stream->timing.v_addressable +
709 						phantom_stream->timing.v_front_porch +
710 						phantom_stream->timing.v_sync_width +
711 						phantom_bp;
712 	phantom_stream->timing.flags.DSC = 0; // Don't need DSC for phantom timing
713 }
714 
enable_phantom_stream(struct dml2_context * ctx,struct dc_state * state,unsigned int dc_pipe_idx,unsigned int svp_height,unsigned int vstartup)715 static struct dc_stream_state *enable_phantom_stream(struct dml2_context *ctx, struct dc_state *state, unsigned int dc_pipe_idx, unsigned int svp_height, unsigned int vstartup)
716 {
717 	struct pipe_ctx *ref_pipe = &state->res_ctx.pipe_ctx[dc_pipe_idx];
718 	struct dc_stream_state *phantom_stream = ctx->config.svp_pstate.callbacks.create_phantom_stream(
719 			ctx->config.svp_pstate.callbacks.dc,
720 			state,
721 			ref_pipe->stream);
722 
723 	/* stream has limited viewport and small timing */
724 	memcpy(&phantom_stream->timing, &ref_pipe->stream->timing, sizeof(phantom_stream->timing));
725 	memcpy(&phantom_stream->src, &ref_pipe->stream->src, sizeof(phantom_stream->src));
726 	memcpy(&phantom_stream->dst, &ref_pipe->stream->dst, sizeof(phantom_stream->dst));
727 	set_phantom_stream_timing(ctx, state, ref_pipe, phantom_stream, dc_pipe_idx, svp_height, vstartup);
728 
729 	ctx->config.svp_pstate.callbacks.add_phantom_stream(ctx->config.svp_pstate.callbacks.dc,
730 			state,
731 			phantom_stream,
732 			ref_pipe->stream);
733 	return phantom_stream;
734 }
735 
enable_phantom_plane(struct dml2_context * ctx,struct dc_state * state,struct dc_stream_state * phantom_stream,unsigned int dc_pipe_idx)736 static void enable_phantom_plane(struct dml2_context *ctx,
737 		struct dc_state *state,
738 		struct dc_stream_state *phantom_stream,
739 		unsigned int dc_pipe_idx)
740 {
741 	struct dc_plane_state *phantom_plane = NULL;
742 	struct dc_plane_state *prev_phantom_plane = NULL;
743 	struct pipe_ctx *curr_pipe = &state->res_ctx.pipe_ctx[dc_pipe_idx];
744 
745 	while (curr_pipe) {
746 		if (curr_pipe->top_pipe && curr_pipe->top_pipe->plane_state == curr_pipe->plane_state) {
747 			phantom_plane = prev_phantom_plane;
748 		} else {
749 			phantom_plane = ctx->config.svp_pstate.callbacks.create_phantom_plane(
750 					ctx->config.svp_pstate.callbacks.dc,
751 					state,
752 					curr_pipe->plane_state);
753 			if (!phantom_plane)
754 				return;
755 		}
756 
757 		memcpy(&phantom_plane->address, &curr_pipe->plane_state->address, sizeof(phantom_plane->address));
758 		memcpy(&phantom_plane->scaling_quality, &curr_pipe->plane_state->scaling_quality,
759 				sizeof(phantom_plane->scaling_quality));
760 		memcpy(&phantom_plane->src_rect, &curr_pipe->plane_state->src_rect, sizeof(phantom_plane->src_rect));
761 		memcpy(&phantom_plane->dst_rect, &curr_pipe->plane_state->dst_rect, sizeof(phantom_plane->dst_rect));
762 		memcpy(&phantom_plane->clip_rect, &curr_pipe->plane_state->clip_rect, sizeof(phantom_plane->clip_rect));
763 		memcpy(&phantom_plane->plane_size, &curr_pipe->plane_state->plane_size,
764 				sizeof(phantom_plane->plane_size));
765 		memcpy(&phantom_plane->tiling_info, &curr_pipe->plane_state->tiling_info,
766 				sizeof(phantom_plane->tiling_info));
767 		memcpy(&phantom_plane->dcc, &curr_pipe->plane_state->dcc, sizeof(phantom_plane->dcc));
768 		//phantom_plane->tiling_info.gfx10compatible.compat_level = curr_pipe->plane_state->tiling_info.gfx10compatible.compat_level;
769 		phantom_plane->format = curr_pipe->plane_state->format;
770 		phantom_plane->rotation = curr_pipe->plane_state->rotation;
771 		phantom_plane->visible = curr_pipe->plane_state->visible;
772 
773 		/* Shadow pipe has small viewport. */
774 		phantom_plane->clip_rect.y = 0;
775 		phantom_plane->clip_rect.height = phantom_stream->timing.v_addressable;
776 
777 		ctx->config.svp_pstate.callbacks.add_phantom_plane(ctx->config.svp_pstate.callbacks.dc, phantom_stream, phantom_plane, state);
778 
779 		curr_pipe = curr_pipe->bottom_pipe;
780 		prev_phantom_plane = phantom_plane;
781 	}
782 }
783 
add_phantom_pipes_for_main_pipe(struct dml2_context * ctx,struct dc_state * state,unsigned int main_pipe_idx,unsigned int svp_height,unsigned int vstartup)784 static void add_phantom_pipes_for_main_pipe(struct dml2_context *ctx, struct dc_state *state, unsigned int main_pipe_idx, unsigned int svp_height, unsigned int vstartup)
785 {
786 	struct dc_stream_state *phantom_stream = NULL;
787 	unsigned int i;
788 
789 	// The index of the DC pipe passed into this function is guarenteed to
790 	// be a valid candidate for SubVP (i.e. has a plane, stream, doesn't
791 	// already have phantom pipe assigned, etc.) by previous checks.
792 	phantom_stream = enable_phantom_stream(ctx, state, main_pipe_idx, svp_height, vstartup);
793 	enable_phantom_plane(ctx, state, phantom_stream, main_pipe_idx);
794 
795 	for (i = 0; i < ctx->config.dcn_pipe_count; i++) {
796 		struct pipe_ctx *pipe = &state->res_ctx.pipe_ctx[i];
797 
798 		// Build scaling params for phantom pipes which were newly added.
799 		// We determine which phantom pipes were added by comparing with
800 		// the phantom stream.
801 		if (pipe->plane_state && pipe->stream && pipe->stream == phantom_stream &&
802 				ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(state, pipe) == SUBVP_PHANTOM) {
803 			pipe->stream->use_dynamic_meta = false;
804 			pipe->plane_state->flip_immediate = false;
805 			if (!ctx->config.svp_pstate.callbacks.build_scaling_params(pipe)) {
806 				// Log / remove phantom pipes since failed to build scaling params
807 			}
808 		}
809 	}
810 }
811 
remove_all_phantom_planes_for_stream(struct dml2_context * ctx,struct dc_stream_state * stream,struct dc_state * context)812 static bool remove_all_phantom_planes_for_stream(struct dml2_context *ctx, struct dc_stream_state *stream, struct dc_state *context)
813 {
814 	int i, old_plane_count;
815 	struct dc_stream_status *stream_status = NULL;
816 	struct dc_plane_state *del_planes[MAX_SURFACE_NUM] = { 0 };
817 
818 	for (i = 0; i < context->stream_count; i++)
819 			if (context->streams[i] == stream) {
820 				stream_status = &context->stream_status[i];
821 				break;
822 			}
823 
824 	if (stream_status == NULL) {
825 		return false;
826 	}
827 
828 	old_plane_count = stream_status->plane_count;
829 
830 	for (i = 0; i < old_plane_count; i++)
831 		del_planes[i] = stream_status->plane_states[i];
832 
833 	for (i = 0; i < old_plane_count; i++) {
834 		if (!ctx->config.svp_pstate.callbacks.remove_phantom_plane(ctx->config.svp_pstate.callbacks.dc, stream, del_planes[i], context))
835 			return false;
836 		ctx->config.svp_pstate.callbacks.release_phantom_plane(ctx->config.svp_pstate.callbacks.dc, context, del_planes[i]);
837 	}
838 
839 	return true;
840 }
841 
dml2_svp_remove_all_phantom_pipes(struct dml2_context * ctx,struct dc_state * state)842 bool dml2_svp_remove_all_phantom_pipes(struct dml2_context *ctx, struct dc_state *state)
843 {
844 	int i;
845 	bool removed_pipe = false;
846 	struct dc_stream_state *phantom_stream = NULL;
847 
848 	for (i = 0; i < ctx->config.dcn_pipe_count; i++) {
849 		struct pipe_ctx *pipe = &state->res_ctx.pipe_ctx[i];
850 		// build scaling params for phantom pipes
851 		if (pipe->plane_state && pipe->stream && ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(state, pipe) == SUBVP_PHANTOM) {
852 			phantom_stream = pipe->stream;
853 
854 			remove_all_phantom_planes_for_stream(ctx, phantom_stream, state);
855 			ctx->config.svp_pstate.callbacks.remove_phantom_stream(ctx->config.svp_pstate.callbacks.dc, state, phantom_stream);
856 			ctx->config.svp_pstate.callbacks.release_phantom_stream(ctx->config.svp_pstate.callbacks.dc, state, phantom_stream);
857 
858 			removed_pipe = true;
859 		}
860 
861 		if (pipe->plane_state) {
862 			pipe->plane_state->is_phantom = false;
863 		}
864 	}
865 	return removed_pipe;
866 }
867 
868 
869 /* Conditions for setting up phantom pipes for SubVP:
870  * 1. Not force disable SubVP
871  * 2. Full update (i.e. !fast_validate)
872  * 3. Enough pipes are available to support SubVP (TODO: Which pipes will use VACTIVE / VBLANK / SUBVP?)
873  * 4. Display configuration passes validation
874  * 5. (Config doesn't support MCLK in VACTIVE/VBLANK || dc->debug.force_subvp_mclk_switch)
875  */
dml2_svp_add_phantom_pipe_to_dc_state(struct dml2_context * ctx,struct dc_state * state,struct dml_mode_support_info_st * mode_support_info)876 bool dml2_svp_add_phantom_pipe_to_dc_state(struct dml2_context *ctx, struct dc_state *state, struct dml_mode_support_info_st *mode_support_info)
877 {
878 	unsigned int dc_pipe_idx, dml_pipe_idx;
879 	unsigned int svp_height, vstartup;
880 
881 	if (ctx->config.svp_pstate.force_disable_subvp)
882 		return false;
883 
884 	if (!all_pipes_have_stream_and_plane(ctx, state))
885 		return false;
886 
887 	if (mpo_in_use(state))
888 		return false;
889 
890 	merge_pipes_for_subvp(ctx, state);
891 	// to re-initialize viewport after the pipe merge
892 	for (int i = 0; i < ctx->config.dcn_pipe_count; i++) {
893 		struct pipe_ctx *pipe_ctx = &state->res_ctx.pipe_ctx[i];
894 
895 		if (!pipe_ctx->plane_state || !pipe_ctx->stream)
896 			continue;
897 
898 		ctx->config.svp_pstate.callbacks.build_scaling_params(pipe_ctx);
899 	}
900 
901 	if (enough_pipes_for_subvp(ctx, state) && assign_subvp_pipe(ctx, state, &dc_pipe_idx)) {
902 		dml_pipe_idx = dml2_helper_find_dml_pipe_idx_by_stream_id(ctx, state->res_ctx.pipe_ctx[dc_pipe_idx].stream->stream_id);
903 		svp_height = mode_support_info->SubViewportLinesNeededInMALL[dml_pipe_idx];
904 		vstartup = dml_get_vstartup_calculated(&ctx->v20.dml_core_ctx, dml_pipe_idx);
905 
906 		add_phantom_pipes_for_main_pipe(ctx, state, dc_pipe_idx, svp_height, vstartup);
907 
908 		return true;
909 	}
910 
911 	return false;
912 }
913