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 (IS_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 	}
614 
615 	if (need_scaling) {
616 		/* In SDV use-case, we need to match left-padding of
617 		 * primary and the video binary. */
618 		if (stream_config_left_padding != -1) {
619 			/* Different than before, we do left&right padding. */
620 			rval =
621 			    CEIL_MUL(in_frame_width + nr_of_left_paddings,
622 				     2 * ISP_VEC_NELEMS);
623 		} else {
624 			/* Different than before, we do left&right padding. */
625 			in_frame_width += dvs_env_width;
626 			rval =
627 			    CEIL_MUL(in_frame_width +
628 				     (left_cropping ? nr_of_left_paddings : 0),
629 				     2 * ISP_VEC_NELEMS);
630 		}
631 	} else {
632 		rval = isp_internal_width;
633 	}
634 
635 	return rval;
636 }
637 
638 int
639 ia_css_binary_fill_info(const struct ia_css_binary_xinfo *xinfo,
640 			bool online,
641 			bool two_ppc,
642 			enum atomisp_input_format stream_format,
643 			const struct ia_css_frame_info *in_info, /* can be NULL */
644 			const struct ia_css_frame_info *bds_out_info, /* can be NULL */
645 			const struct ia_css_frame_info *out_info[], /* can be NULL */
646 			const struct ia_css_frame_info *vf_info, /* can be NULL */
647 			struct ia_css_binary *binary,
648 			struct ia_css_resolution *dvs_env,
649 			int stream_config_left_padding,
650 			bool accelerator) {
651 	const struct ia_css_binary_info *info = &xinfo->sp;
652 	unsigned int dvs_env_width = 0,
653 	dvs_env_height = 0,
654 	vf_log_ds = 0,
655 	s3a_log_deci = 0,
656 	bits_per_pixel = 0,
657 	/* Resolution at SC/3A/DIS kernel. */
658 	sc_3a_dis_width = 0,
659 	/* Resolution at SC/3A/DIS kernel. */
660 	sc_3a_dis_padded_width = 0,
661 	/* Resolution at SC/3A/DIS kernel. */
662 	sc_3a_dis_height = 0,
663 	isp_internal_width = 0,
664 	isp_internal_height = 0,
665 	s3a_isp_width = 0;
666 
667 	bool need_scaling = false;
668 	struct ia_css_resolution binary_dvs_env, internal_res;
669 	int err;
670 	unsigned int i;
671 	const struct ia_css_frame_info *bin_out_info = NULL;
672 
673 	assert(info);
674 	assert(binary);
675 
676 	binary->info = xinfo;
677 	if (!accelerator)
678 	{
679 		/* binary->css_params has been filled by accelerator itself. */
680 		err = ia_css_isp_param_allocate_isp_parameters(
681 		    &binary->mem_params, &binary->css_params,
682 		    &info->mem_initializers);
683 		if (err) {
684 			return err;
685 		}
686 	}
687 	for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++)
688 	{
689 		if (out_info[i] && (out_info[i]->res.width != 0)) {
690 			bin_out_info = out_info[i];
691 			break;
692 		}
693 	}
694 	if (in_info && bin_out_info)
695 	{
696 		need_scaling = (in_info->res.width != bin_out_info->res.width) ||
697 			       (in_info->res.height != bin_out_info->res.height);
698 	}
699 
700 	/* binary_dvs_env has to be equal or larger than SH_CSS_MIN_DVS_ENVELOPE */
701 	binary_dvs_env.width = 0;
702 	binary_dvs_env.height = 0;
703 	ia_css_binary_dvs_env(info, dvs_env, &binary_dvs_env);
704 	dvs_env_width = binary_dvs_env.width;
705 	dvs_env_height = binary_dvs_env.height;
706 	binary->dvs_envelope.width  = dvs_env_width;
707 	binary->dvs_envelope.height = dvs_env_height;
708 
709 	/* internal resolution calculation */
710 	internal_res.width = 0;
711 	internal_res.height = 0;
712 	ia_css_binary_internal_res(in_info, bds_out_info, bin_out_info, dvs_env,
713 				   info, &internal_res);
714 	isp_internal_width = internal_res.width;
715 	isp_internal_height = internal_res.height;
716 
717 	/* internal frame info */
718 	if (bin_out_info) /* { */
719 		binary->internal_frame_info.format = bin_out_info->format;
720 	/* } */
721 	binary->internal_frame_info.res.width       = isp_internal_width;
722 	binary->internal_frame_info.padded_width    = CEIL_MUL(isp_internal_width, 2 * ISP_VEC_NELEMS);
723 	binary->internal_frame_info.res.height      = isp_internal_height;
724 	binary->internal_frame_info.raw_bit_depth   = bits_per_pixel;
725 
726 	if (in_info)
727 	{
728 		binary->effective_in_frame_res.width = in_info->res.width;
729 		binary->effective_in_frame_res.height = in_info->res.height;
730 
731 		bits_per_pixel = in_info->raw_bit_depth;
732 
733 		/* input info */
734 		binary->in_frame_info.res.width = in_info->res.width +
735 						  info->pipeline.left_cropping;
736 		binary->in_frame_info.res.height = in_info->res.height +
737 						   info->pipeline.top_cropping;
738 
739 		binary->in_frame_info.res.width += dvs_env_width;
740 		binary->in_frame_info.res.height += dvs_env_height;
741 
742 		binary->in_frame_info.padded_width =
743 		    binary_in_frame_padded_width(in_info->res.width,
744 						 isp_internal_width,
745 						 dvs_env_width,
746 						 stream_config_left_padding,
747 						 info->pipeline.left_cropping,
748 						 need_scaling);
749 
750 		binary->in_frame_info.format = in_info->format;
751 		binary->in_frame_info.raw_bayer_order = in_info->raw_bayer_order;
752 		binary->in_frame_info.crop_info = in_info->crop_info;
753 	}
754 
755 	if (online)
756 	{
757 		bits_per_pixel = ia_css_util_input_format_bpp(
758 				     stream_format, two_ppc);
759 	}
760 	binary->in_frame_info.raw_bit_depth = bits_per_pixel;
761 
762 	for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++)
763 	{
764 		if (out_info[i]) {
765 			binary->out_frame_info[i].res.width     = out_info[i]->res.width;
766 			binary->out_frame_info[i].res.height    = out_info[i]->res.height;
767 			binary->out_frame_info[i].padded_width  = out_info[i]->padded_width;
768 			if (info->pipeline.mode == IA_CSS_BINARY_MODE_COPY) {
769 				binary->out_frame_info[i].raw_bit_depth = bits_per_pixel;
770 			} else {
771 				/* Only relevant for RAW format.
772 				 * At the moment, all outputs are raw, 16 bit per pixel, except for copy.
773 				 * To do this cleanly, the binary should specify in its info
774 				 * the bit depth per output channel.
775 				 */
776 				binary->out_frame_info[i].raw_bit_depth = 16;
777 			}
778 			binary->out_frame_info[i].format        = out_info[i]->format;
779 		}
780 	}
781 
782 	if (vf_info && (vf_info->res.width != 0))
783 	{
784 		err = ia_css_vf_configure(binary, bin_out_info,
785 					  (struct ia_css_frame_info *)vf_info, &vf_log_ds);
786 		if (err) {
787 			if (!accelerator) {
788 				ia_css_isp_param_destroy_isp_parameters(
789 				    &binary->mem_params,
790 				    &binary->css_params);
791 			}
792 			return err;
793 		}
794 	}
795 	binary->vf_downscale_log2 = vf_log_ds;
796 
797 	binary->online            = online;
798 	binary->input_format      = stream_format;
799 
800 	/* viewfinder output info */
801 	if ((vf_info) && (vf_info->res.width != 0))
802 	{
803 		unsigned int vf_out_vecs, vf_out_width, vf_out_height;
804 
805 		binary->vf_frame_info.format = vf_info->format;
806 		if (!bin_out_info)
807 			return -EINVAL;
808 		vf_out_vecs = __ISP_VF_OUTPUT_WIDTH_VECS(bin_out_info->padded_width,
809 			      vf_log_ds);
810 		vf_out_width = _ISP_VF_OUTPUT_WIDTH(vf_out_vecs);
811 		vf_out_height = _ISP_VF_OUTPUT_HEIGHT(bin_out_info->res.height,
812 						      vf_log_ds);
813 
814 		/* For preview mode, output pin is used instead of vf. */
815 		if (info->pipeline.mode == IA_CSS_BINARY_MODE_PREVIEW) {
816 			binary->out_frame_info[0].res.width =
817 			    (bin_out_info->res.width >> vf_log_ds);
818 			binary->out_frame_info[0].padded_width = vf_out_width;
819 			binary->out_frame_info[0].res.height   = vf_out_height;
820 
821 			binary->vf_frame_info.res.width    = 0;
822 			binary->vf_frame_info.padded_width = 0;
823 			binary->vf_frame_info.res.height   = 0;
824 		} else {
825 			/* we also store the raw downscaled width. This is
826 			 * used for digital zoom in preview to zoom only on
827 			 * the width that we actually want to keep, not on
828 			 * the aligned width. */
829 			binary->vf_frame_info.res.width =
830 			    (bin_out_info->res.width >> vf_log_ds);
831 			binary->vf_frame_info.padded_width = vf_out_width;
832 			binary->vf_frame_info.res.height   = vf_out_height;
833 		}
834 	} else
835 	{
836 		binary->vf_frame_info.res.width    = 0;
837 		binary->vf_frame_info.padded_width = 0;
838 		binary->vf_frame_info.res.height   = 0;
839 	}
840 
841 	if (info->enable.ca_gdc)
842 	{
843 		binary->morph_tbl_width =
844 		    _ISP_MORPH_TABLE_WIDTH(isp_internal_width);
845 		binary->morph_tbl_aligned_width  =
846 		    _ISP_MORPH_TABLE_ALIGNED_WIDTH(isp_internal_width);
847 		binary->morph_tbl_height =
848 		    _ISP_MORPH_TABLE_HEIGHT(isp_internal_height);
849 	} else
850 	{
851 		binary->morph_tbl_width  = 0;
852 		binary->morph_tbl_aligned_width  = 0;
853 		binary->morph_tbl_height = 0;
854 	}
855 
856 	sc_3a_dis_width = binary->in_frame_info.res.width;
857 	sc_3a_dis_padded_width = binary->in_frame_info.padded_width;
858 	sc_3a_dis_height = binary->in_frame_info.res.height;
859 	if (bds_out_info && in_info &&
860 	    bds_out_info->res.width != in_info->res.width)
861 	{
862 		/* TODO: Next, "internal_frame_info" should be derived from
863 		 * bds_out. So this part will change once it is in place! */
864 		sc_3a_dis_width = bds_out_info->res.width + info->pipeline.left_cropping;
865 		sc_3a_dis_padded_width = isp_internal_width;
866 		sc_3a_dis_height = isp_internal_height;
867 	}
868 
869 	s3a_isp_width = _ISP_S3A_ELEMS_ISP_WIDTH(sc_3a_dis_padded_width,
870 			info->pipeline.left_cropping);
871 	if (info->s3a.fixed_s3a_deci_log)
872 	{
873 		s3a_log_deci = info->s3a.fixed_s3a_deci_log;
874 	} else
875 	{
876 		s3a_log_deci = binary_grid_deci_factor_log2(s3a_isp_width,
877 			       sc_3a_dis_height);
878 	}
879 	binary->deci_factor_log2  = s3a_log_deci;
880 
881 	if (info->enable.s3a)
882 	{
883 		binary->s3atbl_width  =
884 		    _ISP_S3ATBL_WIDTH(sc_3a_dis_width,
885 				      s3a_log_deci);
886 		binary->s3atbl_height =
887 		    _ISP_S3ATBL_HEIGHT(sc_3a_dis_height,
888 				       s3a_log_deci);
889 		binary->s3atbl_isp_width =
890 		    _ISP_S3ATBL_ISP_WIDTH(s3a_isp_width,
891 					  s3a_log_deci);
892 		binary->s3atbl_isp_height =
893 		    _ISP_S3ATBL_ISP_HEIGHT(sc_3a_dis_height,
894 					   s3a_log_deci);
895 	} else
896 	{
897 		binary->s3atbl_width  = 0;
898 		binary->s3atbl_height = 0;
899 		binary->s3atbl_isp_width  = 0;
900 		binary->s3atbl_isp_height = 0;
901 	}
902 
903 	if (info->enable.sc)
904 	{
905 		binary->sctbl_width_per_color = _ISP_SCTBL_WIDTH_PER_COLOR(sc_3a_dis_padded_width, s3a_log_deci);
906 		binary->sctbl_aligned_width_per_color = SH_CSS_MAX_SCTBL_ALIGNED_WIDTH_PER_COLOR;
907 		binary->sctbl_height = _ISP_SCTBL_HEIGHT(sc_3a_dis_height, s3a_log_deci);
908 	} else
909 	{
910 		binary->sctbl_width_per_color         = 0;
911 		binary->sctbl_aligned_width_per_color = 0;
912 		binary->sctbl_height                  = 0;
913 	}
914 	ia_css_sdis_init_info(&binary->dis,
915 			      sc_3a_dis_width,
916 			      sc_3a_dis_padded_width,
917 			      sc_3a_dis_height,
918 			      info->pipeline.isp_pipe_version,
919 			      info->enable.dis);
920 	if (info->pipeline.left_cropping)
921 		binary->left_padding = 2 * ISP_VEC_NELEMS - info->pipeline.left_cropping;
922 	else
923 		binary->left_padding = 0;
924 
925 	return 0;
926 }
927 
928 static int __ia_css_binary_find(struct ia_css_binary_descr *descr,
929 				struct ia_css_binary *binary) {
930 	int mode;
931 	bool online;
932 	bool two_ppc;
933 	enum atomisp_input_format stream_format;
934 	const struct ia_css_frame_info *req_in_info,
935 		*req_bds_out_info,
936 		*req_out_info[IA_CSS_BINARY_MAX_OUTPUT_PORTS],
937 		*req_bin_out_info = NULL,
938 		*req_vf_info;
939 
940 	struct ia_css_binary_xinfo *xcandidate;
941 	bool need_ds, need_dz, need_dvs, need_xnr, need_dpc;
942 	bool striped;
943 	bool enable_yuv_ds;
944 	bool enable_high_speed;
945 	bool enable_dvs_6axis;
946 	bool enable_reduced_pipe;
947 	bool enable_capture_pp_bli;
948 	int err = -EINVAL;
949 	bool continuous;
950 	unsigned int isp_pipe_version;
951 	struct ia_css_resolution dvs_env, internal_res;
952 	unsigned int i;
953 
954 	assert(descr);
955 	/* MW: used after an error check, may accept NULL, but doubtfull */
956 	assert(binary);
957 
958 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
959 			    "ia_css_binary_find() enter: descr=%p, (mode=%d), binary=%p\n",
960 			    descr, descr->mode,
961 			    binary);
962 
963 	mode = descr->mode;
964 	online = descr->online;
965 	two_ppc = descr->two_ppc;
966 	stream_format = descr->stream_format;
967 	req_in_info = descr->in_info;
968 	req_bds_out_info = descr->bds_out_info;
969 	for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) {
970 		req_out_info[i] = descr->out_info[i];
971 		if (req_out_info[i] && (req_out_info[i]->res.width != 0))
972 			req_bin_out_info = req_out_info[i];
973 	}
974 	if (!req_bin_out_info)
975 		return -EINVAL;
976 	req_vf_info = descr->vf_info;
977 
978 	need_xnr = descr->enable_xnr;
979 	need_ds = descr->enable_fractional_ds;
980 	need_dz = false;
981 	need_dvs = false;
982 	need_dpc = descr->enable_dpc;
983 
984 	enable_yuv_ds = descr->enable_yuv_ds;
985 	enable_high_speed = descr->enable_high_speed;
986 	enable_dvs_6axis  = descr->enable_dvs_6axis;
987 	enable_reduced_pipe = descr->enable_reduced_pipe;
988 	enable_capture_pp_bli = descr->enable_capture_pp_bli;
989 	continuous = descr->continuous;
990 	striped = descr->striped;
991 	isp_pipe_version = descr->isp_pipe_version;
992 
993 	dvs_env.width = 0;
994 	dvs_env.height = 0;
995 	internal_res.width = 0;
996 	internal_res.height = 0;
997 
998 	if (mode == IA_CSS_BINARY_MODE_VIDEO) {
999 		dvs_env = descr->dvs_env;
1000 		need_dz = descr->enable_dz;
1001 		/* Video is the only mode that has a nodz variant. */
1002 		need_dvs = dvs_env.width || dvs_env.height;
1003 	}
1004 
1005 	/* print a map of the binary file */
1006 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,	"BINARY INFO:\n");
1007 	for (i = 0; i < IA_CSS_BINARY_NUM_MODES; i++) {
1008 		xcandidate = binary_infos[i];
1009 		if (xcandidate) {
1010 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,	"%d:\n", i);
1011 			while (xcandidate) {
1012 				ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, " Name:%s Type:%d Cont:%d\n",
1013 						    xcandidate->blob->name, xcandidate->type,
1014 						    xcandidate->sp.enable.continuous);
1015 				xcandidate = xcandidate->next;
1016 			}
1017 		}
1018 	}
1019 
1020 	/* printf("sh_css_binary_find: pipe version %d\n", isp_pipe_version); */
1021 	for (xcandidate = binary_infos[mode]; xcandidate;
1022 	     xcandidate = xcandidate->next) {
1023 		struct ia_css_binary_info *candidate = &xcandidate->sp;
1024 		/* printf("sh_css_binary_find: evaluating candidate:
1025 		 * %d\n",candidate->id); */
1026 		ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1027 				    "ia_css_binary_find() candidate = %p, mode = %d ID = %d\n",
1028 				    candidate, candidate->pipeline.mode, candidate->id);
1029 
1030 		/*
1031 		 * MW: Only a limited set of jointly configured binaries can
1032 		 * be used in a continuous preview/video mode unless it is
1033 		 * the copy mode and runs on SP.
1034 		*/
1035 		if (!candidate->enable.continuous &&
1036 		    continuous && (mode != IA_CSS_BINARY_MODE_COPY)) {
1037 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1038 					    "ia_css_binary_find() [%d] continue: !%d && %d && (%d != %d)\n",
1039 					    __LINE__, candidate->enable.continuous,
1040 					    continuous, mode,
1041 					    IA_CSS_BINARY_MODE_COPY);
1042 			continue;
1043 		}
1044 		if (striped && candidate->iterator.num_stripes == 1) {
1045 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1046 					    "ia_css_binary_find() [%d] continue: binary is not striped\n",
1047 					    __LINE__);
1048 			continue;
1049 		}
1050 
1051 		if (candidate->pipeline.isp_pipe_version != isp_pipe_version &&
1052 		    (mode != IA_CSS_BINARY_MODE_COPY) &&
1053 		    (mode != IA_CSS_BINARY_MODE_CAPTURE_PP) &&
1054 		    (mode != IA_CSS_BINARY_MODE_VF_PP)) {
1055 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1056 					    "ia_css_binary_find() [%d] continue: (%d != %d)\n",
1057 					    __LINE__,
1058 					    candidate->pipeline.isp_pipe_version, isp_pipe_version);
1059 			continue;
1060 		}
1061 		if (!candidate->enable.reduced_pipe && enable_reduced_pipe) {
1062 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1063 					    "ia_css_binary_find() [%d] continue: !%d && %d\n",
1064 					    __LINE__,
1065 					    candidate->enable.reduced_pipe,
1066 					    enable_reduced_pipe);
1067 			continue;
1068 		}
1069 		if (!candidate->enable.dvs_6axis && enable_dvs_6axis) {
1070 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1071 					    "ia_css_binary_find() [%d] continue: !%d && %d\n",
1072 					    __LINE__,
1073 					    candidate->enable.dvs_6axis,
1074 					    enable_dvs_6axis);
1075 			continue;
1076 		}
1077 		if (candidate->enable.high_speed && !enable_high_speed) {
1078 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1079 					    "ia_css_binary_find() [%d] continue: %d && !%d\n",
1080 					    __LINE__,
1081 					    candidate->enable.high_speed,
1082 					    enable_high_speed);
1083 			continue;
1084 		}
1085 		if (!candidate->enable.xnr && need_xnr) {
1086 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1087 					    "ia_css_binary_find() [%d] continue: %d && !%d\n",
1088 					    __LINE__,
1089 					    candidate->enable.xnr,
1090 					    need_xnr);
1091 			continue;
1092 		}
1093 		if (!(candidate->enable.ds & 2) && enable_yuv_ds) {
1094 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1095 					    "ia_css_binary_find() [%d] continue: !%d && %d\n",
1096 					    __LINE__,
1097 					    ((candidate->enable.ds & 2) != 0),
1098 					    enable_yuv_ds);
1099 			continue;
1100 		}
1101 		if ((candidate->enable.ds & 2) && !enable_yuv_ds) {
1102 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1103 					    "ia_css_binary_find() [%d] continue: %d && !%d\n",
1104 					    __LINE__,
1105 					    ((candidate->enable.ds & 2) != 0),
1106 					    enable_yuv_ds);
1107 			continue;
1108 		}
1109 
1110 		if (mode == IA_CSS_BINARY_MODE_VIDEO &&
1111 		    candidate->enable.ds && need_ds)
1112 			need_dz = false;
1113 
1114 		/* when we require vf output, we need to have vf_veceven */
1115 		if ((req_vf_info) && !(candidate->enable.vf_veceven ||
1116 				       /* or variable vf vec even */
1117 				       candidate->vf_dec.is_variable ||
1118 				       /* or more than one output pin. */
1119 				       xcandidate->num_output_pins > 1)) {
1120 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1121 					    "ia_css_binary_find() [%d] continue: (%p != NULL) && !(%d || %d || (%d >%d))\n",
1122 					    __LINE__, req_vf_info,
1123 					    candidate->enable.vf_veceven,
1124 					    candidate->vf_dec.is_variable,
1125 					    xcandidate->num_output_pins, 1);
1126 			continue;
1127 		}
1128 		if (!candidate->enable.dvs_envelope && need_dvs) {
1129 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1130 					    "ia_css_binary_find() [%d] continue: !%d && %d\n",
1131 					    __LINE__,
1132 					    candidate->enable.dvs_envelope, (int)need_dvs);
1133 			continue;
1134 		}
1135 		/* internal_res check considers input, output, and dvs envelope sizes */
1136 		ia_css_binary_internal_res(req_in_info, req_bds_out_info,
1137 					   req_bin_out_info, &dvs_env, candidate, &internal_res);
1138 		if (internal_res.width > candidate->internal.max_width) {
1139 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1140 					    "ia_css_binary_find() [%d] continue: (%d > %d)\n",
1141 					    __LINE__, internal_res.width,
1142 					    candidate->internal.max_width);
1143 			continue;
1144 		}
1145 		if (internal_res.height > candidate->internal.max_height) {
1146 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1147 					    "ia_css_binary_find() [%d] continue: (%d > %d)\n",
1148 					    __LINE__, internal_res.height,
1149 					    candidate->internal.max_height);
1150 			continue;
1151 		}
1152 		if (!candidate->enable.ds && need_ds && !(xcandidate->num_output_pins > 1)) {
1153 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1154 					    "ia_css_binary_find() [%d] continue: !%d && %d\n",
1155 					    __LINE__, candidate->enable.ds, (int)need_ds);
1156 			continue;
1157 		}
1158 		if (!candidate->enable.uds && !candidate->enable.dvs_6axis && need_dz) {
1159 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1160 					    "ia_css_binary_find() [%d] continue: !%d && !%d && %d\n",
1161 					    __LINE__, candidate->enable.uds,
1162 					    candidate->enable.dvs_6axis, (int)need_dz);
1163 			continue;
1164 		}
1165 		if (online && candidate->input.source == IA_CSS_BINARY_INPUT_MEMORY) {
1166 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1167 					    "ia_css_binary_find() [%d] continue: %d && (%d == %d)\n",
1168 					    __LINE__, online, candidate->input.source,
1169 					    IA_CSS_BINARY_INPUT_MEMORY);
1170 			continue;
1171 		}
1172 		if (!online && candidate->input.source == IA_CSS_BINARY_INPUT_SENSOR) {
1173 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1174 					    "ia_css_binary_find() [%d] continue: !%d && (%d == %d)\n",
1175 					    __LINE__, online, candidate->input.source,
1176 					    IA_CSS_BINARY_INPUT_SENSOR);
1177 			continue;
1178 		}
1179 		if (req_bin_out_info->res.width < candidate->output.min_width ||
1180 		    req_bin_out_info->res.width > candidate->output.max_width) {
1181 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1182 					    "ia_css_binary_find() [%d] continue: (%d > %d) || (%d < %d)\n",
1183 					    __LINE__,
1184 					    req_bin_out_info->padded_width,
1185 					    candidate->output.min_width,
1186 					    req_bin_out_info->padded_width,
1187 					    candidate->output.max_width);
1188 			continue;
1189 		}
1190 		if (xcandidate->num_output_pins > 1 &&
1191 		    /* in case we have a second output pin, */
1192 		    req_vf_info) { /* and we need vf output. */
1193 			if (req_vf_info->res.width > candidate->output.max_width) {
1194 				ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1195 						    "ia_css_binary_find() [%d] continue: (%d < %d)\n",
1196 						    __LINE__,
1197 						    req_vf_info->res.width,
1198 						    candidate->output.max_width);
1199 				continue;
1200 			}
1201 		}
1202 		if (req_in_info->padded_width > candidate->input.max_width) {
1203 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1204 					    "ia_css_binary_find() [%d] continue: (%d > %d)\n",
1205 					    __LINE__, req_in_info->padded_width,
1206 					    candidate->input.max_width);
1207 			continue;
1208 		}
1209 		if (!binary_supports_output_format(xcandidate, req_bin_out_info->format)) {
1210 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1211 					    "ia_css_binary_find() [%d] continue: !%d\n",
1212 					    __LINE__,
1213 					    binary_supports_output_format(xcandidate, req_bin_out_info->format));
1214 			continue;
1215 		}
1216 		if (xcandidate->num_output_pins > 1 &&
1217 		    /* in case we have a second output pin, */
1218 		    req_vf_info                   && /* and we need vf output. */
1219 		    /* check if the required vf format
1220 		    is supported. */
1221 		    !binary_supports_output_format(xcandidate, req_vf_info->format)) {
1222 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1223 					    "ia_css_binary_find() [%d] continue: (%d > %d) && (%p != NULL) && !%d\n",
1224 					    __LINE__, xcandidate->num_output_pins, 1,
1225 					    req_vf_info,
1226 					    binary_supports_output_format(xcandidate, req_vf_info->format));
1227 			continue;
1228 		}
1229 
1230 		/* Check if vf_veceven supports the requested vf format */
1231 		if (xcandidate->num_output_pins == 1 &&
1232 		    req_vf_info && candidate->enable.vf_veceven &&
1233 		    !binary_supports_vf_format(xcandidate, req_vf_info->format)) {
1234 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1235 					    "ia_css_binary_find() [%d] continue: (%d == %d) && (%p != NULL) && %d && !%d\n",
1236 					    __LINE__, xcandidate->num_output_pins, 1,
1237 					    req_vf_info, candidate->enable.vf_veceven,
1238 					    binary_supports_vf_format(xcandidate, req_vf_info->format));
1239 			continue;
1240 		}
1241 
1242 		/* Check if vf_veceven supports the requested vf width */
1243 		if (xcandidate->num_output_pins == 1 &&
1244 		    req_vf_info && candidate->enable.vf_veceven) { /* and we need vf output. */
1245 			if (req_vf_info->res.width > candidate->output.max_width) {
1246 				ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1247 						    "ia_css_binary_find() [%d] continue: (%d < %d)\n",
1248 						    __LINE__,
1249 						    req_vf_info->res.width,
1250 						    candidate->output.max_width);
1251 				continue;
1252 			}
1253 		}
1254 
1255 		if (!supports_bds_factor(candidate->bds.supported_bds_factors,
1256 					 descr->required_bds_factor)) {
1257 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1258 					    "ia_css_binary_find() [%d] continue: 0x%x & 0x%x)\n",
1259 					    __LINE__, candidate->bds.supported_bds_factors,
1260 					    descr->required_bds_factor);
1261 			continue;
1262 		}
1263 
1264 		if (!candidate->enable.dpc && need_dpc) {
1265 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1266 					    "ia_css_binary_find() [%d] continue: 0x%x & 0x%x)\n",
1267 					    __LINE__, candidate->enable.dpc,
1268 					    descr->enable_dpc);
1269 			continue;
1270 		}
1271 
1272 		if (candidate->uds.use_bci && enable_capture_pp_bli) {
1273 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1274 					    "ia_css_binary_find() [%d] continue: 0x%x & 0x%x)\n",
1275 					    __LINE__, candidate->uds.use_bci,
1276 					    descr->enable_capture_pp_bli);
1277 			continue;
1278 		}
1279 
1280 		/* reconfigure any variable properties of the binary */
1281 		err = ia_css_binary_fill_info(xcandidate, online, two_ppc,
1282 					      stream_format, req_in_info,
1283 					      req_bds_out_info,
1284 					      req_out_info, req_vf_info,
1285 					      binary, &dvs_env,
1286 					      descr->stream_config_left_padding,
1287 					      false);
1288 
1289 		if (err)
1290 			break;
1291 		binary_init_metrics(&binary->metrics, &binary->info->sp);
1292 		break;
1293 	}
1294 
1295 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1296 			    "ia_css_binary_find() selected = %p, mode = %d ID = %d\n",
1297 			    xcandidate, xcandidate ? xcandidate->sp.pipeline.mode : 0, xcandidate ? xcandidate->sp.id : 0);
1298 
1299 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1300 			    "ia_css_binary_find() leave: return_err=%d\n", err);
1301 
1302 	if (!err && xcandidate)
1303 		dev_dbg(atomisp_dev,
1304 			"Using binary %s (id %d), type %d, mode %d, continuous %s\n",
1305 			xcandidate->blob->name,
1306 			xcandidate->sp.id,
1307 			xcandidate->type,
1308 			xcandidate->sp.pipeline.mode,
1309 			xcandidate->sp.enable.continuous ? "true" : "false");
1310 
1311 
1312 	return err;
1313 }
1314 
1315 int ia_css_binary_find(struct ia_css_binary_descr *descr,
1316 		       struct ia_css_binary *binary)
1317 {
1318 	int ret = __ia_css_binary_find(descr, binary);
1319 
1320 	if (unlikely(ret)) {
1321 		dev_dbg(atomisp_dev, "Seeking for binary failed at:");
1322 		dump_stack();
1323 	}
1324 
1325 	return ret;
1326 }
1327 
1328 unsigned
1329 ia_css_binary_max_vf_width(void)
1330 {
1331 	/* This is (should be) true for IPU1 and IPU2 */
1332 	/* For IPU3 (SkyCam) this pointer is guaranteed to be NULL simply because such a binary does not exist  */
1333 	if (binary_infos[IA_CSS_BINARY_MODE_VF_PP])
1334 		return binary_infos[IA_CSS_BINARY_MODE_VF_PP]->sp.output.max_width;
1335 	return 0;
1336 }
1337 
1338 void
1339 ia_css_binary_destroy_isp_parameters(struct ia_css_binary *binary)
1340 {
1341 	if (binary) {
1342 		ia_css_isp_param_destroy_isp_parameters(&binary->mem_params,
1343 							&binary->css_params);
1344 	}
1345 }
1346 
1347 void
1348 ia_css_binary_get_isp_binaries(struct ia_css_binary_xinfo **binaries,
1349 			       uint32_t *num_isp_binaries)
1350 {
1351 	assert(binaries);
1352 
1353 	if (num_isp_binaries)
1354 		*num_isp_binaries = 0;
1355 
1356 	*binaries = all_binaries;
1357 	if (all_binaries && num_isp_binaries) {
1358 		/* -1 to account for sp binary which is not stored in all_binaries */
1359 		if (sh_css_num_binaries > 0)
1360 			*num_isp_binaries = sh_css_num_binaries - 1;
1361 	}
1362 }
1363