1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Support for Intel Camera Imaging ISP subsystem.
4  * Copyright (c) 2015, Intel Corporation.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  */
15 
16 #include <linux/math.h>
17 
18 #include <math_support.h>
19 #include <gdc_device.h>	/* HR_GDC_N */
20 
21 #include "hmm.h"
22 
23 #include "isp.h"	/* ISP_VEC_NELEMS */
24 
25 #include "ia_css_binary.h"
26 #include "ia_css_debug.h"
27 #include "ia_css_util.h"
28 #include "ia_css_isp_param.h"
29 #include "sh_css_internal.h"
30 #include "sh_css_sp.h"
31 #include "sh_css_firmware.h"
32 #include "sh_css_defs.h"
33 #include "sh_css_legacy.h"
34 
35 #include "atomisp_internal.h"
36 
37 #include "vf/vf_1.0/ia_css_vf.host.h"
38 #include "sc/sc_1.0/ia_css_sc.host.h"
39 #include "sdis/sdis_1.0/ia_css_sdis.host.h"
40 #include "fixedbds/fixedbds_1.0/ia_css_fixedbds_param.h"	/* FRAC_ACC */
41 
42 #include "camera/pipe/interface/ia_css_pipe_binarydesc.h"
43 
44 #include "assert_support.h"
45 
46 #define IMPLIES(a, b)           (!(a) || (b))   /* A => B */
47 
48 static struct ia_css_binary_xinfo *all_binaries; /* ISP binaries only (no SP) */
49 static struct ia_css_binary_xinfo
50 	*binary_infos[IA_CSS_BINARY_NUM_MODES] = { NULL, };
51 
52 static void
53 ia_css_binary_dvs_env(const struct ia_css_binary_info *info,
54 		      const struct ia_css_resolution *dvs_env,
55 		      struct ia_css_resolution *binary_dvs_env)
56 {
57 	if (info->enable.dvs_envelope) {
58 		assert(dvs_env);
59 		binary_dvs_env->width  = max(dvs_env->width, SH_CSS_MIN_DVS_ENVELOPE);
60 		binary_dvs_env->height = max(dvs_env->height, SH_CSS_MIN_DVS_ENVELOPE);
61 	}
62 }
63 
64 static void
65 ia_css_binary_internal_res(const struct ia_css_frame_info *in_info,
66 			   const struct ia_css_frame_info *bds_out_info,
67 			   const struct ia_css_frame_info *out_info,
68 			   const struct ia_css_resolution *dvs_env,
69 			   const struct ia_css_binary_info *info,
70 			   struct ia_css_resolution *internal_res)
71 {
72 	unsigned int isp_tmp_internal_width = 0,
73 		     isp_tmp_internal_height = 0;
74 	bool binary_supports_yuv_ds = info->enable.ds & 2;
75 	struct ia_css_resolution binary_dvs_env;
76 
77 	binary_dvs_env.width = 0;
78 	binary_dvs_env.height = 0;
79 	ia_css_binary_dvs_env(info, dvs_env, &binary_dvs_env);
80 
81 	if (binary_supports_yuv_ds) {
82 		if (in_info) {
83 			isp_tmp_internal_width = in_info->res.width
84 						 + info->pipeline.left_cropping + binary_dvs_env.width;
85 			isp_tmp_internal_height = in_info->res.height
86 						  + info->pipeline.top_cropping + binary_dvs_env.height;
87 		}
88 	} else if ((bds_out_info) && (out_info) &&
89 		   /* TODO: hack to make video_us case work. this should be reverted after
90 		   a nice solution in ISP */
91 		   (bds_out_info->res.width >= out_info->res.width)) {
92 		isp_tmp_internal_width = bds_out_info->padded_width;
93 		isp_tmp_internal_height = bds_out_info->res.height;
94 	} else {
95 		if (out_info) {
96 			isp_tmp_internal_width = out_info->padded_width;
97 			isp_tmp_internal_height = out_info->res.height;
98 		}
99 	}
100 
101 	/* We first calculate the resolutions used by the ISP. After that,
102 	 * we use those resolutions to compute sizes for tables etc. */
103 	internal_res->width = __ISP_INTERNAL_WIDTH(isp_tmp_internal_width,
104 			      (int)binary_dvs_env.width,
105 			      info->pipeline.left_cropping, info->pipeline.mode,
106 			      info->pipeline.c_subsampling,
107 			      info->output.num_chunks, info->pipeline.pipelining);
108 	internal_res->height = __ISP_INTERNAL_HEIGHT(isp_tmp_internal_height,
109 			       info->pipeline.top_cropping,
110 			       binary_dvs_env.height);
111 }
112 
113 /* Computation results of the origin coordinate of bayer on the shading table. */
114 struct sh_css_shading_table_bayer_origin_compute_results {
115 	u32 bayer_scale_hor_ratio_in;	/* Horizontal ratio (in) of bayer scaling. */
116 	u32 bayer_scale_hor_ratio_out;	/* Horizontal ratio (out) of bayer scaling. */
117 	u32 bayer_scale_ver_ratio_in;	/* Vertical ratio (in) of bayer scaling. */
118 	u32 bayer_scale_ver_ratio_out;	/* Vertical ratio (out) of bayer scaling. */
119 	u32 sc_bayer_origin_x_bqs_on_shading_table; /* X coordinate (in bqs) of bayer origin on shading table. */
120 	u32 sc_bayer_origin_y_bqs_on_shading_table; /* Y coordinate (in bqs) of bayer origin on shading table. */
121 };
122 
123 /* Get the requirements for the shading correction. */
124 static int
125 ia_css_binary_compute_shading_table_bayer_origin(
126     const struct ia_css_binary *binary,				/* [in] */
127     unsigned int required_bds_factor,				/* [in] */
128     const struct ia_css_stream_config *stream_config,		/* [in] */
129     struct sh_css_shading_table_bayer_origin_compute_results *res)	/* [out] */
130 {
131 	int err;
132 
133 	/* Rational fraction of the fixed bayer downscaling factor. */
134 	struct u32_fract bds;
135 
136 	/* Left padding set by InputFormatter. */
137 	unsigned int left_padding_bqs;			/* in bqs */
138 
139 	/* Flag for the NEED_BDS_FACTOR_2_00 macro defined in isp kernels. */
140 	unsigned int need_bds_factor_2_00;
141 
142 	/* Left padding adjusted inside the isp. */
143 	unsigned int left_padding_adjusted_bqs;		/* in bqs */
144 
145 	/* Bad pixels caused by filters.
146 	NxN-filter (before/after bayer scaling) moves the image position
147 	to right/bottom directions by a few pixels.
148 	It causes bad pixels at left/top sides,
149 	and effective bayer size decreases. */
150 	unsigned int bad_bqs_on_left_before_bs;	/* in bqs */
151 	unsigned int bad_bqs_on_left_after_bs;	/* in bqs */
152 	unsigned int bad_bqs_on_top_before_bs;	/* in bqs */
153 	unsigned int bad_bqs_on_top_after_bs;	/* in bqs */
154 
155 	/* Get the rational fraction of bayer downscaling factor. */
156 	err = sh_css_bds_factor_get_fract(required_bds_factor, &bds);
157 	if (err)
158 		return err;
159 
160 	/* Set the left padding set by InputFormatter. (ifmtr.c) */
161 	if (stream_config->left_padding == -1)
162 		left_padding_bqs = _ISP_BQS(binary->left_padding);
163 	else
164 		left_padding_bqs = (unsigned int)((int)ISP_VEC_NELEMS
165 				   - _ISP_BQS(stream_config->left_padding));
166 
167 	/* Set the left padding adjusted inside the isp.
168 	When bds_factor 2.00 is needed, some padding is added to left_padding
169 	inside the isp, before bayer downscaling. (raw.isp.c)
170 	(Hopefully, left_crop/left_padding/top_crop should be defined in css
171 	appropriately, depending on bds_factor.)
172 	*/
173 	need_bds_factor_2_00 = ((binary->info->sp.bds.supported_bds_factors &
174 				(PACK_BDS_FACTOR(SH_CSS_BDS_FACTOR_2_00) |
175 				 PACK_BDS_FACTOR(SH_CSS_BDS_FACTOR_2_50) |
176 				 PACK_BDS_FACTOR(SH_CSS_BDS_FACTOR_3_00) |
177 				 PACK_BDS_FACTOR(SH_CSS_BDS_FACTOR_4_00) |
178 				 PACK_BDS_FACTOR(SH_CSS_BDS_FACTOR_4_50) |
179 				 PACK_BDS_FACTOR(SH_CSS_BDS_FACTOR_5_00) |
180 				 PACK_BDS_FACTOR(SH_CSS_BDS_FACTOR_6_00) |
181 				 PACK_BDS_FACTOR(SH_CSS_BDS_FACTOR_8_00))) != 0);
182 
183 	if (need_bds_factor_2_00 && binary->info->sp.pipeline.left_cropping > 0)
184 		left_padding_adjusted_bqs = left_padding_bqs + ISP_VEC_NELEMS;
185 	else
186 		left_padding_adjusted_bqs = left_padding_bqs;
187 
188 	/* Currently, the bad pixel caused by filters before bayer scaling
189 	is NOT considered, because the bad pixel is subtle.
190 	When some large filter is used in the future,
191 	we need to consider the bad pixel.
192 
193 	Currently, when bds_factor isn't 1.00, 3x3 anti-alias filter is applied
194 	to each color plane(Gr/R/B/Gb) before bayer downscaling.
195 	This filter moves each color plane to right/bottom directions
196 	by 1 pixel at the most, depending on downscaling factor.
197 	*/
198 	bad_bqs_on_left_before_bs = 0;
199 	bad_bqs_on_top_before_bs = 0;
200 
201 	/* Currently, the bad pixel caused by filters after bayer scaling
202 	is NOT considered, because the bad pixel is subtle.
203 	When some large filter is used in the future,
204 	we need to consider the bad pixel.
205 
206 	Currently, when DPC&BNR is processed between bayer scaling and
207 	shading correction, DPC&BNR moves each color plane to
208 	right/bottom directions by 1 pixel.
209 	*/
210 	bad_bqs_on_left_after_bs = 0;
211 	bad_bqs_on_top_after_bs = 0;
212 
213 	/* Calculate the origin of bayer (real sensor data area)
214 	located on the shading table during the shading correction. */
215 	res->sc_bayer_origin_x_bqs_on_shading_table =
216 		((left_padding_adjusted_bqs + bad_bqs_on_left_before_bs)
217 		* bds.denominator + bds.numerator / 2) / bds.numerator
218 		+ bad_bqs_on_left_after_bs;
219 	/* "+ bds.numerator / 2": rounding for division by bds.numerator */
220 	res->sc_bayer_origin_y_bqs_on_shading_table =
221 		(bad_bqs_on_top_before_bs * bds.denominator + bds.numerator / 2) / bds.numerator
222 		+ bad_bqs_on_top_after_bs;
223 	/* "+ bds.numerator / 2": rounding for division by bds.numerator */
224 
225 	res->bayer_scale_hor_ratio_in  = bds.numerator;
226 	res->bayer_scale_hor_ratio_out = bds.denominator;
227 	res->bayer_scale_ver_ratio_in  = bds.numerator;
228 	res->bayer_scale_ver_ratio_out = bds.denominator;
229 
230 	return err;
231 }
232 
233 /* Get the shading information of Shading Correction Type 1. */
234 static int
235 binary_get_shading_info_type_1(const struct ia_css_binary *binary,	/* [in] */
236 			       unsigned int required_bds_factor,			/* [in] */
237 			       const struct ia_css_stream_config *stream_config,	/* [in] */
238 			       struct ia_css_shading_info *info)			/* [out] */
239 {
240 	int err;
241 	struct sh_css_shading_table_bayer_origin_compute_results res;
242 
243 	assert(binary);
244 	assert(info);
245 
246 	info->type = IA_CSS_SHADING_CORRECTION_TYPE_1;
247 
248 	info->info.type_1.enable	    = binary->info->sp.enable.sc;
249 	info->info.type_1.num_hor_grids	    = binary->sctbl_width_per_color;
250 	info->info.type_1.num_ver_grids	    = binary->sctbl_height;
251 	info->info.type_1.bqs_per_grid_cell = (1 << binary->deci_factor_log2);
252 
253 	/* Initialize by default values. */
254 	info->info.type_1.bayer_scale_hor_ratio_in	= 1;
255 	info->info.type_1.bayer_scale_hor_ratio_out	= 1;
256 	info->info.type_1.bayer_scale_ver_ratio_in	= 1;
257 	info->info.type_1.bayer_scale_ver_ratio_out	= 1;
258 	info->info.type_1.sc_bayer_origin_x_bqs_on_shading_table = 0;
259 	info->info.type_1.sc_bayer_origin_y_bqs_on_shading_table = 0;
260 
261 	err = ia_css_binary_compute_shading_table_bayer_origin(
262 	    binary,
263 	    required_bds_factor,
264 	    stream_config,
265 	    &res);
266 	if (err)
267 		return err;
268 
269 	info->info.type_1.bayer_scale_hor_ratio_in	= res.bayer_scale_hor_ratio_in;
270 	info->info.type_1.bayer_scale_hor_ratio_out	= res.bayer_scale_hor_ratio_out;
271 	info->info.type_1.bayer_scale_ver_ratio_in	= res.bayer_scale_ver_ratio_in;
272 	info->info.type_1.bayer_scale_ver_ratio_out	= res.bayer_scale_ver_ratio_out;
273 	info->info.type_1.sc_bayer_origin_x_bqs_on_shading_table = res.sc_bayer_origin_x_bqs_on_shading_table;
274 	info->info.type_1.sc_bayer_origin_y_bqs_on_shading_table = res.sc_bayer_origin_y_bqs_on_shading_table;
275 
276 	return err;
277 }
278 
279 
280 int
281 ia_css_binary_get_shading_info(const struct ia_css_binary *binary,			/* [in] */
282 			       enum ia_css_shading_correction_type type,		/* [in] */
283 			       unsigned int required_bds_factor,			/* [in] */
284 			       const struct ia_css_stream_config *stream_config,	/* [in] */
285 			       struct ia_css_shading_info *shading_info,		/* [out] */
286 			       struct ia_css_pipe_config *pipe_config)			/* [out] */
287 {
288 	int err;
289 
290 	assert(binary);
291 	assert(shading_info);
292 
293 	IA_CSS_ENTER_PRIVATE("binary=%p, type=%d, required_bds_factor=%d, stream_config=%p",
294 			     binary, type, required_bds_factor, stream_config);
295 
296 	if (type == IA_CSS_SHADING_CORRECTION_TYPE_1)
297 		err = binary_get_shading_info_type_1(binary,
298 						     required_bds_factor,
299 						     stream_config,
300 						     shading_info);
301 	else
302 		err = -ENOTSUPP;
303 
304 	IA_CSS_LEAVE_ERR_PRIVATE(err);
305 	return err;
306 }
307 
308 static void sh_css_binary_common_grid_info(const struct ia_css_binary *binary,
309 	struct ia_css_grid_info *info)
310 {
311 	assert(binary);
312 	assert(info);
313 
314 	info->isp_in_width = binary->internal_frame_info.res.width;
315 	info->isp_in_height = binary->internal_frame_info.res.height;
316 
317 	info->vamem_type = IA_CSS_VAMEM_TYPE_2;
318 }
319 
320 void
321 ia_css_binary_dvs_grid_info(const struct ia_css_binary *binary,
322 			    struct ia_css_grid_info *info,
323 			    struct ia_css_pipe *pipe)
324 {
325 	struct ia_css_dvs_grid_info *dvs_info;
326 
327 	(void)pipe;
328 	assert(binary);
329 	assert(info);
330 
331 	dvs_info = &info->dvs_grid.dvs_grid_info;
332 
333 	/* for DIS, we use a division instead of a ceil_div. If this is smaller
334 	 * than the 3a grid size, it indicates that the outer values are not
335 	 * valid for DIS.
336 	 */
337 	dvs_info->enable            = binary->info->sp.enable.dis;
338 	dvs_info->width             = binary->dis.grid.dim.width;
339 	dvs_info->height            = binary->dis.grid.dim.height;
340 	dvs_info->aligned_width     = binary->dis.grid.pad.width;
341 	dvs_info->aligned_height    = binary->dis.grid.pad.height;
342 	dvs_info->bqs_per_grid_cell = 1 << binary->dis.deci_factor_log2;
343 	dvs_info->num_hor_coefs     = binary->dis.coef.dim.width;
344 	dvs_info->num_ver_coefs     = binary->dis.coef.dim.height;
345 
346 	sh_css_binary_common_grid_info(binary, info);
347 }
348 
349 void
350 ia_css_binary_dvs_stat_grid_info(
351     const struct ia_css_binary *binary,
352     struct ia_css_grid_info *info,
353     struct ia_css_pipe *pipe)
354 {
355 	(void)pipe;
356 	sh_css_binary_common_grid_info(binary, info);
357 	return;
358 }
359 
360 int
361 ia_css_binary_3a_grid_info(const struct ia_css_binary *binary,
362 			   struct ia_css_grid_info *info,
363 			   struct ia_css_pipe *pipe) {
364 	struct ia_css_3a_grid_info *s3a_info;
365 	int err = 0;
366 
367 	IA_CSS_ENTER_PRIVATE("binary=%p, info=%p, pipe=%p",
368 			     binary, info, pipe);
369 
370 	assert(binary);
371 	assert(info);
372 	s3a_info = &info->s3a_grid;
373 
374 	/* 3A statistics grid */
375 	s3a_info->enable            = binary->info->sp.enable.s3a;
376 	s3a_info->width             = binary->s3atbl_width;
377 	s3a_info->height            = binary->s3atbl_height;
378 	s3a_info->aligned_width     = binary->s3atbl_isp_width;
379 	s3a_info->aligned_height    = binary->s3atbl_isp_height;
380 	s3a_info->bqs_per_grid_cell = (1 << binary->deci_factor_log2);
381 	s3a_info->deci_factor_log2  = binary->deci_factor_log2;
382 	s3a_info->elem_bit_depth    = SH_CSS_BAYER_BITS;
383 	s3a_info->use_dmem          = binary->info->sp.s3a.s3atbl_use_dmem;
384 	s3a_info->has_histogram     = 0;
385 	IA_CSS_LEAVE_ERR_PRIVATE(err);
386 	return err;
387 }
388 
389 static void
390 binary_init_pc_histogram(struct sh_css_pc_histogram *histo)
391 {
392 	assert(histo);
393 
394 	histo->length = 0;
395 	histo->run = NULL;
396 	histo->stall = NULL;
397 }
398 
399 static void
400 binary_init_metrics(struct sh_css_binary_metrics *metrics,
401 		    const struct ia_css_binary_info *info)
402 {
403 	assert(metrics);
404 	assert(info);
405 
406 	metrics->mode = info->pipeline.mode;
407 	metrics->id   = info->id;
408 	metrics->next = NULL;
409 	binary_init_pc_histogram(&metrics->isp_histogram);
410 	binary_init_pc_histogram(&metrics->sp_histogram);
411 }
412 
413 /* move to host part of output module */
414 static bool
415 binary_supports_output_format(const struct ia_css_binary_xinfo *info,
416 			      enum ia_css_frame_format format)
417 {
418 	int i;
419 
420 	assert(info);
421 
422 	for (i = 0; i < info->num_output_formats; i++) {
423 		if (info->output_formats[i] == format)
424 			return true;
425 	}
426 	return false;
427 }
428 
429 static bool
430 binary_supports_vf_format(const struct ia_css_binary_xinfo *info,
431 			  enum ia_css_frame_format format)
432 {
433 	int i;
434 
435 	assert(info);
436 
437 	for (i = 0; i < info->num_vf_formats; i++) {
438 		if (info->vf_formats[i] == format)
439 			return true;
440 	}
441 	return false;
442 }
443 
444 /* move to host part of bds module */
445 static bool
446 supports_bds_factor(u32 supported_factors,
447 		    uint32_t bds_factor)
448 {
449 	return ((supported_factors & PACK_BDS_FACTOR(bds_factor)) != 0);
450 }
451 
452 static int
453 binary_init_info(struct ia_css_binary_xinfo *info, unsigned int i,
454 		 bool *binary_found) {
455 	const unsigned char *blob = sh_css_blob_info[i].blob;
456 	unsigned int size = sh_css_blob_info[i].header.blob.size;
457 
458 	if ((!info) || (!binary_found))
459 		return -EINVAL;
460 
461 	*info = sh_css_blob_info[i].header.info.isp;
462 	*binary_found = blob;
463 	info->blob_index = i;
464 	/* we don't have this binary, skip it */
465 	if (!size)
466 		return 0;
467 
468 	info->xmem_addr = sh_css_load_blob(blob, size);
469 	if (!info->xmem_addr)
470 		return -ENOMEM;
471 	return 0;
472 }
473 
474 /* When binaries are put at the beginning, they will only
475  * be selected if no other primary matches.
476  */
477 int
478 ia_css_binary_init_infos(void) {
479 	unsigned int i;
480 	unsigned int num_of_isp_binaries = sh_css_num_binaries - NUM_OF_SPS - NUM_OF_BLS;
481 
482 	if (num_of_isp_binaries == 0)
483 		return 0;
484 
485 	all_binaries = kvmalloc(num_of_isp_binaries * sizeof(*all_binaries),
486 				GFP_KERNEL);
487 	if (!all_binaries)
488 		return -ENOMEM;
489 
490 	for (i = 0; i < num_of_isp_binaries; i++)
491 	{
492 		int ret;
493 		struct ia_css_binary_xinfo *binary = &all_binaries[i];
494 		bool binary_found;
495 
496 		ret = binary_init_info(binary, i, &binary_found);
497 		if (ret)
498 			return ret;
499 		if (!binary_found)
500 			continue;
501 		/* Prepend new binary information */
502 		binary->next = binary_infos[binary->sp.pipeline.mode];
503 		binary_infos[binary->sp.pipeline.mode] = binary;
504 		binary->blob = &sh_css_blob_info[i];
505 		binary->mem_offsets = sh_css_blob_info[i].mem_offsets;
506 	}
507 	return 0;
508 }
509 
510 int
511 ia_css_binary_uninit(void) {
512 	unsigned int i;
513 	struct ia_css_binary_xinfo *b;
514 
515 	for (i = 0; i < IA_CSS_BINARY_NUM_MODES; i++)
516 	{
517 		for (b = binary_infos[i]; b; b = b->next) {
518 			if (b->xmem_addr)
519 				hmm_free(b->xmem_addr);
520 			b->xmem_addr = mmgr_NULL;
521 		}
522 		binary_infos[i] = NULL;
523 	}
524 	kvfree(all_binaries);
525 	return 0;
526 }
527 
528 /* @brief Compute decimation factor for 3A statistics and shading correction.
529  *
530  * @param[in]	width	Frame width in pixels.
531  * @param[in]	height	Frame height in pixels.
532  * @return	Log2 of decimation factor (= grid cell size) in bayer quads.
533  */
534 static int
535 binary_grid_deci_factor_log2(int width, int height)
536 {
537 	/* 3A/Shading decimation factor spcification (at August 2008)
538 	 * ------------------------------------------------------------------
539 	 * [Image Width (BQ)] [Decimation Factor (BQ)] [Resulting grid cells]
540 	 * 1280 ?c             32                       40 ?c
541 	 *  640 ?c 1279        16                       40 ?c 80
542 	 *      ?c  639         8                          ?c 80
543 	 * ------------------------------------------------------------------
544 	 */
545 	/* Maximum and minimum decimation factor by the specification */
546 #define MAX_SPEC_DECI_FACT_LOG2		5
547 #define MIN_SPEC_DECI_FACT_LOG2		3
548 	/* the smallest frame width in bayer quads when decimation factor (log2) is 5 or 4, by the specification */
549 #define DECI_FACT_LOG2_5_SMALLEST_FRAME_WIDTH_BQ	1280
550 #define DECI_FACT_LOG2_4_SMALLEST_FRAME_WIDTH_BQ	640
551 
552 	int smallest_factor; /* the smallest factor (log2) where the number of cells does not exceed the limitation */
553 	int spec_factor;     /* the factor (log2) which satisfies the specification */
554 
555 	/* Currently supported maximum width and height are 5120(=80*64) and 3840(=60*64). */
556 	assert(ISP_BQ_GRID_WIDTH(width,
557 				 MAX_SPEC_DECI_FACT_LOG2) <= SH_CSS_MAX_BQ_GRID_WIDTH);
558 	assert(ISP_BQ_GRID_HEIGHT(height,
559 				  MAX_SPEC_DECI_FACT_LOG2) <= SH_CSS_MAX_BQ_GRID_HEIGHT);
560 
561 	/* Compute the smallest factor. */
562 	smallest_factor = MAX_SPEC_DECI_FACT_LOG2;
563 	while (ISP_BQ_GRID_WIDTH(width,
564 				 smallest_factor - 1) <= SH_CSS_MAX_BQ_GRID_WIDTH &&
565 	       ISP_BQ_GRID_HEIGHT(height, smallest_factor - 1) <= SH_CSS_MAX_BQ_GRID_HEIGHT
566 	       && smallest_factor > MIN_SPEC_DECI_FACT_LOG2)
567 		smallest_factor--;
568 
569 	/* Get the factor by the specification. */
570 	if (_ISP_BQS(width) >= DECI_FACT_LOG2_5_SMALLEST_FRAME_WIDTH_BQ)
571 		spec_factor = 5;
572 	else if (_ISP_BQS(width) >= DECI_FACT_LOG2_4_SMALLEST_FRAME_WIDTH_BQ)
573 		spec_factor = 4;
574 	else
575 		spec_factor = 3;
576 
577 	/* If smallest_factor is smaller than or equal to spec_factor, choose spec_factor to follow the specification.
578 	   If smallest_factor is larger than spec_factor, choose smallest_factor.
579 
580 		ex. width=2560, height=1920
581 			smallest_factor=4, spec_factor=5
582 			smallest_factor < spec_factor   ->   return spec_factor
583 
584 		ex. width=300, height=3000
585 			smallest_factor=5, spec_factor=3
586 			smallest_factor > spec_factor   ->   return smallest_factor
587 	*/
588 	return max(smallest_factor, spec_factor);
589 
590 #undef MAX_SPEC_DECI_FACT_LOG2
591 #undef MIN_SPEC_DECI_FACT_LOG2
592 #undef DECI_FACT_LOG2_5_SMALLEST_FRAME_WIDTH_BQ
593 #undef DECI_FACT_LOG2_4_SMALLEST_FRAME_WIDTH_BQ
594 }
595 
596 static int
597 binary_in_frame_padded_width(int in_frame_width,
598 			     int isp_internal_width,
599 			     int dvs_env_width,
600 			     int stream_config_left_padding,
601 			     int left_cropping,
602 			     bool need_scaling)
603 {
604 	int rval;
605 	int nr_of_left_paddings;	/* number of paddings pixels on the left of an image line */
606 
607 #if defined(ISP2401)
608 	/* the output image line of Input System 2401 does not have the left paddings  */
609 	nr_of_left_paddings = 0;
610 #else
611 	/* in other cases, the left padding pixels are always 128 */
612 	nr_of_left_paddings = 2 * ISP_VEC_NELEMS;
613 #endif
614 	if (need_scaling) {
615 		/* In SDV use-case, we need to match left-padding of
616 		 * primary and the video binary. */
617 		if (stream_config_left_padding != -1) {
618 			/* Different than before, we do left&right padding. */
619 			rval =
620 			    CEIL_MUL(in_frame_width + nr_of_left_paddings,
621 				     2 * ISP_VEC_NELEMS);
622 		} else {
623 			/* Different than before, we do left&right padding. */
624 			in_frame_width += dvs_env_width;
625 			rval =
626 			    CEIL_MUL(in_frame_width +
627 				     (left_cropping ? nr_of_left_paddings : 0),
628 				     2 * ISP_VEC_NELEMS);
629 		}
630 	} else {
631 		rval = isp_internal_width;
632 	}
633 
634 	return rval;
635 }
636 
637 int
638 ia_css_binary_fill_info(const struct ia_css_binary_xinfo *xinfo,
639 			bool online,
640 			bool two_ppc,
641 			enum atomisp_input_format stream_format,
642 			const struct ia_css_frame_info *in_info, /* can be NULL */
643 			const struct ia_css_frame_info *bds_out_info, /* can be NULL */
644 			const struct ia_css_frame_info *out_info[], /* can be NULL */
645 			const struct ia_css_frame_info *vf_info, /* can be NULL */
646 			struct ia_css_binary *binary,
647 			struct ia_css_resolution *dvs_env,
648 			int stream_config_left_padding,
649 			bool accelerator) {
650 	const struct ia_css_binary_info *info = &xinfo->sp;
651 	unsigned int dvs_env_width = 0,
652 	dvs_env_height = 0,
653 	vf_log_ds = 0,
654 	s3a_log_deci = 0,
655 	bits_per_pixel = 0,
656 	/* Resolution at SC/3A/DIS kernel. */
657 	sc_3a_dis_width = 0,
658 	/* Resolution at SC/3A/DIS kernel. */
659 	sc_3a_dis_padded_width = 0,
660 	/* Resolution at SC/3A/DIS kernel. */
661 	sc_3a_dis_height = 0,
662 	isp_internal_width = 0,
663 	isp_internal_height = 0,
664 	s3a_isp_width = 0;
665 
666 	bool need_scaling = false;
667 	struct ia_css_resolution binary_dvs_env, internal_res;
668 	int err;
669 	unsigned int i;
670 	const struct ia_css_frame_info *bin_out_info = NULL;
671 
672 	assert(info);
673 	assert(binary);
674 
675 	binary->info = xinfo;
676 	if (!accelerator)
677 	{
678 		/* binary->css_params has been filled by accelerator itself. */
679 		err = ia_css_isp_param_allocate_isp_parameters(
680 		    &binary->mem_params, &binary->css_params,
681 		    &info->mem_initializers);
682 		if (err) {
683 			return err;
684 		}
685 	}
686 	for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++)
687 	{
688 		if (out_info[i] && (out_info[i]->res.width != 0)) {
689 			bin_out_info = out_info[i];
690 			break;
691 		}
692 	}
693 	if (in_info && bin_out_info)
694 	{
695 		need_scaling = (in_info->res.width != bin_out_info->res.width) ||
696 			       (in_info->res.height != bin_out_info->res.height);
697 	}
698 
699 	/* binary_dvs_env has to be equal or larger than SH_CSS_MIN_DVS_ENVELOPE */
700 	binary_dvs_env.width = 0;
701 	binary_dvs_env.height = 0;
702 	ia_css_binary_dvs_env(info, dvs_env, &binary_dvs_env);
703 	dvs_env_width = binary_dvs_env.width;
704 	dvs_env_height = binary_dvs_env.height;
705 	binary->dvs_envelope.width  = dvs_env_width;
706 	binary->dvs_envelope.height = dvs_env_height;
707 
708 	/* internal resolution calculation */
709 	internal_res.width = 0;
710 	internal_res.height = 0;
711 	ia_css_binary_internal_res(in_info, bds_out_info, bin_out_info, dvs_env,
712 				   info, &internal_res);
713 	isp_internal_width = internal_res.width;
714 	isp_internal_height = internal_res.height;
715 
716 	/* internal frame info */
717 	if (bin_out_info) /* { */
718 		binary->internal_frame_info.format = bin_out_info->format;
719 	/* } */
720 	binary->internal_frame_info.res.width       = isp_internal_width;
721 	binary->internal_frame_info.padded_width    = CEIL_MUL(isp_internal_width, 2 * ISP_VEC_NELEMS);
722 	binary->internal_frame_info.res.height      = isp_internal_height;
723 	binary->internal_frame_info.raw_bit_depth   = bits_per_pixel;
724 
725 	if (in_info)
726 	{
727 		binary->effective_in_frame_res.width = in_info->res.width;
728 		binary->effective_in_frame_res.height = in_info->res.height;
729 
730 		bits_per_pixel = in_info->raw_bit_depth;
731 
732 		/* input info */
733 		binary->in_frame_info.res.width = in_info->res.width +
734 						  info->pipeline.left_cropping;
735 		binary->in_frame_info.res.height = in_info->res.height +
736 						   info->pipeline.top_cropping;
737 
738 		binary->in_frame_info.res.width += dvs_env_width;
739 		binary->in_frame_info.res.height += dvs_env_height;
740 
741 		binary->in_frame_info.padded_width =
742 		    binary_in_frame_padded_width(in_info->res.width,
743 						 isp_internal_width,
744 						 dvs_env_width,
745 						 stream_config_left_padding,
746 						 info->pipeline.left_cropping,
747 						 need_scaling);
748 
749 		binary->in_frame_info.format = in_info->format;
750 		binary->in_frame_info.raw_bayer_order = in_info->raw_bayer_order;
751 		binary->in_frame_info.crop_info = in_info->crop_info;
752 	}
753 
754 	if (online)
755 	{
756 		bits_per_pixel = ia_css_util_input_format_bpp(
757 				     stream_format, two_ppc);
758 	}
759 	binary->in_frame_info.raw_bit_depth = bits_per_pixel;
760 
761 	for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++)
762 	{
763 		if (out_info[i]) {
764 			binary->out_frame_info[i].res.width     = out_info[i]->res.width;
765 			binary->out_frame_info[i].res.height    = out_info[i]->res.height;
766 			binary->out_frame_info[i].padded_width  = out_info[i]->padded_width;
767 			if (info->pipeline.mode == IA_CSS_BINARY_MODE_COPY) {
768 				binary->out_frame_info[i].raw_bit_depth = bits_per_pixel;
769 			} else {
770 				/* Only relevant for RAW format.
771 				 * At the moment, all outputs are raw, 16 bit per pixel, except for copy.
772 				 * To do this cleanly, the binary should specify in its info
773 				 * the bit depth per output channel.
774 				 */
775 				binary->out_frame_info[i].raw_bit_depth = 16;
776 			}
777 			binary->out_frame_info[i].format        = out_info[i]->format;
778 		}
779 	}
780 
781 	if (vf_info && (vf_info->res.width != 0))
782 	{
783 		err = ia_css_vf_configure(binary, bin_out_info,
784 					  (struct ia_css_frame_info *)vf_info, &vf_log_ds);
785 		if (err) {
786 			if (!accelerator) {
787 				ia_css_isp_param_destroy_isp_parameters(
788 				    &binary->mem_params,
789 				    &binary->css_params);
790 			}
791 			return err;
792 		}
793 	}
794 	binary->vf_downscale_log2 = vf_log_ds;
795 
796 	binary->online            = online;
797 	binary->input_format      = stream_format;
798 
799 	/* viewfinder output info */
800 	if ((vf_info) && (vf_info->res.width != 0))
801 	{
802 		unsigned int vf_out_vecs, vf_out_width, vf_out_height;
803 
804 		binary->vf_frame_info.format = vf_info->format;
805 		if (!bin_out_info)
806 			return -EINVAL;
807 		vf_out_vecs = __ISP_VF_OUTPUT_WIDTH_VECS(bin_out_info->padded_width,
808 			      vf_log_ds);
809 		vf_out_width = _ISP_VF_OUTPUT_WIDTH(vf_out_vecs);
810 		vf_out_height = _ISP_VF_OUTPUT_HEIGHT(bin_out_info->res.height,
811 						      vf_log_ds);
812 
813 		/* For preview mode, output pin is used instead of vf. */
814 		if (info->pipeline.mode == IA_CSS_BINARY_MODE_PREVIEW) {
815 			binary->out_frame_info[0].res.width =
816 			    (bin_out_info->res.width >> vf_log_ds);
817 			binary->out_frame_info[0].padded_width = vf_out_width;
818 			binary->out_frame_info[0].res.height   = vf_out_height;
819 
820 			binary->vf_frame_info.res.width    = 0;
821 			binary->vf_frame_info.padded_width = 0;
822 			binary->vf_frame_info.res.height   = 0;
823 		} else {
824 			/* we also store the raw downscaled width. This is
825 			 * used for digital zoom in preview to zoom only on
826 			 * the width that we actually want to keep, not on
827 			 * the aligned width. */
828 			binary->vf_frame_info.res.width =
829 			    (bin_out_info->res.width >> vf_log_ds);
830 			binary->vf_frame_info.padded_width = vf_out_width;
831 			binary->vf_frame_info.res.height   = vf_out_height;
832 		}
833 	} else
834 	{
835 		binary->vf_frame_info.res.width    = 0;
836 		binary->vf_frame_info.padded_width = 0;
837 		binary->vf_frame_info.res.height   = 0;
838 	}
839 
840 	if (info->enable.ca_gdc)
841 	{
842 		binary->morph_tbl_width =
843 		    _ISP_MORPH_TABLE_WIDTH(isp_internal_width);
844 		binary->morph_tbl_aligned_width  =
845 		    _ISP_MORPH_TABLE_ALIGNED_WIDTH(isp_internal_width);
846 		binary->morph_tbl_height =
847 		    _ISP_MORPH_TABLE_HEIGHT(isp_internal_height);
848 	} else
849 	{
850 		binary->morph_tbl_width  = 0;
851 		binary->morph_tbl_aligned_width  = 0;
852 		binary->morph_tbl_height = 0;
853 	}
854 
855 	sc_3a_dis_width = binary->in_frame_info.res.width;
856 	sc_3a_dis_padded_width = binary->in_frame_info.padded_width;
857 	sc_3a_dis_height = binary->in_frame_info.res.height;
858 	if (bds_out_info && in_info &&
859 	    bds_out_info->res.width != in_info->res.width)
860 	{
861 		/* TODO: Next, "internal_frame_info" should be derived from
862 		 * bds_out. So this part will change once it is in place! */
863 		sc_3a_dis_width = bds_out_info->res.width + info->pipeline.left_cropping;
864 		sc_3a_dis_padded_width = isp_internal_width;
865 		sc_3a_dis_height = isp_internal_height;
866 	}
867 
868 	s3a_isp_width = _ISP_S3A_ELEMS_ISP_WIDTH(sc_3a_dis_padded_width,
869 			info->pipeline.left_cropping);
870 	if (info->s3a.fixed_s3a_deci_log)
871 	{
872 		s3a_log_deci = info->s3a.fixed_s3a_deci_log;
873 	} else
874 	{
875 		s3a_log_deci = binary_grid_deci_factor_log2(s3a_isp_width,
876 			       sc_3a_dis_height);
877 	}
878 	binary->deci_factor_log2  = s3a_log_deci;
879 
880 	if (info->enable.s3a)
881 	{
882 		binary->s3atbl_width  =
883 		    _ISP_S3ATBL_WIDTH(sc_3a_dis_width,
884 				      s3a_log_deci);
885 		binary->s3atbl_height =
886 		    _ISP_S3ATBL_HEIGHT(sc_3a_dis_height,
887 				       s3a_log_deci);
888 		binary->s3atbl_isp_width =
889 		    _ISP_S3ATBL_ISP_WIDTH(s3a_isp_width,
890 					  s3a_log_deci);
891 		binary->s3atbl_isp_height =
892 		    _ISP_S3ATBL_ISP_HEIGHT(sc_3a_dis_height,
893 					   s3a_log_deci);
894 	} else
895 	{
896 		binary->s3atbl_width  = 0;
897 		binary->s3atbl_height = 0;
898 		binary->s3atbl_isp_width  = 0;
899 		binary->s3atbl_isp_height = 0;
900 	}
901 
902 	if (info->enable.sc)
903 	{
904 		binary->sctbl_width_per_color = _ISP_SCTBL_WIDTH_PER_COLOR(sc_3a_dis_padded_width, s3a_log_deci);
905 		binary->sctbl_aligned_width_per_color = SH_CSS_MAX_SCTBL_ALIGNED_WIDTH_PER_COLOR;
906 		binary->sctbl_height = _ISP_SCTBL_HEIGHT(sc_3a_dis_height, s3a_log_deci);
907 	} else
908 	{
909 		binary->sctbl_width_per_color         = 0;
910 		binary->sctbl_aligned_width_per_color = 0;
911 		binary->sctbl_height                  = 0;
912 	}
913 	ia_css_sdis_init_info(&binary->dis,
914 			      sc_3a_dis_width,
915 			      sc_3a_dis_padded_width,
916 			      sc_3a_dis_height,
917 			      info->pipeline.isp_pipe_version,
918 			      info->enable.dis);
919 	if (info->pipeline.left_cropping)
920 		binary->left_padding = 2 * ISP_VEC_NELEMS - info->pipeline.left_cropping;
921 	else
922 		binary->left_padding = 0;
923 
924 	return 0;
925 }
926 
927 static int __ia_css_binary_find(struct ia_css_binary_descr *descr,
928 				struct ia_css_binary *binary) {
929 	int mode;
930 	bool online;
931 	bool two_ppc;
932 	enum atomisp_input_format stream_format;
933 	const struct ia_css_frame_info *req_in_info,
934 		*req_bds_out_info,
935 		*req_out_info[IA_CSS_BINARY_MAX_OUTPUT_PORTS],
936 		*req_bin_out_info = NULL,
937 		*req_vf_info;
938 
939 	struct ia_css_binary_xinfo *xcandidate;
940 	bool need_ds, need_dz, need_dvs, need_xnr, need_dpc;
941 	bool striped;
942 	bool enable_yuv_ds;
943 	bool enable_high_speed;
944 	bool enable_dvs_6axis;
945 	bool enable_reduced_pipe;
946 	bool enable_capture_pp_bli;
947 	int err = -EINVAL;
948 	bool continuous;
949 	unsigned int isp_pipe_version;
950 	struct ia_css_resolution dvs_env, internal_res;
951 	unsigned int i;
952 
953 	assert(descr);
954 	/* MW: used after an error check, may accept NULL, but doubtfull */
955 	assert(binary);
956 
957 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
958 			    "ia_css_binary_find() enter: descr=%p, (mode=%d), binary=%p\n",
959 			    descr, descr->mode,
960 			    binary);
961 
962 	mode = descr->mode;
963 	online = descr->online;
964 	two_ppc = descr->two_ppc;
965 	stream_format = descr->stream_format;
966 	req_in_info = descr->in_info;
967 	req_bds_out_info = descr->bds_out_info;
968 	for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) {
969 		req_out_info[i] = descr->out_info[i];
970 		if (req_out_info[i] && (req_out_info[i]->res.width != 0))
971 			req_bin_out_info = req_out_info[i];
972 	}
973 	if (!req_bin_out_info)
974 		return -EINVAL;
975 	req_vf_info = descr->vf_info;
976 
977 	need_xnr = descr->enable_xnr;
978 	need_ds = descr->enable_fractional_ds;
979 	need_dz = false;
980 	need_dvs = false;
981 	need_dpc = descr->enable_dpc;
982 
983 	enable_yuv_ds = descr->enable_yuv_ds;
984 	enable_high_speed = descr->enable_high_speed;
985 	enable_dvs_6axis  = descr->enable_dvs_6axis;
986 	enable_reduced_pipe = descr->enable_reduced_pipe;
987 	enable_capture_pp_bli = descr->enable_capture_pp_bli;
988 	continuous = descr->continuous;
989 	striped = descr->striped;
990 	isp_pipe_version = descr->isp_pipe_version;
991 
992 	dvs_env.width = 0;
993 	dvs_env.height = 0;
994 	internal_res.width = 0;
995 	internal_res.height = 0;
996 
997 	if (mode == IA_CSS_BINARY_MODE_VIDEO) {
998 		dvs_env = descr->dvs_env;
999 		need_dz = descr->enable_dz;
1000 		/* Video is the only mode that has a nodz variant. */
1001 		need_dvs = dvs_env.width || dvs_env.height;
1002 	}
1003 
1004 	/* print a map of the binary file */
1005 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,	"BINARY INFO:\n");
1006 	for (i = 0; i < IA_CSS_BINARY_NUM_MODES; i++) {
1007 		xcandidate = binary_infos[i];
1008 		if (xcandidate) {
1009 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,	"%d:\n", i);
1010 			while (xcandidate) {
1011 				ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, " Name:%s Type:%d Cont:%d\n",
1012 						    xcandidate->blob->name, xcandidate->type,
1013 						    xcandidate->sp.enable.continuous);
1014 				xcandidate = xcandidate->next;
1015 			}
1016 		}
1017 	}
1018 
1019 	/* printf("sh_css_binary_find: pipe version %d\n", isp_pipe_version); */
1020 	for (xcandidate = binary_infos[mode]; xcandidate;
1021 	     xcandidate = xcandidate->next) {
1022 		struct ia_css_binary_info *candidate = &xcandidate->sp;
1023 		/* printf("sh_css_binary_find: evaluating candidate:
1024 		 * %d\n",candidate->id); */
1025 		ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1026 				    "ia_css_binary_find() candidate = %p, mode = %d ID = %d\n",
1027 				    candidate, candidate->pipeline.mode, candidate->id);
1028 
1029 		/*
1030 		 * MW: Only a limited set of jointly configured binaries can
1031 		 * be used in a continuous preview/video mode unless it is
1032 		 * the copy mode and runs on SP.
1033 		*/
1034 		if (!candidate->enable.continuous &&
1035 		    continuous && (mode != IA_CSS_BINARY_MODE_COPY)) {
1036 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1037 					    "ia_css_binary_find() [%d] continue: !%d && %d && (%d != %d)\n",
1038 					    __LINE__, candidate->enable.continuous,
1039 					    continuous, mode,
1040 					    IA_CSS_BINARY_MODE_COPY);
1041 			continue;
1042 		}
1043 		if (striped && candidate->iterator.num_stripes == 1) {
1044 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1045 					    "ia_css_binary_find() [%d] continue: binary is not striped\n",
1046 					    __LINE__);
1047 			continue;
1048 		}
1049 
1050 		if (candidate->pipeline.isp_pipe_version != isp_pipe_version &&
1051 		    (mode != IA_CSS_BINARY_MODE_COPY) &&
1052 		    (mode != IA_CSS_BINARY_MODE_CAPTURE_PP) &&
1053 		    (mode != IA_CSS_BINARY_MODE_VF_PP)) {
1054 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1055 					    "ia_css_binary_find() [%d] continue: (%d != %d)\n",
1056 					    __LINE__,
1057 					    candidate->pipeline.isp_pipe_version, isp_pipe_version);
1058 			continue;
1059 		}
1060 		if (!candidate->enable.reduced_pipe && enable_reduced_pipe) {
1061 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1062 					    "ia_css_binary_find() [%d] continue: !%d && %d\n",
1063 					    __LINE__,
1064 					    candidate->enable.reduced_pipe,
1065 					    enable_reduced_pipe);
1066 			continue;
1067 		}
1068 		if (!candidate->enable.dvs_6axis && enable_dvs_6axis) {
1069 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1070 					    "ia_css_binary_find() [%d] continue: !%d && %d\n",
1071 					    __LINE__,
1072 					    candidate->enable.dvs_6axis,
1073 					    enable_dvs_6axis);
1074 			continue;
1075 		}
1076 		if (candidate->enable.high_speed && !enable_high_speed) {
1077 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1078 					    "ia_css_binary_find() [%d] continue: %d && !%d\n",
1079 					    __LINE__,
1080 					    candidate->enable.high_speed,
1081 					    enable_high_speed);
1082 			continue;
1083 		}
1084 		if (!candidate->enable.xnr && need_xnr) {
1085 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1086 					    "ia_css_binary_find() [%d] continue: %d && !%d\n",
1087 					    __LINE__,
1088 					    candidate->enable.xnr,
1089 					    need_xnr);
1090 			continue;
1091 		}
1092 		if (!(candidate->enable.ds & 2) && enable_yuv_ds) {
1093 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1094 					    "ia_css_binary_find() [%d] continue: !%d && %d\n",
1095 					    __LINE__,
1096 					    ((candidate->enable.ds & 2) != 0),
1097 					    enable_yuv_ds);
1098 			continue;
1099 		}
1100 		if ((candidate->enable.ds & 2) && !enable_yuv_ds) {
1101 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1102 					    "ia_css_binary_find() [%d] continue: %d && !%d\n",
1103 					    __LINE__,
1104 					    ((candidate->enable.ds & 2) != 0),
1105 					    enable_yuv_ds);
1106 			continue;
1107 		}
1108 
1109 		if (mode == IA_CSS_BINARY_MODE_VIDEO &&
1110 		    candidate->enable.ds && need_ds)
1111 			need_dz = false;
1112 
1113 		/* when we require vf output, we need to have vf_veceven */
1114 		if ((req_vf_info) && !(candidate->enable.vf_veceven ||
1115 				       /* or variable vf vec even */
1116 				       candidate->vf_dec.is_variable ||
1117 				       /* or more than one output pin. */
1118 				       xcandidate->num_output_pins > 1)) {
1119 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1120 					    "ia_css_binary_find() [%d] continue: (%p != NULL) && !(%d || %d || (%d >%d))\n",
1121 					    __LINE__, req_vf_info,
1122 					    candidate->enable.vf_veceven,
1123 					    candidate->vf_dec.is_variable,
1124 					    xcandidate->num_output_pins, 1);
1125 			continue;
1126 		}
1127 		if (!candidate->enable.dvs_envelope && need_dvs) {
1128 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1129 					    "ia_css_binary_find() [%d] continue: !%d && %d\n",
1130 					    __LINE__,
1131 					    candidate->enable.dvs_envelope, (int)need_dvs);
1132 			continue;
1133 		}
1134 		/* internal_res check considers input, output, and dvs envelope sizes */
1135 		ia_css_binary_internal_res(req_in_info, req_bds_out_info,
1136 					   req_bin_out_info, &dvs_env, candidate, &internal_res);
1137 		if (internal_res.width > candidate->internal.max_width) {
1138 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1139 					    "ia_css_binary_find() [%d] continue: (%d > %d)\n",
1140 					    __LINE__, internal_res.width,
1141 					    candidate->internal.max_width);
1142 			continue;
1143 		}
1144 		if (internal_res.height > candidate->internal.max_height) {
1145 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1146 					    "ia_css_binary_find() [%d] continue: (%d > %d)\n",
1147 					    __LINE__, internal_res.height,
1148 					    candidate->internal.max_height);
1149 			continue;
1150 		}
1151 		if (!candidate->enable.ds && need_ds && !(xcandidate->num_output_pins > 1)) {
1152 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1153 					    "ia_css_binary_find() [%d] continue: !%d && %d\n",
1154 					    __LINE__, candidate->enable.ds, (int)need_ds);
1155 			continue;
1156 		}
1157 		if (!candidate->enable.uds && !candidate->enable.dvs_6axis && need_dz) {
1158 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1159 					    "ia_css_binary_find() [%d] continue: !%d && !%d && %d\n",
1160 					    __LINE__, candidate->enable.uds,
1161 					    candidate->enable.dvs_6axis, (int)need_dz);
1162 			continue;
1163 		}
1164 		if (online && candidate->input.source == IA_CSS_BINARY_INPUT_MEMORY) {
1165 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1166 					    "ia_css_binary_find() [%d] continue: %d && (%d == %d)\n",
1167 					    __LINE__, online, candidate->input.source,
1168 					    IA_CSS_BINARY_INPUT_MEMORY);
1169 			continue;
1170 		}
1171 		if (!online && candidate->input.source == IA_CSS_BINARY_INPUT_SENSOR) {
1172 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1173 					    "ia_css_binary_find() [%d] continue: !%d && (%d == %d)\n",
1174 					    __LINE__, online, candidate->input.source,
1175 					    IA_CSS_BINARY_INPUT_SENSOR);
1176 			continue;
1177 		}
1178 		if (req_bin_out_info->res.width < candidate->output.min_width ||
1179 		    req_bin_out_info->res.width > candidate->output.max_width) {
1180 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1181 					    "ia_css_binary_find() [%d] continue: (%d > %d) || (%d < %d)\n",
1182 					    __LINE__,
1183 					    req_bin_out_info->padded_width,
1184 					    candidate->output.min_width,
1185 					    req_bin_out_info->padded_width,
1186 					    candidate->output.max_width);
1187 			continue;
1188 		}
1189 		if (xcandidate->num_output_pins > 1 &&
1190 		    /* in case we have a second output pin, */
1191 		    req_vf_info) { /* and we need vf output. */
1192 			if (req_vf_info->res.width > candidate->output.max_width) {
1193 				ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1194 						    "ia_css_binary_find() [%d] continue: (%d < %d)\n",
1195 						    __LINE__,
1196 						    req_vf_info->res.width,
1197 						    candidate->output.max_width);
1198 				continue;
1199 			}
1200 		}
1201 		if (req_in_info->padded_width > candidate->input.max_width) {
1202 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1203 					    "ia_css_binary_find() [%d] continue: (%d > %d)\n",
1204 					    __LINE__, req_in_info->padded_width,
1205 					    candidate->input.max_width);
1206 			continue;
1207 		}
1208 		if (!binary_supports_output_format(xcandidate, req_bin_out_info->format)) {
1209 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1210 					    "ia_css_binary_find() [%d] continue: !%d\n",
1211 					    __LINE__,
1212 					    binary_supports_output_format(xcandidate, req_bin_out_info->format));
1213 			continue;
1214 		}
1215 		if (xcandidate->num_output_pins > 1 &&
1216 		    /* in case we have a second output pin, */
1217 		    req_vf_info                   && /* and we need vf output. */
1218 		    /* check if the required vf format
1219 		    is supported. */
1220 		    !binary_supports_output_format(xcandidate, req_vf_info->format)) {
1221 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1222 					    "ia_css_binary_find() [%d] continue: (%d > %d) && (%p != NULL) && !%d\n",
1223 					    __LINE__, xcandidate->num_output_pins, 1,
1224 					    req_vf_info,
1225 					    binary_supports_output_format(xcandidate, req_vf_info->format));
1226 			continue;
1227 		}
1228 
1229 		/* Check if vf_veceven supports the requested vf format */
1230 		if (xcandidate->num_output_pins == 1 &&
1231 		    req_vf_info && candidate->enable.vf_veceven &&
1232 		    !binary_supports_vf_format(xcandidate, req_vf_info->format)) {
1233 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1234 					    "ia_css_binary_find() [%d] continue: (%d == %d) && (%p != NULL) && %d && !%d\n",
1235 					    __LINE__, xcandidate->num_output_pins, 1,
1236 					    req_vf_info, candidate->enable.vf_veceven,
1237 					    binary_supports_vf_format(xcandidate, req_vf_info->format));
1238 			continue;
1239 		}
1240 
1241 		/* Check if vf_veceven supports the requested vf width */
1242 		if (xcandidate->num_output_pins == 1 &&
1243 		    req_vf_info && candidate->enable.vf_veceven) { /* and we need vf output. */
1244 			if (req_vf_info->res.width > candidate->output.max_width) {
1245 				ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1246 						    "ia_css_binary_find() [%d] continue: (%d < %d)\n",
1247 						    __LINE__,
1248 						    req_vf_info->res.width,
1249 						    candidate->output.max_width);
1250 				continue;
1251 			}
1252 		}
1253 
1254 		if (!supports_bds_factor(candidate->bds.supported_bds_factors,
1255 					 descr->required_bds_factor)) {
1256 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1257 					    "ia_css_binary_find() [%d] continue: 0x%x & 0x%x)\n",
1258 					    __LINE__, candidate->bds.supported_bds_factors,
1259 					    descr->required_bds_factor);
1260 			continue;
1261 		}
1262 
1263 		if (!candidate->enable.dpc && need_dpc) {
1264 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1265 					    "ia_css_binary_find() [%d] continue: 0x%x & 0x%x)\n",
1266 					    __LINE__, candidate->enable.dpc,
1267 					    descr->enable_dpc);
1268 			continue;
1269 		}
1270 
1271 		if (candidate->uds.use_bci && enable_capture_pp_bli) {
1272 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1273 					    "ia_css_binary_find() [%d] continue: 0x%x & 0x%x)\n",
1274 					    __LINE__, candidate->uds.use_bci,
1275 					    descr->enable_capture_pp_bli);
1276 			continue;
1277 		}
1278 
1279 		/* reconfigure any variable properties of the binary */
1280 		err = ia_css_binary_fill_info(xcandidate, online, two_ppc,
1281 					      stream_format, req_in_info,
1282 					      req_bds_out_info,
1283 					      req_out_info, req_vf_info,
1284 					      binary, &dvs_env,
1285 					      descr->stream_config_left_padding,
1286 					      false);
1287 
1288 		if (err)
1289 			break;
1290 		binary_init_metrics(&binary->metrics, &binary->info->sp);
1291 		break;
1292 	}
1293 
1294 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1295 			    "ia_css_binary_find() selected = %p, mode = %d ID = %d\n",
1296 			    xcandidate, xcandidate ? xcandidate->sp.pipeline.mode : 0, xcandidate ? xcandidate->sp.id : 0);
1297 
1298 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1299 			    "ia_css_binary_find() leave: return_err=%d\n", err);
1300 
1301 	if (!err && xcandidate)
1302 		dev_dbg(atomisp_dev,
1303 			"Using binary %s (id %d), type %d, mode %d, continuous %s\n",
1304 			xcandidate->blob->name,
1305 			xcandidate->sp.id,
1306 			xcandidate->type,
1307 			xcandidate->sp.pipeline.mode,
1308 			xcandidate->sp.enable.continuous ? "true" : "false");
1309 
1310 
1311 	return err;
1312 }
1313 
1314 int ia_css_binary_find(struct ia_css_binary_descr *descr,
1315 		       struct ia_css_binary *binary)
1316 {
1317 	int ret = __ia_css_binary_find(descr, binary);
1318 
1319 	if (unlikely(ret)) {
1320 		dev_dbg(atomisp_dev, "Seeking for binary failed at:");
1321 		dump_stack();
1322 	}
1323 
1324 	return ret;
1325 }
1326 
1327 unsigned
1328 ia_css_binary_max_vf_width(void)
1329 {
1330 	/* This is (should be) true for IPU1 and IPU2 */
1331 	/* For IPU3 (SkyCam) this pointer is guaranteed to be NULL simply because such a binary does not exist  */
1332 	if (binary_infos[IA_CSS_BINARY_MODE_VF_PP])
1333 		return binary_infos[IA_CSS_BINARY_MODE_VF_PP]->sp.output.max_width;
1334 	return 0;
1335 }
1336 
1337 void
1338 ia_css_binary_destroy_isp_parameters(struct ia_css_binary *binary)
1339 {
1340 	if (binary) {
1341 		ia_css_isp_param_destroy_isp_parameters(&binary->mem_params,
1342 							&binary->css_params);
1343 	}
1344 }
1345 
1346 void
1347 ia_css_binary_get_isp_binaries(struct ia_css_binary_xinfo **binaries,
1348 			       uint32_t *num_isp_binaries)
1349 {
1350 	assert(binaries);
1351 
1352 	if (num_isp_binaries)
1353 		*num_isp_binaries = 0;
1354 
1355 	*binaries = all_binaries;
1356 	if (all_binaries && num_isp_binaries) {
1357 		/* -1 to account for sp binary which is not stored in all_binaries */
1358 		if (sh_css_num_binaries > 0)
1359 			*num_isp_binaries = sh_css_num_binaries - 1;
1360 	}
1361 }
1362