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