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 /*! \file */
17 #include <linux/mm.h>
18 #include <linux/slab.h>
19 #include <linux/vmalloc.h>
20 
21 #include "hmm.h"
22 
23 #include "atomisp_internal.h"
24 
25 #include "ia_css.h"
26 #include "sh_css_hrt.h"		/* only for file 2 MIPI */
27 #include "ia_css_buffer.h"
28 #include "ia_css_binary.h"
29 #include "sh_css_internal.h"
30 #include "sh_css_mipi.h"
31 #include "sh_css_sp.h"		/* sh_css_sp_group */
32 #include "ia_css_isys.h"
33 #include "ia_css_frame.h"
34 #include "sh_css_defs.h"
35 #include "sh_css_firmware.h"
36 #include "sh_css_params.h"
37 #include "sh_css_params_internal.h"
38 #include "sh_css_param_shading.h"
39 #include "ia_css_refcount.h"
40 #include "ia_css_rmgr.h"
41 #include "ia_css_debug.h"
42 #include "ia_css_debug_pipe.h"
43 #include "ia_css_device_access.h"
44 #include "device_access.h"
45 #include "sh_css_legacy.h"
46 #include "ia_css_pipeline.h"
47 #include "ia_css_stream.h"
48 #include "sh_css_stream_format.h"
49 #include "ia_css_pipe.h"
50 #include "ia_css_util.h"
51 #include "ia_css_pipe_util.h"
52 #include "ia_css_pipe_binarydesc.h"
53 #include "ia_css_pipe_stagedesc.h"
54 
55 #include "tag.h"
56 #include "assert_support.h"
57 #include "math_support.h"
58 #include "sw_event_global.h"			/* Event IDs.*/
59 #if !defined(ISP2401)
60 #include "ia_css_ifmtr.h"
61 #endif
62 #include "input_system.h"
63 #include "mmu_device.h"		/* mmu_set_page_table_base_index(), ... */
64 #include "ia_css_mmu_private.h" /* sh_css_mmu_set_page_table_base_index() */
65 #include "gdc_device.h"		/* HRT_GDC_N */
66 #include "dma.h"		/* dma_set_max_burst_size() */
67 #include "irq.h"		/* virq */
68 #include "sp.h"			/* cnd_sp_irq_enable() */
69 #include "isp.h"		/* cnd_isp_irq_enable, ISP_VEC_NELEMS */
70 #include "gp_device.h"		/* gp_device_reg_store() */
71 #define __INLINE_GPIO__
72 #include "gpio.h"
73 #include "timed_ctrl.h"
74 #include "ia_css_inputfifo.h"
75 #define WITH_PC_MONITORING  0
76 
77 #define SH_CSS_VIDEO_BUFFER_ALIGNMENT 0
78 
79 
80 #include "ia_css_spctrl.h"
81 #include "ia_css_version_data.h"
82 #include "sh_css_struct.h"
83 #include "ia_css_bufq.h"
84 #include "ia_css_timer.h" /* clock_value_t */
85 
86 #include "isp/modes/interface/input_buf.isp.h"
87 
88 /* Name of the sp program: should not be built-in */
89 #define SP_PROG_NAME "sp"
90 /* Size of Refcount List */
91 #define REFCOUNT_SIZE 1000
92 
93 /*
94  * for JPEG, we don't know the length of the image upfront,
95  * but since we support sensor up to 16MP, we take this as
96  * upper limit.
97  */
98 #define JPEG_BYTES (16 * 1024 * 1024)
99 
100 #define STATS_ENABLED(stage) (stage && stage->binary && stage->binary->info && \
101 	(stage->binary->info->sp.enable.s3a || stage->binary->info->sp.enable.dis))
102 
103 struct sh_css my_css;
104 
105 int  __printf(1, 0) (*sh_css_printf)(const char *fmt, va_list args) = NULL;
106 
107 /*
108  * modes of work: stream_create and stream_destroy will update the save/restore
109  * data only when in working mode, not suspend/resume
110  */
111 enum ia_sh_css_modes {
112 	sh_css_mode_none = 0,
113 	sh_css_mode_working,
114 	sh_css_mode_suspend,
115 	sh_css_mode_resume
116 };
117 
118 /**
119  * struct sh_css_stream_seed - a stream seed, to save and restore the
120  * stream data.
121  *
122  * @orig_stream:	pointer to restore the original handle
123  * @stream:		handle, used as ID too.
124  * @stream_config:	stream config struct
125  * @num_pipes:		number of pipes
126  * @pipes:		pipe handles
127  * @orig_pipes:		pointer to restore original handle
128  * @pipe_config:	pipe config structs
129  *
130  * the stream seed contains all the data required to "grow" the seed again
131  * after it was closed.
132 */
133 struct sh_css_stream_seed {
134 	struct ia_css_stream		**orig_stream;
135 	struct ia_css_stream		*stream;
136 	struct ia_css_stream_config	stream_config;
137 	int				num_pipes;
138 	struct ia_css_pipe		*pipes[IA_CSS_PIPE_ID_NUM];
139 	struct ia_css_pipe		**orig_pipes[IA_CSS_PIPE_ID_NUM];
140 	struct ia_css_pipe_config	pipe_config[IA_CSS_PIPE_ID_NUM];
141 };
142 
143 #define MAX_ACTIVE_STREAMS	5
144 /*
145  * A global struct for save/restore to hold all the data that should
146  * sustain power-down: MMU base, IRQ type, env for routines, binary loaded FW
147  * and the stream seeds.
148  */
149 struct sh_css_save {
150 	enum ia_sh_css_modes		mode;
151 	u32		       mmu_base;		/* the last mmu_base */
152 	enum ia_css_irq_type           irq_type;
153 	struct sh_css_stream_seed      stream_seeds[MAX_ACTIVE_STREAMS];
154 	struct ia_css_fw	       *loaded_fw;	/* fw struct previously loaded */
155 	struct ia_css_env	       driver_env;	/* driver-supplied env copy */
156 };
157 
158 static bool my_css_save_initialized;	/* if my_css_save was initialized */
159 static struct sh_css_save my_css_save;
160 
161 /*
162  * pqiao NOTICE: this is for css internal buffer recycling when stopping
163  * pipeline,
164  * this array is temporary and will be replaced by resource manager
165  */
166 
167 /* Taking the biggest Size for number of Elements */
168 #define MAX_HMM_BUFFER_NUM	\
169 	(SH_CSS_MAX_NUM_QUEUES * (IA_CSS_NUM_ELEMS_SP2HOST_BUFFER_QUEUE + 2))
170 
171 struct sh_css_hmm_buffer_record {
172 	bool in_use;
173 	enum ia_css_buffer_type type;
174 	struct ia_css_rmgr_vbuf_handle *h_vbuf;
175 	hrt_address kernel_ptr;
176 };
177 
178 static struct sh_css_hmm_buffer_record hmm_buffer_record[MAX_HMM_BUFFER_NUM];
179 
180 #define GPIO_FLASH_PIN_MASK BIT(HIVE_GPIO_STROBE_TRIGGER_PIN)
181 
182 static bool fw_explicitly_loaded;
183 
184 /*
185  * Local prototypes
186  */
187 
188 static int
189 allocate_delay_frames(struct ia_css_pipe *pipe);
190 
191 static int
192 sh_css_pipe_start(struct ia_css_stream *stream);
193 
194 /*
195  * @brief Check if all "ia_css_pipe" instances in the target
196  * "ia_css_stream" instance have stopped.
197  *
198  * @param[in] stream	Point to the target "ia_css_stream" instance.
199  *
200  * @return
201  * - true, if all "ia_css_pipe" instances in the target "ia_css_stream"
202  *   instance have ben stopped.
203  * - false, otherwise.
204  */
205 
206 /* ISP 2401 */
207 static int
208 ia_css_pipe_check_format(struct ia_css_pipe *pipe,
209 			 enum ia_css_frame_format format);
210 
211 /* ISP 2401 */
212 static int
213 ia_css_pipe_load_extension(struct ia_css_pipe *pipe,
214 			   struct ia_css_fw_info *firmware);
215 
216 static void
217 ia_css_pipe_unload_extension(struct ia_css_pipe *pipe,
218 			     struct ia_css_fw_info *firmware);
219 static void
220 ia_css_reset_defaults(struct sh_css *css);
221 
222 static void
223 sh_css_init_host_sp_control_vars(void);
224 
225 static int
226 set_num_primary_stages(unsigned int *num, enum ia_css_pipe_version version);
227 
228 static bool
229 need_capture_pp(const struct ia_css_pipe *pipe);
230 
231 static bool
232 need_yuv_scaler_stage(const struct ia_css_pipe *pipe);
233 
234 static int ia_css_pipe_create_cas_scaler_desc_single_output(
235     struct ia_css_frame_info *cas_scaler_in_info,
236     struct ia_css_frame_info *cas_scaler_out_info,
237     struct ia_css_frame_info *cas_scaler_vf_info,
238     struct ia_css_cas_binary_descr *descr);
239 
240 static void ia_css_pipe_destroy_cas_scaler_desc(struct ia_css_cas_binary_descr
241 	*descr);
242 
243 static bool
244 need_downscaling(const struct ia_css_resolution in_res,
245 		 const struct ia_css_resolution out_res);
246 
247 static bool need_capt_ldc(const struct ia_css_pipe *pipe);
248 
249 static int
250 sh_css_pipe_load_binaries(struct ia_css_pipe *pipe);
251 
252 static
253 int sh_css_pipe_get_viewfinder_frame_info(
254     struct ia_css_pipe *pipe,
255     struct ia_css_frame_info *info,
256     unsigned int idx);
257 
258 static int
259 sh_css_pipe_get_output_frame_info(struct ia_css_pipe *pipe,
260 				  struct ia_css_frame_info *info,
261 				  unsigned int idx);
262 
263 static int
264 capture_start(struct ia_css_pipe *pipe);
265 
266 static int
267 video_start(struct ia_css_pipe *pipe);
268 
269 static int
270 preview_start(struct ia_css_pipe *pipe);
271 
272 static int
273 yuvpp_start(struct ia_css_pipe *pipe);
274 
275 static bool copy_on_sp(struct ia_css_pipe *pipe);
276 
277 static int
278 init_vf_frameinfo_defaults(struct ia_css_pipe *pipe,
279 			   struct ia_css_frame *vf_frame, unsigned int idx);
280 
281 static int
282 init_in_frameinfo_memory_defaults(struct ia_css_pipe *pipe,
283 				  struct ia_css_frame *frame, enum ia_css_frame_format format);
284 
285 static int
286 init_out_frameinfo_defaults(struct ia_css_pipe *pipe,
287 			    struct ia_css_frame *out_frame, unsigned int idx);
288 
289 static int
290 sh_css_pipeline_add_acc_stage(struct ia_css_pipeline *pipeline,
291 			      const void *acc_fw);
292 
293 static int
294 alloc_continuous_frames(struct ia_css_pipe *pipe, bool init_time);
295 
296 static void
297 pipe_global_init(void);
298 
299 static int
300 pipe_generate_pipe_num(const struct ia_css_pipe *pipe,
301 		       unsigned int *pipe_number);
302 
303 static void
304 pipe_release_pipe_num(unsigned int pipe_num);
305 
306 static int
307 create_host_pipeline_structure(struct ia_css_stream *stream);
308 
309 static int
310 create_host_pipeline(struct ia_css_stream *stream);
311 
312 static int
313 create_host_preview_pipeline(struct ia_css_pipe *pipe);
314 
315 static int
316 create_host_video_pipeline(struct ia_css_pipe *pipe);
317 
318 static int
319 create_host_copy_pipeline(struct ia_css_pipe *pipe,
320 			  unsigned int max_input_width,
321 			  struct ia_css_frame *out_frame);
322 
323 static int
324 create_host_isyscopy_capture_pipeline(struct ia_css_pipe *pipe);
325 
326 static int
327 create_host_capture_pipeline(struct ia_css_pipe *pipe);
328 
329 static int
330 create_host_yuvpp_pipeline(struct ia_css_pipe *pipe);
331 
332 static int
333 create_host_acc_pipeline(struct ia_css_pipe *pipe);
334 
335 static unsigned int
336 sh_css_get_sw_interrupt_value(unsigned int irq);
337 
338 static struct ia_css_binary *ia_css_pipe_get_shading_correction_binary(
339     const struct ia_css_pipe *pipe);
340 
341 static struct ia_css_binary *
342 ia_css_pipe_get_s3a_binary(const struct ia_css_pipe *pipe);
343 
344 static struct ia_css_binary *
345 ia_css_pipe_get_sdis_binary(const struct ia_css_pipe *pipe);
346 
347 static void
348 sh_css_hmm_buffer_record_init(void);
349 
350 static void
351 sh_css_hmm_buffer_record_uninit(void);
352 
353 static void
354 sh_css_hmm_buffer_record_reset(struct sh_css_hmm_buffer_record *buffer_record);
355 
356 static struct sh_css_hmm_buffer_record
357 *sh_css_hmm_buffer_record_acquire(struct ia_css_rmgr_vbuf_handle *h_vbuf,
358 				  enum ia_css_buffer_type type,
359 				  hrt_address kernel_ptr);
360 
361 static struct sh_css_hmm_buffer_record
362 *sh_css_hmm_buffer_record_validate(ia_css_ptr ddr_buffer_addr,
363 				   enum ia_css_buffer_type type);
364 
365 void
366 ia_css_get_acc_configs(
367     struct ia_css_pipe *pipe,
368     struct ia_css_isp_config *config);
369 
370 
371 #ifdef ISP2401
372 static unsigned int get_crop_lines_for_bayer_order(const struct
373 	ia_css_stream_config *config);
374 static unsigned int get_crop_columns_for_bayer_order(const struct
375 	ia_css_stream_config *config);
376 static void get_pipe_extra_pixel(struct ia_css_pipe *pipe,
377 				 unsigned int *extra_row, unsigned int *extra_column);
378 
379 #endif
380 
381 static void
382 sh_css_pipe_free_shading_table(struct ia_css_pipe *pipe)
383 {
384 	if (!pipe) {
385 		IA_CSS_ERROR("NULL input parameter");
386 		return;
387 	}
388 
389 	if (pipe->shading_table)
390 		ia_css_shading_table_free(pipe->shading_table);
391 	pipe->shading_table = NULL;
392 }
393 
394 static enum ia_css_frame_format yuv420_copy_formats[] = {
395 	IA_CSS_FRAME_FORMAT_NV12,
396 	IA_CSS_FRAME_FORMAT_NV21,
397 	IA_CSS_FRAME_FORMAT_YV12,
398 	IA_CSS_FRAME_FORMAT_YUV420,
399 	IA_CSS_FRAME_FORMAT_YUV420_16,
400 	IA_CSS_FRAME_FORMAT_CSI_MIPI_YUV420_8,
401 	IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8
402 };
403 
404 static enum ia_css_frame_format yuv422_copy_formats[] = {
405 	IA_CSS_FRAME_FORMAT_NV12,
406 	IA_CSS_FRAME_FORMAT_NV16,
407 	IA_CSS_FRAME_FORMAT_NV21,
408 	IA_CSS_FRAME_FORMAT_NV61,
409 	IA_CSS_FRAME_FORMAT_YV12,
410 	IA_CSS_FRAME_FORMAT_YV16,
411 	IA_CSS_FRAME_FORMAT_YUV420,
412 	IA_CSS_FRAME_FORMAT_YUV420_16,
413 	IA_CSS_FRAME_FORMAT_YUV422,
414 	IA_CSS_FRAME_FORMAT_YUV422_16,
415 	IA_CSS_FRAME_FORMAT_UYVY,
416 	IA_CSS_FRAME_FORMAT_YUYV
417 };
418 
419 /*
420  * Verify whether the selected output format is can be produced
421  * by the copy binary given the stream format.
422  */
423 static int
424 verify_copy_out_frame_format(struct ia_css_pipe *pipe)
425 {
426 	enum ia_css_frame_format out_fmt = pipe->output_info[0].format;
427 	unsigned int i, found = 0;
428 
429 	assert(pipe);
430 	assert(pipe->stream);
431 
432 	switch (pipe->stream->config.input_config.format) {
433 	case ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY:
434 	case ATOMISP_INPUT_FORMAT_YUV420_8:
435 		for (i = 0; i < ARRAY_SIZE(yuv420_copy_formats) && !found; i++)
436 			found = (out_fmt == yuv420_copy_formats[i]);
437 		break;
438 	case ATOMISP_INPUT_FORMAT_YUV420_10:
439 	case ATOMISP_INPUT_FORMAT_YUV420_16:
440 		found = (out_fmt == IA_CSS_FRAME_FORMAT_YUV420_16);
441 		break;
442 	case ATOMISP_INPUT_FORMAT_YUV422_8:
443 		for (i = 0; i < ARRAY_SIZE(yuv422_copy_formats) && !found; i++)
444 			found = (out_fmt == yuv422_copy_formats[i]);
445 		break;
446 	case ATOMISP_INPUT_FORMAT_YUV422_10:
447 	case ATOMISP_INPUT_FORMAT_YUV422_16:
448 		found = (out_fmt == IA_CSS_FRAME_FORMAT_YUV422_16 ||
449 			 out_fmt == IA_CSS_FRAME_FORMAT_YUV420_16);
450 		break;
451 	case ATOMISP_INPUT_FORMAT_RGB_444:
452 	case ATOMISP_INPUT_FORMAT_RGB_555:
453 	case ATOMISP_INPUT_FORMAT_RGB_565:
454 		found = (out_fmt == IA_CSS_FRAME_FORMAT_RGBA888 ||
455 			 out_fmt == IA_CSS_FRAME_FORMAT_RGB565);
456 		break;
457 	case ATOMISP_INPUT_FORMAT_RGB_666:
458 	case ATOMISP_INPUT_FORMAT_RGB_888:
459 		found = (out_fmt == IA_CSS_FRAME_FORMAT_RGBA888 ||
460 			 out_fmt == IA_CSS_FRAME_FORMAT_YUV420);
461 		break;
462 	case ATOMISP_INPUT_FORMAT_RAW_6:
463 	case ATOMISP_INPUT_FORMAT_RAW_7:
464 	case ATOMISP_INPUT_FORMAT_RAW_8:
465 	case ATOMISP_INPUT_FORMAT_RAW_10:
466 	case ATOMISP_INPUT_FORMAT_RAW_12:
467 	case ATOMISP_INPUT_FORMAT_RAW_14:
468 	case ATOMISP_INPUT_FORMAT_RAW_16:
469 		found = (out_fmt == IA_CSS_FRAME_FORMAT_RAW) ||
470 		(out_fmt == IA_CSS_FRAME_FORMAT_RAW_PACKED);
471 		break;
472 	case ATOMISP_INPUT_FORMAT_BINARY_8:
473 		found = (out_fmt == IA_CSS_FRAME_FORMAT_BINARY_8);
474 		break;
475 	default:
476 		break;
477 	}
478 	if (!found)
479 		return -EINVAL;
480 	return 0;
481 }
482 
483 unsigned int
484 ia_css_stream_input_format_bits_per_pixel(struct ia_css_stream *stream)
485 {
486 	int bpp = 0;
487 
488 	if (stream)
489 		bpp = ia_css_util_input_format_bpp(stream->config.input_config.format,
490 						   stream->config.pixels_per_clock == 2);
491 
492 	return bpp;
493 }
494 
495 /* TODO: move define to proper file in tools */
496 #define GP_ISEL_TPG_MODE 0x90058
497 
498 #if !defined(ISP2401)
499 static int
500 sh_css_config_input_network(struct ia_css_stream *stream)
501 {
502 	unsigned int fmt_type;
503 	struct ia_css_pipe *pipe = stream->last_pipe;
504 	struct ia_css_binary *binary = NULL;
505 	int err = 0;
506 
507 	assert(stream);
508 	assert(pipe);
509 
510 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
511 			    "sh_css_config_input_network() enter:\n");
512 
513 	if (pipe->pipeline.stages)
514 		binary = pipe->pipeline.stages->binary;
515 
516 	err = ia_css_isys_convert_stream_format_to_mipi_format(
517 	    stream->config.input_config.format,
518 	    stream->csi_rx_config.comp,
519 	    &fmt_type);
520 	if (err)
521 		return err;
522 	sh_css_sp_program_input_circuit(fmt_type,
523 					stream->config.channel_id,
524 					stream->config.mode);
525 
526 	if ((binary && (binary->online || stream->config.continuous)) ||
527 	    pipe->config.mode == IA_CSS_PIPE_MODE_COPY) {
528 		err = ia_css_ifmtr_configure(&stream->config,
529 					     binary);
530 		if (err)
531 			return err;
532 	}
533 
534 	if (stream->config.mode == IA_CSS_INPUT_MODE_TPG ||
535 	    stream->config.mode == IA_CSS_INPUT_MODE_PRBS) {
536 		unsigned int hblank_cycles = 100,
537 		vblank_lines = 6,
538 		width,
539 		height,
540 		vblank_cycles;
541 		width  = (stream->config.input_config.input_res.width) / (1 +
542 			(stream->config.pixels_per_clock == 2));
543 		height = stream->config.input_config.input_res.height;
544 		vblank_cycles = vblank_lines * (width + hblank_cycles);
545 		sh_css_sp_configure_sync_gen(width, height, hblank_cycles,
546 					     vblank_cycles);
547 		if (pipe->stream->config.mode == IA_CSS_INPUT_MODE_TPG)
548 			ia_css_device_store_uint32(GP_ISEL_TPG_MODE, 0);
549 	}
550 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
551 			    "sh_css_config_input_network() leave:\n");
552 	return 0;
553 }
554 #elif defined(ISP2401)
555 static unsigned int csi2_protocol_calculate_max_subpixels_per_line(
556     enum atomisp_input_format	format,
557     unsigned int			pixels_per_line)
558 {
559 	unsigned int rval;
560 
561 	switch (format) {
562 	case ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY:
563 		/*
564 		 * The frame format layout is shown below.
565 		 *
566 		 *		Line	0:	UYY0 UYY0 ... UYY0
567 		 *		Line	1:	VYY0 VYY0 ... VYY0
568 		 *		Line	2:	UYY0 UYY0 ... UYY0
569 		 *		Line	3:	VYY0 VYY0 ... VYY0
570 		 *		...
571 		 *		Line (n-2):	UYY0 UYY0 ... UYY0
572 		 *		Line (n-1):	VYY0 VYY0 ... VYY0
573 		 *
574 		 *	In this frame format, the even-line is
575 		 *	as wide as the odd-line.
576 		 *	The 0 is introduced by the input system
577 		 *	(mipi backend).
578 		 */
579 		rval = pixels_per_line * 2;
580 		break;
581 	case ATOMISP_INPUT_FORMAT_YUV420_8:
582 	case ATOMISP_INPUT_FORMAT_YUV420_10:
583 	case ATOMISP_INPUT_FORMAT_YUV420_16:
584 		/*
585 		 * The frame format layout is shown below.
586 		 *
587 		 *		Line	0:	YYYY YYYY ... YYYY
588 		 *		Line	1:	UYVY UYVY ... UYVY UYVY
589 		 *		Line	2:	YYYY YYYY ... YYYY
590 		 *		Line	3:	UYVY UYVY ... UYVY UYVY
591 		 *		...
592 		 *		Line (n-2):	YYYY YYYY ... YYYY
593 		 *		Line (n-1):	UYVY UYVY ... UYVY UYVY
594 		 *
595 		 * In this frame format, the odd-line is twice
596 		 * wider than the even-line.
597 		 */
598 		rval = pixels_per_line * 2;
599 		break;
600 	case ATOMISP_INPUT_FORMAT_YUV422_8:
601 	case ATOMISP_INPUT_FORMAT_YUV422_10:
602 	case ATOMISP_INPUT_FORMAT_YUV422_16:
603 		/*
604 		 * The frame format layout is shown below.
605 		 *
606 		 *		Line	0:	UYVY UYVY ... UYVY
607 		 *		Line	1:	UYVY UYVY ... UYVY
608 		 *		Line	2:	UYVY UYVY ... UYVY
609 		 *		Line	3:	UYVY UYVY ... UYVY
610 		 *		...
611 		 *		Line (n-2):	UYVY UYVY ... UYVY
612 		 *		Line (n-1):	UYVY UYVY ... UYVY
613 		 *
614 		 * In this frame format, the even-line is
615 		 * as wide as the odd-line.
616 		 */
617 		rval = pixels_per_line * 2;
618 		break;
619 	case ATOMISP_INPUT_FORMAT_RGB_444:
620 	case ATOMISP_INPUT_FORMAT_RGB_555:
621 	case ATOMISP_INPUT_FORMAT_RGB_565:
622 	case ATOMISP_INPUT_FORMAT_RGB_666:
623 	case ATOMISP_INPUT_FORMAT_RGB_888:
624 		/*
625 		 * The frame format layout is shown below.
626 		 *
627 		 *		Line	0:	ABGR ABGR ... ABGR
628 		 *		Line	1:	ABGR ABGR ... ABGR
629 		 *		Line	2:	ABGR ABGR ... ABGR
630 		 *		Line	3:	ABGR ABGR ... ABGR
631 		 *		...
632 		 *		Line (n-2):	ABGR ABGR ... ABGR
633 		 *		Line (n-1):	ABGR ABGR ... ABGR
634 		 *
635 		 * In this frame format, the even-line is
636 		 * as wide as the odd-line.
637 		 */
638 		rval = pixels_per_line * 4;
639 		break;
640 	case ATOMISP_INPUT_FORMAT_RAW_6:
641 	case ATOMISP_INPUT_FORMAT_RAW_7:
642 	case ATOMISP_INPUT_FORMAT_RAW_8:
643 	case ATOMISP_INPUT_FORMAT_RAW_10:
644 	case ATOMISP_INPUT_FORMAT_RAW_12:
645 	case ATOMISP_INPUT_FORMAT_RAW_14:
646 	case ATOMISP_INPUT_FORMAT_RAW_16:
647 	case ATOMISP_INPUT_FORMAT_BINARY_8:
648 	case ATOMISP_INPUT_FORMAT_USER_DEF1:
649 	case ATOMISP_INPUT_FORMAT_USER_DEF2:
650 	case ATOMISP_INPUT_FORMAT_USER_DEF3:
651 	case ATOMISP_INPUT_FORMAT_USER_DEF4:
652 	case ATOMISP_INPUT_FORMAT_USER_DEF5:
653 	case ATOMISP_INPUT_FORMAT_USER_DEF6:
654 	case ATOMISP_INPUT_FORMAT_USER_DEF7:
655 	case ATOMISP_INPUT_FORMAT_USER_DEF8:
656 		/*
657 		 * The frame format layout is shown below.
658 		 *
659 		 *		Line	0:	Pixel ... Pixel
660 		 *		Line	1:	Pixel ... Pixel
661 		 *		Line	2:	Pixel ... Pixel
662 		 *		Line	3:	Pixel ... Pixel
663 		 *		...
664 		 *		Line (n-2):	Pixel ... Pixel
665 		 *		Line (n-1):	Pixel ... Pixel
666 		 *
667 		 * In this frame format, the even-line is
668 		 * as wide as the odd-line.
669 		 */
670 		rval = pixels_per_line;
671 		break;
672 	default:
673 		rval = 0;
674 		break;
675 	}
676 
677 	return rval;
678 }
679 
680 static bool sh_css_translate_stream_cfg_to_input_system_input_port_id(
681     struct ia_css_stream_config *stream_cfg,
682     ia_css_isys_descr_t	*isys_stream_descr)
683 {
684 	bool rc;
685 
686 	rc = true;
687 	switch (stream_cfg->mode) {
688 	case IA_CSS_INPUT_MODE_TPG:
689 
690 		if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID0)
691 			isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT0_ID;
692 		else if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID1)
693 			isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT1_ID;
694 		else if (stream_cfg->source.tpg.id == IA_CSS_TPG_ID2)
695 			isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT2_ID;
696 
697 		break;
698 	case IA_CSS_INPUT_MODE_PRBS:
699 
700 		if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID0)
701 			isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT0_ID;
702 		else if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID1)
703 			isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT1_ID;
704 		else if (stream_cfg->source.prbs.id == IA_CSS_PRBS_ID2)
705 			isys_stream_descr->input_port_id = INPUT_SYSTEM_PIXELGEN_PORT2_ID;
706 
707 		break;
708 	case IA_CSS_INPUT_MODE_BUFFERED_SENSOR:
709 
710 		if (stream_cfg->source.port.port == MIPI_PORT0_ID)
711 			isys_stream_descr->input_port_id = INPUT_SYSTEM_CSI_PORT0_ID;
712 		else if (stream_cfg->source.port.port == MIPI_PORT1_ID)
713 			isys_stream_descr->input_port_id = INPUT_SYSTEM_CSI_PORT1_ID;
714 		else if (stream_cfg->source.port.port == MIPI_PORT2_ID)
715 			isys_stream_descr->input_port_id = INPUT_SYSTEM_CSI_PORT2_ID;
716 
717 		break;
718 	default:
719 		rc = false;
720 		break;
721 	}
722 
723 	return rc;
724 }
725 
726 static bool sh_css_translate_stream_cfg_to_input_system_input_port_type(
727     struct ia_css_stream_config *stream_cfg,
728     ia_css_isys_descr_t	*isys_stream_descr)
729 {
730 	bool rc;
731 
732 	rc = true;
733 	switch (stream_cfg->mode) {
734 	case IA_CSS_INPUT_MODE_TPG:
735 
736 		isys_stream_descr->mode = INPUT_SYSTEM_SOURCE_TYPE_TPG;
737 
738 		break;
739 	case IA_CSS_INPUT_MODE_PRBS:
740 
741 		isys_stream_descr->mode = INPUT_SYSTEM_SOURCE_TYPE_PRBS;
742 
743 		break;
744 	case IA_CSS_INPUT_MODE_SENSOR:
745 	case IA_CSS_INPUT_MODE_BUFFERED_SENSOR:
746 
747 		isys_stream_descr->mode = INPUT_SYSTEM_SOURCE_TYPE_SENSOR;
748 		break;
749 
750 	default:
751 		rc = false;
752 		break;
753 	}
754 
755 	return rc;
756 }
757 
758 static bool sh_css_translate_stream_cfg_to_input_system_input_port_attr(
759     struct ia_css_stream_config *stream_cfg,
760     ia_css_isys_descr_t	*isys_stream_descr,
761     int isys_stream_idx)
762 {
763 	bool rc;
764 
765 	rc = true;
766 	switch (stream_cfg->mode) {
767 	case IA_CSS_INPUT_MODE_TPG:
768 		if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_RAMP)
769 			isys_stream_descr->tpg_port_attr.mode = PIXELGEN_TPG_MODE_RAMP;
770 		else if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_CHECKERBOARD)
771 			isys_stream_descr->tpg_port_attr.mode = PIXELGEN_TPG_MODE_CHBO;
772 		else if (stream_cfg->source.tpg.mode == IA_CSS_TPG_MODE_MONO)
773 			isys_stream_descr->tpg_port_attr.mode = PIXELGEN_TPG_MODE_MONO;
774 		else
775 			rc = false;
776 
777 		/*
778 		 * TODO
779 		 * - Make "color_cfg" as part of "ia_css_tpg_config".
780 		 */
781 		isys_stream_descr->tpg_port_attr.color_cfg.R1 = 51;
782 		isys_stream_descr->tpg_port_attr.color_cfg.G1 = 102;
783 		isys_stream_descr->tpg_port_attr.color_cfg.B1 = 255;
784 		isys_stream_descr->tpg_port_attr.color_cfg.R2 = 0;
785 		isys_stream_descr->tpg_port_attr.color_cfg.G2 = 100;
786 		isys_stream_descr->tpg_port_attr.color_cfg.B2 = 160;
787 
788 		isys_stream_descr->tpg_port_attr.mask_cfg.h_mask =
789 		    stream_cfg->source.tpg.x_mask;
790 		isys_stream_descr->tpg_port_attr.mask_cfg.v_mask =
791 		    stream_cfg->source.tpg.y_mask;
792 		isys_stream_descr->tpg_port_attr.mask_cfg.hv_mask =
793 		    stream_cfg->source.tpg.xy_mask;
794 
795 		isys_stream_descr->tpg_port_attr.delta_cfg.h_delta =
796 		    stream_cfg->source.tpg.x_delta;
797 		isys_stream_descr->tpg_port_attr.delta_cfg.v_delta =
798 		    stream_cfg->source.tpg.y_delta;
799 
800 		/*
801 		 * TODO
802 		 * - Make "sync_gen_cfg" as part of "ia_css_tpg_config".
803 		 */
804 		isys_stream_descr->tpg_port_attr.sync_gen_cfg.hblank_cycles = 100;
805 		isys_stream_descr->tpg_port_attr.sync_gen_cfg.vblank_cycles = 100;
806 		isys_stream_descr->tpg_port_attr.sync_gen_cfg.pixels_per_clock =
807 		    stream_cfg->pixels_per_clock;
808 		isys_stream_descr->tpg_port_attr.sync_gen_cfg.nr_of_frames = (uint32_t)~(0x0);
809 		isys_stream_descr->tpg_port_attr.sync_gen_cfg.pixels_per_line =
810 		    stream_cfg->isys_config[IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX].input_res.width;
811 		isys_stream_descr->tpg_port_attr.sync_gen_cfg.lines_per_frame =
812 		    stream_cfg->isys_config[IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX].input_res.height;
813 
814 		break;
815 	case IA_CSS_INPUT_MODE_PRBS:
816 
817 		isys_stream_descr->prbs_port_attr.seed0 = stream_cfg->source.prbs.seed;
818 		isys_stream_descr->prbs_port_attr.seed1 = stream_cfg->source.prbs.seed1;
819 
820 		/*
821 		 * TODO
822 		 * - Make "sync_gen_cfg" as part of "ia_css_prbs_config".
823 		 */
824 		isys_stream_descr->prbs_port_attr.sync_gen_cfg.hblank_cycles = 100;
825 		isys_stream_descr->prbs_port_attr.sync_gen_cfg.vblank_cycles = 100;
826 		isys_stream_descr->prbs_port_attr.sync_gen_cfg.pixels_per_clock =
827 		    stream_cfg->pixels_per_clock;
828 		isys_stream_descr->prbs_port_attr.sync_gen_cfg.nr_of_frames = (uint32_t)~(0x0);
829 		isys_stream_descr->prbs_port_attr.sync_gen_cfg.pixels_per_line =
830 		    stream_cfg->isys_config[IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX].input_res.width;
831 		isys_stream_descr->prbs_port_attr.sync_gen_cfg.lines_per_frame =
832 		    stream_cfg->isys_config[IA_CSS_STREAM_DEFAULT_ISYS_STREAM_IDX].input_res.height;
833 
834 		break;
835 	case IA_CSS_INPUT_MODE_BUFFERED_SENSOR: {
836 		int err;
837 		unsigned int fmt_type;
838 
839 		err = ia_css_isys_convert_stream_format_to_mipi_format(
840 			  stream_cfg->isys_config[isys_stream_idx].format,
841 			  MIPI_PREDICTOR_NONE,
842 			  &fmt_type);
843 		if (err)
844 			rc = false;
845 
846 		isys_stream_descr->csi_port_attr.active_lanes =
847 		    stream_cfg->source.port.num_lanes;
848 		isys_stream_descr->csi_port_attr.fmt_type = fmt_type;
849 		isys_stream_descr->csi_port_attr.ch_id = stream_cfg->channel_id;
850 #ifdef ISP2401
851 		isys_stream_descr->online = stream_cfg->online;
852 #endif
853 		err |= ia_css_isys_convert_compressed_format(
854 			   &stream_cfg->source.port.compression,
855 			   isys_stream_descr);
856 		if (err)
857 			rc = false;
858 
859 		/* metadata */
860 		isys_stream_descr->metadata.enable = false;
861 		if (stream_cfg->metadata_config.resolution.height > 0) {
862 			err = ia_css_isys_convert_stream_format_to_mipi_format(
863 				  stream_cfg->metadata_config.data_type,
864 				  MIPI_PREDICTOR_NONE,
865 				  &fmt_type);
866 			if (err)
867 				rc = false;
868 			isys_stream_descr->metadata.fmt_type = fmt_type;
869 			isys_stream_descr->metadata.bits_per_pixel =
870 			    ia_css_util_input_format_bpp(stream_cfg->metadata_config.data_type, true);
871 			isys_stream_descr->metadata.pixels_per_line =
872 			    stream_cfg->metadata_config.resolution.width;
873 			isys_stream_descr->metadata.lines_per_frame =
874 			    stream_cfg->metadata_config.resolution.height;
875 #ifdef ISP2401
876 			/*
877 			 * For new input system, number of str2mmio requests must be even.
878 			 * So we round up number of metadata lines to be even.
879 			 */
880 			if (isys_stream_descr->metadata.lines_per_frame > 0)
881 				isys_stream_descr->metadata.lines_per_frame +=
882 				    (isys_stream_descr->metadata.lines_per_frame & 1);
883 #endif
884 			isys_stream_descr->metadata.align_req_in_bytes =
885 			    ia_css_csi2_calculate_input_system_alignment(
886 				stream_cfg->metadata_config.data_type);
887 			isys_stream_descr->metadata.enable = true;
888 		}
889 
890 		break;
891 	}
892 	default:
893 		rc = false;
894 		break;
895 	}
896 
897 	return rc;
898 }
899 
900 static bool sh_css_translate_stream_cfg_to_input_system_input_port_resolution(
901     struct ia_css_stream_config *stream_cfg,
902     ia_css_isys_descr_t	*isys_stream_descr,
903     int isys_stream_idx)
904 {
905 	unsigned int bits_per_subpixel;
906 	unsigned int max_subpixels_per_line;
907 	unsigned int lines_per_frame;
908 	unsigned int align_req_in_bytes;
909 	enum atomisp_input_format fmt_type;
910 
911 	fmt_type = stream_cfg->isys_config[isys_stream_idx].format;
912 	if ((stream_cfg->mode == IA_CSS_INPUT_MODE_SENSOR ||
913 	     stream_cfg->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) &&
914 	    stream_cfg->source.port.compression.type != IA_CSS_CSI2_COMPRESSION_TYPE_NONE) {
915 		if (stream_cfg->source.port.compression.uncompressed_bits_per_pixel ==
916 		    UNCOMPRESSED_BITS_PER_PIXEL_10)
917 			fmt_type = ATOMISP_INPUT_FORMAT_RAW_10;
918 		else if (stream_cfg->source.port.compression.uncompressed_bits_per_pixel ==
919 			   UNCOMPRESSED_BITS_PER_PIXEL_12)
920 			fmt_type = ATOMISP_INPUT_FORMAT_RAW_12;
921 		else
922 			return false;
923 	}
924 
925 	bits_per_subpixel =
926 	    sh_css_stream_format_2_bits_per_subpixel(fmt_type);
927 	if (bits_per_subpixel == 0)
928 		return false;
929 
930 	max_subpixels_per_line =
931 	    csi2_protocol_calculate_max_subpixels_per_line(fmt_type,
932 		    stream_cfg->isys_config[isys_stream_idx].input_res.width);
933 	if (max_subpixels_per_line == 0)
934 		return false;
935 
936 	lines_per_frame = stream_cfg->isys_config[isys_stream_idx].input_res.height;
937 	if (lines_per_frame == 0)
938 		return false;
939 
940 	align_req_in_bytes = ia_css_csi2_calculate_input_system_alignment(fmt_type);
941 
942 	/* HW needs subpixel info for their settings */
943 	isys_stream_descr->input_port_resolution.bits_per_pixel = bits_per_subpixel;
944 	isys_stream_descr->input_port_resolution.pixels_per_line =
945 	    max_subpixels_per_line;
946 	isys_stream_descr->input_port_resolution.lines_per_frame = lines_per_frame;
947 	isys_stream_descr->input_port_resolution.align_req_in_bytes =
948 	    align_req_in_bytes;
949 
950 	return true;
951 }
952 
953 static bool sh_css_translate_stream_cfg_to_isys_stream_descr(
954     struct ia_css_stream_config *stream_cfg,
955     bool early_polling,
956     ia_css_isys_descr_t	*isys_stream_descr,
957     int isys_stream_idx)
958 {
959 	bool rc;
960 
961 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
962 			    "sh_css_translate_stream_cfg_to_isys_stream_descr() enter:\n");
963 	rc  = sh_css_translate_stream_cfg_to_input_system_input_port_id(stream_cfg,
964 		isys_stream_descr);
965 	rc &= sh_css_translate_stream_cfg_to_input_system_input_port_type(stream_cfg,
966 		isys_stream_descr);
967 	rc &= sh_css_translate_stream_cfg_to_input_system_input_port_attr(stream_cfg,
968 		isys_stream_descr, isys_stream_idx);
969 	rc &= sh_css_translate_stream_cfg_to_input_system_input_port_resolution(
970 		  stream_cfg, isys_stream_descr, isys_stream_idx);
971 
972 	isys_stream_descr->raw_packed = stream_cfg->pack_raw_pixels;
973 	isys_stream_descr->linked_isys_stream_id = (int8_t)
974 		stream_cfg->isys_config[isys_stream_idx].linked_isys_stream_id;
975 
976 	if (IS_ISP2401)
977 		ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
978 				    "sh_css_translate_stream_cfg_to_isys_stream_descr() leave:\n");
979 
980 	return rc;
981 }
982 
983 static bool sh_css_translate_binary_info_to_input_system_output_port_attr(
984     struct ia_css_binary *binary,
985     ia_css_isys_descr_t     *isys_stream_descr)
986 {
987 	if (!binary)
988 		return false;
989 
990 	isys_stream_descr->output_port_attr.left_padding = binary->left_padding;
991 	isys_stream_descr->output_port_attr.max_isp_input_width =
992 	    binary->info->sp.input.max_width;
993 
994 	return true;
995 }
996 
997 static int
998 sh_css_config_input_network(struct ia_css_stream *stream)
999 {
1000 	bool					rc;
1001 	ia_css_isys_descr_t			isys_stream_descr;
1002 	unsigned int				sp_thread_id;
1003 	struct sh_css_sp_pipeline_terminal	*sp_pipeline_input_terminal;
1004 	struct ia_css_pipe *pipe = NULL;
1005 	struct ia_css_binary *binary = NULL;
1006 	int i;
1007 	u32 isys_stream_id;
1008 	bool early_polling = false;
1009 
1010 	assert(stream);
1011 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
1012 			    "sh_css_config_input_network() enter 0x%p:\n", stream);
1013 
1014 	if (stream->config.continuous) {
1015 		if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_CAPTURE)
1016 			pipe = stream->last_pipe;
1017 		else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_YUVPP)
1018 			pipe = stream->last_pipe;
1019 		else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_PREVIEW)
1020 			pipe = stream->last_pipe->pipe_settings.preview.copy_pipe;
1021 		else if (stream->last_pipe->config.mode == IA_CSS_PIPE_MODE_VIDEO)
1022 			pipe = stream->last_pipe->pipe_settings.video.copy_pipe;
1023 	} else {
1024 		pipe = stream->last_pipe;
1025 	}
1026 
1027 	if (!pipe)
1028 		return -EINVAL;
1029 
1030 	if (pipe->pipeline.stages)
1031 		if (pipe->pipeline.stages->binary)
1032 			binary = pipe->pipeline.stages->binary;
1033 
1034 	if (binary) {
1035 		/*
1036 		 * this was being done in ifmtr in 2400.
1037 		 * online and cont bypass the init_in_frameinfo_memory_defaults
1038 		 * so need to do it here
1039 		 */
1040 		ia_css_get_crop_offsets(pipe, &binary->in_frame_info);
1041 	}
1042 
1043 	/* get the SP thread id */
1044 	rc = ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &sp_thread_id);
1045 	if (!rc)
1046 		return -EINVAL;
1047 	/* get the target input terminal */
1048 	sp_pipeline_input_terminal = &sh_css_sp_group.pipe_io[sp_thread_id].input;
1049 
1050 	for (i = 0; i < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH; i++) {
1051 		/* initialization */
1052 		memset((void *)(&isys_stream_descr), 0, sizeof(ia_css_isys_descr_t));
1053 		sp_pipeline_input_terminal->context.virtual_input_system_stream[i].valid = 0;
1054 		sp_pipeline_input_terminal->ctrl.virtual_input_system_stream_cfg[i].valid = 0;
1055 
1056 		if (!stream->config.isys_config[i].valid)
1057 			continue;
1058 
1059 		/* translate the stream configuration to the Input System (2401) configuration */
1060 		rc = sh_css_translate_stream_cfg_to_isys_stream_descr(
1061 			 &stream->config,
1062 			 early_polling,
1063 			 &(isys_stream_descr), i);
1064 
1065 		if (stream->config.online) {
1066 			rc &= sh_css_translate_binary_info_to_input_system_output_port_attr(
1067 				  binary,
1068 				  &(isys_stream_descr));
1069 		}
1070 
1071 		if (!rc)
1072 			return -EINVAL;
1073 
1074 		isys_stream_id = ia_css_isys_generate_stream_id(sp_thread_id, i);
1075 
1076 		/* create the virtual Input System (2401) */
1077 		rc =  ia_css_isys_stream_create(
1078 			  &(isys_stream_descr),
1079 			  &sp_pipeline_input_terminal->context.virtual_input_system_stream[i],
1080 			  isys_stream_id);
1081 		if (!rc)
1082 			return -EINVAL;
1083 
1084 		/* calculate the configuration of the virtual Input System (2401) */
1085 		rc = ia_css_isys_stream_calculate_cfg(
1086 			 &sp_pipeline_input_terminal->context.virtual_input_system_stream[i],
1087 			 &(isys_stream_descr),
1088 			 &sp_pipeline_input_terminal->ctrl.virtual_input_system_stream_cfg[i]);
1089 		if (!rc) {
1090 			ia_css_isys_stream_destroy(
1091 			    &sp_pipeline_input_terminal->context.virtual_input_system_stream[i]);
1092 			return -EINVAL;
1093 		}
1094 	}
1095 
1096 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
1097 			    "sh_css_config_input_network() leave:\n");
1098 
1099 	return 0;
1100 }
1101 
1102 static inline struct ia_css_pipe *stream_get_last_pipe(
1103     struct ia_css_stream *stream)
1104 {
1105 	struct ia_css_pipe *last_pipe = NULL;
1106 
1107 	if (stream)
1108 		last_pipe = stream->last_pipe;
1109 
1110 	return last_pipe;
1111 }
1112 
1113 static inline struct ia_css_pipe *stream_get_copy_pipe(
1114     struct ia_css_stream *stream)
1115 {
1116 	struct ia_css_pipe *copy_pipe = NULL;
1117 	struct ia_css_pipe *last_pipe = NULL;
1118 	enum ia_css_pipe_id pipe_id;
1119 
1120 	last_pipe = stream_get_last_pipe(stream);
1121 
1122 	if ((stream) &&
1123 	    (last_pipe) &&
1124 	    (stream->config.continuous)) {
1125 		pipe_id = last_pipe->mode;
1126 		switch (pipe_id) {
1127 		case IA_CSS_PIPE_ID_PREVIEW:
1128 			copy_pipe = last_pipe->pipe_settings.preview.copy_pipe;
1129 			break;
1130 		case IA_CSS_PIPE_ID_VIDEO:
1131 			copy_pipe = last_pipe->pipe_settings.video.copy_pipe;
1132 			break;
1133 		default:
1134 			copy_pipe = NULL;
1135 			break;
1136 		}
1137 	}
1138 
1139 	return copy_pipe;
1140 }
1141 
1142 static inline struct ia_css_pipe *stream_get_target_pipe(
1143     struct ia_css_stream *stream)
1144 {
1145 	struct ia_css_pipe *target_pipe;
1146 
1147 	/* get the pipe that consumes the stream */
1148 	if (stream->config.continuous)
1149 		target_pipe = stream_get_copy_pipe(stream);
1150 	else
1151 		target_pipe = stream_get_last_pipe(stream);
1152 
1153 	return target_pipe;
1154 }
1155 
1156 static int stream_csi_rx_helper(
1157     struct ia_css_stream *stream,
1158     int (*func)(enum mipi_port_id, uint32_t))
1159 {
1160 	int retval = -EINVAL;
1161 	u32 sp_thread_id, stream_id;
1162 	bool rc;
1163 	struct ia_css_pipe *target_pipe = NULL;
1164 
1165 	if ((!stream) || (stream->config.mode != IA_CSS_INPUT_MODE_BUFFERED_SENSOR))
1166 		goto exit;
1167 
1168 	target_pipe = stream_get_target_pipe(stream);
1169 
1170 	if (!target_pipe)
1171 		goto exit;
1172 
1173 	rc = ia_css_pipeline_get_sp_thread_id(
1174 		 ia_css_pipe_get_pipe_num(target_pipe),
1175 		 &sp_thread_id);
1176 
1177 	if (!rc)
1178 		goto exit;
1179 
1180 	/* (un)register all valid "virtual isys streams" within the ia_css_stream */
1181 	stream_id = 0;
1182 	do {
1183 		if (stream->config.isys_config[stream_id].valid) {
1184 			u32 isys_stream_id = ia_css_isys_generate_stream_id(sp_thread_id, stream_id);
1185 
1186 			retval = func(stream->config.source.port.port, isys_stream_id);
1187 		}
1188 		stream_id++;
1189 	} while ((retval == 0) &&
1190 		 (stream_id < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH));
1191 
1192 exit:
1193 	return retval;
1194 }
1195 
1196 static inline int stream_register_with_csi_rx(
1197     struct ia_css_stream *stream)
1198 {
1199 	return stream_csi_rx_helper(stream, ia_css_isys_csi_rx_register_stream);
1200 }
1201 
1202 static inline int stream_unregister_with_csi_rx(
1203     struct ia_css_stream *stream)
1204 {
1205 	return stream_csi_rx_helper(stream, ia_css_isys_csi_rx_unregister_stream);
1206 }
1207 #endif
1208 
1209 
1210 static void
1211 start_binary(struct ia_css_pipe *pipe,
1212 	     struct ia_css_binary *binary)
1213 {
1214 	assert(pipe);
1215 	/* Acceleration uses firmware, the binary thus can be NULL */
1216 
1217 	if (binary)
1218 		sh_css_metrics_start_binary(&binary->metrics);
1219 
1220 
1221 #if !defined(ISP2401)
1222 	if (pipe->stream->reconfigure_css_rx) {
1223 		ia_css_isys_rx_configure(&pipe->stream->csi_rx_config,
1224 					 pipe->stream->config.mode);
1225 		pipe->stream->reconfigure_css_rx = false;
1226 	}
1227 #endif
1228 }
1229 
1230 /* start the copy function on the SP */
1231 static int
1232 start_copy_on_sp(struct ia_css_pipe *pipe,
1233 		 struct ia_css_frame *out_frame)
1234 {
1235 	(void)out_frame;
1236 
1237 	if ((!pipe) || (!pipe->stream))
1238 		return -EINVAL;
1239 
1240 #if !defined(ISP2401)
1241 	if (pipe->stream->reconfigure_css_rx)
1242 		ia_css_isys_rx_disable();
1243 #endif
1244 
1245 	if (pipe->stream->config.input_config.format != ATOMISP_INPUT_FORMAT_BINARY_8)
1246 		return -EINVAL;
1247 	sh_css_sp_start_binary_copy(ia_css_pipe_get_pipe_num(pipe), out_frame, pipe->stream->config.pixels_per_clock == 2);
1248 
1249 #if !defined(ISP2401)
1250 	if (pipe->stream->reconfigure_css_rx) {
1251 		ia_css_isys_rx_configure(&pipe->stream->csi_rx_config,
1252 					 pipe->stream->config.mode);
1253 		pipe->stream->reconfigure_css_rx = false;
1254 	}
1255 #endif
1256 
1257 	return 0;
1258 }
1259 
1260 void sh_css_binary_args_reset(struct sh_css_binary_args *args)
1261 {
1262 	unsigned int i;
1263 
1264 	for (i = 0; i < NUM_VIDEO_TNR_FRAMES; i++)
1265 		args->tnr_frames[i] = NULL;
1266 	for (i = 0; i < MAX_NUM_VIDEO_DELAY_FRAMES; i++)
1267 		args->delay_frames[i] = NULL;
1268 	args->in_frame      = NULL;
1269 	for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++)
1270 		args->out_frame[i] = NULL;
1271 	args->out_vf_frame  = NULL;
1272 	args->copy_vf       = false;
1273 	args->copy_output   = true;
1274 	args->vf_downscale_log2 = 0;
1275 }
1276 
1277 static void start_pipe(
1278     struct ia_css_pipe *me,
1279     enum sh_css_pipe_config_override copy_ovrd,
1280     enum ia_css_input_mode input_mode)
1281 {
1282 	IA_CSS_ENTER_PRIVATE("me = %p, copy_ovrd = %d, input_mode = %d",
1283 			     me, copy_ovrd, input_mode);
1284 
1285 	assert(me); /* all callers are in this file and call with non null argument */
1286 
1287 	sh_css_sp_init_pipeline(&me->pipeline,
1288 				me->mode,
1289 				(uint8_t)ia_css_pipe_get_pipe_num(me),
1290 				me->config.default_capture_config.enable_xnr != 0,
1291 				me->stream->config.pixels_per_clock == 2,
1292 				me->stream->config.continuous,
1293 				false,
1294 				me->required_bds_factor,
1295 				copy_ovrd,
1296 				input_mode,
1297 				&me->stream->config.metadata_config,
1298 				&me->stream->info.metadata_info
1299 				, (input_mode == IA_CSS_INPUT_MODE_MEMORY) ?
1300 				(enum mipi_port_id)0 :
1301 				me->stream->config.source.port.port);
1302 
1303 	if (me->config.mode != IA_CSS_PIPE_MODE_COPY) {
1304 		struct ia_css_pipeline_stage *stage;
1305 
1306 		stage = me->pipeline.stages;
1307 		if (stage) {
1308 			me->pipeline.current_stage = stage;
1309 			start_binary(me, stage->binary);
1310 		}
1311 	}
1312 	IA_CSS_LEAVE_PRIVATE("void");
1313 }
1314 
1315 void
1316 sh_css_invalidate_shading_tables(struct ia_css_stream *stream)
1317 {
1318 	int i;
1319 
1320 	assert(stream);
1321 
1322 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1323 			    "sh_css_invalidate_shading_tables() enter:\n");
1324 
1325 	for (i = 0; i < stream->num_pipes; i++) {
1326 		assert(stream->pipes[i]);
1327 		sh_css_pipe_free_shading_table(stream->pipes[i]);
1328 	}
1329 
1330 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
1331 			    "sh_css_invalidate_shading_tables() leave: return_void\n");
1332 }
1333 
1334 static void
1335 enable_interrupts(enum ia_css_irq_type irq_type)
1336 {
1337 #ifndef ISP2401
1338 	enum mipi_port_id port;
1339 #endif
1340 	bool enable_pulse = irq_type != IA_CSS_IRQ_TYPE_EDGE;
1341 
1342 	IA_CSS_ENTER_PRIVATE("");
1343 	/* Enable IRQ on the SP which signals that SP goes to idle
1344 	 * (aka ready state) */
1345 	cnd_sp_irq_enable(SP0_ID, true);
1346 	/* Set the IRQ device 0 to either level or pulse */
1347 	irq_enable_pulse(IRQ0_ID, enable_pulse);
1348 
1349 	cnd_virq_enable_channel(virq_sp, true);
1350 
1351 	/* Enable SW interrupt 0, this is used to signal ISYS events */
1352 	cnd_virq_enable_channel(
1353 	    (enum virq_id)(IRQ_SW_CHANNEL0_ID + IRQ_SW_CHANNEL_OFFSET),
1354 	    true);
1355 	/* Enable SW interrupt 1, this is used to signal PSYS events */
1356 	cnd_virq_enable_channel(
1357 	    (enum virq_id)(IRQ_SW_CHANNEL1_ID + IRQ_SW_CHANNEL_OFFSET),
1358 	    true);
1359 
1360 #ifndef ISP2401
1361 	for (port = 0; port < N_MIPI_PORT_ID; port++)
1362 		ia_css_isys_rx_enable_all_interrupts(port);
1363 #endif
1364 
1365 	IA_CSS_LEAVE_PRIVATE("");
1366 }
1367 
1368 static bool sh_css_setup_spctrl_config(const struct ia_css_fw_info *fw,
1369 				       const char *program,
1370 				       ia_css_spctrl_cfg  *spctrl_cfg)
1371 {
1372 	if ((!fw) || (!spctrl_cfg))
1373 		return false;
1374 	spctrl_cfg->sp_entry = 0;
1375 	spctrl_cfg->program_name = (char *)(program);
1376 
1377 	spctrl_cfg->ddr_data_offset =  fw->blob.data_source;
1378 	spctrl_cfg->dmem_data_addr = fw->blob.data_target;
1379 	spctrl_cfg->dmem_bss_addr = fw->blob.bss_target;
1380 	spctrl_cfg->data_size = fw->blob.data_size;
1381 	spctrl_cfg->bss_size = fw->blob.bss_size;
1382 
1383 	spctrl_cfg->spctrl_config_dmem_addr = fw->info.sp.init_dmem_data;
1384 	spctrl_cfg->spctrl_state_dmem_addr = fw->info.sp.sw_state;
1385 
1386 	spctrl_cfg->code_size = fw->blob.size;
1387 	spctrl_cfg->code      = fw->blob.code;
1388 	spctrl_cfg->sp_entry  = fw->info.sp.sp_entry; /* entry function ptr on SP */
1389 
1390 	return true;
1391 }
1392 
1393 void
1394 ia_css_unload_firmware(void)
1395 {
1396 	if (sh_css_num_binaries) {
1397 		/* we have already loaded before so get rid of the old stuff */
1398 		ia_css_binary_uninit();
1399 		sh_css_unload_firmware();
1400 	}
1401 	fw_explicitly_loaded = false;
1402 }
1403 
1404 static void
1405 ia_css_reset_defaults(struct sh_css *css)
1406 {
1407 	struct sh_css default_css;
1408 
1409 	/* Reset everything to zero */
1410 	memset(&default_css, 0, sizeof(default_css));
1411 
1412 	/* Initialize the non zero values */
1413 	default_css.check_system_idle = true;
1414 	default_css.num_cont_raw_frames = NUM_CONTINUOUS_FRAMES;
1415 
1416 	/*
1417 	 * All should be 0: but memset does it already.
1418 	 * default_css.num_mipi_frames[N_CSI_PORTS] = 0;
1419 	 */
1420 
1421 	default_css.irq_type = IA_CSS_IRQ_TYPE_EDGE;
1422 
1423 	/* Set the defaults to the output */
1424 	*css = default_css;
1425 }
1426 
1427 int
1428 ia_css_load_firmware(struct device *dev, const struct ia_css_env *env,
1429 		     const struct ia_css_fw  *fw)
1430 {
1431 	int err;
1432 
1433 	if (!env)
1434 		return -EINVAL;
1435 	if (!fw)
1436 		return -EINVAL;
1437 
1438 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_load_firmware() enter\n");
1439 
1440 	/* make sure we initialize my_css */
1441 	if (my_css.flush != env->cpu_mem_env.flush) {
1442 		ia_css_reset_defaults(&my_css);
1443 		my_css.flush = env->cpu_mem_env.flush;
1444 	}
1445 
1446 	ia_css_unload_firmware(); /* in case we are called twice */
1447 	err = sh_css_load_firmware(dev, fw->data, fw->bytes);
1448 	if (!err) {
1449 		err = ia_css_binary_init_infos();
1450 		if (!err)
1451 			fw_explicitly_loaded = true;
1452 	}
1453 
1454 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_load_firmware() leave\n");
1455 	return err;
1456 }
1457 
1458 int
1459 ia_css_init(struct device *dev, const struct ia_css_env *env,
1460 	    const struct ia_css_fw  *fw,
1461 	    u32                 mmu_l1_base,
1462 	    enum ia_css_irq_type     irq_type)
1463 {
1464 	int err;
1465 	ia_css_spctrl_cfg spctrl_cfg;
1466 
1467 	void (*flush_func)(struct ia_css_acc_fw *fw);
1468 	hrt_data select, enable;
1469 
1470 	/*
1471 	 * The C99 standard does not specify the exact object representation of structs;
1472 	 * the representation is compiler dependent.
1473 	 *
1474 	 * The structs that are communicated between host and SP/ISP should have the
1475 	 * exact same object representation. The compiler that is used to compile the
1476 	 * firmware is hivecc.
1477 	 *
1478 	 * To check if a different compiler, used to compile a host application, uses
1479 	 * another object representation, macros are defined specifying the size of
1480 	 * the structs as expected by the firmware.
1481 	 *
1482 	 * A host application shall verify that a sizeof( ) of the struct is equal to
1483 	 * the SIZE_OF_XXX macro of the corresponding struct. If they are not
1484 	 * equal, functionality will break.
1485 	 */
1486 
1487 	/* Check struct sh_css_ddr_address_map */
1488 	COMPILATION_ERROR_IF(sizeof(struct sh_css_ddr_address_map)		!= SIZE_OF_SH_CSS_DDR_ADDRESS_MAP_STRUCT);
1489 	/* Check struct host_sp_queues */
1490 	COMPILATION_ERROR_IF(sizeof(struct host_sp_queues)			!= SIZE_OF_HOST_SP_QUEUES_STRUCT);
1491 	COMPILATION_ERROR_IF(sizeof(struct ia_css_circbuf_desc_s)		!= SIZE_OF_IA_CSS_CIRCBUF_DESC_S_STRUCT);
1492 	COMPILATION_ERROR_IF(sizeof(struct ia_css_circbuf_elem_s)		!= SIZE_OF_IA_CSS_CIRCBUF_ELEM_S_STRUCT);
1493 
1494 	/* Check struct host_sp_communication */
1495 	COMPILATION_ERROR_IF(sizeof(struct host_sp_communication)		!= SIZE_OF_HOST_SP_COMMUNICATION_STRUCT);
1496 	COMPILATION_ERROR_IF(sizeof(struct sh_css_event_irq_mask)		!= SIZE_OF_SH_CSS_EVENT_IRQ_MASK_STRUCT);
1497 
1498 	/* Check struct sh_css_hmm_buffer */
1499 	COMPILATION_ERROR_IF(sizeof(struct sh_css_hmm_buffer)			!= SIZE_OF_SH_CSS_HMM_BUFFER_STRUCT);
1500 	COMPILATION_ERROR_IF(sizeof(struct ia_css_isp_3a_statistics)		!= SIZE_OF_IA_CSS_ISP_3A_STATISTICS_STRUCT);
1501 	COMPILATION_ERROR_IF(sizeof(struct ia_css_isp_dvs_statistics)		!= SIZE_OF_IA_CSS_ISP_DVS_STATISTICS_STRUCT);
1502 	COMPILATION_ERROR_IF(sizeof(struct ia_css_metadata)			!= SIZE_OF_IA_CSS_METADATA_STRUCT);
1503 
1504 	/* Check struct ia_css_init_dmem_cfg */
1505 	COMPILATION_ERROR_IF(sizeof(struct ia_css_sp_init_dmem_cfg)		!= SIZE_OF_IA_CSS_SP_INIT_DMEM_CFG_STRUCT);
1506 
1507 	if (!fw && !fw_explicitly_loaded)
1508 		return -EINVAL;
1509 	if (!env)
1510 		return -EINVAL;
1511 
1512 	sh_css_printf = env->print_env.debug_print;
1513 
1514 	IA_CSS_ENTER("void");
1515 
1516 	flush_func     = env->cpu_mem_env.flush;
1517 
1518 	pipe_global_init();
1519 	ia_css_pipeline_init();
1520 	ia_css_queue_map_init();
1521 
1522 	ia_css_device_access_init(&env->hw_access_env);
1523 
1524 	select = gpio_reg_load(GPIO0_ID, _gpio_block_reg_do_select)
1525 	& (~GPIO_FLASH_PIN_MASK);
1526 	enable = gpio_reg_load(GPIO0_ID, _gpio_block_reg_do_e)
1527 	| GPIO_FLASH_PIN_MASK;
1528 	sh_css_mmu_set_page_table_base_index(mmu_l1_base);
1529 
1530 	my_css_save.mmu_base = mmu_l1_base;
1531 
1532 	ia_css_reset_defaults(&my_css);
1533 
1534 	my_css_save.driver_env = *env;
1535 	my_css.flush     = flush_func;
1536 
1537 	err = ia_css_rmgr_init();
1538 	if (err) {
1539 		IA_CSS_LEAVE_ERR(err);
1540 		return err;
1541 	}
1542 
1543 	IA_CSS_LOG("init: %d", my_css_save_initialized);
1544 
1545 	if (!my_css_save_initialized) {
1546 		my_css_save_initialized = true;
1547 		my_css_save.mode = sh_css_mode_working;
1548 		memset(my_css_save.stream_seeds, 0,
1549 		       sizeof(struct sh_css_stream_seed) * MAX_ACTIVE_STREAMS);
1550 		IA_CSS_LOG("init: %d mode=%d", my_css_save_initialized, my_css_save.mode);
1551 	}
1552 
1553 	mipi_init();
1554 
1555 #ifndef ISP2401
1556 	/*
1557 	 * In case this has been programmed already, update internal
1558 	 * data structure ...
1559 	 * DEPRECATED
1560 	 */
1561 	my_css.page_table_base_index = mmu_get_page_table_base_index(MMU0_ID);
1562 
1563 #endif
1564 	my_css.irq_type = irq_type;
1565 
1566 	my_css_save.irq_type = irq_type;
1567 
1568 	enable_interrupts(my_css.irq_type);
1569 
1570 	/* configure GPIO to output mode */
1571 	gpio_reg_store(GPIO0_ID, _gpio_block_reg_do_select, select);
1572 	gpio_reg_store(GPIO0_ID, _gpio_block_reg_do_e, enable);
1573 	gpio_reg_store(GPIO0_ID, _gpio_block_reg_do_0, 0);
1574 
1575 	err = ia_css_refcount_init(REFCOUNT_SIZE);
1576 	if (err) {
1577 		IA_CSS_LEAVE_ERR(err);
1578 		return err;
1579 	}
1580 	err = sh_css_params_init();
1581 	if (err) {
1582 		IA_CSS_LEAVE_ERR(err);
1583 		return err;
1584 	}
1585 	if (fw) {
1586 		ia_css_unload_firmware(); /* in case we already had firmware loaded */
1587 		err = sh_css_load_firmware(dev, fw->data, fw->bytes);
1588 		if (err) {
1589 			IA_CSS_LEAVE_ERR(err);
1590 			return err;
1591 		}
1592 		err = ia_css_binary_init_infos();
1593 		if (err) {
1594 			IA_CSS_LEAVE_ERR(err);
1595 			return err;
1596 		}
1597 		fw_explicitly_loaded = false;
1598 
1599 		my_css_save.loaded_fw = (struct ia_css_fw *)fw;
1600 	}
1601 	if (!sh_css_setup_spctrl_config(&sh_css_sp_fw, SP_PROG_NAME, &spctrl_cfg))
1602 		return -EINVAL;
1603 
1604 	err = ia_css_spctrl_load_fw(SP0_ID, &spctrl_cfg);
1605 	if (err) {
1606 		IA_CSS_LEAVE_ERR(err);
1607 		return err;
1608 	}
1609 
1610 	if (!sh_css_hrt_system_is_idle()) {
1611 		IA_CSS_LEAVE_ERR(-EBUSY);
1612 		return -EBUSY;
1613 	}
1614 	/*
1615 	 * can be called here, queuing works, but:
1616 	 * - when sp is started later, it will wipe queued items
1617 	 * so for now we leave it for later and make sure
1618 	 * updates are not called to frequently.
1619 	 * sh_css_init_buffer_queues();
1620 	 */
1621 
1622 #if defined(ISP2401)
1623 	gp_device_reg_store(GP_DEVICE0_ID, _REG_GP_SWITCH_ISYS2401_ADDR, 1);
1624 #endif
1625 
1626 
1627 	if (!IS_ISP2401)
1628 		dma_set_max_burst_size(DMA0_ID, HIVE_DMA_BUS_DDR_CONN,
1629 				       ISP2400_DMA_MAX_BURST_LENGTH);
1630 	else
1631 		dma_set_max_burst_size(DMA0_ID, HIVE_DMA_BUS_DDR_CONN,
1632 				       ISP2401_DMA_MAX_BURST_LENGTH);
1633 
1634 	if (ia_css_isys_init() != INPUT_SYSTEM_ERR_NO_ERROR)
1635 		err = -EINVAL;
1636 
1637 	sh_css_params_map_and_store_default_gdc_lut();
1638 
1639 	IA_CSS_LEAVE_ERR(err);
1640 	return err;
1641 }
1642 
1643 int
1644 ia_css_enable_isys_event_queue(bool enable)
1645 {
1646 	if (sh_css_sp_is_running())
1647 		return -EBUSY;
1648 	sh_css_sp_enable_isys_event_queue(enable);
1649 	return 0;
1650 }
1651 
1652 /* For Acceleration API: Flush FW (shared buffer pointer) arguments */
1653 void
1654 sh_css_flush(struct ia_css_acc_fw *fw)
1655 {
1656 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "sh_css_flush() enter:\n");
1657 	if ((fw) && (my_css.flush))
1658 		my_css.flush(fw);
1659 }
1660 
1661 /*
1662  * Mapping sp threads. Currently, this is done when a stream is created and
1663  * pipelines are ready to be converted to sp pipelines. Be careful if you are
1664  * doing it from stream_create since we could run out of sp threads due to
1665  * allocation on inactive pipelines.
1666  */
1667 static int
1668 map_sp_threads(struct ia_css_stream *stream, bool map)
1669 {
1670 	struct ia_css_pipe *main_pipe = NULL;
1671 	struct ia_css_pipe *copy_pipe = NULL;
1672 	struct ia_css_pipe *capture_pipe = NULL;
1673 	struct ia_css_pipe *acc_pipe = NULL;
1674 	int err = 0;
1675 	enum ia_css_pipe_id pipe_id;
1676 
1677 	IA_CSS_ENTER_PRIVATE("stream = %p, map = %s",
1678 			     stream, map ? "true" : "false");
1679 
1680 	if (!stream) {
1681 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
1682 		return -EINVAL;
1683 	}
1684 
1685 	main_pipe = stream->last_pipe;
1686 	pipe_id	= main_pipe->mode;
1687 
1688 	ia_css_pipeline_map(main_pipe->pipe_num, map);
1689 
1690 	switch (pipe_id) {
1691 	case IA_CSS_PIPE_ID_PREVIEW:
1692 		copy_pipe    = main_pipe->pipe_settings.preview.copy_pipe;
1693 		capture_pipe = main_pipe->pipe_settings.preview.capture_pipe;
1694 		acc_pipe     = main_pipe->pipe_settings.preview.acc_pipe;
1695 		break;
1696 
1697 	case IA_CSS_PIPE_ID_VIDEO:
1698 		copy_pipe    = main_pipe->pipe_settings.video.copy_pipe;
1699 		capture_pipe = main_pipe->pipe_settings.video.capture_pipe;
1700 		break;
1701 
1702 	case IA_CSS_PIPE_ID_CAPTURE:
1703 	case IA_CSS_PIPE_ID_ACC:
1704 	default:
1705 		break;
1706 	}
1707 
1708 	if (acc_pipe)
1709 		ia_css_pipeline_map(acc_pipe->pipe_num, map);
1710 
1711 	if (capture_pipe)
1712 		ia_css_pipeline_map(capture_pipe->pipe_num, map);
1713 
1714 	/* Firmware expects copy pipe to be the last pipe mapped. (if needed) */
1715 	if (copy_pipe)
1716 		ia_css_pipeline_map(copy_pipe->pipe_num, map);
1717 
1718 	/* DH regular multi pipe - not continuous mode: map the next pipes too */
1719 	if (!stream->config.continuous) {
1720 		int i;
1721 
1722 		for (i = 1; i < stream->num_pipes; i++)
1723 			ia_css_pipeline_map(stream->pipes[i]->pipe_num, map);
1724 	}
1725 
1726 	IA_CSS_LEAVE_ERR_PRIVATE(err);
1727 	return err;
1728 }
1729 
1730 /*
1731  * creates a host pipeline skeleton for all pipes in a stream. Called during
1732  * stream_create.
1733  */
1734 static int
1735 create_host_pipeline_structure(struct ia_css_stream *stream)
1736 {
1737 	struct ia_css_pipe *copy_pipe = NULL, *capture_pipe = NULL;
1738 	struct ia_css_pipe *acc_pipe = NULL;
1739 	enum ia_css_pipe_id pipe_id;
1740 	struct ia_css_pipe *main_pipe = NULL;
1741 	int err = 0;
1742 	unsigned int copy_pipe_delay = 0,
1743 	capture_pipe_delay = 0;
1744 
1745 	IA_CSS_ENTER_PRIVATE("stream = %p", stream);
1746 
1747 	if (!stream) {
1748 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
1749 		return -EINVAL;
1750 	}
1751 
1752 	main_pipe	= stream->last_pipe;
1753 	if (!main_pipe) {
1754 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
1755 		return -EINVAL;
1756 	}
1757 
1758 	pipe_id	= main_pipe->mode;
1759 
1760 	switch (pipe_id) {
1761 	case IA_CSS_PIPE_ID_PREVIEW:
1762 		copy_pipe    = main_pipe->pipe_settings.preview.copy_pipe;
1763 		copy_pipe_delay = main_pipe->dvs_frame_delay;
1764 		capture_pipe = main_pipe->pipe_settings.preview.capture_pipe;
1765 		capture_pipe_delay = IA_CSS_FRAME_DELAY_0;
1766 		acc_pipe     = main_pipe->pipe_settings.preview.acc_pipe;
1767 		err = ia_css_pipeline_create(&main_pipe->pipeline, main_pipe->mode,
1768 					     main_pipe->pipe_num, main_pipe->dvs_frame_delay);
1769 		break;
1770 
1771 	case IA_CSS_PIPE_ID_VIDEO:
1772 		copy_pipe    = main_pipe->pipe_settings.video.copy_pipe;
1773 		copy_pipe_delay = main_pipe->dvs_frame_delay;
1774 		capture_pipe = main_pipe->pipe_settings.video.capture_pipe;
1775 		capture_pipe_delay = IA_CSS_FRAME_DELAY_0;
1776 		err = ia_css_pipeline_create(&main_pipe->pipeline, main_pipe->mode,
1777 					     main_pipe->pipe_num, main_pipe->dvs_frame_delay);
1778 		break;
1779 
1780 	case IA_CSS_PIPE_ID_CAPTURE:
1781 		capture_pipe = main_pipe;
1782 		capture_pipe_delay = main_pipe->dvs_frame_delay;
1783 		break;
1784 
1785 	case IA_CSS_PIPE_ID_YUVPP:
1786 		err = ia_css_pipeline_create(&main_pipe->pipeline, main_pipe->mode,
1787 					     main_pipe->pipe_num, main_pipe->dvs_frame_delay);
1788 		break;
1789 
1790 	case IA_CSS_PIPE_ID_ACC:
1791 		err = ia_css_pipeline_create(&main_pipe->pipeline, main_pipe->mode,
1792 					     main_pipe->pipe_num, main_pipe->dvs_frame_delay);
1793 		break;
1794 
1795 	default:
1796 		err = -EINVAL;
1797 	}
1798 
1799 	if (!(err) && copy_pipe)
1800 		err = ia_css_pipeline_create(&copy_pipe->pipeline,
1801 					     copy_pipe->mode,
1802 					     copy_pipe->pipe_num,
1803 					     copy_pipe_delay);
1804 
1805 	if (!(err) && capture_pipe)
1806 		err = ia_css_pipeline_create(&capture_pipe->pipeline,
1807 					     capture_pipe->mode,
1808 					     capture_pipe->pipe_num,
1809 					     capture_pipe_delay);
1810 
1811 	if (!(err) && acc_pipe)
1812 		err = ia_css_pipeline_create(&acc_pipe->pipeline, acc_pipe->mode,
1813 					     acc_pipe->pipe_num, main_pipe->dvs_frame_delay);
1814 
1815 	/* DH regular multi pipe - not continuous mode: create the next pipelines too */
1816 	if (!stream->config.continuous) {
1817 		int i;
1818 
1819 		for (i = 1; i < stream->num_pipes && 0 == err; i++) {
1820 			main_pipe = stream->pipes[i];
1821 			err = ia_css_pipeline_create(&main_pipe->pipeline,
1822 						     main_pipe->mode,
1823 						     main_pipe->pipe_num,
1824 						     main_pipe->dvs_frame_delay);
1825 		}
1826 	}
1827 
1828 	IA_CSS_LEAVE_ERR_PRIVATE(err);
1829 	return err;
1830 }
1831 
1832 /*
1833  * creates a host pipeline for all pipes in a stream. Called during
1834  * stream_start.
1835  */
1836 static int
1837 create_host_pipeline(struct ia_css_stream *stream)
1838 {
1839 	struct ia_css_pipe *copy_pipe = NULL, *capture_pipe = NULL;
1840 	struct ia_css_pipe *acc_pipe = NULL;
1841 	enum ia_css_pipe_id pipe_id;
1842 	struct ia_css_pipe *main_pipe = NULL;
1843 	int err = 0;
1844 	unsigned int max_input_width = 0;
1845 
1846 	IA_CSS_ENTER_PRIVATE("stream = %p", stream);
1847 	if (!stream) {
1848 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
1849 		return -EINVAL;
1850 	}
1851 
1852 	main_pipe	= stream->last_pipe;
1853 	pipe_id	= main_pipe->mode;
1854 
1855 	/*
1856 	 * No continuous frame allocation for capture pipe. It uses the
1857 	 * "main" pipe's frames.
1858 	 */
1859 	if ((pipe_id == IA_CSS_PIPE_ID_PREVIEW) ||
1860 	    (pipe_id == IA_CSS_PIPE_ID_VIDEO)) {
1861 		/*
1862 		 * About
1863 		 *    pipe_id == IA_CSS_PIPE_ID_PREVIEW &&
1864 		 *    stream->config.mode != IA_CSS_INPUT_MODE_MEMORY:
1865 		 *
1866 		 * The original condition pipe_id == IA_CSS_PIPE_ID_PREVIEW is
1867 		 * too strong. E.g. in SkyCam (with memory based input frames)
1868 		 * there is no continuous mode and thus no need for allocated
1869 		 * continuous frames.
1870 		 * This is not only for SkyCam but for all preview cases that
1871 		 * use DDR based input frames. For this reason the
1872 		 * stream->config.mode != IA_CSS_INPUT_MODE_MEMORY has beed
1873 		 * added.
1874 		 */
1875 		if (stream->config.continuous ||
1876 		    (pipe_id == IA_CSS_PIPE_ID_PREVIEW &&
1877 		     stream->config.mode != IA_CSS_INPUT_MODE_MEMORY)) {
1878 			err = alloc_continuous_frames(main_pipe, true);
1879 			if (err)
1880 				goto ERR;
1881 		}
1882 	}
1883 
1884 #if !defined(ISP2401)
1885 	/* old isys: need to allocate_mipi_frames() even in IA_CSS_PIPE_MODE_COPY */
1886 	if (pipe_id != IA_CSS_PIPE_ID_ACC) {
1887 		err = allocate_mipi_frames(main_pipe, &stream->info);
1888 		if (err)
1889 			goto ERR;
1890 	}
1891 #elif defined(ISP2401)
1892 	if ((pipe_id != IA_CSS_PIPE_ID_ACC) &&
1893 	    (main_pipe->config.mode != IA_CSS_PIPE_MODE_COPY)) {
1894 		err = allocate_mipi_frames(main_pipe, &stream->info);
1895 		if (err)
1896 			goto ERR;
1897 	}
1898 #endif
1899 
1900 	switch (pipe_id) {
1901 	case IA_CSS_PIPE_ID_PREVIEW:
1902 		copy_pipe    = main_pipe->pipe_settings.preview.copy_pipe;
1903 		capture_pipe = main_pipe->pipe_settings.preview.capture_pipe;
1904 		acc_pipe     = main_pipe->pipe_settings.preview.acc_pipe;
1905 		max_input_width =
1906 		    main_pipe->pipe_settings.preview.preview_binary.info->sp.input.max_width;
1907 
1908 		err = create_host_preview_pipeline(main_pipe);
1909 		if (err)
1910 			goto ERR;
1911 
1912 		break;
1913 
1914 	case IA_CSS_PIPE_ID_VIDEO:
1915 		copy_pipe    = main_pipe->pipe_settings.video.copy_pipe;
1916 		capture_pipe = main_pipe->pipe_settings.video.capture_pipe;
1917 		max_input_width =
1918 		    main_pipe->pipe_settings.video.video_binary.info->sp.input.max_width;
1919 
1920 		err = create_host_video_pipeline(main_pipe);
1921 		if (err)
1922 			goto ERR;
1923 
1924 		break;
1925 
1926 	case IA_CSS_PIPE_ID_CAPTURE:
1927 		capture_pipe = main_pipe;
1928 
1929 		break;
1930 
1931 	case IA_CSS_PIPE_ID_YUVPP:
1932 		err = create_host_yuvpp_pipeline(main_pipe);
1933 		if (err)
1934 			goto ERR;
1935 
1936 		break;
1937 
1938 	case IA_CSS_PIPE_ID_ACC:
1939 		err = create_host_acc_pipeline(main_pipe);
1940 		if (err)
1941 			goto ERR;
1942 
1943 		break;
1944 	default:
1945 		err = -EINVAL;
1946 	}
1947 	if (err)
1948 		goto ERR;
1949 
1950 	if (copy_pipe) {
1951 		err = create_host_copy_pipeline(copy_pipe, max_input_width,
1952 						main_pipe->continuous_frames[0]);
1953 		if (err)
1954 			goto ERR;
1955 	}
1956 
1957 	if (capture_pipe) {
1958 		err = create_host_capture_pipeline(capture_pipe);
1959 		if (err)
1960 			goto ERR;
1961 	}
1962 
1963 	if (acc_pipe) {
1964 		err = create_host_acc_pipeline(acc_pipe);
1965 		if (err)
1966 			goto ERR;
1967 	}
1968 
1969 	/* DH regular multi pipe - not continuous mode: create the next pipelines too */
1970 	if (!stream->config.continuous) {
1971 		int i;
1972 
1973 		for (i = 1; i < stream->num_pipes && 0 == err; i++) {
1974 			switch (stream->pipes[i]->mode) {
1975 			case IA_CSS_PIPE_ID_PREVIEW:
1976 				err = create_host_preview_pipeline(stream->pipes[i]);
1977 				break;
1978 			case IA_CSS_PIPE_ID_VIDEO:
1979 				err = create_host_video_pipeline(stream->pipes[i]);
1980 				break;
1981 			case IA_CSS_PIPE_ID_CAPTURE:
1982 				err = create_host_capture_pipeline(stream->pipes[i]);
1983 				break;
1984 			case IA_CSS_PIPE_ID_YUVPP:
1985 				err = create_host_yuvpp_pipeline(stream->pipes[i]);
1986 				break;
1987 			case IA_CSS_PIPE_ID_ACC:
1988 				err = create_host_acc_pipeline(stream->pipes[i]);
1989 				break;
1990 			default:
1991 				err = -EINVAL;
1992 			}
1993 			if (err)
1994 				goto ERR;
1995 		}
1996 	}
1997 
1998 ERR:
1999 	IA_CSS_LEAVE_ERR_PRIVATE(err);
2000 	return err;
2001 }
2002 
2003 static const struct ia_css_pipe default_pipe = IA_CSS_DEFAULT_PIPE;
2004 static const struct ia_css_preview_settings preview = IA_CSS_DEFAULT_PREVIEW_SETTINGS;
2005 static const struct ia_css_capture_settings capture = IA_CSS_DEFAULT_CAPTURE_SETTINGS;
2006 static const struct ia_css_video_settings video = IA_CSS_DEFAULT_VIDEO_SETTINGS;
2007 static const struct ia_css_yuvpp_settings yuvpp = IA_CSS_DEFAULT_YUVPP_SETTINGS;
2008 
2009 static int
2010 init_pipe_defaults(enum ia_css_pipe_mode mode,
2011 		   struct ia_css_pipe *pipe,
2012 		   bool copy_pipe)
2013 {
2014 	if (!pipe) {
2015 		IA_CSS_ERROR("NULL pipe parameter");
2016 		return -EINVAL;
2017 	}
2018 
2019 	/* Initialize pipe to pre-defined defaults */
2020 	memcpy(pipe, &default_pipe, sizeof(default_pipe));
2021 
2022 	/* TODO: JB should not be needed, but temporary backward reference */
2023 	switch (mode) {
2024 	case IA_CSS_PIPE_MODE_PREVIEW:
2025 		pipe->mode = IA_CSS_PIPE_ID_PREVIEW;
2026 		memcpy(&pipe->pipe_settings.preview, &preview, sizeof(preview));
2027 		break;
2028 	case IA_CSS_PIPE_MODE_CAPTURE:
2029 		if (copy_pipe)
2030 			pipe->mode = IA_CSS_PIPE_ID_COPY;
2031 		else
2032 			pipe->mode = IA_CSS_PIPE_ID_CAPTURE;
2033 
2034 		memcpy(&pipe->pipe_settings.capture, &capture, sizeof(capture));
2035 		break;
2036 	case IA_CSS_PIPE_MODE_VIDEO:
2037 		pipe->mode = IA_CSS_PIPE_ID_VIDEO;
2038 		memcpy(&pipe->pipe_settings.video, &video, sizeof(video));
2039 		break;
2040 	case IA_CSS_PIPE_MODE_ACC:
2041 		pipe->mode = IA_CSS_PIPE_ID_ACC;
2042 		break;
2043 	case IA_CSS_PIPE_MODE_COPY:
2044 		pipe->mode = IA_CSS_PIPE_ID_CAPTURE;
2045 		break;
2046 	case IA_CSS_PIPE_MODE_YUVPP:
2047 		pipe->mode = IA_CSS_PIPE_ID_YUVPP;
2048 		memcpy(&pipe->pipe_settings.yuvpp, &yuvpp, sizeof(yuvpp));
2049 		break;
2050 	default:
2051 		return -EINVAL;
2052 	}
2053 
2054 	return 0;
2055 }
2056 
2057 static void
2058 pipe_global_init(void)
2059 {
2060 	u8 i;
2061 
2062 	my_css.pipe_counter = 0;
2063 	for (i = 0; i < IA_CSS_PIPELINE_NUM_MAX; i++)
2064 		my_css.all_pipes[i] = NULL;
2065 }
2066 
2067 static int
2068 pipe_generate_pipe_num(const struct ia_css_pipe *pipe,
2069 		       unsigned int *pipe_number)
2070 {
2071 	const u8 INVALID_PIPE_NUM = (uint8_t)~(0);
2072 	u8 pipe_num = INVALID_PIPE_NUM;
2073 	u8 i;
2074 
2075 	if (!pipe) {
2076 		IA_CSS_ERROR("NULL pipe parameter");
2077 		return -EINVAL;
2078 	}
2079 
2080 	/* Assign a new pipe_num .... search for empty place */
2081 	for (i = 0; i < IA_CSS_PIPELINE_NUM_MAX; i++) {
2082 		if (!my_css.all_pipes[i]) {
2083 			/* position is reserved */
2084 			my_css.all_pipes[i] = (struct ia_css_pipe *)pipe;
2085 			pipe_num = i;
2086 			break;
2087 		}
2088 	}
2089 	if (pipe_num == INVALID_PIPE_NUM) {
2090 		/* Max number of pipes already allocated */
2091 		IA_CSS_ERROR("Max number of pipes already created");
2092 		return -ENOSPC;
2093 	}
2094 
2095 	my_css.pipe_counter++;
2096 
2097 	IA_CSS_LOG("pipe_num (%d)", pipe_num);
2098 
2099 	*pipe_number = pipe_num;
2100 	return 0;
2101 }
2102 
2103 static void
2104 pipe_release_pipe_num(unsigned int pipe_num)
2105 {
2106 	my_css.all_pipes[pipe_num] = NULL;
2107 	my_css.pipe_counter--;
2108 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
2109 			    "pipe_release_pipe_num (%d)\n", pipe_num);
2110 }
2111 
2112 static int
2113 create_pipe(enum ia_css_pipe_mode mode,
2114 	    struct ia_css_pipe **pipe,
2115 	    bool copy_pipe)
2116 {
2117 	int err = 0;
2118 	struct ia_css_pipe *me;
2119 
2120 	if (!pipe) {
2121 		IA_CSS_ERROR("NULL pipe parameter");
2122 		return -EINVAL;
2123 	}
2124 
2125 	me = kmalloc(sizeof(*me), GFP_KERNEL);
2126 	if (!me)
2127 		return -ENOMEM;
2128 
2129 	err = init_pipe_defaults(mode, me, copy_pipe);
2130 	if (err) {
2131 		kfree(me);
2132 		return err;
2133 	}
2134 
2135 	err = pipe_generate_pipe_num(me, &me->pipe_num);
2136 	if (err) {
2137 		kfree(me);
2138 		return err;
2139 	}
2140 
2141 	*pipe = me;
2142 	return 0;
2143 }
2144 
2145 struct ia_css_pipe *
2146 find_pipe_by_num(uint32_t pipe_num)
2147 {
2148 	unsigned int i;
2149 
2150 	for (i = 0; i < IA_CSS_PIPELINE_NUM_MAX; i++) {
2151 		if (my_css.all_pipes[i] &&
2152 		    ia_css_pipe_get_pipe_num(my_css.all_pipes[i]) == pipe_num) {
2153 			return my_css.all_pipes[i];
2154 		}
2155 	}
2156 	return NULL;
2157 }
2158 
2159 static void sh_css_pipe_free_acc_binaries(
2160     struct ia_css_pipe *pipe)
2161 {
2162 	struct ia_css_pipeline *pipeline;
2163 	struct ia_css_pipeline_stage *stage;
2164 
2165 	if (!pipe) {
2166 		IA_CSS_ERROR("NULL input pointer");
2167 		return;
2168 	}
2169 	pipeline = &pipe->pipeline;
2170 
2171 	/* loop through the stages and unload them */
2172 	for (stage = pipeline->stages; stage; stage = stage->next) {
2173 		struct ia_css_fw_info *firmware = (struct ia_css_fw_info *)
2174 						  stage->firmware;
2175 		if (firmware)
2176 			ia_css_pipe_unload_extension(pipe, firmware);
2177 	}
2178 }
2179 
2180 int
2181 ia_css_pipe_destroy(struct ia_css_pipe *pipe)
2182 {
2183 	int err = 0;
2184 
2185 	IA_CSS_ENTER("pipe = %p", pipe);
2186 
2187 	if (!pipe) {
2188 		IA_CSS_LEAVE_ERR(-EINVAL);
2189 		return -EINVAL;
2190 	}
2191 
2192 	if (pipe->stream) {
2193 		IA_CSS_LOG("ia_css_stream_destroy not called!");
2194 		IA_CSS_LEAVE_ERR(-EINVAL);
2195 		return -EINVAL;
2196 	}
2197 
2198 	switch (pipe->config.mode) {
2199 	case IA_CSS_PIPE_MODE_PREVIEW:
2200 		/*
2201 		 * need to take into account that this function is also called
2202 		 * on the internal copy pipe
2203 		 */
2204 		if (pipe->mode == IA_CSS_PIPE_ID_PREVIEW) {
2205 			ia_css_frame_free_multiple(NUM_CONTINUOUS_FRAMES,
2206 						   pipe->continuous_frames);
2207 			ia_css_metadata_free_multiple(NUM_CONTINUOUS_FRAMES,
2208 						      pipe->cont_md_buffers);
2209 			if (pipe->pipe_settings.preview.copy_pipe) {
2210 				err = ia_css_pipe_destroy(pipe->pipe_settings.preview.copy_pipe);
2211 				ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
2212 						    "ia_css_pipe_destroy(): destroyed internal copy pipe err=%d\n",
2213 						    err);
2214 			}
2215 		}
2216 		break;
2217 	case IA_CSS_PIPE_MODE_VIDEO:
2218 		if (pipe->mode == IA_CSS_PIPE_ID_VIDEO) {
2219 			ia_css_frame_free_multiple(NUM_CONTINUOUS_FRAMES,
2220 						   pipe->continuous_frames);
2221 			ia_css_metadata_free_multiple(NUM_CONTINUOUS_FRAMES,
2222 						      pipe->cont_md_buffers);
2223 			if (pipe->pipe_settings.video.copy_pipe) {
2224 				err = ia_css_pipe_destroy(pipe->pipe_settings.video.copy_pipe);
2225 				ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
2226 						    "ia_css_pipe_destroy(): destroyed internal copy pipe err=%d\n",
2227 						    err);
2228 			}
2229 		}
2230 #ifndef ISP2401
2231 		ia_css_frame_free_multiple(NUM_VIDEO_TNR_FRAMES,
2232 					   pipe->pipe_settings.video.tnr_frames);
2233 #else
2234 		ia_css_frame_free_multiple(NUM_VIDEO_TNR_FRAMES,
2235 					   pipe->pipe_settings.video.tnr_frames);
2236 #endif
2237 		ia_css_frame_free_multiple(MAX_NUM_VIDEO_DELAY_FRAMES,
2238 					   pipe->pipe_settings.video.delay_frames);
2239 		break;
2240 	case IA_CSS_PIPE_MODE_CAPTURE:
2241 		ia_css_frame_free_multiple(MAX_NUM_VIDEO_DELAY_FRAMES,
2242 					   pipe->pipe_settings.capture.delay_frames);
2243 		break;
2244 	case IA_CSS_PIPE_MODE_ACC:
2245 		sh_css_pipe_free_acc_binaries(pipe);
2246 		break;
2247 	case IA_CSS_PIPE_MODE_COPY:
2248 		break;
2249 	case IA_CSS_PIPE_MODE_YUVPP:
2250 		break;
2251 	}
2252 
2253 	if (pipe->scaler_pp_lut != mmgr_NULL) {
2254 		hmm_free(pipe->scaler_pp_lut);
2255 		pipe->scaler_pp_lut = mmgr_NULL;
2256 	}
2257 
2258 	my_css.active_pipes[ia_css_pipe_get_pipe_num(pipe)] = NULL;
2259 	sh_css_pipe_free_shading_table(pipe);
2260 
2261 	ia_css_pipeline_destroy(&pipe->pipeline);
2262 	pipe_release_pipe_num(ia_css_pipe_get_pipe_num(pipe));
2263 
2264 	/* Temporarily, not every sh_css_pipe has an acc_extension. */
2265 	if (pipe->config.acc_extension)
2266 		ia_css_pipe_unload_extension(pipe, pipe->config.acc_extension);
2267 
2268 	kfree(pipe);
2269 	IA_CSS_LEAVE("err = %d", err);
2270 	return err;
2271 }
2272 
2273 void
2274 ia_css_uninit(void)
2275 {
2276 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_uninit() enter: void\n");
2277 
2278 	sh_css_params_free_default_gdc_lut();
2279 
2280 	/* TODO: JB: implement decent check and handling of freeing mipi frames */
2281 	if (!mipi_is_free())
2282 		dev_warn(atomisp_dev, "mipi frames are not freed.\n");
2283 
2284 	/* cleanup generic data */
2285 	sh_css_params_uninit();
2286 	ia_css_refcount_uninit();
2287 
2288 	ia_css_rmgr_uninit();
2289 
2290 #if !defined(ISP2401)
2291 	/* needed for reprogramming the inputformatter after power cycle of css */
2292 	ifmtr_set_if_blocking_mode_reset = true;
2293 #endif
2294 
2295 	if (!fw_explicitly_loaded)
2296 		ia_css_unload_firmware();
2297 
2298 	ia_css_spctrl_unload_fw(SP0_ID);
2299 	sh_css_sp_set_sp_running(false);
2300 	/* check and free any remaining mipi frames */
2301 	free_mipi_frames(NULL);
2302 
2303 	sh_css_sp_reset_global_vars();
2304 
2305 	ia_css_isys_uninit();
2306 
2307 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_uninit() leave: return_void\n");
2308 }
2309 
2310 int ia_css_irq_translate(
2311     unsigned int *irq_infos)
2312 {
2313 	enum virq_id	irq;
2314 	enum hrt_isp_css_irq_status status = hrt_isp_css_irq_status_more_irqs;
2315 	unsigned int infos = 0;
2316 
2317 	/* irq_infos can be NULL, but that would make the function useless */
2318 	/* assert(irq_infos != NULL); */
2319 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
2320 			    "ia_css_irq_translate() enter: irq_infos=%p\n", irq_infos);
2321 
2322 	while (status == hrt_isp_css_irq_status_more_irqs) {
2323 		status = virq_get_channel_id(&irq);
2324 		if (status == hrt_isp_css_irq_status_error)
2325 			return -EINVAL;
2326 
2327 
2328 		switch (irq) {
2329 		case virq_sp:
2330 			/*
2331 			 * When SP goes to idle, info is available in the
2332 			 * event queue.
2333 			 */
2334 			infos |= IA_CSS_IRQ_INFO_EVENTS_READY;
2335 			break;
2336 		case virq_isp:
2337 			break;
2338 		case virq_isys_sof:
2339 			infos |= IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF;
2340 			break;
2341 		case virq_isys_eof:
2342 			infos |= IA_CSS_IRQ_INFO_CSS_RECEIVER_EOF;
2343 			break;
2344 		case virq_isys_csi:
2345 			infos |= IA_CSS_IRQ_INFO_INPUT_SYSTEM_ERROR;
2346 			break;
2347 #if !defined(ISP2401)
2348 		case virq_ifmt0_id:
2349 			infos |= IA_CSS_IRQ_INFO_IF_ERROR;
2350 			break;
2351 #endif
2352 		case virq_dma:
2353 			infos |= IA_CSS_IRQ_INFO_DMA_ERROR;
2354 			break;
2355 		case virq_sw_pin_0:
2356 			infos |= sh_css_get_sw_interrupt_value(0);
2357 			break;
2358 		case virq_sw_pin_1:
2359 			infos |= sh_css_get_sw_interrupt_value(1);
2360 			/* pqiao TODO: also assumption here */
2361 			break;
2362 		default:
2363 			break;
2364 		}
2365 	}
2366 
2367 	if (irq_infos)
2368 		*irq_infos = infos;
2369 
2370 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
2371 			    "ia_css_irq_translate() leave: irq_infos=%u\n",
2372 			    infos);
2373 
2374 	return 0;
2375 }
2376 
2377 int ia_css_irq_enable(
2378     enum ia_css_irq_info info,
2379     bool enable)
2380 {
2381 	enum virq_id	irq = N_virq_id;
2382 
2383 	IA_CSS_ENTER("info=%d, enable=%d", info, enable);
2384 
2385 	switch (info) {
2386 #if !defined(ISP2401)
2387 	case IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF:
2388 		irq = virq_isys_sof;
2389 		break;
2390 	case IA_CSS_IRQ_INFO_CSS_RECEIVER_EOF:
2391 		irq = virq_isys_eof;
2392 		break;
2393 	case IA_CSS_IRQ_INFO_INPUT_SYSTEM_ERROR:
2394 		irq = virq_isys_csi;
2395 		break;
2396 	case IA_CSS_IRQ_INFO_IF_ERROR:
2397 		irq = virq_ifmt0_id;
2398 		break;
2399 #else
2400 	case IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF:
2401 	case IA_CSS_IRQ_INFO_CSS_RECEIVER_EOF:
2402 	case IA_CSS_IRQ_INFO_INPUT_SYSTEM_ERROR:
2403 	case IA_CSS_IRQ_INFO_IF_ERROR:
2404 		/* Just ignore those unused IRQs without printing errors */
2405 		return 0;
2406 #endif
2407 	case IA_CSS_IRQ_INFO_DMA_ERROR:
2408 		irq = virq_dma;
2409 		break;
2410 	case IA_CSS_IRQ_INFO_SW_0:
2411 		irq = virq_sw_pin_0;
2412 		break;
2413 	case IA_CSS_IRQ_INFO_SW_1:
2414 		irq = virq_sw_pin_1;
2415 		break;
2416 	default:
2417 		IA_CSS_LEAVE_ERR(-EINVAL);
2418 		return -EINVAL;
2419 	}
2420 
2421 	cnd_virq_enable_channel(irq, enable);
2422 
2423 	IA_CSS_LEAVE_ERR(0);
2424 	return 0;
2425 }
2426 
2427 
2428 static unsigned int
2429 sh_css_get_sw_interrupt_value(unsigned int irq)
2430 {
2431 	unsigned int irq_value;
2432 
2433 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
2434 			    "sh_css_get_sw_interrupt_value() enter: irq=%d\n", irq);
2435 	irq_value = sh_css_sp_get_sw_interrupt_value(irq);
2436 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
2437 			    "sh_css_get_sw_interrupt_value() leave: irq_value=%d\n", irq_value);
2438 	return irq_value;
2439 }
2440 
2441 /*
2442  * configure and load the copy binary, the next binary is used to
2443  * determine whether the copy binary needs to do left padding.
2444  */
2445 static int load_copy_binary(
2446     struct ia_css_pipe *pipe,
2447     struct ia_css_binary *copy_binary,
2448     struct ia_css_binary *next_binary)
2449 {
2450 	struct ia_css_frame_info copy_out_info, copy_in_info, copy_vf_info;
2451 	unsigned int left_padding;
2452 	int err;
2453 	struct ia_css_binary_descr copy_descr;
2454 
2455 	/* next_binary can be NULL */
2456 	assert(pipe);
2457 	assert(copy_binary);
2458 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
2459 			    "load_copy_binary() enter:\n");
2460 
2461 	if (next_binary) {
2462 		copy_out_info = next_binary->in_frame_info;
2463 		left_padding = next_binary->left_padding;
2464 	} else {
2465 		copy_out_info = pipe->output_info[0];
2466 		copy_vf_info = pipe->vf_output_info[0];
2467 		ia_css_frame_info_set_format(&copy_vf_info, IA_CSS_FRAME_FORMAT_YUV_LINE);
2468 		left_padding = 0;
2469 	}
2470 
2471 	ia_css_pipe_get_copy_binarydesc(pipe, &copy_descr,
2472 					&copy_in_info, &copy_out_info,
2473 					(next_binary) ? NULL : NULL/*TODO: &copy_vf_info*/);
2474 	err = ia_css_binary_find(&copy_descr, copy_binary);
2475 	if (err)
2476 		return err;
2477 	copy_binary->left_padding = left_padding;
2478 	return 0;
2479 }
2480 
2481 static int
2482 alloc_continuous_frames(struct ia_css_pipe *pipe, bool init_time)
2483 {
2484 	int err = 0;
2485 	struct ia_css_frame_info ref_info;
2486 	enum ia_css_pipe_id pipe_id;
2487 	bool continuous;
2488 	unsigned int i, idx;
2489 	unsigned int num_frames;
2490 
2491 	IA_CSS_ENTER_PRIVATE("pipe = %p, init_time = %d", pipe, init_time);
2492 
2493 	if ((!pipe) || (!pipe->stream)) {
2494 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
2495 		return -EINVAL;
2496 	}
2497 
2498 	pipe_id = pipe->mode;
2499 	continuous = pipe->stream->config.continuous;
2500 
2501 	if (continuous) {
2502 		if (init_time) {
2503 			num_frames = pipe->stream->config.init_num_cont_raw_buf;
2504 			pipe->stream->continuous_pipe = pipe;
2505 		} else {
2506 			num_frames = pipe->stream->config.target_num_cont_raw_buf;
2507 		}
2508 	} else {
2509 		num_frames = NUM_ONLINE_INIT_CONTINUOUS_FRAMES;
2510 	}
2511 
2512 	if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) {
2513 		ref_info = pipe->pipe_settings.preview.preview_binary.in_frame_info;
2514 	} else if (pipe_id == IA_CSS_PIPE_ID_VIDEO) {
2515 		ref_info = pipe->pipe_settings.video.video_binary.in_frame_info;
2516 	} else {
2517 		/* should not happen */
2518 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
2519 		return -EINVAL;
2520 	}
2521 
2522 #if defined(ISP2401)
2523 	/* For CSI2+, the continuous frame will hold the full input frame */
2524 	ref_info.res.width = pipe->stream->config.input_config.input_res.width;
2525 	ref_info.res.height = pipe->stream->config.input_config.input_res.height;
2526 
2527 	/* Ensure padded width is aligned for 2401 */
2528 	ref_info.padded_width = CEIL_MUL(ref_info.res.width, 2 * ISP_VEC_NELEMS);
2529 #endif
2530 
2531 	if (pipe->stream->config.pack_raw_pixels) {
2532 		ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
2533 				    "alloc_continuous_frames() IA_CSS_FRAME_FORMAT_RAW_PACKED\n");
2534 		ref_info.format = IA_CSS_FRAME_FORMAT_RAW_PACKED;
2535 	} else
2536 	{
2537 		ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
2538 				    "alloc_continuous_frames() IA_CSS_FRAME_FORMAT_RAW\n");
2539 		ref_info.format = IA_CSS_FRAME_FORMAT_RAW;
2540 	}
2541 
2542 	/* Write format back to binary */
2543 	if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) {
2544 		pipe->pipe_settings.preview.preview_binary.in_frame_info.format =
2545 		    ref_info.format;
2546 	} else if (pipe_id == IA_CSS_PIPE_ID_VIDEO) {
2547 		pipe->pipe_settings.video.video_binary.in_frame_info.format = ref_info.format;
2548 	} else {
2549 		/* should not happen */
2550 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
2551 		return -EINVAL;
2552 	}
2553 
2554 	if (init_time)
2555 		idx = 0;
2556 	else
2557 		idx = pipe->stream->config.init_num_cont_raw_buf;
2558 
2559 	for (i = idx; i < NUM_CONTINUOUS_FRAMES; i++) {
2560 		/* free previous frame */
2561 		if (pipe->continuous_frames[i]) {
2562 			ia_css_frame_free(pipe->continuous_frames[i]);
2563 			pipe->continuous_frames[i] = NULL;
2564 		}
2565 		/* free previous metadata buffer */
2566 		ia_css_metadata_free(pipe->cont_md_buffers[i]);
2567 		pipe->cont_md_buffers[i] = NULL;
2568 
2569 		/* check if new frame needed */
2570 		if (i < num_frames) {
2571 			/* allocate new frame */
2572 			err = ia_css_frame_allocate_from_info(
2573 				  &pipe->continuous_frames[i],
2574 				  &ref_info);
2575 			if (err) {
2576 				IA_CSS_LEAVE_ERR_PRIVATE(err);
2577 				return err;
2578 			}
2579 			/* allocate metadata buffer */
2580 			pipe->cont_md_buffers[i] = ia_css_metadata_allocate(
2581 						       &pipe->stream->info.metadata_info);
2582 		}
2583 	}
2584 	IA_CSS_LEAVE_ERR_PRIVATE(0);
2585 	return 0;
2586 }
2587 
2588 int
2589 ia_css_alloc_continuous_frame_remain(struct ia_css_stream *stream)
2590 {
2591 	if (!stream)
2592 		return -EINVAL;
2593 	return alloc_continuous_frames(stream->continuous_pipe, false);
2594 }
2595 
2596 static int
2597 load_preview_binaries(struct ia_css_pipe *pipe)
2598 {
2599 	struct ia_css_frame_info prev_in_info,
2600 		prev_bds_out_info,
2601 		prev_out_info,
2602 		prev_vf_info;
2603 	struct ia_css_binary_descr preview_descr;
2604 	bool online;
2605 	int err = 0;
2606 	bool need_vf_pp = false;
2607 	bool need_isp_copy_binary = false;
2608 #ifdef ISP2401
2609 	bool sensor = false;
2610 #else
2611 	bool continuous;
2612 #endif
2613 	/* preview only have 1 output pin now */
2614 	struct ia_css_frame_info *pipe_out_info = &pipe->output_info[0];
2615 	struct ia_css_preview_settings *mycs  = &pipe->pipe_settings.preview;
2616 
2617 	IA_CSS_ENTER_PRIVATE("");
2618 	assert(pipe);
2619 	assert(pipe->stream);
2620 	assert(pipe->mode == IA_CSS_PIPE_ID_PREVIEW);
2621 
2622 	online = pipe->stream->config.online;
2623 #ifdef ISP2401
2624 	sensor = pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR;
2625 #else
2626 	continuous = pipe->stream->config.continuous;
2627 #endif
2628 
2629 	if (mycs->preview_binary.info)
2630 		return 0;
2631 
2632 	err = ia_css_util_check_input(&pipe->stream->config, false, false);
2633 	if (err)
2634 		return err;
2635 	err = ia_css_frame_check_info(pipe_out_info);
2636 	if (err)
2637 		return err;
2638 
2639 	/*
2640 	 * Note: the current selection of vf_pp binary and
2641 	 * parameterization of the preview binary contains a few pieces
2642 	 * of hardcoded knowledge. This needs to be cleaned up such that
2643 	 * the binary selection becomes more generic.
2644 	 * The vf_pp binary is needed if one or more of the following features
2645 	 * are required:
2646 	 * 1. YUV downscaling.
2647 	 * 2. Digital zoom.
2648 	 * 3. An output format that is not supported by the preview binary.
2649 	 *    In practice this means something other than yuv_line or nv12.
2650 	 * The decision if the vf_pp binary is needed for YUV downscaling is
2651 	 * made after the preview binary selection, since some preview binaries
2652 	 * can perform the requested YUV downscaling.
2653 	 */
2654 	need_vf_pp = pipe->config.enable_dz;
2655 	need_vf_pp |= pipe_out_info->format != IA_CSS_FRAME_FORMAT_YUV_LINE &&
2656 	!(pipe_out_info->format == IA_CSS_FRAME_FORMAT_NV12 ||
2657 	  pipe_out_info->format == IA_CSS_FRAME_FORMAT_NV12_16 ||
2658 	  pipe_out_info->format == IA_CSS_FRAME_FORMAT_NV12_TILEY);
2659 
2660 	/* Preview step 1 */
2661 	if (pipe->vf_yuv_ds_input_info.res.width)
2662 		prev_vf_info = pipe->vf_yuv_ds_input_info;
2663 	else
2664 		prev_vf_info = *pipe_out_info;
2665 	/*
2666 	 * If vf_pp is needed, then preview must output yuv_line.
2667 	 * The exception is when vf_pp is manually disabled, that is only
2668 	 * used in combination with a pipeline extension that requires
2669 	 * yuv_line as input.
2670 	 */
2671 	if (need_vf_pp)
2672 		ia_css_frame_info_set_format(&prev_vf_info,
2673 					     IA_CSS_FRAME_FORMAT_YUV_LINE);
2674 
2675 	err = ia_css_pipe_get_preview_binarydesc(
2676 	    pipe,
2677 	    &preview_descr,
2678 	    &prev_in_info,
2679 	    &prev_bds_out_info,
2680 	    &prev_out_info,
2681 	    &prev_vf_info);
2682 	if (err)
2683 		return err;
2684 	err = ia_css_binary_find(&preview_descr, &mycs->preview_binary);
2685 	if (err)
2686 		return err;
2687 
2688 	/* The vf_pp binary is needed when (further) YUV downscaling is required */
2689 	need_vf_pp |= mycs->preview_binary.out_frame_info[0].res.width != pipe_out_info->res.width;
2690 	need_vf_pp |= mycs->preview_binary.out_frame_info[0].res.height != pipe_out_info->res.height;
2691 
2692 	/*
2693 	 * When vf_pp is needed, then the output format of the selected
2694 	 * preview binary must be yuv_line. If this is not the case,
2695 	 * then the preview binary selection is done again.
2696 	 */
2697 	if (need_vf_pp &&
2698 	    (mycs->preview_binary.out_frame_info[0].format != IA_CSS_FRAME_FORMAT_YUV_LINE)) {
2699 		/* Preview step 2 */
2700 		if (pipe->vf_yuv_ds_input_info.res.width)
2701 			prev_vf_info = pipe->vf_yuv_ds_input_info;
2702 		else
2703 			prev_vf_info = *pipe_out_info;
2704 
2705 		ia_css_frame_info_set_format(&prev_vf_info,
2706 					     IA_CSS_FRAME_FORMAT_YUV_LINE);
2707 
2708 		err = ia_css_pipe_get_preview_binarydesc(
2709 		    pipe,
2710 		    &preview_descr,
2711 		    &prev_in_info,
2712 		    &prev_bds_out_info,
2713 		    &prev_out_info,
2714 		    &prev_vf_info);
2715 		if (err)
2716 			return err;
2717 		err = ia_css_binary_find(&preview_descr,
2718 					 &mycs->preview_binary);
2719 		if (err)
2720 			return err;
2721 	}
2722 
2723 	if (need_vf_pp) {
2724 		struct ia_css_binary_descr vf_pp_descr;
2725 
2726 		/* Viewfinder post-processing */
2727 		ia_css_pipe_get_vfpp_binarydesc(pipe, &vf_pp_descr,
2728 						&mycs->preview_binary.out_frame_info[0],
2729 						pipe_out_info);
2730 		err = ia_css_binary_find(&vf_pp_descr,
2731 					 &mycs->vf_pp_binary);
2732 		if (err)
2733 			return err;
2734 	}
2735 
2736 #ifdef ISP2401
2737 	/*
2738 	 * When the input system is 2401, only the Direct Sensor Mode
2739 	 * Offline Preview uses the ISP copy binary.
2740 	 */
2741 	need_isp_copy_binary = !online && sensor;
2742 #else
2743 	/*
2744 	 * About pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY:
2745 	 * This is typical the case with SkyCam (which has no input system) but it also applies to all cases
2746 	 * where the driver chooses for memory based input frames. In these cases, a copy binary (which typical
2747 	 * copies sensor data to DDR) does not have much use.
2748 	 */
2749 	if (!IS_ISP2401)
2750 		need_isp_copy_binary = !online && !continuous;
2751 	else
2752 		need_isp_copy_binary = !online && !continuous && !(pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY);
2753 #endif
2754 
2755 	/* Copy */
2756 	if (need_isp_copy_binary) {
2757 		err = load_copy_binary(pipe,
2758 				       &mycs->copy_binary,
2759 				       &mycs->preview_binary);
2760 		if (err)
2761 			return err;
2762 	}
2763 
2764 	if (pipe->shading_table) {
2765 		ia_css_shading_table_free(pipe->shading_table);
2766 		pipe->shading_table = NULL;
2767 	}
2768 
2769 	return 0;
2770 }
2771 
2772 static void
2773 ia_css_binary_unload(struct ia_css_binary *binary)
2774 {
2775 	ia_css_binary_destroy_isp_parameters(binary);
2776 }
2777 
2778 static int
2779 unload_preview_binaries(struct ia_css_pipe *pipe)
2780 {
2781 	IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
2782 
2783 	if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) {
2784 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
2785 		return -EINVAL;
2786 	}
2787 	ia_css_binary_unload(&pipe->pipe_settings.preview.copy_binary);
2788 	ia_css_binary_unload(&pipe->pipe_settings.preview.preview_binary);
2789 	ia_css_binary_unload(&pipe->pipe_settings.preview.vf_pp_binary);
2790 
2791 	IA_CSS_LEAVE_ERR_PRIVATE(0);
2792 	return 0;
2793 }
2794 
2795 static const struct ia_css_fw_info *last_output_firmware(
2796     const struct ia_css_fw_info *fw)
2797 {
2798 	const struct ia_css_fw_info *last_fw = NULL;
2799 	/* fw can be NULL */
2800 	IA_CSS_ENTER_LEAVE_PRIVATE("");
2801 
2802 	for (; fw; fw = fw->next) {
2803 		const struct ia_css_fw_info *info = fw;
2804 
2805 		if (info->info.isp.sp.enable.output)
2806 			last_fw = fw;
2807 	}
2808 	return last_fw;
2809 }
2810 
2811 static int add_firmwares(
2812     struct ia_css_pipeline *me,
2813     struct ia_css_binary *binary,
2814     const struct ia_css_fw_info *fw,
2815     const struct ia_css_fw_info *last_fw,
2816     unsigned int binary_mode,
2817     struct ia_css_frame *in_frame,
2818     struct ia_css_frame *out_frame,
2819     struct ia_css_frame *vf_frame,
2820     struct ia_css_pipeline_stage **my_stage,
2821     struct ia_css_pipeline_stage **vf_stage)
2822 {
2823 	int err = 0;
2824 	struct ia_css_pipeline_stage *extra_stage = NULL;
2825 	struct ia_css_pipeline_stage_desc stage_desc;
2826 
2827 	/* all args can be NULL ??? */
2828 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
2829 			    "add_firmwares() enter:\n");
2830 
2831 	for (; fw; fw = fw->next) {
2832 		struct ia_css_frame *out[IA_CSS_BINARY_MAX_OUTPUT_PORTS] = {NULL};
2833 		struct ia_css_frame *in = NULL;
2834 		struct ia_css_frame *vf = NULL;
2835 
2836 		if ((fw == last_fw) && (fw->info.isp.sp.enable.out_frame  != 0))
2837 			out[0] = out_frame;
2838 
2839 		if (fw->info.isp.sp.enable.in_frame != 0)
2840 			in = in_frame;
2841 
2842 		if (fw->info.isp.sp.enable.out_frame != 0)
2843 			vf = vf_frame;
2844 
2845 		ia_css_pipe_get_firmwares_stage_desc(&stage_desc, binary,
2846 						     out, in, vf, fw, binary_mode);
2847 		err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
2848 							   &extra_stage);
2849 		if (err)
2850 			return err;
2851 		if (fw->info.isp.sp.enable.output != 0)
2852 			in_frame = extra_stage->args.out_frame[0];
2853 		if (my_stage && !*my_stage && extra_stage)
2854 			*my_stage = extra_stage;
2855 		if (vf_stage && !*vf_stage && extra_stage &&
2856 		    fw->info.isp.sp.enable.vf_veceven)
2857 			*vf_stage = extra_stage;
2858 	}
2859 	return err;
2860 }
2861 
2862 static int add_vf_pp_stage(
2863     struct ia_css_pipe *pipe,
2864     struct ia_css_frame *in_frame,
2865     struct ia_css_frame *out_frame,
2866     struct ia_css_binary *vf_pp_binary,
2867     struct ia_css_pipeline_stage **vf_pp_stage)
2868 {
2869 	struct ia_css_pipeline *me = NULL;
2870 	const struct ia_css_fw_info *last_fw = NULL;
2871 	int err = 0;
2872 	struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS];
2873 	struct ia_css_pipeline_stage_desc stage_desc;
2874 
2875 	/* out_frame can be NULL ??? */
2876 
2877 	if (!pipe)
2878 		return -EINVAL;
2879 	if (!in_frame)
2880 		return -EINVAL;
2881 	if (!vf_pp_binary)
2882 		return -EINVAL;
2883 	if (!vf_pp_stage)
2884 		return -EINVAL;
2885 
2886 	ia_css_pipe_util_create_output_frames(out_frames);
2887 	me = &pipe->pipeline;
2888 
2889 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
2890 			    "add_vf_pp_stage() enter:\n");
2891 
2892 	*vf_pp_stage = NULL;
2893 
2894 	last_fw = last_output_firmware(pipe->vf_stage);
2895 	if (!pipe->extra_config.disable_vf_pp) {
2896 		if (last_fw) {
2897 			ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
2898 			ia_css_pipe_get_generic_stage_desc(&stage_desc, vf_pp_binary,
2899 							   out_frames, in_frame, NULL);
2900 		} else {
2901 			ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
2902 			ia_css_pipe_get_generic_stage_desc(&stage_desc, vf_pp_binary,
2903 							   out_frames, in_frame, NULL);
2904 		}
2905 		err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, vf_pp_stage);
2906 		if (err)
2907 			return err;
2908 		in_frame = (*vf_pp_stage)->args.out_frame[0];
2909 	}
2910 	err = add_firmwares(me, vf_pp_binary, pipe->vf_stage, last_fw,
2911 			    IA_CSS_BINARY_MODE_VF_PP,
2912 			    in_frame, out_frame, NULL,
2913 			    vf_pp_stage, NULL);
2914 	return err;
2915 }
2916 
2917 static int add_yuv_scaler_stage(
2918     struct ia_css_pipe *pipe,
2919     struct ia_css_pipeline *me,
2920     struct ia_css_frame *in_frame,
2921     struct ia_css_frame *out_frame,
2922     struct ia_css_frame *internal_out_frame,
2923     struct ia_css_binary *yuv_scaler_binary,
2924     struct ia_css_pipeline_stage **pre_vf_pp_stage)
2925 {
2926 	const struct ia_css_fw_info *last_fw;
2927 	int err = 0;
2928 	struct ia_css_frame *vf_frame = NULL;
2929 	struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS];
2930 	struct ia_css_pipeline_stage_desc stage_desc;
2931 
2932 	/* out_frame can be NULL ??? */
2933 	assert(in_frame);
2934 	assert(pipe);
2935 	assert(me);
2936 	assert(yuv_scaler_binary);
2937 	assert(pre_vf_pp_stage);
2938 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
2939 			    "add_yuv_scaler_stage() enter:\n");
2940 
2941 	*pre_vf_pp_stage = NULL;
2942 	ia_css_pipe_util_create_output_frames(out_frames);
2943 
2944 	last_fw = last_output_firmware(pipe->output_stage);
2945 
2946 	if (last_fw) {
2947 		ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
2948 		ia_css_pipe_get_generic_stage_desc(&stage_desc,
2949 						   yuv_scaler_binary, out_frames, in_frame, vf_frame);
2950 	} else {
2951 		ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
2952 		ia_css_pipe_util_set_output_frames(out_frames, 1, internal_out_frame);
2953 		ia_css_pipe_get_generic_stage_desc(&stage_desc,
2954 						   yuv_scaler_binary, out_frames, in_frame, vf_frame);
2955 	}
2956 	err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
2957 						   pre_vf_pp_stage);
2958 	if (err)
2959 		return err;
2960 	in_frame = (*pre_vf_pp_stage)->args.out_frame[0];
2961 
2962 	err = add_firmwares(me, yuv_scaler_binary, pipe->output_stage, last_fw,
2963 			    IA_CSS_BINARY_MODE_CAPTURE_PP,
2964 			    in_frame, out_frame, vf_frame,
2965 			    NULL, pre_vf_pp_stage);
2966 	/* If a firmware produce vf_pp output, we set that as vf_pp input */
2967 	(*pre_vf_pp_stage)->args.vf_downscale_log2 =
2968 	    yuv_scaler_binary->vf_downscale_log2;
2969 
2970 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
2971 			    "add_yuv_scaler_stage() leave:\n");
2972 	return err;
2973 }
2974 
2975 static int add_capture_pp_stage(
2976     struct ia_css_pipe *pipe,
2977     struct ia_css_pipeline *me,
2978     struct ia_css_frame *in_frame,
2979     struct ia_css_frame *out_frame,
2980     struct ia_css_binary *capture_pp_binary,
2981     struct ia_css_pipeline_stage **capture_pp_stage)
2982 {
2983 	const struct ia_css_fw_info *last_fw = NULL;
2984 	int err = 0;
2985 	struct ia_css_frame *vf_frame = NULL;
2986 	struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS];
2987 	struct ia_css_pipeline_stage_desc stage_desc;
2988 
2989 	/* out_frame can be NULL ??? */
2990 	assert(in_frame);
2991 	assert(pipe);
2992 	assert(me);
2993 	assert(capture_pp_binary);
2994 	assert(capture_pp_stage);
2995 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
2996 			    "add_capture_pp_stage() enter:\n");
2997 
2998 	*capture_pp_stage = NULL;
2999 	ia_css_pipe_util_create_output_frames(out_frames);
3000 
3001 	last_fw = last_output_firmware(pipe->output_stage);
3002 	err = ia_css_frame_allocate_from_info(&vf_frame,
3003 					      &capture_pp_binary->vf_frame_info);
3004 	if (err)
3005 		return err;
3006 	if (last_fw)	{
3007 		ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
3008 		ia_css_pipe_get_generic_stage_desc(&stage_desc,
3009 						   capture_pp_binary, out_frames, NULL, vf_frame);
3010 	} else {
3011 		ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
3012 		ia_css_pipe_get_generic_stage_desc(&stage_desc,
3013 						   capture_pp_binary, out_frames, NULL, vf_frame);
3014 	}
3015 	err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
3016 						   capture_pp_stage);
3017 	if (err)
3018 		return err;
3019 	err = add_firmwares(me, capture_pp_binary, pipe->output_stage, last_fw,
3020 			    IA_CSS_BINARY_MODE_CAPTURE_PP,
3021 			    in_frame, out_frame, vf_frame,
3022 			    NULL, capture_pp_stage);
3023 	/* If a firmware produce vf_pp output, we set that as vf_pp input */
3024 	if (*capture_pp_stage) {
3025 		(*capture_pp_stage)->args.vf_downscale_log2 =
3026 		    capture_pp_binary->vf_downscale_log2;
3027 	}
3028 	return err;
3029 }
3030 
3031 static void sh_css_setup_queues(void)
3032 {
3033 	const struct ia_css_fw_info *fw;
3034 	unsigned int HIVE_ADDR_host_sp_queues_initialized;
3035 
3036 	sh_css_hmm_buffer_record_init();
3037 
3038 	sh_css_event_init_irq_mask();
3039 
3040 	fw = &sh_css_sp_fw;
3041 	HIVE_ADDR_host_sp_queues_initialized =
3042 	    fw->info.sp.host_sp_queues_initialized;
3043 
3044 	ia_css_bufq_init();
3045 
3046 	/* set "host_sp_queues_initialized" to "true" */
3047 	sp_dmem_store_uint32(SP0_ID,
3048 			     (unsigned int)sp_address_of(host_sp_queues_initialized),
3049 			     (uint32_t)(1));
3050 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "sh_css_setup_queues() leave:\n");
3051 }
3052 
3053 static int
3054 init_vf_frameinfo_defaults(struct ia_css_pipe *pipe,
3055 			   struct ia_css_frame *vf_frame, unsigned int idx)
3056 {
3057 	int err = 0;
3058 	unsigned int thread_id;
3059 	enum sh_css_queue_id queue_id;
3060 
3061 	assert(vf_frame);
3062 
3063 	sh_css_pipe_get_viewfinder_frame_info(pipe, &vf_frame->info, idx);
3064 	vf_frame->contiguous = false;
3065 	vf_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
3066 	ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
3067 	ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME + idx, thread_id, &queue_id);
3068 	vf_frame->dynamic_queue_id = queue_id;
3069 	vf_frame->buf_type = IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME + idx;
3070 
3071 	err = ia_css_frame_init_planes(vf_frame);
3072 	return err;
3073 }
3074 
3075 #ifdef ISP2401
3076 static unsigned int
3077 get_crop_lines_for_bayer_order(const struct ia_css_stream_config *config)
3078 {
3079 	assert(config);
3080 	if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_BGGR) ||
3081 	    (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG))
3082 		return 1;
3083 
3084 	return 0;
3085 }
3086 
3087 static unsigned int
3088 get_crop_columns_for_bayer_order(const struct ia_css_stream_config *config)
3089 {
3090 	assert(config);
3091 	if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_RGGB) ||
3092 	    (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG))
3093 		return 1;
3094 
3095 	return 0;
3096 }
3097 
3098 /*
3099  * This function is to get the sum of all extra pixels in addition to the effective
3100  * input, it includes dvs envelop and filter run-in
3101  */
3102 static void get_pipe_extra_pixel(struct ia_css_pipe *pipe,
3103 				 unsigned int *extra_row, unsigned int *extra_column)
3104 {
3105 	enum ia_css_pipe_id pipe_id = pipe->mode;
3106 	unsigned int left_cropping = 0, top_cropping = 0;
3107 	unsigned int i;
3108 	struct ia_css_resolution dvs_env = pipe->config.dvs_envelope;
3109 
3110 	/*
3111 	 * The dvs envelope info may not be correctly sent down via pipe config
3112 	 * The check is made and the correct value is populated in the binary info
3113 	 * Use this value when computing crop, else excess lines may get trimmed
3114 	 */
3115 	switch (pipe_id) {
3116 	case IA_CSS_PIPE_ID_PREVIEW:
3117 		if (pipe->pipe_settings.preview.preview_binary.info) {
3118 			left_cropping =
3119 			    pipe->pipe_settings.preview.preview_binary.info->sp.pipeline.left_cropping;
3120 			top_cropping =
3121 			    pipe->pipe_settings.preview.preview_binary.info->sp.pipeline.top_cropping;
3122 		}
3123 		dvs_env = pipe->pipe_settings.preview.preview_binary.dvs_envelope;
3124 		break;
3125 	case IA_CSS_PIPE_ID_VIDEO:
3126 		if (pipe->pipe_settings.video.video_binary.info) {
3127 			left_cropping =
3128 			    pipe->pipe_settings.video.video_binary.info->sp.pipeline.left_cropping;
3129 			top_cropping =
3130 			    pipe->pipe_settings.video.video_binary.info->sp.pipeline.top_cropping;
3131 		}
3132 		dvs_env = pipe->pipe_settings.video.video_binary.dvs_envelope;
3133 		break;
3134 	case IA_CSS_PIPE_ID_CAPTURE:
3135 		for (i = 0; i < pipe->pipe_settings.capture.num_primary_stage; i++) {
3136 			if (pipe->pipe_settings.capture.primary_binary[i].info) {
3137 				left_cropping +=
3138 				    pipe->pipe_settings.capture.primary_binary[i].info->sp.pipeline.left_cropping;
3139 				top_cropping +=
3140 				    pipe->pipe_settings.capture.primary_binary[i].info->sp.pipeline.top_cropping;
3141 			}
3142 			dvs_env.width +=
3143 			    pipe->pipe_settings.capture.primary_binary[i].dvs_envelope.width;
3144 			dvs_env.height +=
3145 			    pipe->pipe_settings.capture.primary_binary[i].dvs_envelope.height;
3146 		}
3147 		break;
3148 	default:
3149 		break;
3150 	}
3151 
3152 	*extra_row = top_cropping + dvs_env.height;
3153 	*extra_column = left_cropping + dvs_env.width;
3154 }
3155 
3156 void
3157 ia_css_get_crop_offsets(
3158     struct ia_css_pipe *pipe,
3159     struct ia_css_frame_info *in_frame)
3160 {
3161 	unsigned int row = 0;
3162 	unsigned int column = 0;
3163 	struct ia_css_resolution *input_res;
3164 	struct ia_css_resolution *effective_res;
3165 	unsigned int extra_row = 0, extra_col = 0;
3166 	unsigned int min_reqd_height, min_reqd_width;
3167 
3168 	assert(pipe);
3169 	assert(pipe->stream);
3170 	assert(in_frame);
3171 
3172 	IA_CSS_ENTER_PRIVATE("pipe = %p effective_wd = %u effective_ht = %u",
3173 			     pipe, pipe->config.input_effective_res.width,
3174 			     pipe->config.input_effective_res.height);
3175 
3176 	input_res = &pipe->stream->config.input_config.input_res;
3177 #ifndef ISP2401
3178 	effective_res = &pipe->stream->config.input_config.effective_res;
3179 #else
3180 	effective_res = &pipe->config.input_effective_res;
3181 #endif
3182 
3183 	get_pipe_extra_pixel(pipe, &extra_row, &extra_col);
3184 
3185 	in_frame->raw_bayer_order = pipe->stream->config.input_config.bayer_order;
3186 
3187 	min_reqd_height = effective_res->height + extra_row;
3188 	min_reqd_width = effective_res->width + extra_col;
3189 
3190 	if (input_res->height > min_reqd_height) {
3191 		row = (input_res->height - min_reqd_height) / 2;
3192 		row &= ~0x1;
3193 	}
3194 	if (input_res->width > min_reqd_width) {
3195 		column = (input_res->width - min_reqd_width) / 2;
3196 		column &= ~0x1;
3197 	}
3198 
3199 	/*
3200 	 * TODO:
3201 	 * 1. Require the special support for RAW10 packed mode.
3202 	 * 2. Require the special support for the online use cases.
3203 	 */
3204 
3205 	/*
3206 	 * ISP expects GRBG bayer order, we skip one line and/or one row
3207 	 * to correct in case the input bayer order is different.
3208 	 */
3209 	column += get_crop_columns_for_bayer_order(&pipe->stream->config);
3210 	row += get_crop_lines_for_bayer_order(&pipe->stream->config);
3211 
3212 	in_frame->crop_info.start_column = column;
3213 	in_frame->crop_info.start_line = row;
3214 
3215 	IA_CSS_LEAVE_PRIVATE("void start_col: %u start_row: %u", column, row);
3216 
3217 	return;
3218 }
3219 #endif
3220 
3221 static int
3222 init_in_frameinfo_memory_defaults(struct ia_css_pipe *pipe,
3223 				  struct ia_css_frame *frame, enum ia_css_frame_format format)
3224 {
3225 	struct ia_css_frame *in_frame;
3226 	int err = 0;
3227 	unsigned int thread_id;
3228 	enum sh_css_queue_id queue_id;
3229 
3230 	assert(frame);
3231 	in_frame = frame;
3232 
3233 	in_frame->info.format = format;
3234 
3235 #ifdef ISP2401
3236 	if (format == IA_CSS_FRAME_FORMAT_RAW)
3237 		in_frame->info.format = (pipe->stream->config.pack_raw_pixels) ?
3238 		IA_CSS_FRAME_FORMAT_RAW_PACKED : IA_CSS_FRAME_FORMAT_RAW;
3239 #endif
3240 
3241 	in_frame->info.res.width = pipe->stream->config.input_config.input_res.width;
3242 	in_frame->info.res.height = pipe->stream->config.input_config.input_res.height;
3243 	in_frame->info.raw_bit_depth =
3244 	ia_css_pipe_util_pipe_input_format_bpp(pipe);
3245 	ia_css_frame_info_set_width(&in_frame->info, pipe->stream->config.input_config.input_res.width, 0);
3246 	in_frame->contiguous = false;
3247 	in_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
3248 	ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
3249 	ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_INPUT_FRAME, thread_id, &queue_id);
3250 	in_frame->dynamic_queue_id = queue_id;
3251 	in_frame->buf_type = IA_CSS_BUFFER_TYPE_INPUT_FRAME;
3252 #ifdef ISP2401
3253 	ia_css_get_crop_offsets(pipe, &in_frame->info);
3254 #endif
3255 	err = ia_css_frame_init_planes(in_frame);
3256 
3257 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
3258 			    "init_in_frameinfo_memory_defaults() bayer_order = %d:\n", in_frame->info.raw_bayer_order);
3259 
3260 	return err;
3261 }
3262 
3263 static int
3264 init_out_frameinfo_defaults(struct ia_css_pipe *pipe,
3265 			    struct ia_css_frame *out_frame, unsigned int idx)
3266 {
3267 	int err = 0;
3268 	unsigned int thread_id;
3269 	enum sh_css_queue_id queue_id;
3270 
3271 	assert(out_frame);
3272 
3273 	sh_css_pipe_get_output_frame_info(pipe, &out_frame->info, idx);
3274 	out_frame->contiguous = false;
3275 	out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
3276 	ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
3277 	ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_OUTPUT_FRAME + idx, thread_id, &queue_id);
3278 	out_frame->dynamic_queue_id = queue_id;
3279 	out_frame->buf_type = IA_CSS_BUFFER_TYPE_OUTPUT_FRAME + idx;
3280 	err = ia_css_frame_init_planes(out_frame);
3281 
3282 	return err;
3283 }
3284 
3285 /* Create stages for video pipe */
3286 static int create_host_video_pipeline(struct ia_css_pipe *pipe)
3287 {
3288 	struct ia_css_pipeline_stage_desc stage_desc;
3289 	struct ia_css_binary *copy_binary, *video_binary,
3290 		       *yuv_scaler_binary, *vf_pp_binary;
3291 	struct ia_css_pipeline_stage *copy_stage  = NULL;
3292 	struct ia_css_pipeline_stage *video_stage = NULL;
3293 	struct ia_css_pipeline_stage *yuv_scaler_stage  = NULL;
3294 	struct ia_css_pipeline_stage *vf_pp_stage = NULL;
3295 	struct ia_css_pipeline *me;
3296 	struct ia_css_frame *in_frame = NULL;
3297 	struct ia_css_frame *out_frame;
3298 	struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS];
3299 	struct ia_css_frame *vf_frame = NULL;
3300 	int err = 0;
3301 	bool need_copy   = false;
3302 	bool need_vf_pp  = false;
3303 	bool need_yuv_pp = false;
3304 	bool need_in_frameinfo_memory = false;
3305 
3306 	unsigned int i, num_yuv_scaler;
3307 	bool *is_output_stage = NULL;
3308 
3309 	IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
3310 	if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_VIDEO)) {
3311 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
3312 		return -EINVAL;
3313 	}
3314 	ia_css_pipe_util_create_output_frames(out_frames);
3315 	out_frame = &pipe->out_frame_struct;
3316 
3317 	/* pipeline already created as part of create_host_pipeline_structure */
3318 	me = &pipe->pipeline;
3319 	ia_css_pipeline_clean(me);
3320 
3321 	me->dvs_frame_delay = pipe->dvs_frame_delay;
3322 
3323 #ifdef ISP2401
3324 	/*
3325 	 * When the input system is 2401, always enable 'in_frameinfo_memory'
3326 	 * except for the following: online or continuous
3327 	 */
3328 	need_in_frameinfo_memory = !(pipe->stream->config.online ||
3329 				     pipe->stream->config.continuous);
3330 #else
3331 	/* Construct in_frame info (only in case we have dynamic input */
3332 	need_in_frameinfo_memory = pipe->stream->config.mode ==
3333 				   IA_CSS_INPUT_MODE_MEMORY;
3334 #endif
3335 
3336 	/* Construct in_frame info (only in case we have dynamic input */
3337 	if (need_in_frameinfo_memory) {
3338 		in_frame = &pipe->in_frame_struct;
3339 		err = init_in_frameinfo_memory_defaults(pipe, in_frame,
3340 							IA_CSS_FRAME_FORMAT_RAW);
3341 		if (err)
3342 			goto ERR;
3343 	}
3344 
3345 	out_frame->data = 0;
3346 	err = init_out_frameinfo_defaults(pipe, out_frame, 0);
3347 	if (err)
3348 		goto ERR;
3349 
3350 	if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) {
3351 		vf_frame = &pipe->vf_frame_struct;
3352 		vf_frame->data = 0;
3353 		err = init_vf_frameinfo_defaults(pipe, vf_frame, 0);
3354 		if (err)
3355 			goto ERR;
3356 	}
3357 
3358 	copy_binary  = &pipe->pipe_settings.video.copy_binary;
3359 	video_binary = &pipe->pipe_settings.video.video_binary;
3360 	vf_pp_binary = &pipe->pipe_settings.video.vf_pp_binary;
3361 
3362 	yuv_scaler_binary = pipe->pipe_settings.video.yuv_scaler_binary;
3363 	num_yuv_scaler  = pipe->pipe_settings.video.num_yuv_scaler;
3364 	is_output_stage = pipe->pipe_settings.video.is_output_stage;
3365 
3366 	need_copy   = (copy_binary && copy_binary->info);
3367 	need_vf_pp  = (vf_pp_binary && vf_pp_binary->info);
3368 	need_yuv_pp = (yuv_scaler_binary && yuv_scaler_binary->info);
3369 
3370 	if (need_copy) {
3371 		ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
3372 		ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary,
3373 						   out_frames, NULL, NULL);
3374 		err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
3375 							   &copy_stage);
3376 		if (err)
3377 			goto ERR;
3378 		in_frame = me->stages->args.out_frame[0];
3379 	} else if (pipe->stream->config.continuous) {
3380 #ifdef ISP2401
3381 		/*
3382 		 * When continuous is enabled, configure in_frame with the
3383 		 * last pipe, which is the copy pipe.
3384 		 */
3385 		in_frame = pipe->stream->last_pipe->continuous_frames[0];
3386 #else
3387 		in_frame = pipe->continuous_frames[0];
3388 #endif
3389 	}
3390 
3391 	ia_css_pipe_util_set_output_frames(out_frames, 0,
3392 					   need_yuv_pp ? NULL : out_frame);
3393 
3394 	/*
3395 	 * when the video binary supports a second output pin,
3396 	 * it can directly produce the vf_frame.
3397 	 */
3398 	if (need_vf_pp) {
3399 		ia_css_pipe_get_generic_stage_desc(&stage_desc, video_binary,
3400 						   out_frames, in_frame, NULL);
3401 	} else {
3402 		ia_css_pipe_get_generic_stage_desc(&stage_desc, video_binary,
3403 						   out_frames, in_frame, vf_frame);
3404 	}
3405 	err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
3406 						   &video_stage);
3407 	if (err)
3408 		goto ERR;
3409 
3410 	/* If we use copy iso video, the input must be yuv iso raw */
3411 	if (video_stage) {
3412 		video_stage->args.copy_vf =
3413 		    video_binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY;
3414 		video_stage->args.copy_output = video_stage->args.copy_vf;
3415 	}
3416 
3417 	/* when the video binary supports only 1 output pin, vf_pp is needed to
3418 	produce the vf_frame.*/
3419 	if (need_vf_pp && video_stage) {
3420 		in_frame = video_stage->args.out_vf_frame;
3421 		err = add_vf_pp_stage(pipe, in_frame, vf_frame, vf_pp_binary,
3422 				      &vf_pp_stage);
3423 		if (err)
3424 			goto ERR;
3425 	}
3426 	if (video_stage) {
3427 		int frm;
3428 
3429 		for (frm = 0; frm < NUM_VIDEO_TNR_FRAMES; frm++) {
3430 			video_stage->args.tnr_frames[frm] =
3431 			    pipe->pipe_settings.video.tnr_frames[frm];
3432 		}
3433 		for (frm = 0; frm < MAX_NUM_VIDEO_DELAY_FRAMES; frm++) {
3434 			video_stage->args.delay_frames[frm] =
3435 			    pipe->pipe_settings.video.delay_frames[frm];
3436 		}
3437 	}
3438 
3439 	/* Append Extension on Video out, if enabled */
3440 	if (!need_vf_pp && video_stage && pipe->config.acc_extension &&
3441 	    (pipe->config.acc_extension->info.isp.type == IA_CSS_ACC_OUTPUT)) {
3442 		struct ia_css_frame *out = NULL;
3443 		struct ia_css_frame *in = NULL;
3444 
3445 		if ((pipe->config.acc_extension->info.isp.sp.enable.output) &&
3446 		    (pipe->config.acc_extension->info.isp.sp.enable.in_frame) &&
3447 		    (pipe->config.acc_extension->info.isp.sp.enable.out_frame)) {
3448 			/* In/Out Frame mapping to support output frame extension.*/
3449 			out = video_stage->args.out_frame[0];
3450 			err = ia_css_frame_allocate_from_info(&in, &pipe->output_info[0]);
3451 			if (err)
3452 				goto ERR;
3453 			video_stage->args.out_frame[0] = in;
3454 		}
3455 
3456 		err = add_firmwares(me, video_binary, pipe->output_stage,
3457 				    last_output_firmware(pipe->output_stage),
3458 				    IA_CSS_BINARY_MODE_VIDEO,
3459 				    in, out, NULL, &video_stage, NULL);
3460 		if (err)
3461 			goto ERR;
3462 	}
3463 
3464 	if (need_yuv_pp && video_stage) {
3465 		struct ia_css_frame *tmp_in_frame = video_stage->args.out_frame[0];
3466 		struct ia_css_frame *tmp_out_frame = NULL;
3467 
3468 		for (i = 0; i < num_yuv_scaler; i++) {
3469 			tmp_out_frame = is_output_stage[i] ? out_frame : NULL;
3470 
3471 			err = add_yuv_scaler_stage(pipe, me, tmp_in_frame,
3472 						   tmp_out_frame, NULL,
3473 						   &yuv_scaler_binary[i],
3474 						   &yuv_scaler_stage);
3475 
3476 			if (err) {
3477 				IA_CSS_LEAVE_ERR_PRIVATE(err);
3478 				return err;
3479 			}
3480 			/* we use output port 1 as internal output port */
3481 			if (yuv_scaler_stage)
3482 				tmp_in_frame = yuv_scaler_stage->args.out_frame[1];
3483 		}
3484 	}
3485 
3486 	pipe->pipeline.acquire_isp_each_stage = false;
3487 	ia_css_pipeline_finalize_stages(&pipe->pipeline,
3488 					pipe->stream->config.continuous);
3489 
3490 ERR:
3491 	IA_CSS_LEAVE_ERR_PRIVATE(err);
3492 	return err;
3493 }
3494 
3495 static int
3496 create_host_acc_pipeline(struct ia_css_pipe *pipe)
3497 {
3498 	int err = 0;
3499 	const struct ia_css_fw_info *fw;
3500 	unsigned int i;
3501 
3502 	IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
3503 	if ((!pipe) || (!pipe->stream)) {
3504 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
3505 		return -EINVAL;
3506 	}
3507 
3508 	pipe->pipeline.num_execs = pipe->config.acc_num_execs;
3509 	/* Reset pipe_qos_config to default disable all QOS extension stages */
3510 	if (pipe->config.acc_extension)
3511 		pipe->pipeline.pipe_qos_config = 0;
3512 
3513 	fw = pipe->vf_stage;
3514 	for (i = 0; fw; fw = fw->next) {
3515 		err = sh_css_pipeline_add_acc_stage(&pipe->pipeline, fw);
3516 		if (err)
3517 			goto ERR;
3518 	}
3519 
3520 	for (i = 0; i < pipe->config.num_acc_stages; i++) {
3521 		struct ia_css_fw_info *fw = pipe->config.acc_stages[i];
3522 
3523 		err = sh_css_pipeline_add_acc_stage(&pipe->pipeline, fw);
3524 		if (err)
3525 			goto ERR;
3526 	}
3527 
3528 	ia_css_pipeline_finalize_stages(&pipe->pipeline, pipe->stream->config.continuous);
3529 
3530 ERR:
3531 	IA_CSS_LEAVE_ERR_PRIVATE(err);
3532 	return err;
3533 }
3534 
3535 /* Create stages for preview */
3536 static int
3537 create_host_preview_pipeline(struct ia_css_pipe *pipe)
3538 {
3539 	struct ia_css_pipeline_stage *copy_stage = NULL;
3540 	struct ia_css_pipeline_stage *preview_stage = NULL;
3541 	struct ia_css_pipeline_stage *vf_pp_stage = NULL;
3542 	struct ia_css_pipeline_stage_desc stage_desc;
3543 	struct ia_css_pipeline *me = NULL;
3544 	struct ia_css_binary *copy_binary, *preview_binary, *vf_pp_binary = NULL;
3545 	struct ia_css_frame *in_frame = NULL;
3546 	int err = 0;
3547 	struct ia_css_frame *out_frame;
3548 	struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS];
3549 	bool need_in_frameinfo_memory = false;
3550 #ifdef ISP2401
3551 	bool sensor = false;
3552 	bool buffered_sensor = false;
3553 	bool online = false;
3554 	bool continuous = false;
3555 #endif
3556 
3557 	IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
3558 	if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) {
3559 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
3560 		return -EINVAL;
3561 	}
3562 
3563 	ia_css_pipe_util_create_output_frames(out_frames);
3564 	/* pipeline already created as part of create_host_pipeline_structure */
3565 	me = &pipe->pipeline;
3566 	ia_css_pipeline_clean(me);
3567 
3568 #ifdef ISP2401
3569 	/*
3570 	 * When the input system is 2401, always enable 'in_frameinfo_memory'
3571 	 * except for the following:
3572 	 * - Direct Sensor Mode Online Preview
3573 	 * - Buffered Sensor Mode Online Preview
3574 	 * - Direct Sensor Mode Continuous Preview
3575 	 * - Buffered Sensor Mode Continuous Preview
3576 	 */
3577 	sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR);
3578 	buffered_sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR);
3579 	online = pipe->stream->config.online;
3580 	continuous = pipe->stream->config.continuous;
3581 	need_in_frameinfo_memory =
3582 	!((sensor && (online || continuous)) || (buffered_sensor && (online || continuous)));
3583 #else
3584 	/* Construct in_frame info (only in case we have dynamic input */
3585 	need_in_frameinfo_memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY;
3586 #endif
3587 	if (need_in_frameinfo_memory) {
3588 		err = init_in_frameinfo_memory_defaults(pipe, &me->in_frame,
3589 							IA_CSS_FRAME_FORMAT_RAW);
3590 		if (err)
3591 			goto ERR;
3592 
3593 		in_frame = &me->in_frame;
3594 	} else {
3595 		in_frame = NULL;
3596 	}
3597 
3598 	err = init_out_frameinfo_defaults(pipe, &me->out_frame[0], 0);
3599 	if (err)
3600 		goto ERR;
3601 	out_frame = &me->out_frame[0];
3602 
3603 	copy_binary    = &pipe->pipe_settings.preview.copy_binary;
3604 	preview_binary = &pipe->pipe_settings.preview.preview_binary;
3605 	if (pipe->pipe_settings.preview.vf_pp_binary.info)
3606 		vf_pp_binary = &pipe->pipe_settings.preview.vf_pp_binary;
3607 
3608 	if (pipe->pipe_settings.preview.copy_binary.info) {
3609 		ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
3610 		ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary,
3611 						   out_frames, NULL, NULL);
3612 		err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
3613 							   &copy_stage);
3614 		if (err)
3615 			goto ERR;
3616 		in_frame = me->stages->args.out_frame[0];
3617 	} else if (pipe->stream->config.continuous) {
3618 #ifdef ISP2401
3619 		/*
3620 		 * When continuous is enabled, configure in_frame with the
3621 		 * last pipe, which is the copy pipe.
3622 		 */
3623 		if (continuous || !online)
3624 			in_frame = pipe->stream->last_pipe->continuous_frames[0];
3625 
3626 #else
3627 		in_frame = pipe->continuous_frames[0];
3628 #endif
3629 	}
3630 
3631 	if (vf_pp_binary) {
3632 		ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
3633 		ia_css_pipe_get_generic_stage_desc(&stage_desc, preview_binary,
3634 						   out_frames, in_frame, NULL);
3635 	} else {
3636 		ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
3637 		ia_css_pipe_get_generic_stage_desc(&stage_desc, preview_binary,
3638 						   out_frames, in_frame, NULL);
3639 	}
3640 	err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
3641 						   &preview_stage);
3642 	if (err)
3643 		goto ERR;
3644 	/* If we use copy iso preview, the input must be yuv iso raw */
3645 	preview_stage->args.copy_vf =
3646 	    preview_binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY;
3647 	preview_stage->args.copy_output = !preview_stage->args.copy_vf;
3648 	if (preview_stage->args.copy_vf && !preview_stage->args.out_vf_frame) {
3649 		/* in case of copy, use the vf frame as output frame */
3650 		preview_stage->args.out_vf_frame =
3651 		    preview_stage->args.out_frame[0];
3652 	}
3653 	if (vf_pp_binary) {
3654 		if (preview_binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY)
3655 			in_frame = preview_stage->args.out_vf_frame;
3656 		else
3657 			in_frame = preview_stage->args.out_frame[0];
3658 		err = add_vf_pp_stage(pipe, in_frame, out_frame, vf_pp_binary,
3659 				      &vf_pp_stage);
3660 		if (err)
3661 			goto ERR;
3662 	}
3663 
3664 	pipe->pipeline.acquire_isp_each_stage = false;
3665 	ia_css_pipeline_finalize_stages(&pipe->pipeline, pipe->stream->config.continuous);
3666 
3667 ERR:
3668 	IA_CSS_LEAVE_ERR_PRIVATE(err);
3669 	return err;
3670 }
3671 
3672 static void send_raw_frames(struct ia_css_pipe *pipe)
3673 {
3674 	if (pipe->stream->config.continuous) {
3675 		unsigned int i;
3676 
3677 		sh_css_update_host2sp_cont_num_raw_frames
3678 		(pipe->stream->config.init_num_cont_raw_buf, true);
3679 		sh_css_update_host2sp_cont_num_raw_frames
3680 		(pipe->stream->config.target_num_cont_raw_buf, false);
3681 
3682 		/* Hand-over all the SP-internal buffers */
3683 		for (i = 0; i < pipe->stream->config.init_num_cont_raw_buf; i++) {
3684 			sh_css_update_host2sp_offline_frame(i,
3685 							    pipe->continuous_frames[i], pipe->cont_md_buffers[i]);
3686 		}
3687 	}
3688 
3689 	return;
3690 }
3691 
3692 static int
3693 preview_start(struct ia_css_pipe *pipe)
3694 {
3695 	int err = 0;
3696 	struct ia_css_pipe *copy_pipe, *capture_pipe;
3697 	struct ia_css_pipe *acc_pipe;
3698 	enum sh_css_pipe_config_override copy_ovrd;
3699 	enum ia_css_input_mode preview_pipe_input_mode;
3700 	unsigned int thread_id;
3701 
3702 	IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
3703 	if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) {
3704 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
3705 		return -EINVAL;
3706 	}
3707 
3708 	preview_pipe_input_mode = pipe->stream->config.mode;
3709 
3710 	copy_pipe    = pipe->pipe_settings.preview.copy_pipe;
3711 	capture_pipe = pipe->pipe_settings.preview.capture_pipe;
3712 	acc_pipe     = pipe->pipe_settings.preview.acc_pipe;
3713 
3714 	sh_css_metrics_start_frame();
3715 
3716 	/* multi stream video needs mipi buffers */
3717 	err = send_mipi_frames(pipe);
3718 	if (err) {
3719 		IA_CSS_LEAVE_ERR_PRIVATE(err);
3720 		return err;
3721 	}
3722 	send_raw_frames(pipe);
3723 
3724 	ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
3725 	copy_ovrd = 1 << thread_id;
3726 
3727 	if (pipe->stream->cont_capt) {
3728 		ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(capture_pipe),
3729 						 &thread_id);
3730 		copy_ovrd |= 1 << thread_id;
3731 	}
3732 
3733 	/* Construct and load the copy pipe */
3734 	if (pipe->stream->config.continuous) {
3735 		sh_css_sp_init_pipeline(&copy_pipe->pipeline,
3736 					IA_CSS_PIPE_ID_COPY,
3737 					(uint8_t)ia_css_pipe_get_pipe_num(copy_pipe),
3738 					false,
3739 					pipe->stream->config.pixels_per_clock == 2, false,
3740 					false, pipe->required_bds_factor,
3741 					copy_ovrd,
3742 					pipe->stream->config.mode,
3743 					&pipe->stream->config.metadata_config,
3744 					&pipe->stream->info.metadata_info,
3745 					pipe->stream->config.source.port.port);
3746 
3747 		/*
3748 		 * make the preview pipe start with mem mode input, copy handles
3749 		 * the actual mode
3750 		 */
3751 		preview_pipe_input_mode = IA_CSS_INPUT_MODE_MEMORY;
3752 	}
3753 
3754 	/* Construct and load the capture pipe */
3755 	if (pipe->stream->cont_capt) {
3756 		sh_css_sp_init_pipeline(&capture_pipe->pipeline,
3757 					IA_CSS_PIPE_ID_CAPTURE,
3758 					(uint8_t)ia_css_pipe_get_pipe_num(capture_pipe),
3759 					capture_pipe->config.default_capture_config.enable_xnr != 0,
3760 					capture_pipe->stream->config.pixels_per_clock == 2,
3761 					true, /* continuous */
3762 					false, /* offline */
3763 					capture_pipe->required_bds_factor,
3764 					0,
3765 					IA_CSS_INPUT_MODE_MEMORY,
3766 					&pipe->stream->config.metadata_config,
3767 					&pipe->stream->info.metadata_info,
3768 					(enum mipi_port_id)0);
3769 	}
3770 
3771 	if (acc_pipe) {
3772 		sh_css_sp_init_pipeline(&acc_pipe->pipeline,
3773 					IA_CSS_PIPE_ID_ACC,
3774 					(uint8_t)ia_css_pipe_get_pipe_num(acc_pipe),
3775 					false,
3776 					pipe->stream->config.pixels_per_clock == 2,
3777 					false, /* continuous */
3778 					false, /* offline */
3779 					pipe->required_bds_factor,
3780 					0,
3781 					IA_CSS_INPUT_MODE_MEMORY,
3782 					NULL,
3783 					NULL,
3784 					(enum mipi_port_id)0);
3785 	}
3786 
3787 	start_pipe(pipe, copy_ovrd, preview_pipe_input_mode);
3788 
3789 	IA_CSS_LEAVE_ERR_PRIVATE(err);
3790 	return err;
3791 }
3792 
3793 int
3794 ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
3795 			   const struct ia_css_buffer *buffer)
3796 {
3797 	int return_err = 0;
3798 	unsigned int thread_id;
3799 	enum sh_css_queue_id queue_id;
3800 	struct ia_css_pipeline *pipeline;
3801 	struct ia_css_pipeline_stage *stage;
3802 	struct ia_css_rmgr_vbuf_handle p_vbuf;
3803 	struct ia_css_rmgr_vbuf_handle *h_vbuf;
3804 	struct sh_css_hmm_buffer ddr_buffer;
3805 	enum ia_css_buffer_type buf_type;
3806 	enum ia_css_pipe_id pipe_id;
3807 	bool ret_err;
3808 
3809 	IA_CSS_ENTER("pipe=%p, buffer=%p", pipe, buffer);
3810 
3811 	if ((!pipe) || (!buffer)) {
3812 		IA_CSS_LEAVE_ERR(-EINVAL);
3813 		return -EINVAL;
3814 	}
3815 
3816 	buf_type = buffer->type;
3817 
3818 	pipe_id = pipe->mode;
3819 
3820 	IA_CSS_LOG("pipe_id=%d, buf_type=%d", pipe_id, buf_type);
3821 
3822 	assert(pipe_id < IA_CSS_PIPE_ID_NUM);
3823 	assert(buf_type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE);
3824 	if (buf_type == IA_CSS_BUFFER_TYPE_INVALID ||
3825 	    buf_type >= IA_CSS_NUM_DYNAMIC_BUFFER_TYPE ||
3826 	    pipe_id >= IA_CSS_PIPE_ID_NUM) {
3827 		IA_CSS_LEAVE_ERR(-EINVAL);
3828 		return -EINVAL;
3829 	}
3830 
3831 	ret_err = ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
3832 	if (!ret_err) {
3833 		IA_CSS_LEAVE_ERR(-EINVAL);
3834 		return -EINVAL;
3835 	}
3836 
3837 	ret_err = ia_css_query_internal_queue_id(buf_type, thread_id, &queue_id);
3838 	if (!ret_err) {
3839 		IA_CSS_LEAVE_ERR(-EINVAL);
3840 		return -EINVAL;
3841 	}
3842 
3843 	if ((queue_id <= SH_CSS_INVALID_QUEUE_ID) || (queue_id >= SH_CSS_MAX_NUM_QUEUES)) {
3844 		IA_CSS_LEAVE_ERR(-EINVAL);
3845 		return -EINVAL;
3846 	}
3847 
3848 	if (!sh_css_sp_is_running()) {
3849 		IA_CSS_LOG("SP is not running!");
3850 		IA_CSS_LEAVE_ERR(-EBUSY);
3851 		/* SP is not running. The queues are not valid */
3852 		return -EBUSY;
3853 	}
3854 
3855 	pipeline = &pipe->pipeline;
3856 
3857 	assert(pipeline ||
3858 	       pipe_id == IA_CSS_PIPE_ID_COPY ||
3859 	       pipe_id == IA_CSS_PIPE_ID_ACC);
3860 
3861 	assert(sizeof(NULL) <= sizeof(ddr_buffer.kernel_ptr));
3862 	ddr_buffer.kernel_ptr = HOST_ADDRESS(NULL);
3863 	ddr_buffer.cookie_ptr = buffer->driver_cookie;
3864 	ddr_buffer.timing_data = buffer->timing_data;
3865 
3866 	if (buf_type == IA_CSS_BUFFER_TYPE_3A_STATISTICS) {
3867 		if (!buffer->data.stats_3a) {
3868 			IA_CSS_LEAVE_ERR(-EINVAL);
3869 			return -EINVAL;
3870 		}
3871 		ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.stats_3a);
3872 		ddr_buffer.payload.s3a = *buffer->data.stats_3a;
3873 	} else if (buf_type == IA_CSS_BUFFER_TYPE_DIS_STATISTICS) {
3874 		if (!buffer->data.stats_dvs) {
3875 			IA_CSS_LEAVE_ERR(-EINVAL);
3876 			return -EINVAL;
3877 		}
3878 		ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.stats_dvs);
3879 		ddr_buffer.payload.dis = *buffer->data.stats_dvs;
3880 	} else if (buf_type == IA_CSS_BUFFER_TYPE_METADATA) {
3881 		if (!buffer->data.metadata) {
3882 			IA_CSS_LEAVE_ERR(-EINVAL);
3883 			return -EINVAL;
3884 		}
3885 		ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.metadata);
3886 		ddr_buffer.payload.metadata = *buffer->data.metadata;
3887 	} else if (buf_type == IA_CSS_BUFFER_TYPE_INPUT_FRAME ||
3888 		   buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME ||
3889 		   buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME ||
3890 		   buf_type == IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME ||
3891 		   buf_type == IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME) {
3892 		if (!buffer->data.frame) {
3893 			IA_CSS_LEAVE_ERR(-EINVAL);
3894 			return -EINVAL;
3895 		}
3896 		ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.frame);
3897 		ddr_buffer.payload.frame.frame_data = buffer->data.frame->data;
3898 		ddr_buffer.payload.frame.flashed = 0;
3899 
3900 		ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
3901 				    "ia_css_pipe_enqueue_buffer() buf_type=%d, data(DDR address)=0x%x\n",
3902 				    buf_type, buffer->data.frame->data);
3903 
3904 	}
3905 
3906 	/* start of test for using rmgr for acq/rel memory */
3907 	p_vbuf.vptr = 0;
3908 	p_vbuf.count = 0;
3909 	p_vbuf.size = sizeof(struct sh_css_hmm_buffer);
3910 	h_vbuf = &p_vbuf;
3911 	/* TODO: change next to correct pool for optimization */
3912 	ia_css_rmgr_acq_vbuf(hmm_buffer_pool, &h_vbuf);
3913 
3914 	if ((!h_vbuf) || (h_vbuf->vptr == 0x0)) {
3915 		IA_CSS_LEAVE_ERR(-EINVAL);
3916 		return -EINVAL;
3917 	}
3918 
3919 	hmm_store(h_vbuf->vptr,
3920 		  (void *)(&ddr_buffer),
3921 		  sizeof(struct sh_css_hmm_buffer));
3922 	if (buf_type == IA_CSS_BUFFER_TYPE_3A_STATISTICS ||
3923 	    buf_type == IA_CSS_BUFFER_TYPE_DIS_STATISTICS ||
3924 	    buf_type == IA_CSS_BUFFER_TYPE_LACE_STATISTICS) {
3925 		if (!pipeline) {
3926 			ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &h_vbuf);
3927 			IA_CSS_LOG("pipeline is empty!");
3928 			IA_CSS_LEAVE_ERR(-EINVAL);
3929 			return -EINVAL;
3930 		}
3931 
3932 		for (stage = pipeline->stages; stage; stage = stage->next) {
3933 			/*
3934 			 * The SP will read the params after it got
3935 			 * empty 3a and dis
3936 			 */
3937 			if (STATS_ENABLED(stage)) {
3938 				/* there is a stage that needs it */
3939 				return_err = ia_css_bufq_enqueue_buffer(thread_id,
3940 									queue_id,
3941 									(uint32_t)h_vbuf->vptr);
3942 			}
3943 		}
3944 	} else if (buf_type == IA_CSS_BUFFER_TYPE_INPUT_FRAME ||
3945 		   buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME ||
3946 		   buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME ||
3947 		   buf_type == IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME ||
3948 		   buf_type == IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME ||
3949 		   buf_type == IA_CSS_BUFFER_TYPE_METADATA) {
3950 		return_err = ia_css_bufq_enqueue_buffer(thread_id,
3951 							queue_id,
3952 							(uint32_t)h_vbuf->vptr);
3953 		if (!return_err &&
3954 		    buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) {
3955 			IA_CSS_LOG("pfp: enqueued OF %d to q %d thread %d",
3956 				   ddr_buffer.payload.frame.frame_data,
3957 				   queue_id, thread_id);
3958 		}
3959 	}
3960 
3961 	if (!return_err) {
3962 		if (sh_css_hmm_buffer_record_acquire(
3963 			h_vbuf, buf_type,
3964 			HOST_ADDRESS(ddr_buffer.kernel_ptr))) {
3965 			IA_CSS_LOG("send vbuf=%p", h_vbuf);
3966 		} else {
3967 			return_err = -EINVAL;
3968 			IA_CSS_ERROR("hmm_buffer_record[]: no available slots\n");
3969 		}
3970 	}
3971 
3972 	/*
3973 	 * Tell the SP which queues are not empty,
3974 	 * by sending the software event.
3975 	 */
3976 	if (!return_err) {
3977 		if (!sh_css_sp_is_running()) {
3978 			/* SP is not running. The queues are not valid */
3979 			IA_CSS_LOG("SP is not running!");
3980 			IA_CSS_LEAVE_ERR(-EBUSY);
3981 			return -EBUSY;
3982 		}
3983 		return_err = ia_css_bufq_enqueue_psys_event(
3984 				 IA_CSS_PSYS_SW_EVENT_BUFFER_ENQUEUED,
3985 				 (uint8_t)thread_id,
3986 				 queue_id,
3987 				 0);
3988 	} else {
3989 		ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &h_vbuf);
3990 		IA_CSS_ERROR("buffer not enqueued");
3991 	}
3992 
3993 	IA_CSS_LEAVE("return value = %d", return_err);
3994 
3995 	return return_err;
3996 }
3997 
3998 /*
3999  * TODO: Free up the hmm memory space.
4000  */
4001 int
4002 ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe,
4003 			   struct ia_css_buffer *buffer)
4004 {
4005 	int return_err;
4006 	enum sh_css_queue_id queue_id;
4007 	ia_css_ptr ddr_buffer_addr = (ia_css_ptr)0;
4008 	struct sh_css_hmm_buffer ddr_buffer;
4009 	enum ia_css_buffer_type buf_type;
4010 	enum ia_css_pipe_id pipe_id;
4011 	unsigned int thread_id;
4012 	hrt_address kernel_ptr = 0;
4013 	bool ret_err;
4014 
4015 	IA_CSS_ENTER("pipe=%p, buffer=%p", pipe, buffer);
4016 
4017 	if ((!pipe) || (!buffer)) {
4018 		IA_CSS_LEAVE_ERR(-EINVAL);
4019 		return -EINVAL;
4020 	}
4021 
4022 	pipe_id = pipe->mode;
4023 
4024 	buf_type = buffer->type;
4025 
4026 	IA_CSS_LOG("pipe_id=%d, buf_type=%d", pipe_id, buf_type);
4027 
4028 	ddr_buffer.kernel_ptr = 0;
4029 
4030 	ret_err = ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
4031 	if (!ret_err) {
4032 		IA_CSS_LEAVE_ERR(-EINVAL);
4033 		return -EINVAL;
4034 	}
4035 
4036 	ret_err = ia_css_query_internal_queue_id(buf_type, thread_id, &queue_id);
4037 	if (!ret_err) {
4038 		IA_CSS_LEAVE_ERR(-EINVAL);
4039 		return -EINVAL;
4040 	}
4041 
4042 	if ((queue_id <= SH_CSS_INVALID_QUEUE_ID) || (queue_id >= SH_CSS_MAX_NUM_QUEUES)) {
4043 		IA_CSS_LEAVE_ERR(-EINVAL);
4044 		return -EINVAL;
4045 	}
4046 
4047 	if (!sh_css_sp_is_running()) {
4048 		IA_CSS_LOG("SP is not running!");
4049 		IA_CSS_LEAVE_ERR(-EBUSY);
4050 		/* SP is not running. The queues are not valid */
4051 		return -EBUSY;
4052 	}
4053 
4054 	return_err = ia_css_bufq_dequeue_buffer(queue_id,
4055 						(uint32_t *)&ddr_buffer_addr);
4056 
4057 	if (!return_err) {
4058 		struct ia_css_frame *frame;
4059 		struct sh_css_hmm_buffer_record *hmm_buffer_record = NULL;
4060 
4061 		IA_CSS_LOG("receive vbuf=%x", (int)ddr_buffer_addr);
4062 
4063 		/* Validate the ddr_buffer_addr and buf_type */
4064 		hmm_buffer_record = sh_css_hmm_buffer_record_validate(
4065 		    ddr_buffer_addr, buf_type);
4066 		if (hmm_buffer_record) {
4067 			/*
4068 			 * valid hmm_buffer_record found. Save the kernel_ptr
4069 			 * for validation after performing hmm_load.  The
4070 			 * vbuf handle and buffer_record can be released.
4071 			 */
4072 			kernel_ptr = hmm_buffer_record->kernel_ptr;
4073 			ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &hmm_buffer_record->h_vbuf);
4074 			sh_css_hmm_buffer_record_reset(hmm_buffer_record);
4075 		} else {
4076 			IA_CSS_ERROR("hmm_buffer_record not found (0x%x) buf_type(%d)",
4077 				     ddr_buffer_addr, buf_type);
4078 			IA_CSS_LEAVE_ERR(-EINVAL);
4079 			return -EINVAL;
4080 		}
4081 
4082 		hmm_load(ddr_buffer_addr,
4083 			 &ddr_buffer,
4084 			 sizeof(struct sh_css_hmm_buffer));
4085 
4086 		/*
4087 		 * if the kernel_ptr is 0 or an invalid, return an error.
4088 		 * do not access the buffer via the kernal_ptr.
4089 		 */
4090 		if ((ddr_buffer.kernel_ptr == 0) ||
4091 		    (kernel_ptr != HOST_ADDRESS(ddr_buffer.kernel_ptr))) {
4092 			IA_CSS_ERROR("kernel_ptr invalid");
4093 			IA_CSS_ERROR("expected: (0x%llx)", (u64)kernel_ptr);
4094 			IA_CSS_ERROR("actual: (0x%llx)", (u64)HOST_ADDRESS(ddr_buffer.kernel_ptr));
4095 			IA_CSS_ERROR("buf_type: %d\n", buf_type);
4096 			IA_CSS_LEAVE_ERR(-EINVAL);
4097 			return -EINVAL;
4098 		}
4099 
4100 		if (ddr_buffer.kernel_ptr != 0) {
4101 			/*
4102 			 * buffer->exp_id : all instances to be removed later
4103 			 * once the driver change is completed. See patch #5758
4104 			 * for reference
4105 			 */
4106 			buffer->exp_id = 0;
4107 			buffer->driver_cookie = ddr_buffer.cookie_ptr;
4108 			buffer->timing_data = ddr_buffer.timing_data;
4109 
4110 			if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME ||
4111 			    buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) {
4112 				buffer->isys_eof_clock_tick.ticks = ddr_buffer.isys_eof_clock_tick;
4113 			}
4114 
4115 			switch (buf_type) {
4116 			case IA_CSS_BUFFER_TYPE_INPUT_FRAME:
4117 			case IA_CSS_BUFFER_TYPE_OUTPUT_FRAME:
4118 			case IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME:
4119 				if (pipe && pipe->stop_requested) {
4120 #if !defined(ISP2401)
4121 					/*
4122 					 * free mipi frames only for old input
4123 					 * system for 2401 it is done in
4124 					 * ia_css_stream_destroy call
4125 					 */
4126 					return_err = free_mipi_frames(pipe);
4127 					if (return_err) {
4128 						IA_CSS_LOG("free_mipi_frames() failed");
4129 						IA_CSS_LEAVE_ERR(return_err);
4130 						return return_err;
4131 					}
4132 #endif
4133 					pipe->stop_requested = false;
4134 				}
4135 				fallthrough;
4136 			case IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME:
4137 			case IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME:
4138 				frame = (struct ia_css_frame *)HOST_ADDRESS(ddr_buffer.kernel_ptr);
4139 				buffer->data.frame = frame;
4140 				buffer->exp_id = ddr_buffer.payload.frame.exp_id;
4141 				frame->exp_id = ddr_buffer.payload.frame.exp_id;
4142 				frame->isp_config_id = ddr_buffer.payload.frame.isp_parameters_id;
4143 				if (ddr_buffer.payload.frame.flashed == 1)
4144 					frame->flash_state =
4145 					    IA_CSS_FRAME_FLASH_STATE_PARTIAL;
4146 				if (ddr_buffer.payload.frame.flashed == 2)
4147 					frame->flash_state =
4148 					    IA_CSS_FRAME_FLASH_STATE_FULL;
4149 				frame->valid = pipe->num_invalid_frames == 0;
4150 				if (!frame->valid)
4151 					pipe->num_invalid_frames--;
4152 
4153 				if (frame->info.format == IA_CSS_FRAME_FORMAT_BINARY_8) {
4154 #ifdef ISP2401
4155 					frame->planes.binary.size = frame->data_bytes;
4156 #else
4157 					frame->planes.binary.size =
4158 					    sh_css_sp_get_binary_copy_size();
4159 #endif
4160 				}
4161 				if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) {
4162 					IA_CSS_LOG("pfp: dequeued OF %d with config id %d thread %d",
4163 						   frame->data, frame->isp_config_id, thread_id);
4164 				}
4165 
4166 				ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
4167 						    "ia_css_pipe_dequeue_buffer() buf_type=%d, data(DDR address)=0x%x\n",
4168 						    buf_type, buffer->data.frame->data);
4169 
4170 				break;
4171 			case IA_CSS_BUFFER_TYPE_3A_STATISTICS:
4172 				buffer->data.stats_3a =
4173 				    (struct ia_css_isp_3a_statistics *)HOST_ADDRESS(ddr_buffer.kernel_ptr);
4174 				buffer->exp_id = ddr_buffer.payload.s3a.exp_id;
4175 				buffer->data.stats_3a->exp_id = ddr_buffer.payload.s3a.exp_id;
4176 				buffer->data.stats_3a->isp_config_id = ddr_buffer.payload.s3a.isp_config_id;
4177 				break;
4178 			case IA_CSS_BUFFER_TYPE_DIS_STATISTICS:
4179 				buffer->data.stats_dvs =
4180 				    (struct ia_css_isp_dvs_statistics *)
4181 				    HOST_ADDRESS(ddr_buffer.kernel_ptr);
4182 				buffer->exp_id = ddr_buffer.payload.dis.exp_id;
4183 				buffer->data.stats_dvs->exp_id = ddr_buffer.payload.dis.exp_id;
4184 				break;
4185 			case IA_CSS_BUFFER_TYPE_LACE_STATISTICS:
4186 				break;
4187 			case IA_CSS_BUFFER_TYPE_METADATA:
4188 				buffer->data.metadata =
4189 				    (struct ia_css_metadata *)HOST_ADDRESS(ddr_buffer.kernel_ptr);
4190 				buffer->exp_id = ddr_buffer.payload.metadata.exp_id;
4191 				buffer->data.metadata->exp_id = ddr_buffer.payload.metadata.exp_id;
4192 				break;
4193 			default:
4194 				return_err = -EINVAL;
4195 				break;
4196 			}
4197 		}
4198 	}
4199 
4200 	/*
4201 	 * Tell the SP which queues are not full,
4202 	 * by sending the software event.
4203 	 */
4204 	if (!return_err) {
4205 		if (!sh_css_sp_is_running()) {
4206 			IA_CSS_LOG("SP is not running!");
4207 			IA_CSS_LEAVE_ERR(-EBUSY);
4208 			/* SP is not running. The queues are not valid */
4209 			return -EBUSY;
4210 		}
4211 		ia_css_bufq_enqueue_psys_event(
4212 		    IA_CSS_PSYS_SW_EVENT_BUFFER_DEQUEUED,
4213 		    0,
4214 		    queue_id,
4215 		    0);
4216 	}
4217 	IA_CSS_LEAVE("buffer=%p", buffer);
4218 
4219 	return return_err;
4220 }
4221 
4222 /*
4223  * Cannot Move this to event module as it is of ia_css_event_type which is declared in ia_css.h
4224  * TODO: modify and move it if possible.
4225  *
4226  * !!!IMPORTANT!!! KEEP THE FOLLOWING IN SYNC:
4227  * 1) "enum ia_css_event_type"					(ia_css_event_public.h)
4228  * 2) "enum sh_css_sp_event_type"				(sh_css_internal.h)
4229  * 3) "enum ia_css_event_type event_id_2_event_mask"		(event_handler.sp.c)
4230  * 4) "enum ia_css_event_type convert_event_sp_to_host_domain"	(sh_css.c)
4231  */
4232 static enum ia_css_event_type convert_event_sp_to_host_domain[] = {
4233 	IA_CSS_EVENT_TYPE_OUTPUT_FRAME_DONE,	/* Output frame ready. */
4234 	IA_CSS_EVENT_TYPE_SECOND_OUTPUT_FRAME_DONE,	/* Second output frame ready. */
4235 	IA_CSS_EVENT_TYPE_VF_OUTPUT_FRAME_DONE,	/* Viewfinder Output frame ready. */
4236 	IA_CSS_EVENT_TYPE_SECOND_VF_OUTPUT_FRAME_DONE,	/* Second viewfinder Output frame ready. */
4237 	IA_CSS_EVENT_TYPE_3A_STATISTICS_DONE,	/* Indication that 3A statistics are available. */
4238 	IA_CSS_EVENT_TYPE_DIS_STATISTICS_DONE,	/* Indication that DIS statistics are available. */
4239 	IA_CSS_EVENT_TYPE_PIPELINE_DONE,	/* Pipeline Done event, sent after last pipeline stage. */
4240 	IA_CSS_EVENT_TYPE_FRAME_TAGGED,		/* Frame tagged. */
4241 	IA_CSS_EVENT_TYPE_INPUT_FRAME_DONE,	/* Input frame ready. */
4242 	IA_CSS_EVENT_TYPE_METADATA_DONE,	/* Metadata ready. */
4243 	IA_CSS_EVENT_TYPE_LACE_STATISTICS_DONE,	/* Indication that LACE statistics are available. */
4244 	IA_CSS_EVENT_TYPE_ACC_STAGE_COMPLETE,	/* Extension stage executed. */
4245 	IA_CSS_EVENT_TYPE_TIMER,		/* Timing measurement data. */
4246 	IA_CSS_EVENT_TYPE_PORT_EOF,		/* End Of Frame event, sent when in buffered sensor mode. */
4247 	IA_CSS_EVENT_TYPE_FW_WARNING,		/* Performance warning encountered by FW */
4248 	IA_CSS_EVENT_TYPE_FW_ASSERT,		/* Assertion hit by FW */
4249 	0,					/* error if sp passes  SH_CSS_SP_EVENT_NR_OF_TYPES as a valid event. */
4250 };
4251 
4252 int
4253 ia_css_dequeue_psys_event(struct ia_css_event *event)
4254 {
4255 	enum ia_css_pipe_id pipe_id = 0;
4256 	u8 payload[4] = {0, 0, 0, 0};
4257 	int ret_err;
4258 
4259 	/*
4260 	 * TODO:
4261 	 * a) use generic decoding function , same as the one used by sp.
4262 	 * b) group decode and dequeue into eventQueue module
4263 	 *
4264 	 * We skip the IA_CSS_ENTER logging call
4265 	 * to avoid flooding the logs when the host application
4266 	 * uses polling.
4267 	 */
4268 	if (!event)
4269 		return -EINVAL;
4270 
4271 	/* SP is not running. The queues are not valid */
4272 	if (!sh_css_sp_is_running())
4273 		return -EBUSY;
4274 
4275 	/* dequeue the event (if any) from the psys event queue */
4276 	ret_err = ia_css_bufq_dequeue_psys_event(payload);
4277 	if (ret_err)
4278 		return ret_err;
4279 
4280 	IA_CSS_LOG("event dequeued from psys event queue");
4281 
4282 	/* Tell the SP that we dequeued an event from the event queue. */
4283 	ia_css_bufq_enqueue_psys_event(
4284 	    IA_CSS_PSYS_SW_EVENT_EVENT_DEQUEUED, 0, 0, 0);
4285 
4286 	/*
4287 	 * Events are decoded into 4 bytes of payload, the first byte
4288 	 * contains the sp event type. This is converted to a host enum.
4289 	 * TODO: can this enum conversion be eliminated
4290 	 */
4291 	event->type = convert_event_sp_to_host_domain[payload[0]];
4292 	/* Some sane default values since not all events use all fields. */
4293 	event->pipe = NULL;
4294 	event->port = MIPI_PORT0_ID;
4295 	event->exp_id = 0;
4296 	event->fw_warning = IA_CSS_FW_WARNING_NONE;
4297 	event->fw_handle = 0;
4298 	event->timer_data = 0;
4299 	event->timer_code = 0;
4300 	event->timer_subcode = 0;
4301 
4302 	if (event->type == IA_CSS_EVENT_TYPE_TIMER) {
4303 		/*
4304 		 * timer event ??? get the 2nd event and decode the data
4305 		 * into the event struct
4306 		 */
4307 		u32 tmp_data;
4308 		/* 1st event: LSB 16-bit timer data and code */
4309 		event->timer_data = ((payload[1] & 0xFF) | ((payload[3] & 0xFF) << 8));
4310 		event->timer_code = payload[2];
4311 		payload[0] = payload[1] = payload[2] = payload[3] = 0;
4312 		ret_err = ia_css_bufq_dequeue_psys_event(payload);
4313 		if (ret_err) {
4314 			/* no 2nd event ??? an error */
4315 			/*
4316 			 * Putting IA_CSS_ERROR is resulting in failures in
4317 			 * Merrifield smoke testing
4318 			 */
4319 			IA_CSS_WARNING("Timer: Error de-queuing the 2nd TIMER event!!!\n");
4320 			return ret_err;
4321 		}
4322 		ia_css_bufq_enqueue_psys_event(
4323 		    IA_CSS_PSYS_SW_EVENT_EVENT_DEQUEUED, 0, 0, 0);
4324 		event->type = convert_event_sp_to_host_domain[payload[0]];
4325 		/* It's a timer */
4326 		if (event->type == IA_CSS_EVENT_TYPE_TIMER) {
4327 			/* 2nd event data: MSB 16-bit timer and subcode */
4328 			tmp_data = ((payload[1] & 0xFF) | ((payload[3] & 0xFF) << 8));
4329 			event->timer_data |= (tmp_data << 16);
4330 			event->timer_subcode = payload[2];
4331 		} else {
4332 			/*
4333 			 * It's a non timer event. So clear first half of the
4334 			 * timer event data.
4335 			 * If the second part of the TIMER event is not
4336 			 * received, we discard the first half of the timer
4337 			 * data and process the non timer event without
4338 			 * affecting the flow. So the non timer event falls
4339 			 * through the code.
4340 			 */
4341 			event->timer_data = 0;
4342 			event->timer_code = 0;
4343 			event->timer_subcode = 0;
4344 			IA_CSS_ERROR("Missing 2nd timer event. Timer event discarded");
4345 		}
4346 	}
4347 	if (event->type == IA_CSS_EVENT_TYPE_PORT_EOF) {
4348 		event->port = (enum mipi_port_id)payload[1];
4349 		event->exp_id = payload[3];
4350 	} else if (event->type == IA_CSS_EVENT_TYPE_FW_WARNING) {
4351 		event->fw_warning = (enum ia_css_fw_warning)payload[1];
4352 		/* exp_id is only available in these warning types */
4353 		if (event->fw_warning == IA_CSS_FW_WARNING_EXP_ID_LOCKED ||
4354 		    event->fw_warning == IA_CSS_FW_WARNING_TAG_EXP_ID_FAILED)
4355 			event->exp_id = payload[3];
4356 	} else if (event->type == IA_CSS_EVENT_TYPE_FW_ASSERT) {
4357 		event->fw_assert_module_id = payload[1]; /* module */
4358 		event->fw_assert_line_no = (payload[2] << 8) + payload[3];
4359 		/* payload[2] is line_no>>8, payload[3] is line_no&0xff */
4360 	} else if (event->type != IA_CSS_EVENT_TYPE_TIMER) {
4361 		/*
4362 		 * pipe related events.
4363 		 * payload[1] contains the pipe_num,
4364 		 * payload[2] contains the pipe_id. These are different.
4365 		 */
4366 		event->pipe = find_pipe_by_num(payload[1]);
4367 		pipe_id = (enum ia_css_pipe_id)payload[2];
4368 		/* Check to see if pipe still exists */
4369 		if (!event->pipe)
4370 			return -EBUSY;
4371 
4372 		if (event->type == IA_CSS_EVENT_TYPE_FRAME_TAGGED) {
4373 			/* find the capture pipe that goes with this */
4374 			int i, n;
4375 
4376 			n = event->pipe->stream->num_pipes;
4377 			for (i = 0; i < n; i++) {
4378 				struct ia_css_pipe *p =
4379 					    event->pipe->stream->pipes[i];
4380 				if (p->config.mode == IA_CSS_PIPE_MODE_CAPTURE) {
4381 					event->pipe = p;
4382 					break;
4383 				}
4384 			}
4385 			event->exp_id = payload[3];
4386 		}
4387 		if (event->type == IA_CSS_EVENT_TYPE_ACC_STAGE_COMPLETE) {
4388 			/* payload[3] contains the acc fw handle. */
4389 			u32 stage_num = (uint32_t)payload[3];
4390 
4391 			ret_err = ia_css_pipeline_get_fw_from_stage(
4392 				      &event->pipe->pipeline,
4393 				      stage_num,
4394 				      &event->fw_handle);
4395 			if (ret_err) {
4396 				IA_CSS_ERROR("Invalid stage num received for ACC event. stage_num:%u",
4397 					     stage_num);
4398 				return ret_err;
4399 			}
4400 		}
4401 	}
4402 
4403 	if (event->pipe)
4404 		IA_CSS_LEAVE("event_id=%d, pipe_id=%d", event->type, pipe_id);
4405 	else
4406 		IA_CSS_LEAVE("event_id=%d", event->type);
4407 
4408 	return 0;
4409 }
4410 
4411 int
4412 ia_css_dequeue_isys_event(struct ia_css_event *event)
4413 {
4414 	u8 payload[4] = {0, 0, 0, 0};
4415 	int err = 0;
4416 
4417 	/*
4418 	 * We skip the IA_CSS_ENTER logging call
4419 	 * to avoid flooding the logs when the host application
4420 	 * uses polling.
4421 	 */
4422 	if (!event)
4423 		return -EINVAL;
4424 
4425 	/* SP is not running. The queues are not valid */
4426 	if (!sh_css_sp_is_running())
4427 		return -EBUSY;
4428 
4429 	err = ia_css_bufq_dequeue_isys_event(payload);
4430 	if (err)
4431 		return err;
4432 
4433 	IA_CSS_LOG("event dequeued from isys event queue");
4434 
4435 	/* Update SP state to indicate that element was dequeued. */
4436 	ia_css_bufq_enqueue_isys_event(IA_CSS_ISYS_SW_EVENT_EVENT_DEQUEUED);
4437 
4438 	/* Fill return struct with appropriate info */
4439 	event->type = IA_CSS_EVENT_TYPE_PORT_EOF;
4440 	/* EOF events are associated with a CSI port, not with a pipe */
4441 	event->pipe = NULL;
4442 	event->port = payload[1];
4443 	event->exp_id = payload[3];
4444 
4445 	IA_CSS_LEAVE_ERR(err);
4446 	return err;
4447 }
4448 
4449 static void
4450 acc_start(struct ia_css_pipe *pipe)
4451 {
4452 	assert(pipe);
4453 	assert(pipe->stream);
4454 
4455 	start_pipe(pipe, SH_CSS_PIPE_CONFIG_OVRD_NO_OVRD,
4456 		   pipe->stream->config.mode);
4457 }
4458 
4459 static int
4460 sh_css_pipe_start(struct ia_css_stream *stream)
4461 {
4462 	int err = 0;
4463 
4464 	struct ia_css_pipe *pipe;
4465 	enum ia_css_pipe_id pipe_id;
4466 	unsigned int thread_id;
4467 
4468 	IA_CSS_ENTER_PRIVATE("stream = %p", stream);
4469 
4470 	if (!stream) {
4471 		IA_CSS_LEAVE_ERR(-EINVAL);
4472 		return -EINVAL;
4473 	}
4474 	pipe = stream->last_pipe;
4475 	if (!pipe) {
4476 		IA_CSS_LEAVE_ERR(-EINVAL);
4477 		return -EINVAL;
4478 	}
4479 
4480 	pipe_id = pipe->mode;
4481 
4482 	if (stream->started) {
4483 		IA_CSS_WARNING("Cannot start stream that is already started");
4484 		IA_CSS_LEAVE_ERR(err);
4485 		return err;
4486 	}
4487 
4488 	pipe->stop_requested = false;
4489 
4490 	switch (pipe_id) {
4491 	case IA_CSS_PIPE_ID_PREVIEW:
4492 		err = preview_start(pipe);
4493 		break;
4494 	case IA_CSS_PIPE_ID_VIDEO:
4495 		err = video_start(pipe);
4496 		break;
4497 	case IA_CSS_PIPE_ID_CAPTURE:
4498 		err = capture_start(pipe);
4499 		break;
4500 	case IA_CSS_PIPE_ID_YUVPP:
4501 		err = yuvpp_start(pipe);
4502 		break;
4503 	case IA_CSS_PIPE_ID_ACC:
4504 		acc_start(pipe);
4505 		break;
4506 	default:
4507 		err = -EINVAL;
4508 	}
4509 	/* DH regular multi pipe - not continuous mode: start the next pipes too */
4510 	if (!stream->config.continuous) {
4511 		int i;
4512 
4513 		for (i = 1; i < stream->num_pipes && 0 == err ; i++) {
4514 			switch (stream->pipes[i]->mode) {
4515 			case IA_CSS_PIPE_ID_PREVIEW:
4516 				stream->pipes[i]->stop_requested = false;
4517 				err = preview_start(stream->pipes[i]);
4518 				break;
4519 			case IA_CSS_PIPE_ID_VIDEO:
4520 				stream->pipes[i]->stop_requested = false;
4521 				err = video_start(stream->pipes[i]);
4522 				break;
4523 			case IA_CSS_PIPE_ID_CAPTURE:
4524 				stream->pipes[i]->stop_requested = false;
4525 				err = capture_start(stream->pipes[i]);
4526 				break;
4527 			case IA_CSS_PIPE_ID_YUVPP:
4528 				stream->pipes[i]->stop_requested = false;
4529 				err = yuvpp_start(stream->pipes[i]);
4530 				break;
4531 			case IA_CSS_PIPE_ID_ACC:
4532 				stream->pipes[i]->stop_requested = false;
4533 				acc_start(stream->pipes[i]);
4534 				break;
4535 			default:
4536 				err = -EINVAL;
4537 			}
4538 		}
4539 	}
4540 	if (err) {
4541 		IA_CSS_LEAVE_ERR_PRIVATE(err);
4542 		return err;
4543 	}
4544 
4545 	/*
4546 	 * Force ISP parameter calculation after a mode change
4547 	 * Acceleration API examples pass NULL for stream but they
4548 	 * don't use ISP parameters anyway. So this should be okay.
4549 	 * The SP binary (jpeg) copy does not use any parameters.
4550 	 */
4551 	if (!copy_on_sp(pipe)) {
4552 		sh_css_invalidate_params(stream);
4553 		err = sh_css_param_update_isp_params(pipe,
4554 						     stream->isp_params_configs, true, NULL);
4555 		if (err) {
4556 			IA_CSS_LEAVE_ERR_PRIVATE(err);
4557 			return err;
4558 		}
4559 	}
4560 
4561 	ia_css_debug_pipe_graph_dump_epilogue();
4562 
4563 	ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
4564 
4565 	if (!sh_css_sp_is_running()) {
4566 		IA_CSS_LEAVE_ERR_PRIVATE(-EBUSY);
4567 		/* SP is not running. The queues are not valid */
4568 		return -EBUSY;
4569 	}
4570 	ia_css_bufq_enqueue_psys_event(IA_CSS_PSYS_SW_EVENT_START_STREAM,
4571 				       (uint8_t)thread_id, 0, 0);
4572 
4573 	/* DH regular multi pipe - not continuous mode: enqueue event to the next pipes too */
4574 	if (!stream->config.continuous) {
4575 		int i;
4576 
4577 		for (i = 1; i < stream->num_pipes; i++) {
4578 			ia_css_pipeline_get_sp_thread_id(
4579 			    ia_css_pipe_get_pipe_num(stream->pipes[i]),
4580 			    &thread_id);
4581 			ia_css_bufq_enqueue_psys_event(
4582 			    IA_CSS_PSYS_SW_EVENT_START_STREAM,
4583 			    (uint8_t)thread_id, 0, 0);
4584 		}
4585 	}
4586 
4587 	/* in case of continuous capture mode, we also start capture thread and copy thread*/
4588 	if (pipe->stream->config.continuous) {
4589 		struct ia_css_pipe *copy_pipe = NULL;
4590 
4591 		if (pipe_id == IA_CSS_PIPE_ID_PREVIEW)
4592 			copy_pipe = pipe->pipe_settings.preview.copy_pipe;
4593 		else if (pipe_id == IA_CSS_PIPE_ID_VIDEO)
4594 			copy_pipe = pipe->pipe_settings.video.copy_pipe;
4595 
4596 		if (!copy_pipe) {
4597 			IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
4598 			return -EINVAL;
4599 		}
4600 		ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(copy_pipe),
4601 						 &thread_id);
4602 		/* by the time we reach here q is initialized and handle is available.*/
4603 		ia_css_bufq_enqueue_psys_event(
4604 		    IA_CSS_PSYS_SW_EVENT_START_STREAM,
4605 		    (uint8_t)thread_id, 0,  0);
4606 	}
4607 	if (pipe->stream->cont_capt) {
4608 		struct ia_css_pipe *capture_pipe = NULL;
4609 
4610 		if (pipe_id == IA_CSS_PIPE_ID_PREVIEW)
4611 			capture_pipe = pipe->pipe_settings.preview.capture_pipe;
4612 		else if (pipe_id == IA_CSS_PIPE_ID_VIDEO)
4613 			capture_pipe = pipe->pipe_settings.video.capture_pipe;
4614 
4615 		if (!capture_pipe) {
4616 			IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
4617 			return -EINVAL;
4618 		}
4619 		ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(capture_pipe),
4620 						 &thread_id);
4621 		/* by the time we reach here q is initialized and handle is available.*/
4622 		ia_css_bufq_enqueue_psys_event(
4623 		    IA_CSS_PSYS_SW_EVENT_START_STREAM,
4624 		    (uint8_t)thread_id, 0,  0);
4625 	}
4626 
4627 	/* in case of PREVIEW mode, check whether QOS acc_pipe is available, then start the qos pipe */
4628 	if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) {
4629 		struct ia_css_pipe *acc_pipe = NULL;
4630 
4631 		acc_pipe = pipe->pipe_settings.preview.acc_pipe;
4632 
4633 		if (acc_pipe) {
4634 			ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(acc_pipe),
4635 							 &thread_id);
4636 			/* by the time we reach here q is initialized and handle is available.*/
4637 			ia_css_bufq_enqueue_psys_event(
4638 			    IA_CSS_PSYS_SW_EVENT_START_STREAM,
4639 			    (uint8_t)thread_id, 0, 0);
4640 		}
4641 	}
4642 
4643 	stream->started = true;
4644 
4645 	IA_CSS_LEAVE_ERR_PRIVATE(err);
4646 	return err;
4647 }
4648 
4649 /* ISP2400 */
4650 void
4651 sh_css_enable_cont_capt(bool enable, bool stop_copy_preview)
4652 {
4653 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
4654 			    "sh_css_enable_cont_capt() enter: enable=%d\n", enable);
4655 //my_css.cont_capt = enable;
4656 	my_css.stop_copy_preview = stop_copy_preview;
4657 }
4658 
4659 bool
4660 sh_css_continuous_is_enabled(uint8_t pipe_num)
4661 {
4662 	struct ia_css_pipe *pipe;
4663 	bool continuous;
4664 
4665 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
4666 			    "sh_css_continuous_is_enabled() enter: pipe_num=%d\n", pipe_num);
4667 
4668 	pipe = find_pipe_by_num(pipe_num);
4669 	continuous = pipe && pipe->stream->config.continuous;
4670 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
4671 			    "sh_css_continuous_is_enabled() leave: enable=%d\n",
4672 			    continuous);
4673 	return continuous;
4674 }
4675 
4676 /* ISP2400 */
4677 int
4678 ia_css_stream_get_max_buffer_depth(struct ia_css_stream *stream,
4679 				   int *buffer_depth)
4680 {
4681 	if (!buffer_depth)
4682 		return -EINVAL;
4683 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_get_max_buffer_depth() enter: void\n");
4684 	(void)stream;
4685 	*buffer_depth = NUM_CONTINUOUS_FRAMES;
4686 	return 0;
4687 }
4688 
4689 int
4690 ia_css_stream_set_buffer_depth(struct ia_css_stream *stream, int buffer_depth)
4691 {
4692 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_set_buffer_depth() enter: num_frames=%d\n", buffer_depth);
4693 	(void)stream;
4694 	if (buffer_depth > NUM_CONTINUOUS_FRAMES || buffer_depth < 1)
4695 		return -EINVAL;
4696 	/* ok, value allowed */
4697 	stream->config.target_num_cont_raw_buf = buffer_depth;
4698 	/* TODO: check what to regarding initialization */
4699 	return 0;
4700 }
4701 
4702 /* ISP2401 */
4703 int
4704 ia_css_stream_get_buffer_depth(struct ia_css_stream *stream,
4705 			       int *buffer_depth)
4706 {
4707 	if (!buffer_depth)
4708 		return -EINVAL;
4709 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_get_buffer_depth() enter: void\n");
4710 	(void)stream;
4711 	*buffer_depth = stream->config.target_num_cont_raw_buf;
4712 	return 0;
4713 }
4714 
4715 #if !defined(ISP2401)
4716 unsigned int
4717 sh_css_get_mipi_sizes_for_check(const unsigned int port, const unsigned int idx)
4718 {
4719 	OP___assert(port < N_CSI_PORTS);
4720 	OP___assert(idx  < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT);
4721 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
4722 			    "sh_css_get_mipi_sizes_for_check(port %d, idx %d): %d\n",
4723 			    port, idx, my_css.mipi_sizes_for_check[port][idx]);
4724 	return my_css.mipi_sizes_for_check[port][idx];
4725 }
4726 #endif
4727 
4728 static int sh_css_pipe_configure_output(
4729     struct ia_css_pipe *pipe,
4730     unsigned int width,
4731     unsigned int height,
4732     unsigned int padded_width,
4733     enum ia_css_frame_format format,
4734     unsigned int idx)
4735 {
4736 	int err = 0;
4737 
4738 	IA_CSS_ENTER_PRIVATE("pipe = %p, width = %d, height = %d, padded width = %d, format = %d, idx = %d",
4739 			     pipe, width, height, padded_width, format, idx);
4740 	if (!pipe) {
4741 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
4742 		return -EINVAL;
4743 	}
4744 
4745 	err = ia_css_util_check_res(width, height);
4746 	if (err) {
4747 		IA_CSS_LEAVE_ERR_PRIVATE(err);
4748 		return err;
4749 	}
4750 	if (pipe->output_info[idx].res.width != width ||
4751 	    pipe->output_info[idx].res.height != height ||
4752 	    pipe->output_info[idx].format != format) {
4753 		ia_css_frame_info_init(
4754 		    &pipe->output_info[idx],
4755 		    width,
4756 		    height,
4757 		    format,
4758 		    padded_width);
4759 	}
4760 	IA_CSS_LEAVE_ERR_PRIVATE(0);
4761 	return 0;
4762 }
4763 
4764 static int
4765 sh_css_pipe_get_shading_info(struct ia_css_pipe *pipe,
4766 			     struct ia_css_shading_info *shading_info,
4767 			     struct ia_css_pipe_config *pipe_config)
4768 {
4769 	int err = 0;
4770 	struct ia_css_binary *binary = NULL;
4771 
4772 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
4773 			    "sh_css_pipe_get_shading_info() enter:\n");
4774 
4775 	binary = ia_css_pipe_get_shading_correction_binary(pipe);
4776 
4777 	if (binary) {
4778 		err = ia_css_binary_get_shading_info(binary,
4779 						     IA_CSS_SHADING_CORRECTION_TYPE_1,
4780 						     pipe->required_bds_factor,
4781 						     (const struct ia_css_stream_config *)&pipe->stream->config,
4782 						     shading_info, pipe_config);
4783 
4784 		/*
4785 		 * Other function calls can be added here when other shading
4786 		 * correction types will be added in the future.
4787 		 */
4788 	} else {
4789 		/*
4790 		 * When the pipe does not have a binary which has the shading
4791 		 * correction, this function does not need to fill the shading
4792 		 * information. It is not a error case, and then
4793 		 * this function should return 0.
4794 		 */
4795 		memset(shading_info, 0, sizeof(*shading_info));
4796 	}
4797 	return err;
4798 }
4799 
4800 static int
4801 sh_css_pipe_get_grid_info(struct ia_css_pipe *pipe,
4802 			  struct ia_css_grid_info *info)
4803 {
4804 	int err = 0;
4805 	struct ia_css_binary *binary = NULL;
4806 
4807 	assert(pipe);
4808 	assert(info);
4809 
4810 	IA_CSS_ENTER_PRIVATE("");
4811 
4812 	binary = ia_css_pipe_get_s3a_binary(pipe);
4813 
4814 	if (binary) {
4815 		err = ia_css_binary_3a_grid_info(binary, info, pipe);
4816 		if (err)
4817 			goto err;
4818 	} else {
4819 		memset(&info->s3a_grid, 0, sizeof(info->s3a_grid));
4820 	}
4821 
4822 	binary = ia_css_pipe_get_sdis_binary(pipe);
4823 
4824 	if (binary) {
4825 		ia_css_binary_dvs_grid_info(binary, info, pipe);
4826 		ia_css_binary_dvs_stat_grid_info(binary, info, pipe);
4827 	} else {
4828 		memset(&info->dvs_grid, 0, sizeof(info->dvs_grid));
4829 		memset(&info->dvs_grid.dvs_stat_grid_info, 0,
4830 			   sizeof(info->dvs_grid.dvs_stat_grid_info));
4831 	}
4832 
4833 	if (binary) {
4834 		/* copy pipe does not have ISP binary*/
4835 		info->isp_in_width = binary->internal_frame_info.res.width;
4836 		info->isp_in_height = binary->internal_frame_info.res.height;
4837 	}
4838 
4839 	info->vamem_type = IA_CSS_VAMEM_TYPE_2;
4840 
4841 err:
4842 	IA_CSS_LEAVE_ERR_PRIVATE(err);
4843 	return err;
4844 }
4845 
4846 /* ISP2401 */
4847 /*
4848  * @brief Check if a format is supported by the pipe.
4849  *
4850  */
4851 static int
4852 ia_css_pipe_check_format(struct ia_css_pipe *pipe,
4853 			 enum ia_css_frame_format format)
4854 {
4855 	const enum ia_css_frame_format *supported_formats;
4856 	int number_of_formats;
4857 	int found = 0;
4858 	int i;
4859 
4860 	IA_CSS_ENTER_PRIVATE("");
4861 
4862 	if (NULL == pipe || NULL == pipe->pipe_settings.video.video_binary.info) {
4863 		IA_CSS_ERROR("Pipe or binary info is not set");
4864 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
4865 		return -EINVAL;
4866 	}
4867 
4868 	supported_formats = pipe->pipe_settings.video.video_binary.info->output_formats;
4869 	number_of_formats = sizeof(pipe->pipe_settings.video.video_binary.info->output_formats) / sizeof(enum ia_css_frame_format);
4870 
4871 	for (i = 0; i < number_of_formats && !found; i++) {
4872 		if (supported_formats[i] == format) {
4873 			found = 1;
4874 			break;
4875 		}
4876 	}
4877 	if (!found) {
4878 		IA_CSS_ERROR("Requested format is not supported by binary");
4879 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
4880 		return -EINVAL;
4881 	}
4882 	IA_CSS_LEAVE_ERR_PRIVATE(0);
4883 	return 0;
4884 }
4885 
4886 static int load_video_binaries(struct ia_css_pipe *pipe)
4887 {
4888 	struct ia_css_frame_info video_in_info, tnr_info,
4889 		       *video_vf_info, video_bds_out_info, *pipe_out_info, *pipe_vf_out_info;
4890 	bool online;
4891 	int err = 0;
4892 	bool continuous = pipe->stream->config.continuous;
4893 	unsigned int i;
4894 	unsigned int num_output_pins;
4895 	struct ia_css_frame_info video_bin_out_info;
4896 	bool need_scaler = false;
4897 	bool vf_res_different_than_output = false;
4898 	bool need_vf_pp = false;
4899 	int vf_ds_log2;
4900 	struct ia_css_video_settings *mycs  = &pipe->pipe_settings.video;
4901 
4902 	IA_CSS_ENTER_PRIVATE("");
4903 	assert(pipe);
4904 	assert(pipe->mode == IA_CSS_PIPE_ID_VIDEO);
4905 	/*
4906 	 * we only test the video_binary because offline video doesn't need a
4907 	 * vf_pp binary and online does not (always use) the copy_binary.
4908 	 * All are always reset at the same time anyway.
4909 	 */
4910 	if (mycs->video_binary.info)
4911 		return 0;
4912 
4913 	online = pipe->stream->config.online;
4914 	pipe_out_info = &pipe->output_info[0];
4915 	pipe_vf_out_info = &pipe->vf_output_info[0];
4916 
4917 	assert(pipe_out_info);
4918 
4919 	/*
4920 	 * There is no explicit input format requirement for raw or yuv
4921 	 * What matters is that there is a binary that supports the stream format.
4922 	 * This is checked in the binary_find(), so no need to check it here
4923 	 */
4924 	err = ia_css_util_check_input(&pipe->stream->config, false, false);
4925 	if (err)
4926 		return err;
4927 	/* cannot have online video and input_mode memory */
4928 	if (online && pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY)
4929 		return -EINVAL;
4930 	if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) {
4931 		err = ia_css_util_check_vf_out_info(pipe_out_info,
4932 						    pipe_vf_out_info);
4933 		if (err)
4934 			return err;
4935 	} else {
4936 		err = ia_css_frame_check_info(pipe_out_info);
4937 		if (err)
4938 			return err;
4939 	}
4940 
4941 	if (pipe->out_yuv_ds_input_info.res.width)
4942 		video_bin_out_info = pipe->out_yuv_ds_input_info;
4943 	else
4944 		video_bin_out_info = *pipe_out_info;
4945 
4946 	/* Video */
4947 	if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) {
4948 		video_vf_info = pipe_vf_out_info;
4949 		vf_res_different_than_output = (video_vf_info->res.width !=
4950 						video_bin_out_info.res.width) ||
4951 					       (video_vf_info->res.height != video_bin_out_info.res.height);
4952 	} else {
4953 		video_vf_info = NULL;
4954 	}
4955 
4956 	need_scaler = need_downscaling(video_bin_out_info.res, pipe_out_info->res);
4957 
4958 	/* we build up the pipeline starting at the end */
4959 	/* YUV post-processing if needed */
4960 	if (need_scaler) {
4961 		struct ia_css_cas_binary_descr cas_scaler_descr = { };
4962 
4963 		/* NV12 is the common format that is supported by both */
4964 		/* yuv_scaler and the video_xx_isp2_min binaries. */
4965 		video_bin_out_info.format = IA_CSS_FRAME_FORMAT_NV12;
4966 
4967 		err = ia_css_pipe_create_cas_scaler_desc_single_output(
4968 			  &video_bin_out_info,
4969 			  pipe_out_info,
4970 			  NULL,
4971 			  &cas_scaler_descr);
4972 		if (err)
4973 			return err;
4974 		mycs->num_yuv_scaler = cas_scaler_descr.num_stage;
4975 		mycs->yuv_scaler_binary = kcalloc(cas_scaler_descr.num_stage,
4976 						  sizeof(struct ia_css_binary),
4977 						  GFP_KERNEL);
4978 		if (!mycs->yuv_scaler_binary) {
4979 			err = -ENOMEM;
4980 			return err;
4981 		}
4982 		mycs->is_output_stage = kcalloc(cas_scaler_descr.num_stage,
4983 						sizeof(bool), GFP_KERNEL);
4984 		if (!mycs->is_output_stage) {
4985 			err = -ENOMEM;
4986 			return err;
4987 		}
4988 		for (i = 0; i < cas_scaler_descr.num_stage; i++) {
4989 			struct ia_css_binary_descr yuv_scaler_descr;
4990 
4991 			mycs->is_output_stage[i] = cas_scaler_descr.is_output_stage[i];
4992 			ia_css_pipe_get_yuvscaler_binarydesc(pipe,
4993 							     &yuv_scaler_descr, &cas_scaler_descr.in_info[i],
4994 							     &cas_scaler_descr.out_info[i],
4995 							     &cas_scaler_descr.internal_out_info[i],
4996 							     &cas_scaler_descr.vf_info[i]);
4997 			err = ia_css_binary_find(&yuv_scaler_descr,
4998 						 &mycs->yuv_scaler_binary[i]);
4999 			if (err) {
5000 				kfree(mycs->is_output_stage);
5001 				mycs->is_output_stage = NULL;
5002 				return err;
5003 			}
5004 		}
5005 		ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr);
5006 	}
5007 
5008 	{
5009 		struct ia_css_binary_descr video_descr;
5010 		enum ia_css_frame_format vf_info_format;
5011 
5012 		err = ia_css_pipe_get_video_binarydesc(pipe,
5013 						       &video_descr, &video_in_info, &video_bds_out_info, &video_bin_out_info,
5014 						       video_vf_info,
5015 						       pipe->stream->config.left_padding);
5016 		if (err)
5017 			return err;
5018 
5019 		/*
5020 		 * In the case where video_vf_info is not NULL, this allows
5021 		 * us to find a potential video library with desired vf format.
5022 		 * If success, no vf_pp binary is needed.
5023 		 * If failed, we will look up video binary with YUV_LINE vf format
5024 		 */
5025 		err = ia_css_binary_find(&video_descr,
5026 					 &mycs->video_binary);
5027 
5028 		if (err) {
5029 			/* This will do another video binary lookup later for YUV_LINE format*/
5030 			if (video_vf_info)
5031 				need_vf_pp = true;
5032 			else
5033 				return err;
5034 		} else if (video_vf_info) {
5035 			/*
5036 			 * The first video binary lookup is successful, but we
5037 			 * may still need vf_pp binary based on additional check
5038 			 */
5039 			num_output_pins = mycs->video_binary.info->num_output_pins;
5040 			vf_ds_log2 = mycs->video_binary.vf_downscale_log2;
5041 
5042 			/*
5043 			 * If the binary has dual output pins, we need vf_pp
5044 			 * if the resolution is different.
5045 			 */
5046 			need_vf_pp |= ((num_output_pins == 2) && vf_res_different_than_output);
5047 
5048 			/*
5049 			 * If the binary has single output pin, we need vf_pp
5050 			 * if additional scaling is needed for vf
5051 			 */
5052 			need_vf_pp |= ((num_output_pins == 1) &&
5053 				       ((video_vf_info->res.width << vf_ds_log2 != pipe_out_info->res.width) ||
5054 					(video_vf_info->res.height << vf_ds_log2 != pipe_out_info->res.height)));
5055 		}
5056 
5057 		if (need_vf_pp) {
5058 			/* save the current vf_info format for restoration later */
5059 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
5060 					    "load_video_binaries() need_vf_pp; find video binary with YUV_LINE again\n");
5061 
5062 			vf_info_format = video_vf_info->format;
5063 
5064 			if (!pipe->config.enable_vfpp_bci)
5065 				ia_css_frame_info_set_format(video_vf_info,
5066 							     IA_CSS_FRAME_FORMAT_YUV_LINE);
5067 
5068 			ia_css_binary_destroy_isp_parameters(&mycs->video_binary);
5069 
5070 			err = ia_css_binary_find(&video_descr,
5071 						 &mycs->video_binary);
5072 
5073 			/* restore original vf_info format */
5074 			ia_css_frame_info_set_format(video_vf_info,
5075 						     vf_info_format);
5076 			if (err)
5077 				return err;
5078 		}
5079 	}
5080 
5081 	/*
5082 	 * If a video binary does not use a ref_frame, we set the frame delay
5083 	 * to 0. This is the case for the 1-stage low-power video binary.
5084 	 */
5085 	if (!mycs->video_binary.info->sp.enable.ref_frame)
5086 		pipe->dvs_frame_delay = 0;
5087 
5088 	/*
5089 	 * The delay latency determines the number of invalid frames after
5090 	 * a stream is started.
5091 	 */
5092 	pipe->num_invalid_frames = pipe->dvs_frame_delay;
5093 	pipe->info.num_invalid_frames = pipe->num_invalid_frames;
5094 
5095 	/*
5096 	 * Viewfinder frames also decrement num_invalid_frames. If the pipe
5097 	 * outputs a viewfinder output, then we need double the number of
5098 	 * invalid frames
5099 	 */
5100 	if (video_vf_info)
5101 		pipe->num_invalid_frames *= 2;
5102 
5103 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
5104 			    "load_video_binaries() num_invalid_frames=%d dvs_frame_delay=%d\n",
5105 			    pipe->num_invalid_frames, pipe->dvs_frame_delay);
5106 
5107 	/* pqiao TODO: temp hack for PO, should be removed after offline YUVPP is enabled */
5108 #if !defined(ISP2401)
5109 	/* Copy */
5110 	if (!online && !continuous) {
5111 		/*
5112 		 * TODO: what exactly needs doing, prepend the copy binary to
5113 		 *	 video base this only on !online?
5114 		 */
5115 		err = load_copy_binary(pipe,
5116 				       &mycs->copy_binary,
5117 				       &mycs->video_binary);
5118 		if (err)
5119 			return err;
5120 	}
5121 #else
5122 	(void)continuous;
5123 #endif
5124 
5125 	if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0] && need_vf_pp) {
5126 		struct ia_css_binary_descr vf_pp_descr;
5127 
5128 		if (mycs->video_binary.vf_frame_info.format
5129 		    == IA_CSS_FRAME_FORMAT_YUV_LINE) {
5130 			ia_css_pipe_get_vfpp_binarydesc(pipe, &vf_pp_descr,
5131 							&mycs->video_binary.vf_frame_info,
5132 							pipe_vf_out_info);
5133 		} else {
5134 			/*
5135 			 * output from main binary is not yuv line. currently
5136 			 * this is possible only when bci is enabled on vfpp
5137 			 * output
5138 			 */
5139 			assert(pipe->config.enable_vfpp_bci);
5140 			ia_css_pipe_get_yuvscaler_binarydesc(pipe, &vf_pp_descr,
5141 							     &mycs->video_binary.vf_frame_info,
5142 							     pipe_vf_out_info, NULL, NULL);
5143 		}
5144 
5145 		err = ia_css_binary_find(&vf_pp_descr,
5146 					 &mycs->vf_pp_binary);
5147 		if (err)
5148 			return err;
5149 	}
5150 
5151 	err = allocate_delay_frames(pipe);
5152 
5153 	if (err)
5154 		return err;
5155 
5156 	if (mycs->video_binary.info->sp.enable.block_output) {
5157 		tnr_info = mycs->video_binary.out_frame_info[0];
5158 
5159 		/* Make tnr reference buffers output block height align */
5160 		tnr_info.res.height = CEIL_MUL(tnr_info.res.height,
5161 					       mycs->video_binary.info->sp.block.output_block_height);
5162 	} else {
5163 		tnr_info = mycs->video_binary.internal_frame_info;
5164 	}
5165 	tnr_info.format = IA_CSS_FRAME_FORMAT_YUV_LINE;
5166 	tnr_info.raw_bit_depth = SH_CSS_TNR_BIT_DEPTH;
5167 
5168 	for (i = 0; i < NUM_VIDEO_TNR_FRAMES; i++) {
5169 		if (mycs->tnr_frames[i]) {
5170 			ia_css_frame_free(mycs->tnr_frames[i]);
5171 			mycs->tnr_frames[i] = NULL;
5172 		}
5173 		err = ia_css_frame_allocate_from_info(
5174 			  &mycs->tnr_frames[i],
5175 			  &tnr_info);
5176 		if (err)
5177 			return err;
5178 	}
5179 	IA_CSS_LEAVE_PRIVATE("");
5180 	return 0;
5181 }
5182 
5183 static int
5184 unload_video_binaries(struct ia_css_pipe *pipe)
5185 {
5186 	unsigned int i;
5187 
5188 	IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
5189 
5190 	if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_VIDEO)) {
5191 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
5192 		return -EINVAL;
5193 	}
5194 	ia_css_binary_unload(&pipe->pipe_settings.video.copy_binary);
5195 	ia_css_binary_unload(&pipe->pipe_settings.video.video_binary);
5196 	ia_css_binary_unload(&pipe->pipe_settings.video.vf_pp_binary);
5197 
5198 	for (i = 0; i < pipe->pipe_settings.video.num_yuv_scaler; i++)
5199 		ia_css_binary_unload(&pipe->pipe_settings.video.yuv_scaler_binary[i]);
5200 
5201 	kfree(pipe->pipe_settings.video.is_output_stage);
5202 	pipe->pipe_settings.video.is_output_stage = NULL;
5203 	kfree(pipe->pipe_settings.video.yuv_scaler_binary);
5204 	pipe->pipe_settings.video.yuv_scaler_binary = NULL;
5205 
5206 	IA_CSS_LEAVE_ERR_PRIVATE(0);
5207 	return 0;
5208 }
5209 
5210 static int video_start(struct ia_css_pipe *pipe)
5211 {
5212 	int err = 0;
5213 	struct ia_css_pipe *copy_pipe, *capture_pipe;
5214 	enum sh_css_pipe_config_override copy_ovrd;
5215 	enum ia_css_input_mode video_pipe_input_mode;
5216 	unsigned int thread_id;
5217 
5218 	IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
5219 	if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_VIDEO)) {
5220 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
5221 		return -EINVAL;
5222 	}
5223 
5224 	video_pipe_input_mode = pipe->stream->config.mode;
5225 
5226 	copy_pipe    = pipe->pipe_settings.video.copy_pipe;
5227 	capture_pipe = pipe->pipe_settings.video.capture_pipe;
5228 
5229 	sh_css_metrics_start_frame();
5230 
5231 	/* multi stream video needs mipi buffers */
5232 
5233 	err = send_mipi_frames(pipe);
5234 	if (err)
5235 		return err;
5236 
5237 	send_raw_frames(pipe);
5238 
5239 	ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
5240 	copy_ovrd = 1 << thread_id;
5241 
5242 	if (pipe->stream->cont_capt) {
5243 		ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(capture_pipe),
5244 						    &thread_id);
5245 		copy_ovrd |= 1 << thread_id;
5246 	}
5247 
5248 	/* Construct and load the copy pipe */
5249 	if (pipe->stream->config.continuous) {
5250 		sh_css_sp_init_pipeline(&copy_pipe->pipeline,
5251 					IA_CSS_PIPE_ID_COPY,
5252 					(uint8_t)ia_css_pipe_get_pipe_num(copy_pipe),
5253 					false,
5254 					pipe->stream->config.pixels_per_clock == 2, false,
5255 					false, pipe->required_bds_factor,
5256 					copy_ovrd,
5257 					pipe->stream->config.mode,
5258 					&pipe->stream->config.metadata_config,
5259 					&pipe->stream->info.metadata_info,
5260 					pipe->stream->config.source.port.port);
5261 
5262 		/*
5263 		 * make the video pipe start with mem mode input, copy handles
5264 		 * the actual mode
5265 		 */
5266 		video_pipe_input_mode = IA_CSS_INPUT_MODE_MEMORY;
5267 	}
5268 
5269 	/* Construct and load the capture pipe */
5270 	if (pipe->stream->cont_capt) {
5271 		sh_css_sp_init_pipeline(&capture_pipe->pipeline,
5272 					IA_CSS_PIPE_ID_CAPTURE,
5273 					(uint8_t)ia_css_pipe_get_pipe_num(capture_pipe),
5274 					capture_pipe->config.default_capture_config.enable_xnr != 0,
5275 					capture_pipe->stream->config.pixels_per_clock == 2,
5276 					true, /* continuous */
5277 					false, /* offline */
5278 					capture_pipe->required_bds_factor,
5279 					0,
5280 					IA_CSS_INPUT_MODE_MEMORY,
5281 					&pipe->stream->config.metadata_config,
5282 					&pipe->stream->info.metadata_info,
5283 					(enum mipi_port_id)0);
5284 	}
5285 
5286 	start_pipe(pipe, copy_ovrd, video_pipe_input_mode);
5287 
5288 	IA_CSS_LEAVE_ERR_PRIVATE(err);
5289 	return err;
5290 }
5291 
5292 static
5293 int sh_css_pipe_get_viewfinder_frame_info(
5294     struct ia_css_pipe *pipe,
5295     struct ia_css_frame_info *info,
5296     unsigned int idx)
5297 {
5298 	assert(pipe);
5299 	assert(info);
5300 
5301 	/* We could print the pointer as input arg, and the values as output */
5302 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
5303 			    "sh_css_pipe_get_viewfinder_frame_info() enter: void\n");
5304 
5305 	if (pipe->mode == IA_CSS_PIPE_ID_CAPTURE &&
5306 	    (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_RAW ||
5307 	     pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER))
5308 		return -EINVAL;
5309 	/* offline video does not generate viewfinder output */
5310 	*info = pipe->vf_output_info[idx];
5311 
5312 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
5313 			    "sh_css_pipe_get_viewfinder_frame_info() leave: \
5314 		info.res.width=%d, info.res.height=%d, \
5315 		info.padded_width=%d, info.format=%d, \
5316 		info.raw_bit_depth=%d, info.raw_bayer_order=%d\n",
5317 			    info->res.width, info->res.height,
5318 			    info->padded_width, info->format,
5319 			    info->raw_bit_depth, info->raw_bayer_order);
5320 
5321 	return 0;
5322 }
5323 
5324 static int
5325 sh_css_pipe_configure_viewfinder(struct ia_css_pipe *pipe, unsigned int width,
5326 				 unsigned int height, unsigned int min_width,
5327 				 enum ia_css_frame_format format,
5328 				 unsigned int idx)
5329 {
5330 	int err = 0;
5331 
5332 	IA_CSS_ENTER_PRIVATE("pipe = %p, width = %d, height = %d, min_width = %d, format = %d, idx = %d\n",
5333 			     pipe, width, height, min_width, format, idx);
5334 
5335 	if (!pipe) {
5336 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
5337 		return -EINVAL;
5338 	}
5339 
5340 	err = ia_css_util_check_res(width, height);
5341 	if (err) {
5342 		IA_CSS_LEAVE_ERR_PRIVATE(err);
5343 		return err;
5344 	}
5345 	if (pipe->vf_output_info[idx].res.width != width ||
5346 	    pipe->vf_output_info[idx].res.height != height ||
5347 	    pipe->vf_output_info[idx].format != format)
5348 		ia_css_frame_info_init(&pipe->vf_output_info[idx], width, height,
5349 				       format, min_width);
5350 
5351 	IA_CSS_LEAVE_ERR_PRIVATE(0);
5352 	return 0;
5353 }
5354 
5355 static int load_copy_binaries(struct ia_css_pipe *pipe)
5356 {
5357 	int err = 0;
5358 
5359 	assert(pipe);
5360 	IA_CSS_ENTER_PRIVATE("");
5361 
5362 	assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
5363 	       pipe->mode == IA_CSS_PIPE_ID_COPY);
5364 	if (pipe->pipe_settings.capture.copy_binary.info)
5365 		return 0;
5366 
5367 	err = ia_css_frame_check_info(&pipe->output_info[0]);
5368 	if (err)
5369 		goto ERR;
5370 
5371 	err = verify_copy_out_frame_format(pipe);
5372 	if (err)
5373 		goto ERR;
5374 
5375 	err = load_copy_binary(pipe,
5376 			       &pipe->pipe_settings.capture.copy_binary,
5377 			       NULL);
5378 
5379 ERR:
5380 	IA_CSS_LEAVE_ERR_PRIVATE(err);
5381 	return err;
5382 }
5383 
5384 static bool need_capture_pp(
5385     const struct ia_css_pipe *pipe)
5386 {
5387 	const struct ia_css_frame_info *out_info = &pipe->output_info[0];
5388 
5389 	IA_CSS_ENTER_LEAVE_PRIVATE("");
5390 	assert(pipe);
5391 	assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE);
5392 
5393 	/* determine whether we need to use the capture_pp binary.
5394 	 * This is needed for:
5395 	 *   1. XNR or
5396 	 *   2. Digital Zoom or
5397 	 *   3. YUV downscaling
5398 	 */
5399 	if (pipe->out_yuv_ds_input_info.res.width &&
5400 	    ((pipe->out_yuv_ds_input_info.res.width != out_info->res.width) ||
5401 	     (pipe->out_yuv_ds_input_info.res.height != out_info->res.height)))
5402 		return true;
5403 
5404 	if (pipe->config.default_capture_config.enable_xnr != 0)
5405 		return true;
5406 
5407 	if ((pipe->stream->isp_params_configs->dz_config.dx < HRT_GDC_N) ||
5408 	    (pipe->stream->isp_params_configs->dz_config.dy < HRT_GDC_N) ||
5409 	    pipe->config.enable_dz)
5410 		return true;
5411 
5412 	return false;
5413 }
5414 
5415 static bool need_capt_ldc(
5416     const struct ia_css_pipe *pipe)
5417 {
5418 	IA_CSS_ENTER_LEAVE_PRIVATE("");
5419 	assert(pipe);
5420 	assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE);
5421 	return (pipe->extra_config.enable_dvs_6axis) ? true : false;
5422 }
5423 
5424 static int set_num_primary_stages(unsigned int *num,
5425 				  enum ia_css_pipe_version version)
5426 {
5427 	int err = 0;
5428 
5429 	if (!num)
5430 		return -EINVAL;
5431 
5432 	switch (version) {
5433 	case IA_CSS_PIPE_VERSION_2_6_1:
5434 		*num = NUM_PRIMARY_HQ_STAGES;
5435 		break;
5436 	case IA_CSS_PIPE_VERSION_2_2:
5437 	case IA_CSS_PIPE_VERSION_1:
5438 		*num = NUM_PRIMARY_STAGES;
5439 		break;
5440 	default:
5441 		err = -EINVAL;
5442 		break;
5443 	}
5444 
5445 	return err;
5446 }
5447 
5448 static int load_primary_binaries(
5449     struct ia_css_pipe *pipe)
5450 {
5451 	bool online = false;
5452 	bool need_pp = false;
5453 	bool need_isp_copy_binary = false;
5454 	bool need_ldc = false;
5455 #ifdef ISP2401
5456 	bool sensor = false;
5457 #else
5458 	bool memory, continuous;
5459 #endif
5460 	struct ia_css_frame_info prim_in_info,
5461 		       prim_out_info,
5462 		       capt_pp_out_info, vf_info,
5463 		       *vf_pp_in_info, *pipe_out_info,
5464 		       *pipe_vf_out_info, *capt_pp_in_info,
5465 		       capt_ldc_out_info;
5466 	int err = 0;
5467 	struct ia_css_capture_settings *mycs;
5468 	unsigned int i;
5469 	bool need_extra_yuv_scaler = false;
5470 	struct ia_css_binary_descr prim_descr[MAX_NUM_PRIMARY_STAGES];
5471 
5472 	IA_CSS_ENTER_PRIVATE("");
5473 	assert(pipe);
5474 	assert(pipe->stream);
5475 	assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
5476 	       pipe->mode == IA_CSS_PIPE_ID_COPY);
5477 
5478 	online = pipe->stream->config.online;
5479 #ifdef ISP2401
5480 	sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR);
5481 #else
5482 	memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY;
5483 	continuous = pipe->stream->config.continuous;
5484 #endif
5485 
5486 	mycs = &pipe->pipe_settings.capture;
5487 	pipe_out_info = &pipe->output_info[0];
5488 	pipe_vf_out_info = &pipe->vf_output_info[0];
5489 
5490 	if (mycs->primary_binary[0].info)
5491 		return 0;
5492 
5493 	err = set_num_primary_stages(&mycs->num_primary_stage,
5494 				     pipe->config.isp_pipe_version);
5495 	if (err) {
5496 		IA_CSS_LEAVE_ERR_PRIVATE(err);
5497 		return err;
5498 	}
5499 
5500 	if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) {
5501 		err = ia_css_util_check_vf_out_info(pipe_out_info, pipe_vf_out_info);
5502 		if (err) {
5503 			IA_CSS_LEAVE_ERR_PRIVATE(err);
5504 			return err;
5505 		}
5506 	} else {
5507 		err = ia_css_frame_check_info(pipe_out_info);
5508 		if (err) {
5509 			IA_CSS_LEAVE_ERR_PRIVATE(err);
5510 			return err;
5511 		}
5512 	}
5513 	need_pp = need_capture_pp(pipe);
5514 
5515 	/*
5516 	 * we use the vf output info to get the primary/capture_pp binary
5517 	 * configured for vf_veceven. It will select the closest downscaling
5518 	 * factor.
5519 	 */
5520 	vf_info = *pipe_vf_out_info;
5521 
5522 	/*
5523 	 * WARNING: The #if def flag has been added below as a
5524 	 * temporary solution to solve the problem of enabling the
5525 	 * view finder in a single binary in a capture flow. The
5526 	 * vf-pp stage has been removed for Skycam in the solution
5527 	 * provided. The vf-pp stage should be re-introduced when
5528 	 * required. This should not be considered as a clean solution.
5529 	 * Proper investigation should be done to come up with the clean
5530 	 * solution.
5531 	 */
5532 	ia_css_frame_info_set_format(&vf_info, IA_CSS_FRAME_FORMAT_YUV_LINE);
5533 
5534 	/*
5535 	 * TODO: All this yuv_scaler and capturepp calculation logic
5536 	 * can be shared later. Capture_pp is also a yuv_scale binary
5537 	 * with extra XNR funcionality. Therefore, it can be made as the
5538 	 * first step of the cascade.
5539 	 */
5540 	capt_pp_out_info = pipe->out_yuv_ds_input_info;
5541 	capt_pp_out_info.format = IA_CSS_FRAME_FORMAT_YUV420;
5542 	capt_pp_out_info.res.width  /= MAX_PREFERRED_YUV_DS_PER_STEP;
5543 	capt_pp_out_info.res.height /= MAX_PREFERRED_YUV_DS_PER_STEP;
5544 	ia_css_frame_info_set_width(&capt_pp_out_info, capt_pp_out_info.res.width, 0);
5545 
5546 	need_extra_yuv_scaler = need_downscaling(capt_pp_out_info.res,
5547 						 pipe_out_info->res);
5548 
5549 	if (need_extra_yuv_scaler) {
5550 		struct ia_css_cas_binary_descr cas_scaler_descr = { };
5551 
5552 		err = ia_css_pipe_create_cas_scaler_desc_single_output(
5553 			  &capt_pp_out_info,
5554 			  pipe_out_info,
5555 			  NULL,
5556 			  &cas_scaler_descr);
5557 		if (err) {
5558 			IA_CSS_LEAVE_ERR_PRIVATE(err);
5559 			return err;
5560 		}
5561 		mycs->num_yuv_scaler = cas_scaler_descr.num_stage;
5562 		mycs->yuv_scaler_binary = kcalloc(cas_scaler_descr.num_stage,
5563 						  sizeof(struct ia_css_binary),
5564 						  GFP_KERNEL);
5565 		if (!mycs->yuv_scaler_binary) {
5566 			err = -ENOMEM;
5567 			IA_CSS_LEAVE_ERR_PRIVATE(err);
5568 			return err;
5569 		}
5570 		mycs->is_output_stage = kcalloc(cas_scaler_descr.num_stage,
5571 						sizeof(bool), GFP_KERNEL);
5572 		if (!mycs->is_output_stage) {
5573 			err = -ENOMEM;
5574 			IA_CSS_LEAVE_ERR_PRIVATE(err);
5575 			return err;
5576 		}
5577 		for (i = 0; i < cas_scaler_descr.num_stage; i++) {
5578 			struct ia_css_binary_descr yuv_scaler_descr;
5579 
5580 			mycs->is_output_stage[i] = cas_scaler_descr.is_output_stage[i];
5581 			ia_css_pipe_get_yuvscaler_binarydesc(pipe,
5582 							     &yuv_scaler_descr, &cas_scaler_descr.in_info[i],
5583 							     &cas_scaler_descr.out_info[i],
5584 							     &cas_scaler_descr.internal_out_info[i],
5585 							     &cas_scaler_descr.vf_info[i]);
5586 			err = ia_css_binary_find(&yuv_scaler_descr,
5587 						 &mycs->yuv_scaler_binary[i]);
5588 			if (err) {
5589 				IA_CSS_LEAVE_ERR_PRIVATE(err);
5590 				return err;
5591 			}
5592 		}
5593 		ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr);
5594 
5595 	} else {
5596 		capt_pp_out_info = pipe->output_info[0];
5597 	}
5598 
5599 	/* TODO Do we disable ldc for skycam */
5600 	need_ldc = need_capt_ldc(pipe);
5601 
5602 	/* we build up the pipeline starting at the end */
5603 	/* Capture post-processing */
5604 	if (need_pp) {
5605 		struct ia_css_binary_descr capture_pp_descr;
5606 
5607 		capt_pp_in_info = need_ldc ? &capt_ldc_out_info : &prim_out_info;
5608 
5609 		ia_css_pipe_get_capturepp_binarydesc(pipe,
5610 						     &capture_pp_descr,
5611 						     capt_pp_in_info,
5612 						     &capt_pp_out_info,
5613 						     &vf_info);
5614 
5615 		err = ia_css_binary_find(&capture_pp_descr,
5616 					 &mycs->capture_pp_binary);
5617 		if (err) {
5618 			IA_CSS_LEAVE_ERR_PRIVATE(err);
5619 			return err;
5620 		}
5621 
5622 		if (need_ldc) {
5623 			struct ia_css_binary_descr capt_ldc_descr;
5624 
5625 			ia_css_pipe_get_ldc_binarydesc(pipe,
5626 						       &capt_ldc_descr,
5627 						       &prim_out_info,
5628 						       &capt_ldc_out_info);
5629 
5630 			err = ia_css_binary_find(&capt_ldc_descr,
5631 						 &mycs->capture_ldc_binary);
5632 			if (err) {
5633 				IA_CSS_LEAVE_ERR_PRIVATE(err);
5634 				return err;
5635 			}
5636 		}
5637 	} else {
5638 		prim_out_info = *pipe_out_info;
5639 	}
5640 
5641 	/* Primary */
5642 	for (i = 0; i < mycs->num_primary_stage; i++) {
5643 		struct ia_css_frame_info *local_vf_info = NULL;
5644 
5645 		if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0] &&
5646 		    (i == mycs->num_primary_stage - 1))
5647 			local_vf_info = &vf_info;
5648 		ia_css_pipe_get_primary_binarydesc(pipe, &prim_descr[i],
5649 						   &prim_in_info, &prim_out_info,
5650 						   local_vf_info, i);
5651 		err = ia_css_binary_find(&prim_descr[i], &mycs->primary_binary[i]);
5652 		if (err) {
5653 			IA_CSS_LEAVE_ERR_PRIVATE(err);
5654 			return err;
5655 		}
5656 	}
5657 
5658 	/* Viewfinder post-processing */
5659 	if (need_pp)
5660 		vf_pp_in_info = &mycs->capture_pp_binary.vf_frame_info;
5661 	else
5662 		vf_pp_in_info = &mycs->primary_binary[mycs->num_primary_stage - 1].vf_frame_info;
5663 
5664 	/*
5665 	 * WARNING: The #if def flag has been added below as a
5666 	 * temporary solution to solve the problem of enabling the
5667 	 * view finder in a single binary in a capture flow. The
5668 	 * vf-pp stage has been removed for Skycam in the solution
5669 	 * provided. The vf-pp stage should be re-introduced when
5670 	 * required. Thisshould not be considered as a clean solution.
5671 	 * Proper  * investigation should be done to come up with the clean
5672 	 * solution.
5673 	 */
5674 	if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) {
5675 		struct ia_css_binary_descr vf_pp_descr;
5676 
5677 		ia_css_pipe_get_vfpp_binarydesc(pipe,
5678 						&vf_pp_descr, vf_pp_in_info, pipe_vf_out_info);
5679 		err = ia_css_binary_find(&vf_pp_descr, &mycs->vf_pp_binary);
5680 		if (err) {
5681 			IA_CSS_LEAVE_ERR_PRIVATE(err);
5682 			return err;
5683 		}
5684 	}
5685 	err = allocate_delay_frames(pipe);
5686 
5687 	if (err)
5688 		return err;
5689 
5690 #ifdef ISP2401
5691 	/*
5692 	 * When the input system is 2401, only the Direct Sensor Mode
5693 	 * Offline Capture uses the ISP copy binary.
5694 	 */
5695 	need_isp_copy_binary = !online && sensor;
5696 #else
5697 	need_isp_copy_binary = !online && !continuous && !memory;
5698 #endif
5699 
5700 	/* ISP Copy */
5701 	if (need_isp_copy_binary) {
5702 		err = load_copy_binary(pipe,
5703 				       &mycs->copy_binary,
5704 				       &mycs->primary_binary[0]);
5705 		if (err) {
5706 			IA_CSS_LEAVE_ERR_PRIVATE(err);
5707 			return err;
5708 		}
5709 	}
5710 
5711 	return 0;
5712 }
5713 
5714 static int
5715 allocate_delay_frames(struct ia_css_pipe *pipe)
5716 {
5717 	unsigned int num_delay_frames = 0, i = 0;
5718 	unsigned int dvs_frame_delay = 0;
5719 	struct ia_css_frame_info ref_info;
5720 	int err = 0;
5721 	enum ia_css_pipe_id mode = IA_CSS_PIPE_ID_VIDEO;
5722 	struct ia_css_frame **delay_frames = NULL;
5723 
5724 	IA_CSS_ENTER_PRIVATE("");
5725 
5726 	if (!pipe) {
5727 		IA_CSS_ERROR("Invalid args - pipe %p", pipe);
5728 		return -EINVAL;
5729 	}
5730 
5731 	mode = pipe->mode;
5732 	dvs_frame_delay = pipe->dvs_frame_delay;
5733 
5734 	if (dvs_frame_delay > 0)
5735 		num_delay_frames = dvs_frame_delay + 1;
5736 
5737 	switch (mode) {
5738 	case IA_CSS_PIPE_ID_CAPTURE: {
5739 		struct ia_css_capture_settings *mycs_capture = &pipe->pipe_settings.capture;
5740 		(void)mycs_capture;
5741 		return err;
5742 	}
5743 	break;
5744 	case IA_CSS_PIPE_ID_VIDEO: {
5745 		struct ia_css_video_settings *mycs_video = &pipe->pipe_settings.video;
5746 
5747 		ref_info = mycs_video->video_binary.internal_frame_info;
5748 
5749 		/*
5750 		 * The ref frame expects
5751 		 * 1. Y plane
5752 		 * 2. UV plane with line interleaving, like below
5753 		 *	UUUUUU(width/2 times) VVVVVVVV..(width/2 times)
5754 		 *
5755 		 * This format is not YUV420(which has Y, U and V planes).
5756 		 * Its closer to NV12, except that the UV plane has UV
5757 		 * interleaving, like UVUVUVUVUVUVUVUVU...
5758 		 *
5759 		 * TODO: make this ref_frame format as a separate frame format
5760 		 */
5761 		ref_info.format        = IA_CSS_FRAME_FORMAT_NV12;
5762 		delay_frames = mycs_video->delay_frames;
5763 	}
5764 	break;
5765 	case IA_CSS_PIPE_ID_PREVIEW: {
5766 		struct ia_css_preview_settings *mycs_preview = &pipe->pipe_settings.preview;
5767 
5768 		ref_info = mycs_preview->preview_binary.internal_frame_info;
5769 
5770 		/*
5771 		 * The ref frame expects
5772 		 * 1. Y plane
5773 		 * 2. UV plane with line interleaving, like below
5774 		 *	UUUUUU(width/2 times) VVVVVVVV..(width/2 times)
5775 		 *
5776 		 * This format is not YUV420(which has Y, U and V planes).
5777 		 * Its closer to NV12, except that the UV plane has UV
5778 		 * interleaving, like UVUVUVUVUVUVUVUVU...
5779 		 *
5780 		 * TODO: make this ref_frame format as a separate frame format
5781 		 */
5782 		ref_info.format        = IA_CSS_FRAME_FORMAT_NV12;
5783 		delay_frames = mycs_preview->delay_frames;
5784 	}
5785 	break;
5786 	default:
5787 		return -EINVAL;
5788 	}
5789 
5790 	ref_info.raw_bit_depth = SH_CSS_REF_BIT_DEPTH;
5791 
5792 	assert(num_delay_frames <= MAX_NUM_VIDEO_DELAY_FRAMES);
5793 	for (i = 0; i < num_delay_frames; i++) {
5794 		err = ia_css_frame_allocate_from_info(&delay_frames[i],	&ref_info);
5795 		if (err)
5796 			return err;
5797 	}
5798 	IA_CSS_LEAVE_PRIVATE("");
5799 	return 0;
5800 }
5801 
5802 static int load_advanced_binaries(struct ia_css_pipe *pipe)
5803 {
5804 	struct ia_css_frame_info pre_in_info, gdc_in_info,
5805 			post_in_info, post_out_info,
5806 			vf_info, *vf_pp_in_info, *pipe_out_info,
5807 			*pipe_vf_out_info;
5808 	bool need_pp;
5809 	bool need_isp_copy = true;
5810 	int err = 0;
5811 
5812 	IA_CSS_ENTER_PRIVATE("");
5813 
5814 	assert(pipe);
5815 	assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
5816 	       pipe->mode == IA_CSS_PIPE_ID_COPY);
5817 	if (pipe->pipe_settings.capture.pre_isp_binary.info)
5818 		return 0;
5819 	pipe_out_info = &pipe->output_info[0];
5820 	pipe_vf_out_info = &pipe->vf_output_info[0];
5821 
5822 	vf_info = *pipe_vf_out_info;
5823 	err = ia_css_util_check_vf_out_info(pipe_out_info, &vf_info);
5824 	if (err)
5825 		return err;
5826 	need_pp = need_capture_pp(pipe);
5827 
5828 	ia_css_frame_info_set_format(&vf_info,
5829 				     IA_CSS_FRAME_FORMAT_YUV_LINE);
5830 
5831 	/* we build up the pipeline starting at the end */
5832 	/* Capture post-processing */
5833 	if (need_pp) {
5834 		struct ia_css_binary_descr capture_pp_descr;
5835 
5836 		ia_css_pipe_get_capturepp_binarydesc(pipe, &capture_pp_descr,
5837 						     &post_out_info,
5838 						     pipe_out_info, &vf_info);
5839 		err = ia_css_binary_find(&capture_pp_descr,
5840 					 &pipe->pipe_settings.capture.capture_pp_binary);
5841 		if (err)
5842 			return err;
5843 	} else {
5844 		post_out_info = *pipe_out_info;
5845 	}
5846 
5847 	/* Post-gdc */
5848 	{
5849 		struct ia_css_binary_descr post_gdc_descr;
5850 
5851 		ia_css_pipe_get_post_gdc_binarydesc(pipe, &post_gdc_descr,
5852 						    &post_in_info,
5853 						    &post_out_info, &vf_info);
5854 		err = ia_css_binary_find(&post_gdc_descr,
5855 					 &pipe->pipe_settings.capture.post_isp_binary);
5856 		if (err)
5857 			return err;
5858 	}
5859 
5860 	/* Gdc */
5861 	{
5862 		struct ia_css_binary_descr gdc_descr;
5863 
5864 		ia_css_pipe_get_gdc_binarydesc(pipe, &gdc_descr, &gdc_in_info,
5865 					       &pipe->pipe_settings.capture.post_isp_binary.in_frame_info);
5866 		err = ia_css_binary_find(&gdc_descr,
5867 					 &pipe->pipe_settings.capture.anr_gdc_binary);
5868 		if (err)
5869 			return err;
5870 	}
5871 	pipe->pipe_settings.capture.anr_gdc_binary.left_padding =
5872 	    pipe->pipe_settings.capture.post_isp_binary.left_padding;
5873 
5874 	/* Pre-gdc */
5875 	{
5876 		struct ia_css_binary_descr pre_gdc_descr;
5877 
5878 		ia_css_pipe_get_pre_gdc_binarydesc(pipe, &pre_gdc_descr, &pre_in_info,
5879 						   &pipe->pipe_settings.capture.anr_gdc_binary.in_frame_info);
5880 		err = ia_css_binary_find(&pre_gdc_descr,
5881 					 &pipe->pipe_settings.capture.pre_isp_binary);
5882 		if (err)
5883 			return err;
5884 	}
5885 	pipe->pipe_settings.capture.pre_isp_binary.left_padding =
5886 	    pipe->pipe_settings.capture.anr_gdc_binary.left_padding;
5887 
5888 	/* Viewfinder post-processing */
5889 	if (need_pp) {
5890 		vf_pp_in_info =
5891 		    &pipe->pipe_settings.capture.capture_pp_binary.vf_frame_info;
5892 	} else {
5893 		vf_pp_in_info =
5894 		    &pipe->pipe_settings.capture.post_isp_binary.vf_frame_info;
5895 	}
5896 
5897 	{
5898 		struct ia_css_binary_descr vf_pp_descr;
5899 
5900 		ia_css_pipe_get_vfpp_binarydesc(pipe,
5901 						&vf_pp_descr, vf_pp_in_info, pipe_vf_out_info);
5902 		err = ia_css_binary_find(&vf_pp_descr,
5903 					 &pipe->pipe_settings.capture.vf_pp_binary);
5904 		if (err)
5905 			return err;
5906 	}
5907 
5908 	/* Copy */
5909 #ifdef ISP2401
5910 	/* For CSI2+, only the direct sensor mode/online requires ISP copy */
5911 	need_isp_copy = pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR;
5912 #endif
5913 	if (need_isp_copy)
5914 		load_copy_binary(pipe,
5915 				 &pipe->pipe_settings.capture.copy_binary,
5916 				 &pipe->pipe_settings.capture.pre_isp_binary);
5917 
5918 	return err;
5919 }
5920 
5921 static int load_bayer_isp_binaries(struct ia_css_pipe *pipe)
5922 {
5923 	struct ia_css_frame_info pre_isp_in_info, *pipe_out_info;
5924 	int err = 0;
5925 	struct ia_css_binary_descr pre_de_descr;
5926 
5927 	IA_CSS_ENTER_PRIVATE("");
5928 	assert(pipe);
5929 	assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
5930 	       pipe->mode == IA_CSS_PIPE_ID_COPY);
5931 	pipe_out_info = &pipe->output_info[0];
5932 
5933 	if (pipe->pipe_settings.capture.pre_isp_binary.info)
5934 		return 0;
5935 
5936 	err = ia_css_frame_check_info(pipe_out_info);
5937 	if (err)
5938 		return err;
5939 
5940 	ia_css_pipe_get_pre_de_binarydesc(pipe, &pre_de_descr,
5941 					  &pre_isp_in_info,
5942 					  pipe_out_info);
5943 
5944 	err = ia_css_binary_find(&pre_de_descr,
5945 				 &pipe->pipe_settings.capture.pre_isp_binary);
5946 
5947 	return err;
5948 }
5949 
5950 static int load_low_light_binaries(struct ia_css_pipe *pipe)
5951 {
5952 	struct ia_css_frame_info pre_in_info, anr_in_info,
5953 			post_in_info, post_out_info,
5954 			vf_info, *pipe_vf_out_info, *pipe_out_info,
5955 			*vf_pp_in_info;
5956 	bool need_pp;
5957 	bool need_isp_copy = true;
5958 	int err = 0;
5959 
5960 	IA_CSS_ENTER_PRIVATE("");
5961 	assert(pipe);
5962 	assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
5963 	       pipe->mode == IA_CSS_PIPE_ID_COPY);
5964 
5965 	if (pipe->pipe_settings.capture.pre_isp_binary.info)
5966 		return 0;
5967 	pipe_vf_out_info = &pipe->vf_output_info[0];
5968 	pipe_out_info = &pipe->output_info[0];
5969 
5970 	vf_info = *pipe_vf_out_info;
5971 	err = ia_css_util_check_vf_out_info(pipe_out_info,
5972 					    &vf_info);
5973 	if (err)
5974 		return err;
5975 	need_pp = need_capture_pp(pipe);
5976 
5977 	ia_css_frame_info_set_format(&vf_info,
5978 				     IA_CSS_FRAME_FORMAT_YUV_LINE);
5979 
5980 	/* we build up the pipeline starting at the end */
5981 	/* Capture post-processing */
5982 	if (need_pp) {
5983 		struct ia_css_binary_descr capture_pp_descr;
5984 
5985 		ia_css_pipe_get_capturepp_binarydesc(pipe, &capture_pp_descr,
5986 						     &post_out_info,
5987 						     pipe_out_info, &vf_info);
5988 		err = ia_css_binary_find(&capture_pp_descr,
5989 					 &pipe->pipe_settings.capture.capture_pp_binary);
5990 		if (err)
5991 			return err;
5992 	} else {
5993 		post_out_info = *pipe_out_info;
5994 	}
5995 
5996 	/* Post-anr */
5997 	{
5998 		struct ia_css_binary_descr post_anr_descr;
5999 
6000 		ia_css_pipe_get_post_anr_binarydesc(pipe,
6001 						    &post_anr_descr, &post_in_info, &post_out_info, &vf_info);
6002 		err = ia_css_binary_find(&post_anr_descr,
6003 					 &pipe->pipe_settings.capture.post_isp_binary);
6004 		if (err)
6005 			return err;
6006 	}
6007 
6008 	/* Anr */
6009 	{
6010 		struct ia_css_binary_descr anr_descr;
6011 
6012 		ia_css_pipe_get_anr_binarydesc(pipe, &anr_descr, &anr_in_info,
6013 					       &pipe->pipe_settings.capture.post_isp_binary.in_frame_info);
6014 		err = ia_css_binary_find(&anr_descr,
6015 					 &pipe->pipe_settings.capture.anr_gdc_binary);
6016 		if (err)
6017 			return err;
6018 	}
6019 	pipe->pipe_settings.capture.anr_gdc_binary.left_padding =
6020 	    pipe->pipe_settings.capture.post_isp_binary.left_padding;
6021 
6022 	/* Pre-anr */
6023 	{
6024 		struct ia_css_binary_descr pre_anr_descr;
6025 
6026 		ia_css_pipe_get_pre_anr_binarydesc(pipe, &pre_anr_descr, &pre_in_info,
6027 						   &pipe->pipe_settings.capture.anr_gdc_binary.in_frame_info);
6028 		err = ia_css_binary_find(&pre_anr_descr,
6029 					 &pipe->pipe_settings.capture.pre_isp_binary);
6030 		if (err)
6031 			return err;
6032 	}
6033 	pipe->pipe_settings.capture.pre_isp_binary.left_padding =
6034 	    pipe->pipe_settings.capture.anr_gdc_binary.left_padding;
6035 
6036 	/* Viewfinder post-processing */
6037 	if (need_pp) {
6038 		vf_pp_in_info =
6039 		    &pipe->pipe_settings.capture.capture_pp_binary.vf_frame_info;
6040 	} else {
6041 		vf_pp_in_info =
6042 		    &pipe->pipe_settings.capture.post_isp_binary.vf_frame_info;
6043 	}
6044 
6045 	{
6046 		struct ia_css_binary_descr vf_pp_descr;
6047 
6048 		ia_css_pipe_get_vfpp_binarydesc(pipe, &vf_pp_descr,
6049 						vf_pp_in_info, pipe_vf_out_info);
6050 		err = ia_css_binary_find(&vf_pp_descr,
6051 					 &pipe->pipe_settings.capture.vf_pp_binary);
6052 		if (err)
6053 			return err;
6054 	}
6055 
6056 	/* Copy */
6057 #ifdef ISP2401
6058 	/* For CSI2+, only the direct sensor mode/online requires ISP copy */
6059 	need_isp_copy = pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR;
6060 #endif
6061 	if (need_isp_copy)
6062 		err = load_copy_binary(pipe,
6063 				       &pipe->pipe_settings.capture.copy_binary,
6064 				       &pipe->pipe_settings.capture.pre_isp_binary);
6065 
6066 	return err;
6067 }
6068 
6069 static bool copy_on_sp(struct ia_css_pipe *pipe)
6070 {
6071 	bool rval;
6072 
6073 	assert(pipe);
6074 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "copy_on_sp() enter:\n");
6075 
6076 	rval = true;
6077 
6078 	rval &=	(pipe->mode == IA_CSS_PIPE_ID_CAPTURE);
6079 
6080 	rval &= (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_RAW);
6081 
6082 	rval &= ((pipe->stream->config.input_config.format ==
6083 		    ATOMISP_INPUT_FORMAT_BINARY_8) ||
6084 		    (pipe->config.mode == IA_CSS_PIPE_MODE_COPY));
6085 
6086 	return rval;
6087 }
6088 
6089 static int load_capture_binaries(struct ia_css_pipe *pipe)
6090 {
6091 	int err = 0;
6092 	bool must_be_raw;
6093 
6094 	IA_CSS_ENTER_PRIVATE("");
6095 	assert(pipe);
6096 	assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
6097 	       pipe->mode == IA_CSS_PIPE_ID_COPY);
6098 
6099 	if (pipe->pipe_settings.capture.primary_binary[0].info) {
6100 		IA_CSS_LEAVE_ERR_PRIVATE(0);
6101 		return 0;
6102 	}
6103 
6104 	/* in primary, advanced,low light or bayer,
6105 						the input format must be raw */
6106 	must_be_raw =
6107 	    pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_ADVANCED ||
6108 	    pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER ||
6109 	    pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT;
6110 	err = ia_css_util_check_input(&pipe->stream->config, must_be_raw, false);
6111 	if (err) {
6112 		IA_CSS_LEAVE_ERR_PRIVATE(err);
6113 		return err;
6114 	}
6115 	if (copy_on_sp(pipe) &&
6116 	    pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8) {
6117 		ia_css_frame_info_init(
6118 		    &pipe->output_info[0],
6119 		    JPEG_BYTES,
6120 		    1,
6121 		    IA_CSS_FRAME_FORMAT_BINARY_8,
6122 		    0);
6123 		IA_CSS_LEAVE_ERR_PRIVATE(0);
6124 		return 0;
6125 	}
6126 
6127 	switch (pipe->config.default_capture_config.mode) {
6128 	case IA_CSS_CAPTURE_MODE_RAW:
6129 		err = load_copy_binaries(pipe);
6130 #if defined(ISP2401)
6131 		if (!err)
6132 			pipe->pipe_settings.capture.copy_binary.online = pipe->stream->config.online;
6133 #endif
6134 		break;
6135 	case IA_CSS_CAPTURE_MODE_BAYER:
6136 		err = load_bayer_isp_binaries(pipe);
6137 		break;
6138 	case IA_CSS_CAPTURE_MODE_PRIMARY:
6139 		err = load_primary_binaries(pipe);
6140 		break;
6141 	case IA_CSS_CAPTURE_MODE_ADVANCED:
6142 		err = load_advanced_binaries(pipe);
6143 		break;
6144 	case IA_CSS_CAPTURE_MODE_LOW_LIGHT:
6145 		err = load_low_light_binaries(pipe);
6146 		break;
6147 	}
6148 	if (err) {
6149 		IA_CSS_LEAVE_ERR_PRIVATE(err);
6150 		return err;
6151 	}
6152 
6153 	IA_CSS_LEAVE_ERR_PRIVATE(err);
6154 	return err;
6155 }
6156 
6157 static int
6158 unload_capture_binaries(struct ia_css_pipe *pipe)
6159 {
6160 	unsigned int i;
6161 
6162 	IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
6163 
6164 	if (!pipe || (pipe->mode != IA_CSS_PIPE_ID_CAPTURE &&
6165 		      pipe->mode != IA_CSS_PIPE_ID_COPY)) {
6166 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
6167 		return -EINVAL;
6168 	}
6169 	ia_css_binary_unload(&pipe->pipe_settings.capture.copy_binary);
6170 	for (i = 0; i < MAX_NUM_PRIMARY_STAGES; i++)
6171 		ia_css_binary_unload(&pipe->pipe_settings.capture.primary_binary[i]);
6172 	ia_css_binary_unload(&pipe->pipe_settings.capture.pre_isp_binary);
6173 	ia_css_binary_unload(&pipe->pipe_settings.capture.anr_gdc_binary);
6174 	ia_css_binary_unload(&pipe->pipe_settings.capture.post_isp_binary);
6175 	ia_css_binary_unload(&pipe->pipe_settings.capture.capture_pp_binary);
6176 	ia_css_binary_unload(&pipe->pipe_settings.capture.capture_ldc_binary);
6177 	ia_css_binary_unload(&pipe->pipe_settings.capture.vf_pp_binary);
6178 
6179 	for (i = 0; i < pipe->pipe_settings.capture.num_yuv_scaler; i++)
6180 		ia_css_binary_unload(&pipe->pipe_settings.capture.yuv_scaler_binary[i]);
6181 
6182 	kfree(pipe->pipe_settings.capture.is_output_stage);
6183 	pipe->pipe_settings.capture.is_output_stage = NULL;
6184 	kfree(pipe->pipe_settings.capture.yuv_scaler_binary);
6185 	pipe->pipe_settings.capture.yuv_scaler_binary = NULL;
6186 
6187 	IA_CSS_LEAVE_ERR_PRIVATE(0);
6188 	return 0;
6189 }
6190 
6191 static bool
6192 need_downscaling(const struct ia_css_resolution in_res,
6193 		 const struct ia_css_resolution out_res)
6194 {
6195 	if (in_res.width > out_res.width || in_res.height > out_res.height)
6196 		return true;
6197 
6198 	return false;
6199 }
6200 
6201 static bool
6202 need_yuv_scaler_stage(const struct ia_css_pipe *pipe)
6203 {
6204 	unsigned int i;
6205 	struct ia_css_resolution in_res, out_res;
6206 
6207 	bool need_format_conversion = false;
6208 
6209 	IA_CSS_ENTER_PRIVATE("");
6210 	assert(pipe);
6211 	assert(pipe->mode == IA_CSS_PIPE_ID_YUVPP);
6212 
6213 	/* TODO: make generic function */
6214 	need_format_conversion =
6215 	    ((pipe->stream->config.input_config.format ==
6216 		ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY) &&
6217 		(pipe->output_info[0].format != IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8));
6218 
6219 	in_res = pipe->config.input_effective_res;
6220 
6221 	if (pipe->config.enable_dz)
6222 		return true;
6223 
6224 	if ((pipe->output_info[0].res.width != 0) && need_format_conversion)
6225 		return true;
6226 
6227 	for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
6228 		out_res = pipe->output_info[i].res;
6229 
6230 		/* A non-zero width means it is a valid output port */
6231 		if ((out_res.width != 0) && need_downscaling(in_res, out_res))
6232 			return true;
6233 	}
6234 
6235 	return false;
6236 }
6237 
6238 /*
6239  * TODO: it is temporarily created from ia_css_pipe_create_cas_scaler_desc
6240  * which has some hard-coded knowledge which prevents reuse of the function.
6241  * Later, merge this with ia_css_pipe_create_cas_scaler_desc
6242  */
6243 static int ia_css_pipe_create_cas_scaler_desc_single_output(
6244 	    struct ia_css_frame_info *cas_scaler_in_info,
6245 	    struct ia_css_frame_info *cas_scaler_out_info,
6246 	    struct ia_css_frame_info *cas_scaler_vf_info,
6247 	    struct ia_css_cas_binary_descr *descr)
6248 {
6249 	unsigned int i;
6250 	unsigned int hor_ds_factor = 0, ver_ds_factor = 0;
6251 	int err = 0;
6252 	struct ia_css_frame_info tmp_in_info;
6253 
6254 	unsigned int max_scale_factor_per_stage = MAX_PREFERRED_YUV_DS_PER_STEP;
6255 
6256 	assert(cas_scaler_in_info);
6257 	assert(cas_scaler_out_info);
6258 
6259 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
6260 			    "ia_css_pipe_create_cas_scaler_desc() enter:\n");
6261 
6262 	/* We assume that this function is used only for single output port case. */
6263 	descr->num_output_stage = 1;
6264 
6265 	hor_ds_factor = CEIL_DIV(cas_scaler_in_info->res.width,
6266 				 cas_scaler_out_info->res.width);
6267 	ver_ds_factor = CEIL_DIV(cas_scaler_in_info->res.height,
6268 				 cas_scaler_out_info->res.height);
6269 	/* use the same horizontal and vertical downscaling factor for simplicity */
6270 	assert(hor_ds_factor == ver_ds_factor);
6271 
6272 	i = 1;
6273 	while (i < hor_ds_factor) {
6274 		descr->num_stage++;
6275 		i *= max_scale_factor_per_stage;
6276 	}
6277 
6278 	descr->in_info = kmalloc(descr->num_stage *
6279 				 sizeof(struct ia_css_frame_info),
6280 				 GFP_KERNEL);
6281 	if (!descr->in_info) {
6282 		err = -ENOMEM;
6283 		goto ERR;
6284 	}
6285 	descr->internal_out_info = kmalloc(descr->num_stage *
6286 					   sizeof(struct ia_css_frame_info),
6287 					   GFP_KERNEL);
6288 	if (!descr->internal_out_info) {
6289 		err = -ENOMEM;
6290 		goto ERR;
6291 	}
6292 	descr->out_info = kmalloc(descr->num_stage *
6293 				  sizeof(struct ia_css_frame_info),
6294 				  GFP_KERNEL);
6295 	if (!descr->out_info) {
6296 		err = -ENOMEM;
6297 		goto ERR;
6298 	}
6299 	descr->vf_info = kmalloc(descr->num_stage *
6300 				 sizeof(struct ia_css_frame_info),
6301 				 GFP_KERNEL);
6302 	if (!descr->vf_info) {
6303 		err = -ENOMEM;
6304 		goto ERR;
6305 	}
6306 	descr->is_output_stage = kmalloc(descr->num_stage * sizeof(bool),
6307 					 GFP_KERNEL);
6308 	if (!descr->is_output_stage) {
6309 		err = -ENOMEM;
6310 		goto ERR;
6311 	}
6312 
6313 	tmp_in_info = *cas_scaler_in_info;
6314 	for (i = 0; i < descr->num_stage; i++) {
6315 		descr->in_info[i] = tmp_in_info;
6316 		if ((tmp_in_info.res.width / max_scale_factor_per_stage) <=
6317 		    cas_scaler_out_info->res.width) {
6318 			descr->is_output_stage[i] = true;
6319 			if ((descr->num_output_stage > 1) && (i != (descr->num_stage - 1))) {
6320 				descr->internal_out_info[i].res.width = cas_scaler_out_info->res.width;
6321 				descr->internal_out_info[i].res.height = cas_scaler_out_info->res.height;
6322 				descr->internal_out_info[i].padded_width = cas_scaler_out_info->padded_width;
6323 				descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420;
6324 			} else {
6325 				assert(i == (descr->num_stage - 1));
6326 				descr->internal_out_info[i].res.width = 0;
6327 				descr->internal_out_info[i].res.height = 0;
6328 			}
6329 			descr->out_info[i].res.width = cas_scaler_out_info->res.width;
6330 			descr->out_info[i].res.height = cas_scaler_out_info->res.height;
6331 			descr->out_info[i].padded_width = cas_scaler_out_info->padded_width;
6332 			descr->out_info[i].format = cas_scaler_out_info->format;
6333 			if (cas_scaler_vf_info) {
6334 				descr->vf_info[i].res.width = cas_scaler_vf_info->res.width;
6335 				descr->vf_info[i].res.height = cas_scaler_vf_info->res.height;
6336 				descr->vf_info[i].padded_width = cas_scaler_vf_info->padded_width;
6337 				ia_css_frame_info_set_format(&descr->vf_info[i], IA_CSS_FRAME_FORMAT_YUV_LINE);
6338 			} else {
6339 				descr->vf_info[i].res.width = 0;
6340 				descr->vf_info[i].res.height = 0;
6341 				descr->vf_info[i].padded_width = 0;
6342 			}
6343 		} else {
6344 			descr->is_output_stage[i] = false;
6345 			descr->internal_out_info[i].res.width = tmp_in_info.res.width /
6346 								max_scale_factor_per_stage;
6347 			descr->internal_out_info[i].res.height = tmp_in_info.res.height /
6348 				max_scale_factor_per_stage;
6349 			descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420;
6350 			ia_css_frame_info_init(&descr->internal_out_info[i],
6351 					       tmp_in_info.res.width / max_scale_factor_per_stage,
6352 					       tmp_in_info.res.height / max_scale_factor_per_stage,
6353 					       IA_CSS_FRAME_FORMAT_YUV420, 0);
6354 			descr->out_info[i].res.width = 0;
6355 			descr->out_info[i].res.height = 0;
6356 			descr->vf_info[i].res.width = 0;
6357 			descr->vf_info[i].res.height = 0;
6358 		}
6359 		tmp_in_info = descr->internal_out_info[i];
6360 	}
6361 ERR:
6362 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
6363 			    "ia_css_pipe_create_cas_scaler_desc() leave, err=%d\n",
6364 			    err);
6365 	return err;
6366 }
6367 
6368 /* FIXME: merge most of this and single output version */
6369 static int
6370 ia_css_pipe_create_cas_scaler_desc(struct ia_css_pipe *pipe,
6371 				   struct ia_css_cas_binary_descr *descr)
6372 {
6373 	struct ia_css_frame_info in_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO;
6374 	struct ia_css_frame_info *out_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE];
6375 	struct ia_css_frame_info *vf_out_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE];
6376 	struct ia_css_frame_info tmp_in_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO;
6377 	unsigned int i, j;
6378 	unsigned int hor_scale_factor[IA_CSS_PIPE_MAX_OUTPUT_STAGE],
6379 		    ver_scale_factor[IA_CSS_PIPE_MAX_OUTPUT_STAGE],
6380 		    scale_factor = 0;
6381 	unsigned int num_stages = 0;
6382 	int err = 0;
6383 
6384 	unsigned int max_scale_factor_per_stage = MAX_PREFERRED_YUV_DS_PER_STEP;
6385 
6386 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
6387 			    "ia_css_pipe_create_cas_scaler_desc() enter:\n");
6388 
6389 	for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
6390 		out_info[i] = NULL;
6391 		vf_out_info[i] = NULL;
6392 		hor_scale_factor[i] = 0;
6393 		ver_scale_factor[i] = 0;
6394 	}
6395 
6396 	in_info.res = pipe->config.input_effective_res;
6397 	in_info.padded_width = in_info.res.width;
6398 	descr->num_output_stage = 0;
6399 	/* Find out how much scaling we need for each output */
6400 	for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
6401 		if (pipe->output_info[i].res.width != 0) {
6402 			out_info[i] = &pipe->output_info[i];
6403 			if (pipe->vf_output_info[i].res.width != 0)
6404 				vf_out_info[i] = &pipe->vf_output_info[i];
6405 			descr->num_output_stage += 1;
6406 		}
6407 
6408 		if (out_info[i]) {
6409 			hor_scale_factor[i] = CEIL_DIV(in_info.res.width, out_info[i]->res.width);
6410 			ver_scale_factor[i] = CEIL_DIV(in_info.res.height, out_info[i]->res.height);
6411 			/* use the same horizontal and vertical scaling factor for simplicity */
6412 			assert(hor_scale_factor[i] == ver_scale_factor[i]);
6413 			scale_factor = 1;
6414 			do {
6415 				num_stages++;
6416 				scale_factor *= max_scale_factor_per_stage;
6417 			} while (scale_factor < hor_scale_factor[i]);
6418 
6419 			in_info.res = out_info[i]->res;
6420 		}
6421 	}
6422 
6423 	if (need_yuv_scaler_stage(pipe) && (num_stages == 0))
6424 		num_stages = 1;
6425 
6426 	descr->num_stage = num_stages;
6427 
6428 	descr->in_info = kmalloc_array(descr->num_stage,
6429 				       sizeof(struct ia_css_frame_info),
6430 				       GFP_KERNEL);
6431 	if (!descr->in_info) {
6432 		err = -ENOMEM;
6433 		goto ERR;
6434 	}
6435 	descr->internal_out_info = kmalloc(descr->num_stage *
6436 					   sizeof(struct ia_css_frame_info),
6437 					   GFP_KERNEL);
6438 	if (!descr->internal_out_info) {
6439 		err = -ENOMEM;
6440 		goto ERR;
6441 	}
6442 	descr->out_info = kmalloc(descr->num_stage *
6443 				  sizeof(struct ia_css_frame_info),
6444 				  GFP_KERNEL);
6445 	if (!descr->out_info) {
6446 		err = -ENOMEM;
6447 		goto ERR;
6448 	}
6449 	descr->vf_info = kmalloc(descr->num_stage *
6450 				 sizeof(struct ia_css_frame_info),
6451 				 GFP_KERNEL);
6452 	if (!descr->vf_info) {
6453 		err = -ENOMEM;
6454 		goto ERR;
6455 	}
6456 	descr->is_output_stage = kmalloc(descr->num_stage * sizeof(bool),
6457 					 GFP_KERNEL);
6458 	if (!descr->is_output_stage) {
6459 		err = -ENOMEM;
6460 		goto ERR;
6461 	}
6462 
6463 	for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
6464 		if (out_info[i]) {
6465 			if (i > 0) {
6466 				assert((out_info[i - 1]->res.width >= out_info[i]->res.width) &&
6467 				       (out_info[i - 1]->res.height >= out_info[i]->res.height));
6468 			}
6469 		}
6470 	}
6471 
6472 	tmp_in_info.res = pipe->config.input_effective_res;
6473 	tmp_in_info.format = IA_CSS_FRAME_FORMAT_YUV420;
6474 	for (i = 0, j = 0; i < descr->num_stage; i++) {
6475 		assert(j < 2);
6476 		assert(out_info[j]);
6477 
6478 		descr->in_info[i] = tmp_in_info;
6479 		if ((tmp_in_info.res.width / max_scale_factor_per_stage) <=
6480 		    out_info[j]->res.width) {
6481 			descr->is_output_stage[i] = true;
6482 			if ((descr->num_output_stage > 1) && (i != (descr->num_stage - 1))) {
6483 				descr->internal_out_info[i].res.width = out_info[j]->res.width;
6484 				descr->internal_out_info[i].res.height = out_info[j]->res.height;
6485 				descr->internal_out_info[i].padded_width = out_info[j]->padded_width;
6486 				descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420;
6487 			} else {
6488 				assert(i == (descr->num_stage - 1));
6489 				descr->internal_out_info[i].res.width = 0;
6490 				descr->internal_out_info[i].res.height = 0;
6491 			}
6492 			descr->out_info[i].res.width = out_info[j]->res.width;
6493 			descr->out_info[i].res.height = out_info[j]->res.height;
6494 			descr->out_info[i].padded_width = out_info[j]->padded_width;
6495 			descr->out_info[i].format = out_info[j]->format;
6496 			if (vf_out_info[j]) {
6497 				descr->vf_info[i].res.width = vf_out_info[j]->res.width;
6498 				descr->vf_info[i].res.height = vf_out_info[j]->res.height;
6499 				descr->vf_info[i].padded_width = vf_out_info[j]->padded_width;
6500 				ia_css_frame_info_set_format(&descr->vf_info[i], IA_CSS_FRAME_FORMAT_YUV_LINE);
6501 			} else {
6502 				descr->vf_info[i].res.width = 0;
6503 				descr->vf_info[i].res.height = 0;
6504 				descr->vf_info[i].padded_width = 0;
6505 			}
6506 			j++;
6507 		} else {
6508 			descr->is_output_stage[i] = false;
6509 			descr->internal_out_info[i].res.width = tmp_in_info.res.width /
6510 								max_scale_factor_per_stage;
6511 			descr->internal_out_info[i].res.height = tmp_in_info.res.height /
6512 				max_scale_factor_per_stage;
6513 			descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420;
6514 			ia_css_frame_info_init(&descr->internal_out_info[i],
6515 					       tmp_in_info.res.width / max_scale_factor_per_stage,
6516 					       tmp_in_info.res.height / max_scale_factor_per_stage,
6517 					       IA_CSS_FRAME_FORMAT_YUV420, 0);
6518 			descr->out_info[i].res.width = 0;
6519 			descr->out_info[i].res.height = 0;
6520 			descr->vf_info[i].res.width = 0;
6521 			descr->vf_info[i].res.height = 0;
6522 		}
6523 		tmp_in_info = descr->internal_out_info[i];
6524 	}
6525 ERR:
6526 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
6527 			    "ia_css_pipe_create_cas_scaler_desc() leave, err=%d\n",
6528 			    err);
6529 	return err;
6530 }
6531 
6532 static void ia_css_pipe_destroy_cas_scaler_desc(struct ia_css_cas_binary_descr
6533 	*descr)
6534 {
6535 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
6536 			    "ia_css_pipe_destroy_cas_scaler_desc() enter:\n");
6537 	kfree(descr->in_info);
6538 	descr->in_info = NULL;
6539 	kfree(descr->internal_out_info);
6540 	descr->internal_out_info = NULL;
6541 	kfree(descr->out_info);
6542 	descr->out_info = NULL;
6543 	kfree(descr->vf_info);
6544 	descr->vf_info = NULL;
6545 	kfree(descr->is_output_stage);
6546 	descr->is_output_stage = NULL;
6547 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
6548 			    "ia_css_pipe_destroy_cas_scaler_desc() leave\n");
6549 }
6550 
6551 static int
6552 load_yuvpp_binaries(struct ia_css_pipe *pipe)
6553 {
6554 	int err = 0;
6555 	bool need_scaler = false;
6556 	struct ia_css_frame_info *vf_pp_in_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE];
6557 	struct ia_css_yuvpp_settings *mycs;
6558 	struct ia_css_binary *next_binary;
6559 	struct ia_css_cas_binary_descr cas_scaler_descr = { };
6560 	unsigned int i, j;
6561 	bool need_isp_copy_binary = false;
6562 
6563 	IA_CSS_ENTER_PRIVATE("");
6564 	assert(pipe);
6565 	assert(pipe->stream);
6566 	assert(pipe->mode == IA_CSS_PIPE_ID_YUVPP);
6567 
6568 	if (pipe->pipe_settings.yuvpp.copy_binary.info)
6569 		goto ERR;
6570 
6571 	/* Set both must_be_raw and must_be_yuv to false then yuvpp can take rgb inputs */
6572 	err = ia_css_util_check_input(&pipe->stream->config, false, false);
6573 	if (err)
6574 		goto ERR;
6575 
6576 	mycs = &pipe->pipe_settings.yuvpp;
6577 
6578 	for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
6579 		if (pipe->vf_output_info[i].res.width != 0) {
6580 			err = ia_css_util_check_vf_out_info(&pipe->output_info[i],
6581 							    &pipe->vf_output_info[i]);
6582 			if (err)
6583 				goto ERR;
6584 		}
6585 		vf_pp_in_info[i] = NULL;
6586 	}
6587 
6588 	need_scaler = need_yuv_scaler_stage(pipe);
6589 
6590 	/* we build up the pipeline starting at the end */
6591 	/* Capture post-processing */
6592 	if (need_scaler) {
6593 		struct ia_css_binary_descr yuv_scaler_descr;
6594 
6595 		err = ia_css_pipe_create_cas_scaler_desc(pipe,
6596 							 &cas_scaler_descr);
6597 		if (err)
6598 			goto ERR;
6599 		mycs->num_output = cas_scaler_descr.num_output_stage;
6600 		mycs->num_yuv_scaler = cas_scaler_descr.num_stage;
6601 		mycs->yuv_scaler_binary = kcalloc(cas_scaler_descr.num_stage,
6602 						  sizeof(struct ia_css_binary),
6603 						  GFP_KERNEL);
6604 		if (!mycs->yuv_scaler_binary) {
6605 			err = -ENOMEM;
6606 			goto ERR;
6607 		}
6608 		mycs->is_output_stage = kcalloc(cas_scaler_descr.num_stage,
6609 						sizeof(bool), GFP_KERNEL);
6610 		if (!mycs->is_output_stage) {
6611 			err = -ENOMEM;
6612 			goto ERR;
6613 		}
6614 		for (i = 0; i < cas_scaler_descr.num_stage; i++) {
6615 			mycs->is_output_stage[i] = cas_scaler_descr.is_output_stage[i];
6616 			ia_css_pipe_get_yuvscaler_binarydesc(pipe,
6617 							     &yuv_scaler_descr,
6618 							     &cas_scaler_descr.in_info[i],
6619 							     &cas_scaler_descr.out_info[i],
6620 							     &cas_scaler_descr.internal_out_info[i],
6621 							     &cas_scaler_descr.vf_info[i]);
6622 			err = ia_css_binary_find(&yuv_scaler_descr,
6623 						 &mycs->yuv_scaler_binary[i]);
6624 			if (err)
6625 				goto ERR;
6626 		}
6627 		ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr);
6628 	} else {
6629 		mycs->num_output = 1;
6630 	}
6631 
6632 	if (need_scaler)
6633 		next_binary = &mycs->yuv_scaler_binary[0];
6634 	else
6635 		next_binary = NULL;
6636 
6637 #if defined(ISP2401)
6638 	/*
6639 	 * NOTES
6640 	 * - Why does the "yuvpp" pipe needs "isp_copy_binary" (i.e. ISP Copy) when
6641 	 *   its input is "ATOMISP_INPUT_FORMAT_YUV422_8"?
6642 	 *
6643 	 *   In most use cases, the first stage in the "yuvpp" pipe is the "yuv_scale_
6644 	 *   binary". However, the "yuv_scale_binary" does NOT support the input-frame
6645 	 *   format as "IA_CSS_STREAM _FORMAT_YUV422_8".
6646 	 *
6647 	 *   Hence, the "isp_copy_binary" is required to be present in front of the "yuv
6648 	 *   _scale_binary". It would translate the input-frame to the frame formats that
6649 	 *   are supported by the "yuv_scale_binary".
6650 	 *
6651 	 *   Please refer to "FrameWork/css/isp/pipes/capture_pp/capture_pp_1.0/capture_
6652 	 *   pp_defs.h" for the list of input-frame formats that are supported by the
6653 	 *   "yuv_scale_binary".
6654 	 */
6655 	need_isp_copy_binary =
6656 	    (pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_YUV422_8);
6657 #else  /* !ISP2401 */
6658 	need_isp_copy_binary = true;
6659 #endif /*  ISP2401 */
6660 
6661 	if (need_isp_copy_binary) {
6662 		err = load_copy_binary(pipe,
6663 				       &mycs->copy_binary,
6664 				       next_binary);
6665 
6666 		if (err)
6667 			goto ERR;
6668 
6669 		/*
6670 		 * NOTES
6671 		 * - Why is "pipe->pipe_settings.capture.copy_binary.online" specified?
6672 		 *
6673 		 *   In some use cases, the first stage in the "yuvpp" pipe is the
6674 		 *   "isp_copy_binary". The "isp_copy_binary" is designed to process
6675 		 *   the input from either the system DDR or from the IPU internal VMEM.
6676 		 *   So it provides the flag "online" to specify where its input is from,
6677 		 *   i.e.:
6678 		 *
6679 		 *      (1) "online <= true", the input is from the IPU internal VMEM.
6680 		 *      (2) "online <= false", the input is from the system DDR.
6681 		 *
6682 		 *   In other use cases, the first stage in the "yuvpp" pipe is the
6683 		 *   "yuv_scale_binary". "The "yuv_scale_binary" is designed to process the
6684 		 *   input ONLY from the system DDR. So it does not provide the flag "online"
6685 		 *   to specify where its input is from.
6686 		 */
6687 		pipe->pipe_settings.capture.copy_binary.online = pipe->stream->config.online;
6688 	}
6689 
6690 	/* Viewfinder post-processing */
6691 	if (need_scaler) {
6692 		for (i = 0, j = 0; i < mycs->num_yuv_scaler; i++) {
6693 			if (mycs->is_output_stage[i]) {
6694 				assert(j < 2);
6695 				vf_pp_in_info[j] =
6696 				    &mycs->yuv_scaler_binary[i].vf_frame_info;
6697 				j++;
6698 			}
6699 		}
6700 		mycs->num_vf_pp = j;
6701 	} else {
6702 		vf_pp_in_info[0] =
6703 		    &mycs->copy_binary.vf_frame_info;
6704 		for (i = 1; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++)
6705 			vf_pp_in_info[i] = NULL;
6706 
6707 		mycs->num_vf_pp = 1;
6708 	}
6709 	mycs->vf_pp_binary = kcalloc(mycs->num_vf_pp,
6710 				     sizeof(struct ia_css_binary),
6711 				     GFP_KERNEL);
6712 	if (!mycs->vf_pp_binary) {
6713 		err = -ENOMEM;
6714 		goto ERR;
6715 	}
6716 
6717 	{
6718 		struct ia_css_binary_descr vf_pp_descr;
6719 
6720 		for (i = 0; i < mycs->num_vf_pp; i++) {
6721 			if (pipe->vf_output_info[i].res.width != 0) {
6722 				ia_css_pipe_get_vfpp_binarydesc(pipe,
6723 								&vf_pp_descr, vf_pp_in_info[i], &pipe->vf_output_info[i]);
6724 				err = ia_css_binary_find(&vf_pp_descr, &mycs->vf_pp_binary[i]);
6725 				if (err)
6726 					goto ERR;
6727 			}
6728 		}
6729 	}
6730 
6731 	if (err)
6732 		goto ERR;
6733 
6734 ERR:
6735 	if (need_scaler)
6736 		ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr);
6737 
6738 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "load_yuvpp_binaries() leave, err=%d\n",
6739 			    err);
6740 	return err;
6741 }
6742 
6743 static int
6744 unload_yuvpp_binaries(struct ia_css_pipe *pipe)
6745 {
6746 	unsigned int i;
6747 
6748 	IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
6749 
6750 	if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP)) {
6751 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
6752 		return -EINVAL;
6753 	}
6754 	ia_css_binary_unload(&pipe->pipe_settings.yuvpp.copy_binary);
6755 	for (i = 0; i < pipe->pipe_settings.yuvpp.num_yuv_scaler; i++)
6756 		ia_css_binary_unload(&pipe->pipe_settings.yuvpp.yuv_scaler_binary[i]);
6757 
6758 	for (i = 0; i < pipe->pipe_settings.yuvpp.num_vf_pp; i++)
6759 		ia_css_binary_unload(&pipe->pipe_settings.yuvpp.vf_pp_binary[i]);
6760 
6761 	kfree(pipe->pipe_settings.yuvpp.is_output_stage);
6762 	pipe->pipe_settings.yuvpp.is_output_stage = NULL;
6763 	kfree(pipe->pipe_settings.yuvpp.yuv_scaler_binary);
6764 	pipe->pipe_settings.yuvpp.yuv_scaler_binary = NULL;
6765 	kfree(pipe->pipe_settings.yuvpp.vf_pp_binary);
6766 	pipe->pipe_settings.yuvpp.vf_pp_binary = NULL;
6767 
6768 	IA_CSS_LEAVE_ERR_PRIVATE(0);
6769 	return 0;
6770 }
6771 
6772 static int yuvpp_start(struct ia_css_pipe *pipe)
6773 {
6774 	int err = 0;
6775 	enum sh_css_pipe_config_override copy_ovrd;
6776 	enum ia_css_input_mode yuvpp_pipe_input_mode;
6777 	unsigned int thread_id;
6778 
6779 	IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
6780 	if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP)) {
6781 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
6782 		return -EINVAL;
6783 	}
6784 
6785 	yuvpp_pipe_input_mode = pipe->stream->config.mode;
6786 
6787 	sh_css_metrics_start_frame();
6788 
6789 	/* multi stream video needs mipi buffers */
6790 
6791 	err = send_mipi_frames(pipe);
6792 	if (err) {
6793 		IA_CSS_LEAVE_ERR_PRIVATE(err);
6794 		return err;
6795 	}
6796 
6797 	ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
6798 	copy_ovrd = 1 << thread_id;
6799 
6800 	start_pipe(pipe, copy_ovrd, yuvpp_pipe_input_mode);
6801 
6802 	IA_CSS_LEAVE_ERR_PRIVATE(err);
6803 	return err;
6804 }
6805 
6806 static int
6807 sh_css_pipe_unload_binaries(struct ia_css_pipe *pipe)
6808 {
6809 	int err = 0;
6810 
6811 	IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
6812 
6813 	if (!pipe) {
6814 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
6815 		return -EINVAL;
6816 	}
6817 	/* PIPE_MODE_COPY has no binaries, but has output frames to outside*/
6818 	if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY) {
6819 		IA_CSS_LEAVE_ERR_PRIVATE(0);
6820 		return 0;
6821 	}
6822 
6823 	switch (pipe->mode) {
6824 	case IA_CSS_PIPE_ID_PREVIEW:
6825 		err = unload_preview_binaries(pipe);
6826 		break;
6827 	case IA_CSS_PIPE_ID_VIDEO:
6828 		err = unload_video_binaries(pipe);
6829 		break;
6830 	case IA_CSS_PIPE_ID_CAPTURE:
6831 		err = unload_capture_binaries(pipe);
6832 		break;
6833 	case IA_CSS_PIPE_ID_YUVPP:
6834 		err = unload_yuvpp_binaries(pipe);
6835 		break;
6836 	default:
6837 		break;
6838 	}
6839 	IA_CSS_LEAVE_ERR_PRIVATE(err);
6840 	return err;
6841 }
6842 
6843 static int
6844 sh_css_pipe_load_binaries(struct ia_css_pipe *pipe)
6845 {
6846 	int err = 0;
6847 
6848 	assert(pipe);
6849 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "sh_css_pipe_load_binaries() enter:\n");
6850 
6851 	/* PIPE_MODE_COPY has no binaries, but has output frames to outside*/
6852 	if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY)
6853 		return err;
6854 
6855 	switch (pipe->mode) {
6856 	case IA_CSS_PIPE_ID_PREVIEW:
6857 		err = load_preview_binaries(pipe);
6858 		break;
6859 	case IA_CSS_PIPE_ID_VIDEO:
6860 		err = load_video_binaries(pipe);
6861 		break;
6862 	case IA_CSS_PIPE_ID_CAPTURE:
6863 		err = load_capture_binaries(pipe);
6864 		break;
6865 	case IA_CSS_PIPE_ID_YUVPP:
6866 		err = load_yuvpp_binaries(pipe);
6867 		break;
6868 	case IA_CSS_PIPE_ID_ACC:
6869 		break;
6870 	default:
6871 		err = -EINVAL;
6872 		break;
6873 	}
6874 	if (err) {
6875 		if (sh_css_pipe_unload_binaries(pipe)) {
6876 			/*
6877 			 * currently css does not support multiple error
6878 			 * returns in a single function, using -EINVAL in
6879 			 * this case
6880 			 */
6881 			err = -EINVAL;
6882 		}
6883 	}
6884 	return err;
6885 }
6886 
6887 static int
6888 create_host_yuvpp_pipeline(struct ia_css_pipe *pipe)
6889 {
6890 	struct ia_css_pipeline *me;
6891 	int err = 0;
6892 	struct ia_css_pipeline_stage *vf_pp_stage = NULL,
6893 		*copy_stage = NULL,
6894 		*yuv_scaler_stage = NULL;
6895 	struct ia_css_binary *copy_binary,
6896 		*vf_pp_binary,
6897 		*yuv_scaler_binary;
6898 	bool need_scaler = false;
6899 	unsigned int num_stage, num_output_stage;
6900 	unsigned int i, j;
6901 
6902 	struct ia_css_frame *in_frame = NULL;
6903 	struct ia_css_frame *out_frame[IA_CSS_PIPE_MAX_OUTPUT_STAGE];
6904 	struct ia_css_frame *bin_out_frame[IA_CSS_BINARY_MAX_OUTPUT_PORTS];
6905 	struct ia_css_frame *vf_frame[IA_CSS_PIPE_MAX_OUTPUT_STAGE];
6906 	struct ia_css_pipeline_stage_desc stage_desc;
6907 	bool need_in_frameinfo_memory = false;
6908 #ifdef ISP2401
6909 	bool sensor = false;
6910 	bool buffered_sensor = false;
6911 	bool online = false;
6912 	bool continuous = false;
6913 #endif
6914 
6915 	IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
6916 	if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP)) {
6917 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
6918 		return -EINVAL;
6919 	}
6920 	me = &pipe->pipeline;
6921 	ia_css_pipeline_clean(me);
6922 	for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
6923 		out_frame[i] = NULL;
6924 		vf_frame[i] = NULL;
6925 	}
6926 	ia_css_pipe_util_create_output_frames(bin_out_frame);
6927 	num_stage  = pipe->pipe_settings.yuvpp.num_yuv_scaler;
6928 	num_output_stage   = pipe->pipe_settings.yuvpp.num_output;
6929 
6930 #ifdef ISP2401
6931 	/*
6932 	 * When the input system is 2401, always enable 'in_frameinfo_memory'
6933 	 * except for the following:
6934 	 * - Direct Sensor Mode Online Capture
6935 	 * - Direct Sensor Mode Continuous Capture
6936 	 * - Buffered Sensor Mode Continuous Capture
6937 	 */
6938 	sensor = pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR;
6939 	buffered_sensor = pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR;
6940 	online = pipe->stream->config.online;
6941 	continuous = pipe->stream->config.continuous;
6942 	need_in_frameinfo_memory =
6943 	!((sensor && (online || continuous)) || (buffered_sensor && continuous));
6944 #else
6945 	/* Construct in_frame info (only in case we have dynamic input */
6946 	need_in_frameinfo_memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY;
6947 #endif
6948 	/*
6949 	 * the input frame can come from:
6950 	 *
6951 	 *  a) memory: connect yuvscaler to me->in_frame
6952 	 *  b) sensor, via copy binary: connect yuvscaler to copy binary later
6953 	 *     on
6954 	 */
6955 	if (need_in_frameinfo_memory) {
6956 		/* TODO: improve for different input formats. */
6957 
6958 		/*
6959 		 * "pipe->stream->config.input_config.format" represents the sensor output
6960 		 * frame format, e.g. YUV422 8-bit.
6961 		 *
6962 		 * "in_frame_format" represents the imaging pipe's input frame format, e.g.
6963 		 * Bayer-Quad RAW.
6964 		 */
6965 		int in_frame_format;
6966 
6967 		if (pipe->stream->config.input_config.format ==
6968 		    ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY) {
6969 			in_frame_format = IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8;
6970 		} else if (pipe->stream->config.input_config.format ==
6971 			    ATOMISP_INPUT_FORMAT_YUV422_8) {
6972 			/*
6973 			 * When the sensor output frame format is "ATOMISP_INPUT_FORMAT_YUV422_8",
6974 			 * the "isp_copy_var" binary is selected as the first stage in the yuvpp
6975 			 * pipe.
6976 			 *
6977 			 * For the "isp_copy_var" binary, it reads the YUV422-8 pixels from
6978 			 * the frame buffer (at DDR) to the frame-line buffer (at VMEM).
6979 			 *
6980 			 * By now, the "isp_copy_var" binary does NOT provide a separated
6981 			 * frame-line buffer to store the YUV422-8 pixels. Instead, it stores
6982 			 * the YUV422-8 pixels in the frame-line buffer which is designed to
6983 			 * store the Bayer-Quad RAW pixels.
6984 			 *
6985 			 * To direct the "isp_copy_var" binary reading from the RAW frame-line
6986 			 * buffer, its input frame format must be specified as "IA_CSS_FRAME_
6987 			 * FORMAT_RAW".
6988 			 */
6989 			in_frame_format = IA_CSS_FRAME_FORMAT_RAW;
6990 		} else {
6991 			in_frame_format = IA_CSS_FRAME_FORMAT_NV12;
6992 		}
6993 
6994 		err = init_in_frameinfo_memory_defaults(pipe,
6995 							&me->in_frame,
6996 							in_frame_format);
6997 
6998 		if (err) {
6999 			IA_CSS_LEAVE_ERR_PRIVATE(err);
7000 			return err;
7001 		}
7002 
7003 		in_frame = &me->in_frame;
7004 	} else {
7005 		in_frame = NULL;
7006 	}
7007 
7008 	for (i = 0; i < num_output_stage; i++) {
7009 		assert(i < IA_CSS_PIPE_MAX_OUTPUT_STAGE);
7010 		if (pipe->output_info[i].res.width != 0) {
7011 			err = init_out_frameinfo_defaults(pipe, &me->out_frame[i], i);
7012 			if (err) {
7013 				IA_CSS_LEAVE_ERR_PRIVATE(err);
7014 				return err;
7015 			}
7016 			out_frame[i] = &me->out_frame[i];
7017 		}
7018 
7019 		/* Construct vf_frame info (only in case we have VF) */
7020 		if (pipe->vf_output_info[i].res.width != 0) {
7021 			err = init_vf_frameinfo_defaults(pipe, &me->vf_frame[i], i);
7022 			if (err) {
7023 				IA_CSS_LEAVE_ERR_PRIVATE(err);
7024 				return err;
7025 			}
7026 			vf_frame[i] = &me->vf_frame[i];
7027 		}
7028 	}
7029 
7030 	copy_binary       = &pipe->pipe_settings.yuvpp.copy_binary;
7031 	vf_pp_binary      = pipe->pipe_settings.yuvpp.vf_pp_binary;
7032 	yuv_scaler_binary = pipe->pipe_settings.yuvpp.yuv_scaler_binary;
7033 	need_scaler = need_yuv_scaler_stage(pipe);
7034 
7035 	if (pipe->pipe_settings.yuvpp.copy_binary.info) {
7036 		struct ia_css_frame *in_frame_local = NULL;
7037 
7038 #ifdef ISP2401
7039 		/* After isp copy is enabled in_frame needs to be passed. */
7040 		if (!online)
7041 			in_frame_local = in_frame;
7042 #endif
7043 
7044 		if (need_scaler) {
7045 			ia_css_pipe_util_set_output_frames(bin_out_frame,
7046 							   0, NULL);
7047 			ia_css_pipe_get_generic_stage_desc(&stage_desc,
7048 							   copy_binary,
7049 							   bin_out_frame,
7050 							   in_frame_local,
7051 							   NULL);
7052 		} else {
7053 			ia_css_pipe_util_set_output_frames(bin_out_frame,
7054 							   0, out_frame[0]);
7055 			ia_css_pipe_get_generic_stage_desc(&stage_desc,
7056 							   copy_binary,
7057 							   bin_out_frame,
7058 							   in_frame_local,
7059 							   NULL);
7060 		}
7061 
7062 		err = ia_css_pipeline_create_and_add_stage(me,
7063 							   &stage_desc,
7064 							   &copy_stage);
7065 
7066 		if (err) {
7067 			IA_CSS_LEAVE_ERR_PRIVATE(err);
7068 			return err;
7069 		}
7070 
7071 		if (copy_stage) {
7072 			/* if we use yuv scaler binary, vf output should be from there */
7073 			copy_stage->args.copy_vf = !need_scaler;
7074 			/* for yuvpp pipe, it should always be enabled */
7075 			copy_stage->args.copy_output = true;
7076 			/* connect output of copy binary to input of yuv scaler */
7077 			in_frame = copy_stage->args.out_frame[0];
7078 		}
7079 	}
7080 
7081 	if (need_scaler) {
7082 		struct ia_css_frame *tmp_out_frame = NULL;
7083 		struct ia_css_frame *tmp_vf_frame = NULL;
7084 		struct ia_css_frame *tmp_in_frame = in_frame;
7085 
7086 		for (i = 0, j = 0; i < num_stage; i++) {
7087 			assert(j < num_output_stage);
7088 			if (pipe->pipe_settings.yuvpp.is_output_stage[i]) {
7089 				tmp_out_frame = out_frame[j];
7090 				tmp_vf_frame = vf_frame[j];
7091 			} else {
7092 				tmp_out_frame = NULL;
7093 				tmp_vf_frame = NULL;
7094 			}
7095 
7096 			err = add_yuv_scaler_stage(pipe, me, tmp_in_frame,
7097 						   tmp_out_frame,
7098 						   NULL,
7099 						   &yuv_scaler_binary[i],
7100 						   &yuv_scaler_stage);
7101 
7102 			if (err) {
7103 				IA_CSS_LEAVE_ERR_PRIVATE(err);
7104 				return err;
7105 			}
7106 			/* we use output port 1 as internal output port */
7107 			tmp_in_frame = yuv_scaler_stage->args.out_frame[1];
7108 			if (pipe->pipe_settings.yuvpp.is_output_stage[i]) {
7109 				if (tmp_vf_frame && (tmp_vf_frame->info.res.width != 0)) {
7110 					in_frame = yuv_scaler_stage->args.out_vf_frame;
7111 					err = add_vf_pp_stage(pipe, in_frame,
7112 							      tmp_vf_frame,
7113 							      &vf_pp_binary[j],
7114 							      &vf_pp_stage);
7115 
7116 					if (err) {
7117 						IA_CSS_LEAVE_ERR_PRIVATE(err);
7118 						return err;
7119 					}
7120 				}
7121 				j++;
7122 			}
7123 		}
7124 	} else if (copy_stage) {
7125 		if (vf_frame[0] && vf_frame[0]->info.res.width != 0) {
7126 			in_frame = copy_stage->args.out_vf_frame;
7127 			err = add_vf_pp_stage(pipe, in_frame, vf_frame[0],
7128 					      &vf_pp_binary[0], &vf_pp_stage);
7129 		}
7130 		if (err) {
7131 			IA_CSS_LEAVE_ERR_PRIVATE(err);
7132 			return err;
7133 		}
7134 	}
7135 
7136 	ia_css_pipeline_finalize_stages(&pipe->pipeline,
7137 					pipe->stream->config.continuous);
7138 
7139 	IA_CSS_LEAVE_ERR_PRIVATE(0);
7140 
7141 	return 0;
7142 }
7143 
7144 static int
7145 create_host_copy_pipeline(struct ia_css_pipe *pipe,
7146 			  unsigned int max_input_width,
7147 			  struct ia_css_frame *out_frame)
7148 {
7149 	struct ia_css_pipeline *me;
7150 	int err = 0;
7151 	struct ia_css_pipeline_stage_desc stage_desc;
7152 
7153 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
7154 			    "create_host_copy_pipeline() enter:\n");
7155 
7156 	/* pipeline already created as part of create_host_pipeline_structure */
7157 	me = &pipe->pipeline;
7158 	ia_css_pipeline_clean(me);
7159 
7160 	/* Construct out_frame info */
7161 	out_frame->contiguous = false;
7162 	out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
7163 
7164 	if (copy_on_sp(pipe) &&
7165 	    pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8) {
7166 		ia_css_frame_info_init(&out_frame->info, JPEG_BYTES, 1,
7167 				       IA_CSS_FRAME_FORMAT_BINARY_8, 0);
7168 	} else if (out_frame->info.format == IA_CSS_FRAME_FORMAT_RAW) {
7169 		out_frame->info.raw_bit_depth =
7170 		ia_css_pipe_util_pipe_input_format_bpp(pipe);
7171 	}
7172 
7173 	me->num_stages = 1;
7174 	me->pipe_id = IA_CSS_PIPE_ID_COPY;
7175 	pipe->mode  = IA_CSS_PIPE_ID_COPY;
7176 
7177 	ia_css_pipe_get_sp_func_stage_desc(&stage_desc, out_frame,
7178 					   IA_CSS_PIPELINE_RAW_COPY,
7179 					   max_input_width);
7180 	err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, NULL);
7181 
7182 	ia_css_pipeline_finalize_stages(&pipe->pipeline,
7183 					pipe->stream->config.continuous);
7184 
7185 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
7186 			    "create_host_copy_pipeline() leave:\n");
7187 
7188 	return err;
7189 }
7190 
7191 static int
7192 create_host_isyscopy_capture_pipeline(struct ia_css_pipe *pipe)
7193 {
7194 	struct ia_css_pipeline *me = &pipe->pipeline;
7195 	int err = 0;
7196 	struct ia_css_pipeline_stage_desc stage_desc;
7197 	struct ia_css_frame *out_frame = &me->out_frame[0];
7198 	struct ia_css_pipeline_stage *out_stage = NULL;
7199 	unsigned int thread_id;
7200 	enum sh_css_queue_id queue_id;
7201 	unsigned int max_input_width = MAX_VECTORS_PER_INPUT_LINE_CONT * ISP_VEC_NELEMS;
7202 
7203 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
7204 			    "create_host_isyscopy_capture_pipeline() enter:\n");
7205 	ia_css_pipeline_clean(me);
7206 
7207 	/* Construct out_frame info */
7208 	err = sh_css_pipe_get_output_frame_info(pipe, &out_frame->info, 0);
7209 	if (err)
7210 		return err;
7211 	out_frame->contiguous = false;
7212 	out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
7213 	ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
7214 	ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, thread_id, &queue_id);
7215 	out_frame->dynamic_queue_id = queue_id;
7216 	out_frame->buf_type = IA_CSS_BUFFER_TYPE_OUTPUT_FRAME;
7217 
7218 	me->num_stages = 1;
7219 	me->pipe_id = IA_CSS_PIPE_ID_CAPTURE;
7220 	pipe->mode  = IA_CSS_PIPE_ID_CAPTURE;
7221 	ia_css_pipe_get_sp_func_stage_desc(&stage_desc, out_frame,
7222 					   IA_CSS_PIPELINE_ISYS_COPY,
7223 					   max_input_width);
7224 	err = ia_css_pipeline_create_and_add_stage(me,
7225 						   &stage_desc, &out_stage);
7226 	if (err)
7227 		return err;
7228 
7229 	ia_css_pipeline_finalize_stages(me, pipe->stream->config.continuous);
7230 
7231 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
7232 			    "create_host_isyscopy_capture_pipeline() leave:\n");
7233 
7234 	return err;
7235 }
7236 
7237 static int
7238 create_host_regular_capture_pipeline(struct ia_css_pipe *pipe)
7239 {
7240 	struct ia_css_pipeline *me;
7241 	int err = 0;
7242 	enum ia_css_capture_mode mode;
7243 	struct ia_css_pipeline_stage *current_stage = NULL;
7244 	struct ia_css_pipeline_stage *yuv_scaler_stage = NULL;
7245 	struct ia_css_binary *copy_binary,
7246 		*primary_binary[MAX_NUM_PRIMARY_STAGES],
7247 		*vf_pp_binary,
7248 		*pre_isp_binary,
7249 		*anr_gdc_binary,
7250 		*post_isp_binary,
7251 		*yuv_scaler_binary,
7252 		*capture_pp_binary,
7253 		*capture_ldc_binary;
7254 	bool need_pp = false;
7255 	bool raw;
7256 
7257 	struct ia_css_frame *in_frame;
7258 	struct ia_css_frame *out_frame;
7259 	struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS];
7260 	struct ia_css_frame *vf_frame;
7261 	struct ia_css_pipeline_stage_desc stage_desc;
7262 	bool need_in_frameinfo_memory = false;
7263 #ifdef ISP2401
7264 	bool sensor = false;
7265 	bool buffered_sensor = false;
7266 	bool online = false;
7267 	bool continuous = false;
7268 #endif
7269 	unsigned int i, num_yuv_scaler, num_primary_stage;
7270 	bool need_yuv_pp = false;
7271 	bool *is_output_stage = NULL;
7272 	bool need_ldc = false;
7273 
7274 	IA_CSS_ENTER_PRIVATE("");
7275 	assert(pipe);
7276 	assert(pipe->stream);
7277 	assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
7278 	       pipe->mode == IA_CSS_PIPE_ID_COPY);
7279 
7280 	me = &pipe->pipeline;
7281 	mode = pipe->config.default_capture_config.mode;
7282 	raw = (mode == IA_CSS_CAPTURE_MODE_RAW);
7283 	ia_css_pipeline_clean(me);
7284 	ia_css_pipe_util_create_output_frames(out_frames);
7285 
7286 #ifdef ISP2401
7287 	/*
7288 	 * When the input system is 2401, always enable 'in_frameinfo_memory'
7289 	 * except for the following:
7290 	 * - Direct Sensor Mode Online Capture
7291 	 * - Direct Sensor Mode Online Capture
7292 	 * - Direct Sensor Mode Continuous Capture
7293 	 * - Buffered Sensor Mode Continuous Capture
7294 	 */
7295 	sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR);
7296 	buffered_sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR);
7297 	online = pipe->stream->config.online;
7298 	continuous = pipe->stream->config.continuous;
7299 	need_in_frameinfo_memory =
7300 	!((sensor && (online || continuous)) || (buffered_sensor && (online || continuous)));
7301 #else
7302 	/* Construct in_frame info (only in case we have dynamic input */
7303 	need_in_frameinfo_memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY;
7304 #endif
7305 	if (need_in_frameinfo_memory) {
7306 		err = init_in_frameinfo_memory_defaults(pipe, &me->in_frame,
7307 							IA_CSS_FRAME_FORMAT_RAW);
7308 		if (err) {
7309 			IA_CSS_LEAVE_ERR_PRIVATE(err);
7310 			return err;
7311 		}
7312 
7313 		in_frame = &me->in_frame;
7314 	} else {
7315 		in_frame = NULL;
7316 	}
7317 
7318 	err = init_out_frameinfo_defaults(pipe, &me->out_frame[0], 0);
7319 	if (err) {
7320 		IA_CSS_LEAVE_ERR_PRIVATE(err);
7321 		return err;
7322 	}
7323 	out_frame = &me->out_frame[0];
7324 
7325 	/* Construct vf_frame info (only in case we have VF) */
7326 	if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) {
7327 		if (mode == IA_CSS_CAPTURE_MODE_RAW || mode == IA_CSS_CAPTURE_MODE_BAYER) {
7328 			/* These modes don't support viewfinder output */
7329 			vf_frame = NULL;
7330 		} else {
7331 			init_vf_frameinfo_defaults(pipe, &me->vf_frame[0], 0);
7332 			vf_frame = &me->vf_frame[0];
7333 		}
7334 	} else {
7335 		vf_frame = NULL;
7336 	}
7337 
7338 	copy_binary       = &pipe->pipe_settings.capture.copy_binary;
7339 	num_primary_stage = pipe->pipe_settings.capture.num_primary_stage;
7340 	if ((num_primary_stage == 0) && (mode == IA_CSS_CAPTURE_MODE_PRIMARY)) {
7341 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
7342 		return -EINVAL;
7343 	}
7344 
7345 	for (i = 0; i < num_primary_stage; i++)
7346 		primary_binary[i] = &pipe->pipe_settings.capture.primary_binary[i];
7347 
7348 	vf_pp_binary      = &pipe->pipe_settings.capture.vf_pp_binary;
7349 	pre_isp_binary    = &pipe->pipe_settings.capture.pre_isp_binary;
7350 	anr_gdc_binary    = &pipe->pipe_settings.capture.anr_gdc_binary;
7351 	post_isp_binary   = &pipe->pipe_settings.capture.post_isp_binary;
7352 	capture_pp_binary = &pipe->pipe_settings.capture.capture_pp_binary;
7353 	yuv_scaler_binary = pipe->pipe_settings.capture.yuv_scaler_binary;
7354 	num_yuv_scaler	  = pipe->pipe_settings.capture.num_yuv_scaler;
7355 	is_output_stage   = pipe->pipe_settings.capture.is_output_stage;
7356 	capture_ldc_binary = &pipe->pipe_settings.capture.capture_ldc_binary;
7357 
7358 	need_pp = (need_capture_pp(pipe) || pipe->output_stage) &&
7359 		    mode != IA_CSS_CAPTURE_MODE_RAW &&
7360 		    mode != IA_CSS_CAPTURE_MODE_BAYER;
7361 	need_yuv_pp = (yuv_scaler_binary && yuv_scaler_binary->info);
7362 	need_ldc = (capture_ldc_binary && capture_ldc_binary->info);
7363 
7364 	if (pipe->pipe_settings.capture.copy_binary.info) {
7365 		if (raw) {
7366 			ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
7367 #if defined(ISP2401)
7368 			if (!continuous) {
7369 				ia_css_pipe_get_generic_stage_desc(&stage_desc,
7370 								   copy_binary,
7371 								   out_frames,
7372 								   in_frame,
7373 								   NULL);
7374 			} else {
7375 				in_frame = pipe->stream->last_pipe->continuous_frames[0];
7376 				ia_css_pipe_get_generic_stage_desc(&stage_desc,
7377 								   copy_binary,
7378 								   out_frames,
7379 								   in_frame,
7380 								   NULL);
7381 			}
7382 #else
7383 			ia_css_pipe_get_generic_stage_desc(&stage_desc,
7384 							   copy_binary,
7385 							   out_frames,
7386 							   NULL, NULL);
7387 #endif
7388 		} else {
7389 			ia_css_pipe_util_set_output_frames(out_frames, 0,
7390 							   in_frame);
7391 			ia_css_pipe_get_generic_stage_desc(&stage_desc,
7392 							   copy_binary,
7393 							   out_frames,
7394 							   NULL, NULL);
7395 		}
7396 
7397 		err = ia_css_pipeline_create_and_add_stage(me,
7398 							   &stage_desc,
7399 							   &current_stage);
7400 		if (err) {
7401 			IA_CSS_LEAVE_ERR_PRIVATE(err);
7402 			return err;
7403 		}
7404 	} else if (pipe->stream->config.continuous) {
7405 		in_frame = pipe->stream->last_pipe->continuous_frames[0];
7406 	}
7407 
7408 	if (mode == IA_CSS_CAPTURE_MODE_PRIMARY) {
7409 		struct ia_css_frame *local_in_frame = NULL;
7410 		struct ia_css_frame *local_out_frame = NULL;
7411 
7412 		for (i = 0; i < num_primary_stage; i++) {
7413 			if (i == 0)
7414 				local_in_frame = in_frame;
7415 			else
7416 				local_in_frame = NULL;
7417 #ifndef ISP2401
7418 			if (!need_pp && (i == num_primary_stage - 1))
7419 #else
7420 			if (!need_pp && (i == num_primary_stage - 1) && !need_ldc)
7421 #endif
7422 				local_out_frame = out_frame;
7423 			else
7424 				local_out_frame = NULL;
7425 			ia_css_pipe_util_set_output_frames(out_frames, 0, local_out_frame);
7426 			/*
7427 			 * WARNING: The #if def flag has been added below as a
7428 			 * temporary solution to solve the problem of enabling the
7429 			 * view finder in a single binary in a capture flow. The
7430 			 * vf-pp stage has been removed from Skycam in the solution
7431 			 * provided. The vf-pp stage should be re-introduced when
7432 			 * required. This  * should not be considered as a clean solution.
7433 			 * Proper investigation should be done to come up with the clean
7434 			 * solution.
7435 			 */
7436 			ia_css_pipe_get_generic_stage_desc(&stage_desc,
7437 							   primary_binary[i],
7438 							   out_frames,
7439 							   local_in_frame,
7440 							   NULL);
7441 			err = ia_css_pipeline_create_and_add_stage(me,
7442 								   &stage_desc,
7443 								   &current_stage);
7444 			if (err) {
7445 				IA_CSS_LEAVE_ERR_PRIVATE(err);
7446 				return err;
7447 			}
7448 		}
7449 		/* If we use copy iso primary, the input must be yuv iso raw */
7450 		current_stage->args.copy_vf =
7451 		    primary_binary[0]->info->sp.pipeline.mode ==
7452 		    IA_CSS_BINARY_MODE_COPY;
7453 		current_stage->args.copy_output = current_stage->args.copy_vf;
7454 	} else if (mode == IA_CSS_CAPTURE_MODE_ADVANCED ||
7455 		    mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT) {
7456 		ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
7457 		ia_css_pipe_get_generic_stage_desc(&stage_desc, pre_isp_binary,
7458 						   out_frames, in_frame, NULL);
7459 		err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
7460 							   NULL);
7461 		if (err) {
7462 			IA_CSS_LEAVE_ERR_PRIVATE(err);
7463 			return err;
7464 		}
7465 		ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
7466 		ia_css_pipe_get_generic_stage_desc(&stage_desc, anr_gdc_binary,
7467 						   out_frames, NULL, NULL);
7468 		err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
7469 							   NULL);
7470 		if (err) {
7471 			IA_CSS_LEAVE_ERR_PRIVATE(err);
7472 			return err;
7473 		}
7474 
7475 		if (need_pp) {
7476 			ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
7477 			ia_css_pipe_get_generic_stage_desc(&stage_desc,
7478 							   post_isp_binary,
7479 							   out_frames,
7480 							   NULL, NULL);
7481 		} else {
7482 			ia_css_pipe_util_set_output_frames(out_frames, 0,
7483 							   out_frame);
7484 			ia_css_pipe_get_generic_stage_desc(&stage_desc,
7485 							   post_isp_binary,
7486 							   out_frames,
7487 							   NULL, NULL);
7488 		}
7489 
7490 		err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
7491 							   &current_stage);
7492 		if (err) {
7493 			IA_CSS_LEAVE_ERR_PRIVATE(err);
7494 			return err;
7495 		}
7496 	} else if (mode == IA_CSS_CAPTURE_MODE_BAYER) {
7497 		ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
7498 		ia_css_pipe_get_generic_stage_desc(&stage_desc, pre_isp_binary,
7499 						   out_frames, in_frame, NULL);
7500 		err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
7501 							   NULL);
7502 		if (err) {
7503 			IA_CSS_LEAVE_ERR_PRIVATE(err);
7504 			return err;
7505 		}
7506 	}
7507 
7508 	if (need_pp && current_stage) {
7509 		struct ia_css_frame *local_in_frame = NULL;
7510 
7511 		local_in_frame = current_stage->args.out_frame[0];
7512 
7513 		if (need_ldc) {
7514 			ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
7515 			ia_css_pipe_get_generic_stage_desc(&stage_desc,
7516 							   capture_ldc_binary,
7517 							   out_frames,
7518 							   local_in_frame,
7519 							   NULL);
7520 			err = ia_css_pipeline_create_and_add_stage(me,
7521 								   &stage_desc,
7522 								   &current_stage);
7523 			local_in_frame = current_stage->args.out_frame[0];
7524 		}
7525 		err = add_capture_pp_stage(pipe, me, local_in_frame,
7526 					   need_yuv_pp ? NULL : out_frame,
7527 					   capture_pp_binary,
7528 					   &current_stage);
7529 		if (err) {
7530 			IA_CSS_LEAVE_ERR_PRIVATE(err);
7531 			return err;
7532 		}
7533 	}
7534 
7535 	if (need_yuv_pp && current_stage) {
7536 		struct ia_css_frame *tmp_in_frame = current_stage->args.out_frame[0];
7537 		struct ia_css_frame *tmp_out_frame = NULL;
7538 
7539 		for (i = 0; i < num_yuv_scaler; i++) {
7540 			if (is_output_stage[i])
7541 				tmp_out_frame = out_frame;
7542 			else
7543 				tmp_out_frame = NULL;
7544 
7545 			err = add_yuv_scaler_stage(pipe, me, tmp_in_frame,
7546 						   tmp_out_frame, NULL,
7547 						   &yuv_scaler_binary[i],
7548 						   &yuv_scaler_stage);
7549 			if (err) {
7550 				IA_CSS_LEAVE_ERR_PRIVATE(err);
7551 				return err;
7552 			}
7553 			/* we use output port 1 as internal output port */
7554 			tmp_in_frame = yuv_scaler_stage->args.out_frame[1];
7555 		}
7556 	}
7557 
7558 	/*
7559 	 * WARNING: The #if def flag has been added below as a
7560 	 * temporary solution to solve the problem of enabling the
7561 	 * view finder in a single binary in a capture flow. The vf-pp
7562 	 * stage has been removed from Skycam in the solution provided.
7563 	 * The vf-pp stage should be re-introduced when required. This
7564 	 * should not be considered as a clean solution. Proper
7565 	 * investigation should be done to come up with the clean solution.
7566 	 */
7567 	if (mode != IA_CSS_CAPTURE_MODE_RAW &&
7568 	    mode != IA_CSS_CAPTURE_MODE_BAYER &&
7569 	    current_stage && vf_frame) {
7570 		in_frame = current_stage->args.out_vf_frame;
7571 		err = add_vf_pp_stage(pipe, in_frame, vf_frame, vf_pp_binary,
7572 				      &current_stage);
7573 		if (err) {
7574 			IA_CSS_LEAVE_ERR_PRIVATE(err);
7575 			return err;
7576 		}
7577 	}
7578 	ia_css_pipeline_finalize_stages(&pipe->pipeline, pipe->stream->config.continuous);
7579 
7580 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
7581 			    "create_host_regular_capture_pipeline() leave:\n");
7582 
7583 	return 0;
7584 }
7585 
7586 static int
7587 create_host_capture_pipeline(struct ia_css_pipe *pipe)
7588 {
7589 	int err = 0;
7590 
7591 	IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
7592 
7593 	if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY)
7594 		err = create_host_isyscopy_capture_pipeline(pipe);
7595 	else
7596 		err = create_host_regular_capture_pipeline(pipe);
7597 	if (err) {
7598 		IA_CSS_LEAVE_ERR_PRIVATE(err);
7599 		return err;
7600 	}
7601 
7602 	IA_CSS_LEAVE_ERR_PRIVATE(err);
7603 
7604 	return err;
7605 }
7606 
7607 static int capture_start(struct ia_css_pipe *pipe)
7608 {
7609 	struct ia_css_pipeline *me;
7610 	unsigned int thread_id;
7611 
7612 	int err = 0;
7613 	enum sh_css_pipe_config_override copy_ovrd;
7614 
7615 	IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
7616 	if (!pipe) {
7617 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
7618 		return -EINVAL;
7619 	}
7620 
7621 	me = &pipe->pipeline;
7622 
7623 	if ((pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_RAW   ||
7624 	     pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER) &&
7625 	    (pipe->config.mode != IA_CSS_PIPE_MODE_COPY)) {
7626 		if (copy_on_sp(pipe)) {
7627 			err = start_copy_on_sp(pipe, &me->out_frame[0]);
7628 			IA_CSS_LEAVE_ERR_PRIVATE(err);
7629 			return err;
7630 		}
7631 	}
7632 
7633 #if !defined(ISP2401)
7634 	/* old isys: need to send_mipi_frames() in all pipe modes */
7635 	err = send_mipi_frames(pipe);
7636 	if (err) {
7637 		IA_CSS_LEAVE_ERR_PRIVATE(err);
7638 		return err;
7639 	}
7640 #else
7641 	if (pipe->config.mode != IA_CSS_PIPE_MODE_COPY) {
7642 		err = send_mipi_frames(pipe);
7643 		if (err) {
7644 			IA_CSS_LEAVE_ERR_PRIVATE(err);
7645 			return err;
7646 		}
7647 	}
7648 #endif
7649 
7650 	ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
7651 	copy_ovrd = 1 << thread_id;
7652 
7653 	start_pipe(pipe, copy_ovrd, pipe->stream->config.mode);
7654 
7655 #if !defined(ISP2401)
7656 	/*
7657 	 * old isys: for IA_CSS_PIPE_MODE_COPY pipe, isys rx has to be configured,
7658 	 * which is currently done in start_binary(); but COPY pipe contains no binary,
7659 	 * and does not call start_binary(); so we need to configure the rx here.
7660 	 */
7661 	if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY &&
7662 	    pipe->stream->reconfigure_css_rx) {
7663 		ia_css_isys_rx_configure(&pipe->stream->csi_rx_config,
7664 					 pipe->stream->config.mode);
7665 		pipe->stream->reconfigure_css_rx = false;
7666 	}
7667 #endif
7668 
7669 	IA_CSS_LEAVE_ERR_PRIVATE(err);
7670 	return err;
7671 }
7672 
7673 static int
7674 sh_css_pipe_get_output_frame_info(struct ia_css_pipe *pipe,
7675 				  struct ia_css_frame_info *info,
7676 				  unsigned int idx)
7677 {
7678 	assert(pipe);
7679 	assert(info);
7680 
7681 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
7682 			    "sh_css_pipe_get_output_frame_info() enter:\n");
7683 
7684 	*info = pipe->output_info[idx];
7685 	if (copy_on_sp(pipe) &&
7686 	    pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8) {
7687 		ia_css_frame_info_init(
7688 		    info,
7689 		    JPEG_BYTES,
7690 		    1,
7691 		    IA_CSS_FRAME_FORMAT_BINARY_8,
7692 		    0);
7693 	} else if (info->format == IA_CSS_FRAME_FORMAT_RAW ||
7694 		   info->format == IA_CSS_FRAME_FORMAT_RAW_PACKED) {
7695 		info->raw_bit_depth =
7696 		ia_css_pipe_util_pipe_input_format_bpp(pipe);
7697 	}
7698 
7699 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
7700 			    "sh_css_pipe_get_output_frame_info() leave:\n");
7701 	return 0;
7702 }
7703 
7704 void
7705 ia_css_stream_send_input_frame(const struct ia_css_stream *stream,
7706 			       const unsigned short *data,
7707 			       unsigned int width,
7708 			       unsigned int height)
7709 {
7710 	assert(stream);
7711 
7712 	ia_css_inputfifo_send_input_frame(
7713 	    data, width, height,
7714 	    stream->config.channel_id,
7715 	    stream->config.input_config.format,
7716 	    stream->config.pixels_per_clock == 2);
7717 }
7718 
7719 void
7720 ia_css_stream_start_input_frame(const struct ia_css_stream *stream)
7721 {
7722 	assert(stream);
7723 
7724 	ia_css_inputfifo_start_frame(
7725 	    stream->config.channel_id,
7726 	    stream->config.input_config.format,
7727 	    stream->config.pixels_per_clock == 2);
7728 }
7729 
7730 void
7731 ia_css_stream_send_input_line(const struct ia_css_stream *stream,
7732 			      const unsigned short *data,
7733 			      unsigned int width,
7734 			      const unsigned short *data2,
7735 			      unsigned int width2)
7736 {
7737 	assert(stream);
7738 
7739 	ia_css_inputfifo_send_line(stream->config.channel_id,
7740 				   data, width, data2, width2);
7741 }
7742 
7743 void
7744 ia_css_stream_send_input_embedded_line(const struct ia_css_stream *stream,
7745 				       enum atomisp_input_format format,
7746 				       const unsigned short *data,
7747 				       unsigned int width)
7748 {
7749 	assert(stream);
7750 	if (!data || width == 0)
7751 		return;
7752 	ia_css_inputfifo_send_embedded_line(stream->config.channel_id,
7753 					    format, data, width);
7754 }
7755 
7756 void
7757 ia_css_stream_end_input_frame(const struct ia_css_stream *stream)
7758 {
7759 	assert(stream);
7760 
7761 	ia_css_inputfifo_end_frame(stream->config.channel_id);
7762 }
7763 
7764 static void
7765 append_firmware(struct ia_css_fw_info **l, struct ia_css_fw_info *firmware)
7766 {
7767 	IA_CSS_ENTER_PRIVATE("l = %p, firmware = %p", l, firmware);
7768 	if (!l) {
7769 		IA_CSS_ERROR("NULL fw_info");
7770 		IA_CSS_LEAVE_PRIVATE("");
7771 		return;
7772 	}
7773 	while (*l)
7774 		l = &(*l)->next;
7775 	*l = firmware;
7776 	/* when multiple acc extensions are loaded, 'next' can be not NULL */
7777 	/*firmware->next = NULL;*/
7778 	IA_CSS_LEAVE_PRIVATE("");
7779 }
7780 
7781 static void
7782 remove_firmware(struct ia_css_fw_info **l, struct ia_css_fw_info *firmware)
7783 {
7784 	assert(*l);
7785 	assert(firmware);
7786 	(void)l;
7787 	(void)firmware;
7788 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "remove_firmware() enter:\n");
7789 
7790 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "remove_firmware() leave:\n");
7791 	return; /* removing single and multiple firmware is handled in acc_unload_extension() */
7792 }
7793 
7794 static int upload_isp_code(struct ia_css_fw_info *firmware)
7795 {
7796 	ia_css_ptr binary;
7797 
7798 	if (!firmware) {
7799 		IA_CSS_ERROR("NULL input parameter");
7800 		return -EINVAL;
7801 	}
7802 	binary = firmware->info.isp.xmem_addr;
7803 
7804 	if (!binary) {
7805 		unsigned int size = firmware->blob.size;
7806 		const unsigned char *blob;
7807 		const unsigned char *binary_name;
7808 
7809 		binary_name =
7810 		    (const unsigned char *)(IA_CSS_EXT_ISP_PROG_NAME(
7811 						firmware));
7812 		blob = binary_name +
7813 			strlen((const char *)binary_name) +
7814 			1;
7815 		binary = sh_css_load_blob(blob, size);
7816 		firmware->info.isp.xmem_addr = binary;
7817 	}
7818 
7819 	if (!binary)
7820 		return -ENOMEM;
7821 	return 0;
7822 }
7823 
7824 static int
7825 acc_load_extension(struct ia_css_fw_info *firmware)
7826 {
7827 	int err;
7828 	struct ia_css_fw_info *hd = firmware;
7829 
7830 	while (hd) {
7831 		err = upload_isp_code(hd);
7832 		if (err)
7833 			return err;
7834 		hd = hd->next;
7835 	}
7836 
7837 	if (!firmware)
7838 		return -EINVAL;
7839 	firmware->loaded = true;
7840 	return 0;
7841 }
7842 
7843 static void
7844 acc_unload_extension(struct ia_css_fw_info *firmware)
7845 {
7846 	struct ia_css_fw_info *hd = firmware;
7847 	struct ia_css_fw_info *hdn = NULL;
7848 
7849 	if (!firmware) /* should not happen */
7850 		return;
7851 	/* unload and remove multiple firmwares */
7852 	while (hd) {
7853 		hdn = (hd->next) ? &(*hd->next) : NULL;
7854 		if (hd->info.isp.xmem_addr) {
7855 			hmm_free(hd->info.isp.xmem_addr);
7856 			hd->info.isp.xmem_addr = mmgr_NULL;
7857 		}
7858 		hd->isp_code = NULL;
7859 		hd->next = NULL;
7860 		hd = hdn;
7861 	}
7862 
7863 	firmware->loaded = false;
7864 }
7865 
7866 /* Load firmware for extension */
7867 static int
7868 ia_css_pipe_load_extension(struct ia_css_pipe *pipe,
7869 			   struct ia_css_fw_info *firmware)
7870 {
7871 	int err = 0;
7872 
7873 	IA_CSS_ENTER_PRIVATE("fw = %p pipe = %p", firmware, pipe);
7874 
7875 	if ((!firmware) || (!pipe)) {
7876 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
7877 		return -EINVAL;
7878 	}
7879 
7880 	if (firmware->info.isp.type == IA_CSS_ACC_OUTPUT)
7881 		append_firmware(&pipe->output_stage, firmware);
7882 	else if (firmware->info.isp.type == IA_CSS_ACC_VIEWFINDER)
7883 		append_firmware(&pipe->vf_stage, firmware);
7884 	err = acc_load_extension(firmware);
7885 
7886 	IA_CSS_LEAVE_ERR_PRIVATE(err);
7887 	return err;
7888 }
7889 
7890 /* Unload firmware for extension */
7891 static void
7892 ia_css_pipe_unload_extension(struct ia_css_pipe *pipe,
7893 			     struct ia_css_fw_info *firmware)
7894 {
7895 	IA_CSS_ENTER_PRIVATE("fw = %p pipe = %p", firmware, pipe);
7896 
7897 	if ((!firmware) || (!pipe)) {
7898 		IA_CSS_ERROR("NULL input parameters");
7899 		IA_CSS_LEAVE_PRIVATE("");
7900 		return;
7901 	}
7902 
7903 	if (firmware->info.isp.type == IA_CSS_ACC_OUTPUT)
7904 		remove_firmware(&pipe->output_stage, firmware);
7905 	else if (firmware->info.isp.type == IA_CSS_ACC_VIEWFINDER)
7906 		remove_firmware(&pipe->vf_stage, firmware);
7907 	acc_unload_extension(firmware);
7908 
7909 	IA_CSS_LEAVE_PRIVATE("");
7910 }
7911 
7912 bool
7913 ia_css_pipeline_uses_params(struct ia_css_pipeline *me)
7914 {
7915 	struct ia_css_pipeline_stage *stage;
7916 
7917 	assert(me);
7918 
7919 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
7920 			    "ia_css_pipeline_uses_params() enter: me=%p\n", me);
7921 
7922 	for (stage = me->stages; stage; stage = stage->next)
7923 		if (stage->binary_info && stage->binary_info->enable.params) {
7924 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
7925 					    "ia_css_pipeline_uses_params() leave: return_bool=true\n");
7926 			return true;
7927 		}
7928 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
7929 			    "ia_css_pipeline_uses_params() leave: return_bool=false\n");
7930 	return false;
7931 }
7932 
7933 static int
7934 sh_css_pipeline_add_acc_stage(struct ia_css_pipeline *pipeline,
7935 			      const void *acc_fw)
7936 {
7937 	struct ia_css_fw_info *fw = (struct ia_css_fw_info *)acc_fw;
7938 	/* In QoS case, load_extension already called, so skipping */
7939 	int	err = 0;
7940 
7941 	if (!fw->loaded)
7942 		err = acc_load_extension(fw);
7943 
7944 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
7945 			    "sh_css_pipeline_add_acc_stage() enter: pipeline=%p, acc_fw=%p\n",
7946 			    pipeline, acc_fw);
7947 
7948 	if (!err) {
7949 		struct ia_css_pipeline_stage_desc stage_desc;
7950 
7951 		ia_css_pipe_get_acc_stage_desc(&stage_desc, NULL, fw);
7952 		err = ia_css_pipeline_create_and_add_stage(pipeline,
7953 							   &stage_desc,
7954 							   NULL);
7955 	}
7956 
7957 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
7958 			    "sh_css_pipeline_add_acc_stage() leave: return_err=%d\n", err);
7959 	return err;
7960 }
7961 
7962 /*
7963  * @brief Tag a specific frame in continuous capture.
7964  * Refer to "sh_css_internal.h" for details.
7965  */
7966 int ia_css_stream_capture_frame(struct ia_css_stream *stream,
7967 				unsigned int exp_id)
7968 {
7969 	struct sh_css_tag_descr tag_descr;
7970 	u32 encoded_tag_descr;
7971 	int err;
7972 
7973 	assert(stream);
7974 	IA_CSS_ENTER("exp_id=%d", exp_id);
7975 
7976 	/* Only continuous streams have a tagger */
7977 	if (exp_id == 0 || !stream->config.continuous) {
7978 		IA_CSS_LEAVE_ERR(-EINVAL);
7979 		return -EINVAL;
7980 	}
7981 
7982 	if (!sh_css_sp_is_running()) {
7983 		/* SP is not running. The queues are not valid */
7984 		IA_CSS_LEAVE_ERR(-EBUSY);
7985 		return -EBUSY;
7986 	}
7987 
7988 	/* Create the tag descriptor from the parameters */
7989 	sh_css_create_tag_descr(0, 0, 0, exp_id, &tag_descr);
7990 	/* Encode the tag descriptor into a 32-bit value */
7991 	encoded_tag_descr = sh_css_encode_tag_descr(&tag_descr);
7992 	/*
7993 	 * Enqueue the encoded tag to the host2sp queue.
7994 	 * Note: The pipe and stage IDs for tag_cmd queue are hard-coded to 0
7995 	 * on both host and the SP side.
7996 	 * It is mainly because it is enough to have only one tag_cmd queue
7997 	 */
7998 	err = ia_css_bufq_enqueue_tag_cmd(encoded_tag_descr);
7999 
8000 	IA_CSS_LEAVE_ERR(err);
8001 	return err;
8002 }
8003 
8004 /*
8005  * @brief Configure the continuous capture.
8006  * Refer to "sh_css_internal.h" for details.
8007  */
8008 int ia_css_stream_capture(struct ia_css_stream *stream, int num_captures,
8009 			  unsigned int skip, int offset)
8010 {
8011 	struct sh_css_tag_descr tag_descr;
8012 	unsigned int encoded_tag_descr;
8013 	int return_err;
8014 
8015 	if (!stream)
8016 		return -EINVAL;
8017 
8018 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8019 			    "ia_css_stream_capture() enter: num_captures=%d, skip=%d, offset=%d\n",
8020 			    num_captures, skip, offset);
8021 
8022 	/* Check if the tag descriptor is valid */
8023 	if (num_captures < SH_CSS_MINIMUM_TAG_ID) {
8024 		ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8025 				    "ia_css_stream_capture() leave: return_err=%d\n",
8026 				    -EINVAL);
8027 		return -EINVAL;
8028 	}
8029 
8030 	/* Create the tag descriptor from the parameters */
8031 	sh_css_create_tag_descr(num_captures, skip, offset, 0, &tag_descr);
8032 
8033 	/* Encode the tag descriptor into a 32-bit value */
8034 	encoded_tag_descr = sh_css_encode_tag_descr(&tag_descr);
8035 
8036 	if (!sh_css_sp_is_running()) {
8037 		/* SP is not running. The queues are not valid */
8038 		ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8039 				    "ia_css_stream_capture() leaving:queues unavailable\n");
8040 		return -EBUSY;
8041 	}
8042 
8043 	/*
8044 	 * Enqueue the encoded tag to the host2sp queue.
8045 	 * Note: The pipe and stage IDs for tag_cmd queue are hard-coded to 0
8046 	 * on both host and the SP side.
8047 	 * It is mainly because it is enough to have only one tag_cmd queue
8048 	 */
8049 	return_err = ia_css_bufq_enqueue_tag_cmd((uint32_t)encoded_tag_descr);
8050 
8051 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8052 			    "ia_css_stream_capture() leave: return_err=%d\n",
8053 			    return_err);
8054 
8055 	return return_err;
8056 }
8057 
8058 void ia_css_stream_request_flash(struct ia_css_stream *stream)
8059 {
8060 	(void)stream;
8061 
8062 	assert(stream);
8063 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8064 			    "ia_css_stream_request_flash() enter: void\n");
8065 
8066 #ifndef ISP2401
8067 	sh_css_write_host2sp_command(host2sp_cmd_start_flash);
8068 #else
8069 	if (sh_css_sp_is_running()) {
8070 		if (!sh_css_write_host2sp_command(host2sp_cmd_start_flash)) {
8071 			IA_CSS_ERROR("Call to 'sh-css_write_host2sp_command()' failed");
8072 			ia_css_debug_dump_sp_sw_debug_info();
8073 			ia_css_debug_dump_debug_info(NULL);
8074 		}
8075 	} else {
8076 		IA_CSS_LOG("SP is not running!");
8077 	}
8078 
8079 #endif
8080 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8081 			    "ia_css_stream_request_flash() leave: return_void\n");
8082 }
8083 
8084 static void
8085 sh_css_init_host_sp_control_vars(void)
8086 {
8087 	const struct ia_css_fw_info *fw;
8088 	unsigned int HIVE_ADDR_ia_css_ispctrl_sp_isp_started;
8089 
8090 	unsigned int HIVE_ADDR_host_sp_queues_initialized;
8091 	unsigned int HIVE_ADDR_sp_sleep_mode;
8092 	unsigned int HIVE_ADDR_ia_css_dmaproxy_sp_invalidate_tlb;
8093 	unsigned int HIVE_ADDR_sp_stop_copy_preview;
8094 	unsigned int HIVE_ADDR_host_sp_com;
8095 	unsigned int o = offsetof(struct host_sp_communication, host2sp_command)
8096 			    / sizeof(int);
8097 
8098 	unsigned int i;
8099 
8100 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
8101 			    "sh_css_init_host_sp_control_vars() enter: void\n");
8102 
8103 	fw = &sh_css_sp_fw;
8104 	HIVE_ADDR_ia_css_ispctrl_sp_isp_started = fw->info.sp.isp_started;
8105 
8106 	HIVE_ADDR_host_sp_queues_initialized =
8107 	    fw->info.sp.host_sp_queues_initialized;
8108 	HIVE_ADDR_sp_sleep_mode = fw->info.sp.sleep_mode;
8109 	HIVE_ADDR_ia_css_dmaproxy_sp_invalidate_tlb = fw->info.sp.invalidate_tlb;
8110 	HIVE_ADDR_sp_stop_copy_preview = fw->info.sp.stop_copy_preview;
8111 	HIVE_ADDR_host_sp_com = fw->info.sp.host_sp_com;
8112 
8113 	sp_dmem_store_uint32(SP0_ID,
8114 			     (unsigned int)sp_address_of(ia_css_ispctrl_sp_isp_started),
8115 			     (uint32_t)(0));
8116 
8117 	sp_dmem_store_uint32(SP0_ID,
8118 			     (unsigned int)sp_address_of(host_sp_queues_initialized),
8119 			     (uint32_t)(0));
8120 	sp_dmem_store_uint32(SP0_ID,
8121 			     (unsigned int)sp_address_of(sp_sleep_mode),
8122 			     (uint32_t)(0));
8123 	sp_dmem_store_uint32(SP0_ID,
8124 			     (unsigned int)sp_address_of(ia_css_dmaproxy_sp_invalidate_tlb),
8125 			     (uint32_t)(false));
8126 	sp_dmem_store_uint32(SP0_ID,
8127 			     (unsigned int)sp_address_of(sp_stop_copy_preview),
8128 			     my_css.stop_copy_preview ? (uint32_t)(1) : (uint32_t)(0));
8129 	store_sp_array_uint(host_sp_com, o, host2sp_cmd_ready);
8130 
8131 	for (i = 0; i < N_CSI_PORTS; i++) {
8132 		sh_css_update_host2sp_num_mipi_frames
8133 		(my_css.num_mipi_frames[i]);
8134 	}
8135 
8136 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
8137 			    "sh_css_init_host_sp_control_vars() leave: return_void\n");
8138 }
8139 
8140 /*
8141  * create the internal structures and fill in the configuration data
8142  */
8143 
8144 static const struct
8145 ia_css_pipe_config ia_css_pipe_default_config = DEFAULT_PIPE_CONFIG;
8146 
8147 void ia_css_pipe_config_defaults(struct ia_css_pipe_config *pipe_config)
8148 {
8149 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_pipe_config_defaults()\n");
8150 	memcpy(pipe_config, &ia_css_pipe_default_config, sizeof(*pipe_config));
8151 }
8152 
8153 void
8154 ia_css_pipe_extra_config_defaults(struct ia_css_pipe_extra_config *extra_config)
8155 {
8156 	if (!extra_config) {
8157 		IA_CSS_ERROR("NULL input parameter");
8158 		return;
8159 	}
8160 
8161 	extra_config->enable_raw_binning = false;
8162 	extra_config->enable_yuv_ds = false;
8163 	extra_config->enable_high_speed = false;
8164 	extra_config->enable_dvs_6axis = false;
8165 	extra_config->enable_reduced_pipe = false;
8166 	extra_config->disable_vf_pp = false;
8167 	extra_config->enable_fractional_ds = false;
8168 }
8169 
8170 void ia_css_stream_config_defaults(struct ia_css_stream_config *stream_config)
8171 {
8172 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_config_defaults()\n");
8173 	assert(stream_config);
8174 	memset(stream_config, 0, sizeof(*stream_config));
8175 	stream_config->online = true;
8176 	stream_config->left_padding = -1;
8177 	stream_config->pixels_per_clock = 1;
8178 	/*
8179 	 * temporary default value for backwards compatibility.
8180 	 * This field used to be hardcoded within CSS but this has now
8181 	 * been moved to the stream_config struct.
8182 	 */
8183 	stream_config->source.port.rxcount = 0x04040404;
8184 }
8185 
8186 static int
8187 ia_css_acc_pipe_create(struct ia_css_pipe *pipe)
8188 {
8189 	int err = 0;
8190 
8191 	if (!pipe) {
8192 		IA_CSS_ERROR("NULL input parameter");
8193 		return -EINVAL;
8194 	}
8195 
8196 	/* There is not meaning for num_execs = 0 semantically. Run at least once. */
8197 	if (pipe->config.acc_num_execs == 0)
8198 		pipe->config.acc_num_execs = 1;
8199 
8200 	if (pipe->config.acc_extension)
8201 		err = ia_css_pipe_load_extension(pipe, pipe->config.acc_extension);
8202 
8203 	return err;
8204 }
8205 
8206 int ia_css_pipe_create(const struct ia_css_pipe_config *config,
8207 		       struct ia_css_pipe **pipe)
8208 {
8209 	int err = 0;
8210 
8211 	IA_CSS_ENTER_PRIVATE("config = %p, pipe = %p", config, pipe);
8212 
8213 	if (!config || !pipe) {
8214 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
8215 		return -EINVAL;
8216 	}
8217 
8218 	err = ia_css_pipe_create_extra(config, NULL, pipe);
8219 
8220 	if (err == 0)
8221 		IA_CSS_LOG("pipe created successfully = %p", *pipe);
8222 
8223 	IA_CSS_LEAVE_ERR_PRIVATE(err);
8224 
8225 	return err;
8226 }
8227 
8228 int
8229 ia_css_pipe_create_extra(const struct ia_css_pipe_config *config,
8230 			 const struct ia_css_pipe_extra_config *extra_config,
8231 			 struct ia_css_pipe **pipe)
8232 {
8233 	int err = -EINVAL;
8234 	struct ia_css_pipe *internal_pipe = NULL;
8235 	unsigned int i;
8236 
8237 	IA_CSS_ENTER_PRIVATE("config = %p, extra_config = %p and pipe = %p", config, extra_config, pipe);
8238 
8239 	/* do not allow to create more than the maximum limit */
8240 	if (my_css.pipe_counter >= IA_CSS_PIPELINE_NUM_MAX) {
8241 		IA_CSS_LEAVE_ERR_PRIVATE(-ENOSPC);
8242 		return -EINVAL;
8243 	}
8244 
8245 	if ((!pipe) || (!config)) {
8246 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
8247 		return -EINVAL;
8248 	}
8249 
8250 	ia_css_debug_dump_pipe_config(config);
8251 	ia_css_debug_dump_pipe_extra_config(extra_config);
8252 
8253 	err = create_pipe(config->mode, &internal_pipe, false);
8254 	if (err) {
8255 		IA_CSS_LEAVE_ERR_PRIVATE(err);
8256 		return err;
8257 	}
8258 
8259 	/* now we have a pipe structure to fill */
8260 	internal_pipe->config = *config;
8261 	if (extra_config)
8262 		internal_pipe->extra_config = *extra_config;
8263 	else
8264 		ia_css_pipe_extra_config_defaults(&internal_pipe->extra_config);
8265 
8266 	if (config->mode == IA_CSS_PIPE_MODE_ACC) {
8267 		/*
8268 		 * Temporary hack to migrate acceleration to CSS 2.0.
8269 		 * In the future the code for all pipe types should be
8270 		 * unified.
8271 		 */
8272 		*pipe = internal_pipe;
8273 		if (!internal_pipe->config.acc_extension &&
8274 		    internal_pipe->config.num_acc_stages ==
8275 		    0) { /* if no acc binary and no standalone stage */
8276 			*pipe = NULL;
8277 			IA_CSS_LEAVE_ERR_PRIVATE(0);
8278 			return 0;
8279 		}
8280 		return ia_css_acc_pipe_create(internal_pipe);
8281 	}
8282 
8283 	/*
8284 	 * Use config value when dvs_frame_delay setting equal to 2,
8285 	 * otherwise always 1 by default
8286 	 */
8287 	if (internal_pipe->config.dvs_frame_delay == IA_CSS_FRAME_DELAY_2)
8288 		internal_pipe->dvs_frame_delay = 2;
8289 	else
8290 		internal_pipe->dvs_frame_delay = 1;
8291 
8292 	/*
8293 	 * we still keep enable_raw_binning for backward compatibility,
8294 	 * for any new fractional bayer downscaling, we should use
8295 	 * bayer_ds_out_res. if both are specified, bayer_ds_out_res will
8296 	 * take precedence.if none is specified, we set bayer_ds_out_res
8297 	 * equal to IF output resolution(IF may do cropping on sensor output)
8298 	 * or use default decimation factor 1.
8299 	 */
8300 
8301 	/* YUV downscaling */
8302 	if ((internal_pipe->config.vf_pp_in_res.width ||
8303 	     internal_pipe->config.capt_pp_in_res.width)) {
8304 		enum ia_css_frame_format format;
8305 
8306 		if (internal_pipe->config.vf_pp_in_res.width) {
8307 			format = IA_CSS_FRAME_FORMAT_YUV_LINE;
8308 			ia_css_frame_info_init(
8309 			    &internal_pipe->vf_yuv_ds_input_info,
8310 			    internal_pipe->config.vf_pp_in_res.width,
8311 			    internal_pipe->config.vf_pp_in_res.height,
8312 			    format, 0);
8313 		}
8314 		if (internal_pipe->config.capt_pp_in_res.width) {
8315 			format = IA_CSS_FRAME_FORMAT_YUV420;
8316 			ia_css_frame_info_init(
8317 			    &internal_pipe->out_yuv_ds_input_info,
8318 			    internal_pipe->config.capt_pp_in_res.width,
8319 			    internal_pipe->config.capt_pp_in_res.height,
8320 			    format, 0);
8321 		}
8322 	}
8323 	if (internal_pipe->config.vf_pp_in_res.width &&
8324 	    internal_pipe->config.mode == IA_CSS_PIPE_MODE_PREVIEW) {
8325 		ia_css_frame_info_init(
8326 		    &internal_pipe->vf_yuv_ds_input_info,
8327 		    internal_pipe->config.vf_pp_in_res.width,
8328 		    internal_pipe->config.vf_pp_in_res.height,
8329 		    IA_CSS_FRAME_FORMAT_YUV_LINE, 0);
8330 	}
8331 	/* handle bayer downscaling output info */
8332 	if (internal_pipe->config.bayer_ds_out_res.width) {
8333 		ia_css_frame_info_init(
8334 		    &internal_pipe->bds_output_info,
8335 		    internal_pipe->config.bayer_ds_out_res.width,
8336 		    internal_pipe->config.bayer_ds_out_res.height,
8337 		    IA_CSS_FRAME_FORMAT_RAW, 0);
8338 	}
8339 
8340 	/* handle output info, assume always needed */
8341 	for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
8342 		if (internal_pipe->config.output_info[i].res.width) {
8343 			err = sh_css_pipe_configure_output(
8344 				    internal_pipe,
8345 				    internal_pipe->config.output_info[i].res.width,
8346 				    internal_pipe->config.output_info[i].res.height,
8347 				    internal_pipe->config.output_info[i].padded_width,
8348 				    internal_pipe->config.output_info[i].format,
8349 				    i);
8350 			if (err) {
8351 				IA_CSS_LEAVE_ERR_PRIVATE(err);
8352 				kvfree(internal_pipe);
8353 				internal_pipe = NULL;
8354 				return err;
8355 			}
8356 		}
8357 
8358 		/* handle vf output info, when configured */
8359 		internal_pipe->enable_viewfinder[i] =
8360 		    (internal_pipe->config.vf_output_info[i].res.width != 0);
8361 		if (internal_pipe->config.vf_output_info[i].res.width) {
8362 			err = sh_css_pipe_configure_viewfinder(
8363 				    internal_pipe,
8364 				    internal_pipe->config.vf_output_info[i].res.width,
8365 				    internal_pipe->config.vf_output_info[i].res.height,
8366 				    internal_pipe->config.vf_output_info[i].padded_width,
8367 				    internal_pipe->config.vf_output_info[i].format,
8368 				    i);
8369 			if (err) {
8370 				IA_CSS_LEAVE_ERR_PRIVATE(err);
8371 				kvfree(internal_pipe);
8372 				internal_pipe = NULL;
8373 				return err;
8374 			}
8375 		}
8376 	}
8377 	if (internal_pipe->config.acc_extension) {
8378 		err = ia_css_pipe_load_extension(internal_pipe,
8379 						 internal_pipe->config.acc_extension);
8380 		if (err) {
8381 			IA_CSS_LEAVE_ERR_PRIVATE(err);
8382 			kvfree(internal_pipe);
8383 			return err;
8384 		}
8385 	}
8386 	/* set all info to zeroes first */
8387 	memset(&internal_pipe->info, 0, sizeof(internal_pipe->info));
8388 
8389 	/* all went well, return the pipe */
8390 	*pipe = internal_pipe;
8391 	IA_CSS_LEAVE_ERR_PRIVATE(0);
8392 	return 0;
8393 }
8394 
8395 int
8396 ia_css_pipe_get_info(const struct ia_css_pipe *pipe,
8397 		     struct ia_css_pipe_info *pipe_info)
8398 {
8399 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8400 			    "ia_css_pipe_get_info()\n");
8401 	if (!pipe_info) {
8402 		ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR,
8403 				    "ia_css_pipe_get_info: pipe_info cannot be NULL\n");
8404 		return -EINVAL;
8405 	}
8406 	if (!pipe || !pipe->stream) {
8407 		ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR,
8408 				    "ia_css_pipe_get_info: ia_css_stream_create needs to be called before ia_css_[stream/pipe]_get_info\n");
8409 		return -EINVAL;
8410 	}
8411 	/* we succeeded return the info */
8412 	*pipe_info = pipe->info;
8413 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_pipe_get_info() leave\n");
8414 	return 0;
8415 }
8416 
8417 bool ia_css_pipe_has_dvs_stats(struct ia_css_pipe_info *pipe_info)
8418 {
8419 	unsigned int i;
8420 
8421 	if (pipe_info) {
8422 		for (i = 0; i < IA_CSS_DVS_STAT_NUM_OF_LEVELS; i++) {
8423 			if (pipe_info->grid_info.dvs_grid.dvs_stat_grid_info.grd_cfg[i].grd_start.enable)
8424 				return true;
8425 		}
8426 	}
8427 
8428 	return false;
8429 }
8430 
8431 int
8432 ia_css_pipe_override_frame_format(struct ia_css_pipe *pipe,
8433 				  int pin_index,
8434 				  enum ia_css_frame_format new_format)
8435 {
8436 	int err = 0;
8437 
8438 	IA_CSS_ENTER_PRIVATE("pipe = %p, pin_index = %d, new_formats = %d", pipe, pin_index, new_format);
8439 
8440 	if (!pipe) {
8441 		IA_CSS_ERROR("pipe is not set");
8442 		err = -EINVAL;
8443 		IA_CSS_LEAVE_ERR_PRIVATE(err);
8444 		return err;
8445 	}
8446 	if (0 != pin_index && 1 != pin_index) {
8447 		IA_CSS_ERROR("pin index is not valid");
8448 		err = -EINVAL;
8449 		IA_CSS_LEAVE_ERR_PRIVATE(err);
8450 		return err;
8451 	}
8452 	if (new_format != IA_CSS_FRAME_FORMAT_NV12_TILEY) {
8453 		IA_CSS_ERROR("new format is not valid");
8454 		err = -EINVAL;
8455 		IA_CSS_LEAVE_ERR_PRIVATE(err);
8456 		return err;
8457 	} else {
8458 		err = ia_css_pipe_check_format(pipe, new_format);
8459 		if (!err) {
8460 			if (pin_index == 0)
8461 				pipe->output_info[0].format = new_format;
8462 			else
8463 				pipe->vf_output_info[0].format = new_format;
8464 		}
8465 	}
8466 	IA_CSS_LEAVE_ERR_PRIVATE(err);
8467 	return err;
8468 }
8469 
8470 #if !defined(ISP2401)
8471 /* Configuration of INPUT_SYSTEM_VERSION_2401 is done on SP */
8472 static int
8473 ia_css_stream_configure_rx(struct ia_css_stream *stream)
8474 {
8475 	struct ia_css_input_port *config;
8476 
8477 	assert(stream);
8478 
8479 	config = &stream->config.source.port;
8480 	/* AM: this code is not reliable, especially for 2400 */
8481 	if (config->num_lanes == 1)
8482 		stream->csi_rx_config.mode = MONO_1L_1L_0L;
8483 	else if (config->num_lanes == 2)
8484 		stream->csi_rx_config.mode = MONO_2L_1L_0L;
8485 	else if (config->num_lanes == 3)
8486 		stream->csi_rx_config.mode = MONO_3L_1L_0L;
8487 	else if (config->num_lanes == 4)
8488 		stream->csi_rx_config.mode = MONO_4L_1L_0L;
8489 	else if (config->num_lanes != 0)
8490 		return -EINVAL;
8491 
8492 	if (config->port > MIPI_PORT2_ID)
8493 		return -EINVAL;
8494 	stream->csi_rx_config.port =
8495 	ia_css_isys_port_to_mipi_port(config->port);
8496 	stream->csi_rx_config.timeout    = config->timeout;
8497 	stream->csi_rx_config.initcount  = 0;
8498 	stream->csi_rx_config.synccount  = 0x28282828;
8499 	stream->csi_rx_config.rxcount    = config->rxcount;
8500 	if (config->compression.type == IA_CSS_CSI2_COMPRESSION_TYPE_NONE)
8501 		stream->csi_rx_config.comp = MIPI_PREDICTOR_NONE;
8502 	else
8503 		/*
8504 		 * not implemented yet, requires extension of the rx_cfg_t
8505 		 * struct
8506 		 */
8507 		return -EINVAL;
8508 
8509 	stream->csi_rx_config.is_two_ppc = (stream->config.pixels_per_clock == 2);
8510 	stream->reconfigure_css_rx = true;
8511 	return 0;
8512 }
8513 #endif
8514 
8515 static struct ia_css_pipe *
8516 find_pipe(struct ia_css_pipe *pipes[], unsigned int num_pipes,
8517 	  enum ia_css_pipe_mode mode, bool copy_pipe)
8518 {
8519 	unsigned int i;
8520 
8521 	assert(pipes);
8522 	for (i = 0; i < num_pipes; i++) {
8523 		assert(pipes[i]);
8524 		if (pipes[i]->config.mode != mode)
8525 			continue;
8526 		if (copy_pipe && pipes[i]->mode != IA_CSS_PIPE_ID_COPY)
8527 			continue;
8528 		return pipes[i];
8529 	}
8530 	return NULL;
8531 }
8532 
8533 static int
8534 ia_css_acc_stream_create(struct ia_css_stream *stream)
8535 {
8536 	int i;
8537 	int err = 0;
8538 
8539 	IA_CSS_ENTER_PRIVATE("stream = %p", stream);
8540 
8541 	if (!stream) {
8542 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
8543 		return -EINVAL;
8544 	}
8545 
8546 	for (i = 0;  i < stream->num_pipes; i++) {
8547 		struct ia_css_pipe *pipe = stream->pipes[i];
8548 
8549 		if (!pipe) {
8550 			IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
8551 			return -EINVAL;
8552 		}
8553 
8554 		pipe->stream = stream;
8555 	}
8556 
8557 	/* Map SP threads before doing anything. */
8558 	err = map_sp_threads(stream, true);
8559 	if (err) {
8560 		IA_CSS_LEAVE_ERR_PRIVATE(err);
8561 		return err;
8562 	}
8563 
8564 	for (i = 0;  i < stream->num_pipes; i++) {
8565 		struct ia_css_pipe *pipe = stream->pipes[i];
8566 
8567 		assert(pipe);
8568 		ia_css_pipe_map_queue(pipe, true);
8569 	}
8570 
8571 	err = create_host_pipeline_structure(stream);
8572 	if (err) {
8573 		IA_CSS_LEAVE_ERR_PRIVATE(err);
8574 		return err;
8575 	}
8576 
8577 	stream->started = false;
8578 
8579 	IA_CSS_LEAVE_ERR_PRIVATE(0);
8580 
8581 	return 0;
8582 }
8583 
8584 static int
8585 metadata_info_init(const struct ia_css_metadata_config *mdc,
8586 		   struct ia_css_metadata_info *md)
8587 {
8588 	/* Either both width and height should be set or neither */
8589 	if ((mdc->resolution.height > 0) ^ (mdc->resolution.width > 0))
8590 		return -EINVAL;
8591 
8592 	md->resolution = mdc->resolution;
8593 	/*
8594 	 * We round up the stride to a multiple of the width
8595 	 * of the port going to DDR, this is a HW requirements (DMA).
8596 	 */
8597 	md->stride = CEIL_MUL(mdc->resolution.width, HIVE_ISP_DDR_WORD_BYTES);
8598 	md->size = mdc->resolution.height * md->stride;
8599 	return 0;
8600 }
8601 
8602 int
8603 ia_css_stream_create(const struct ia_css_stream_config *stream_config,
8604 		     int num_pipes,
8605 		     struct ia_css_pipe *pipes[],
8606 		     struct ia_css_stream **stream)
8607 {
8608 	struct ia_css_pipe *curr_pipe;
8609 	struct ia_css_stream *curr_stream = NULL;
8610 	bool spcopyonly;
8611 	bool sensor_binning_changed;
8612 	int i, j;
8613 	int err = -EINVAL;
8614 	struct ia_css_metadata_info md_info;
8615 	struct ia_css_resolution effective_res;
8616 
8617 	IA_CSS_ENTER("num_pipes=%d", num_pipes);
8618 	ia_css_debug_dump_stream_config(stream_config, num_pipes);
8619 
8620 	/* some checks */
8621 	if (num_pipes == 0 ||
8622 	    !stream ||
8623 	    !pipes) {
8624 		err = -EINVAL;
8625 		IA_CSS_LEAVE_ERR(err);
8626 		return err;
8627 	}
8628 
8629 #if !defined(ISP2401)
8630 	/* We don't support metadata for JPEG stream, since they both use str2mem */
8631 	if (stream_config->input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8 &&
8632 	    stream_config->metadata_config.resolution.height > 0) {
8633 		err = -EINVAL;
8634 		IA_CSS_LEAVE_ERR(err);
8635 		return err;
8636 	}
8637 #endif
8638 
8639 #ifdef ISP2401
8640 	if (stream_config->online && stream_config->pack_raw_pixels) {
8641 		IA_CSS_LOG("online and pack raw is invalid on input system 2401");
8642 		err = -EINVAL;
8643 		IA_CSS_LEAVE_ERR(err);
8644 		return err;
8645 	}
8646 #endif
8647 
8648 	ia_css_debug_pipe_graph_dump_stream_config(stream_config);
8649 
8650 	/* check if mipi size specified */
8651 	if (stream_config->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR)
8652 #ifdef ISP2401
8653 		if (!stream_config->online)
8654 #endif
8655 		{
8656 			unsigned int port = (unsigned int)stream_config->source.port.port;
8657 
8658 			if (port >= N_MIPI_PORT_ID) {
8659 				err = -EINVAL;
8660 				IA_CSS_LEAVE_ERR(err);
8661 				return err;
8662 			}
8663 
8664 			if (my_css.size_mem_words != 0) {
8665 				my_css.mipi_frame_size[port] = my_css.size_mem_words;
8666 			} else if (stream_config->mipi_buffer_config.size_mem_words != 0) {
8667 				my_css.mipi_frame_size[port] = stream_config->mipi_buffer_config.size_mem_words;
8668 			} else {
8669 				ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8670 						    "ia_css_stream_create() exit: error, need to set mipi frame size.\n");
8671 				assert(stream_config->mipi_buffer_config.size_mem_words != 0);
8672 				err = -EINVAL;
8673 				IA_CSS_LEAVE_ERR(err);
8674 				return err;
8675 			}
8676 
8677 			if (my_css.size_mem_words != 0) {
8678 				my_css.num_mipi_frames[port] =
8679 				    2; /* Temp change: Default for backwards compatibility. */
8680 			} else if (stream_config->mipi_buffer_config.nof_mipi_buffers != 0) {
8681 				my_css.num_mipi_frames[port] =
8682 				    stream_config->mipi_buffer_config.nof_mipi_buffers;
8683 			} else {
8684 				ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8685 						    "ia_css_stream_create() exit: error, need to set number of mipi frames.\n");
8686 				assert(stream_config->mipi_buffer_config.nof_mipi_buffers != 0);
8687 				err = -EINVAL;
8688 				IA_CSS_LEAVE_ERR(err);
8689 				return err;
8690 			}
8691 		}
8692 
8693 	/* Currently we only supported metadata up to a certain size. */
8694 	err = metadata_info_init(&stream_config->metadata_config, &md_info);
8695 	if (err) {
8696 		IA_CSS_LEAVE_ERR(err);
8697 		return err;
8698 	}
8699 
8700 	/* allocate the stream instance */
8701 	curr_stream = kzalloc(sizeof(struct ia_css_stream), GFP_KERNEL);
8702 	if (!curr_stream) {
8703 		err = -ENOMEM;
8704 		IA_CSS_LEAVE_ERR(err);
8705 		return err;
8706 	}
8707 	/* default all to 0 */
8708 	curr_stream->info.metadata_info = md_info;
8709 
8710 	/* allocate pipes */
8711 	curr_stream->num_pipes = num_pipes;
8712 	curr_stream->pipes = kcalloc(num_pipes, sizeof(struct ia_css_pipe *), GFP_KERNEL);
8713 	if (!curr_stream->pipes) {
8714 		curr_stream->num_pipes = 0;
8715 		kfree(curr_stream);
8716 		curr_stream = NULL;
8717 		err = -ENOMEM;
8718 		IA_CSS_LEAVE_ERR(err);
8719 		return err;
8720 	}
8721 	/* store pipes */
8722 	spcopyonly = (num_pipes == 1) && (pipes[0]->config.mode == IA_CSS_PIPE_MODE_COPY);
8723 	for (i = 0; i < num_pipes; i++)
8724 		curr_stream->pipes[i] = pipes[i];
8725 	curr_stream->last_pipe = curr_stream->pipes[0];
8726 	/* take over stream config */
8727 	curr_stream->config = *stream_config;
8728 
8729 #if defined(ISP2401)
8730 	if (stream_config->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR &&
8731 	    stream_config->online)
8732 		curr_stream->config.online = false;
8733 #endif
8734 
8735 #ifdef ISP2401
8736 	if (curr_stream->config.online) {
8737 		curr_stream->config.source.port.num_lanes =
8738 		    stream_config->source.port.num_lanes;
8739 		curr_stream->config.mode =  IA_CSS_INPUT_MODE_BUFFERED_SENSOR;
8740 	}
8741 #endif
8742 	/* in case driver doesn't configure init number of raw buffers, configure it here */
8743 	if (curr_stream->config.target_num_cont_raw_buf == 0)
8744 		curr_stream->config.target_num_cont_raw_buf = NUM_CONTINUOUS_FRAMES;
8745 	if (curr_stream->config.init_num_cont_raw_buf == 0)
8746 		curr_stream->config.init_num_cont_raw_buf = curr_stream->config.target_num_cont_raw_buf;
8747 
8748 	/* Enable locking & unlocking of buffers in RAW buffer pool */
8749 	if (curr_stream->config.ia_css_enable_raw_buffer_locking)
8750 		sh_css_sp_configure_enable_raw_pool_locking(
8751 		    curr_stream->config.lock_all);
8752 
8753 	/* copy mode specific stuff */
8754 	switch (curr_stream->config.mode) {
8755 	case IA_CSS_INPUT_MODE_SENSOR:
8756 	case IA_CSS_INPUT_MODE_BUFFERED_SENSOR:
8757 #if !defined(ISP2401)
8758 		ia_css_stream_configure_rx(curr_stream);
8759 #endif
8760 		break;
8761 	case IA_CSS_INPUT_MODE_TPG:
8762 #if !defined(ISP2401)
8763 		IA_CSS_LOG("tpg_configuration: x_mask=%d, y_mask=%d, x_delta=%d, y_delta=%d, xy_mask=%d",
8764 			   curr_stream->config.source.tpg.x_mask,
8765 			   curr_stream->config.source.tpg.y_mask,
8766 			   curr_stream->config.source.tpg.x_delta,
8767 			   curr_stream->config.source.tpg.y_delta,
8768 			   curr_stream->config.source.tpg.xy_mask);
8769 
8770 		sh_css_sp_configure_tpg(
8771 		    curr_stream->config.source.tpg.x_mask,
8772 		    curr_stream->config.source.tpg.y_mask,
8773 		    curr_stream->config.source.tpg.x_delta,
8774 		    curr_stream->config.source.tpg.y_delta,
8775 		    curr_stream->config.source.tpg.xy_mask);
8776 #endif
8777 		break;
8778 	case IA_CSS_INPUT_MODE_PRBS:
8779 #if !defined(ISP2401)
8780 		IA_CSS_LOG("mode prbs");
8781 		sh_css_sp_configure_prbs(curr_stream->config.source.prbs.seed);
8782 #endif
8783 		break;
8784 	case IA_CSS_INPUT_MODE_MEMORY:
8785 		IA_CSS_LOG("mode memory");
8786 		curr_stream->reconfigure_css_rx = false;
8787 		break;
8788 	default:
8789 		IA_CSS_LOG("mode sensor/default");
8790 	}
8791 
8792 	for (i = 0; i < num_pipes; i++) {
8793 		struct ia_css_resolution effective_res;
8794 
8795 		curr_pipe = pipes[i];
8796 		/* set current stream */
8797 		curr_pipe->stream = curr_stream;
8798 		/* take over effective info */
8799 
8800 		effective_res = curr_pipe->config.input_effective_res;
8801 		if (effective_res.height == 0 || effective_res.width == 0) {
8802 			effective_res = curr_pipe->stream->config.input_config.effective_res;
8803 
8804 			curr_pipe->config.input_effective_res = effective_res;
8805 		}
8806 		IA_CSS_LOG("effective_res=%dx%d",
8807 			   effective_res.width,
8808 			   effective_res.height);
8809 	}
8810 
8811 	err = ia_css_stream_isp_parameters_init(curr_stream);
8812 	if (err)
8813 		goto ERR;
8814 	IA_CSS_LOG("isp_params_configs: %p", curr_stream->isp_params_configs);
8815 
8816 	if (num_pipes == 1 && pipes[0]->config.mode == IA_CSS_PIPE_MODE_ACC) {
8817 		*stream = curr_stream;
8818 		err = ia_css_acc_stream_create(curr_stream);
8819 		goto ERR;
8820 	}
8821 	/* sensor binning */
8822 	if (!spcopyonly) {
8823 		sensor_binning_changed =
8824 		    sh_css_params_set_binning_factor(curr_stream,
8825 						     curr_stream->config.sensor_binning_factor);
8826 	} else {
8827 		sensor_binning_changed = false;
8828 	}
8829 
8830 	IA_CSS_LOG("sensor_binning=%d, changed=%d",
8831 		   curr_stream->config.sensor_binning_factor, sensor_binning_changed);
8832 	/* loop over pipes */
8833 	IA_CSS_LOG("num_pipes=%d", num_pipes);
8834 	curr_stream->cont_capt = false;
8835 	/* Temporary hack: we give the preview pipe a reference to the capture
8836 	    * pipe in continuous capture mode. */
8837 	if (curr_stream->config.continuous) {
8838 		/* Search for the preview pipe and create the copy pipe */
8839 		struct ia_css_pipe *preview_pipe;
8840 		struct ia_css_pipe *video_pipe;
8841 		struct ia_css_pipe *acc_pipe;
8842 		struct ia_css_pipe *capture_pipe = NULL;
8843 		struct ia_css_pipe *copy_pipe = NULL;
8844 
8845 		if (num_pipes >= 2) {
8846 			curr_stream->cont_capt = true;
8847 			curr_stream->disable_cont_vf = curr_stream->config.disable_cont_viewfinder;
8848 			curr_stream->stop_copy_preview = my_css.stop_copy_preview;
8849 		}
8850 
8851 		/* Create copy pipe here, since it may not be exposed to the driver */
8852 		preview_pipe = find_pipe(pipes, num_pipes,
8853 					 IA_CSS_PIPE_MODE_PREVIEW, false);
8854 		video_pipe = find_pipe(pipes, num_pipes,
8855 				       IA_CSS_PIPE_MODE_VIDEO, false);
8856 		acc_pipe = find_pipe(pipes, num_pipes, IA_CSS_PIPE_MODE_ACC,
8857 				     false);
8858 		if (acc_pipe && num_pipes == 2 && curr_stream->cont_capt)
8859 			curr_stream->cont_capt =
8860 			    false; /* preview + QoS case will not need cont_capt switch */
8861 		if (curr_stream->cont_capt) {
8862 			capture_pipe = find_pipe(pipes, num_pipes,
8863 						 IA_CSS_PIPE_MODE_CAPTURE,
8864 						 false);
8865 			if (!capture_pipe) {
8866 				err = -EINVAL;
8867 				goto ERR;
8868 			}
8869 		}
8870 		/* We do not support preview and video pipe at the same time */
8871 		if (preview_pipe && video_pipe) {
8872 			err = -EINVAL;
8873 			goto ERR;
8874 		}
8875 
8876 		if (preview_pipe && !preview_pipe->pipe_settings.preview.copy_pipe) {
8877 			err = create_pipe(IA_CSS_PIPE_MODE_CAPTURE, &copy_pipe, true);
8878 			if (err)
8879 				goto ERR;
8880 			ia_css_pipe_config_defaults(&copy_pipe->config);
8881 			preview_pipe->pipe_settings.preview.copy_pipe = copy_pipe;
8882 			copy_pipe->stream = curr_stream;
8883 		}
8884 		if (preview_pipe && curr_stream->cont_capt)
8885 			preview_pipe->pipe_settings.preview.capture_pipe = capture_pipe;
8886 
8887 		if (video_pipe && !video_pipe->pipe_settings.video.copy_pipe) {
8888 			err = create_pipe(IA_CSS_PIPE_MODE_CAPTURE, &copy_pipe, true);
8889 			if (err)
8890 				goto ERR;
8891 			ia_css_pipe_config_defaults(&copy_pipe->config);
8892 			video_pipe->pipe_settings.video.copy_pipe = copy_pipe;
8893 			copy_pipe->stream = curr_stream;
8894 		}
8895 		if (video_pipe && curr_stream->cont_capt)
8896 			video_pipe->pipe_settings.video.capture_pipe = capture_pipe;
8897 
8898 		if (preview_pipe && acc_pipe)
8899 			preview_pipe->pipe_settings.preview.acc_pipe = acc_pipe;
8900 	}
8901 	for (i = 0; i < num_pipes; i++) {
8902 		curr_pipe = pipes[i];
8903 		/* set current stream */
8904 		curr_pipe->stream = curr_stream;
8905 
8906 		/* take over effective info */
8907 
8908 		effective_res = curr_pipe->config.input_effective_res;
8909 		err = ia_css_util_check_res(
8910 			effective_res.width,
8911 			effective_res.height);
8912 		if (err)
8913 			goto ERR;
8914 
8915 		/* sensor binning per pipe */
8916 		if (sensor_binning_changed)
8917 			sh_css_pipe_free_shading_table(curr_pipe);
8918 	}
8919 
8920 	/* now pipes have been configured, info should be available */
8921 	for (i = 0; i < num_pipes; i++) {
8922 		struct ia_css_pipe_info *pipe_info = NULL;
8923 
8924 		curr_pipe = pipes[i];
8925 
8926 		err = sh_css_pipe_load_binaries(curr_pipe);
8927 		if (err)
8928 			goto ERR;
8929 
8930 		/* handle each pipe */
8931 		pipe_info = &curr_pipe->info;
8932 		for (j = 0; j < IA_CSS_PIPE_MAX_OUTPUT_STAGE; j++) {
8933 			err = sh_css_pipe_get_output_frame_info(curr_pipe,
8934 								&pipe_info->output_info[j], j);
8935 			if (err)
8936 				goto ERR;
8937 		}
8938 
8939 		if (!spcopyonly) {
8940 			if (!IS_ISP2401)
8941 				err = sh_css_pipe_get_shading_info(curr_pipe,
8942 								   &pipe_info->shading_info,
8943 								   NULL);
8944 			else
8945 				err = sh_css_pipe_get_shading_info(curr_pipe,
8946 								   &pipe_info->shading_info,
8947 								   &curr_pipe->config);
8948 
8949 			if (err)
8950 				goto ERR;
8951 			err = sh_css_pipe_get_grid_info(curr_pipe,
8952 							&pipe_info->grid_info);
8953 			if (err)
8954 				goto ERR;
8955 			for (j = 0; j < IA_CSS_PIPE_MAX_OUTPUT_STAGE; j++) {
8956 				sh_css_pipe_get_viewfinder_frame_info(curr_pipe,
8957 								      &pipe_info->vf_output_info[j],
8958 								      j);
8959 				if (err)
8960 					goto ERR;
8961 			}
8962 		}
8963 
8964 		my_css.active_pipes[ia_css_pipe_get_pipe_num(curr_pipe)] = curr_pipe;
8965 	}
8966 
8967 	curr_stream->started = false;
8968 
8969 	/* Map SP threads before doing anything. */
8970 	err = map_sp_threads(curr_stream, true);
8971 	if (err) {
8972 		IA_CSS_LOG("map_sp_threads: return_err=%d", err);
8973 		goto ERR;
8974 	}
8975 
8976 	for (i = 0; i < num_pipes; i++) {
8977 		curr_pipe = pipes[i];
8978 		ia_css_pipe_map_queue(curr_pipe, true);
8979 	}
8980 
8981 	/* Create host side pipeline objects without stages */
8982 	err = create_host_pipeline_structure(curr_stream);
8983 	if (err) {
8984 		IA_CSS_LOG("create_host_pipeline_structure: return_err=%d", err);
8985 		goto ERR;
8986 	}
8987 
8988 	/* assign curr_stream */
8989 	*stream = curr_stream;
8990 
8991 ERR:
8992 	if (!err) {
8993 		/* working mode: enter into the seed list */
8994 		if (my_css_save.mode == sh_css_mode_working) {
8995 			for (i = 0; i < MAX_ACTIVE_STREAMS; i++) {
8996 				if (!my_css_save.stream_seeds[i].stream) {
8997 					IA_CSS_LOG("entered stream into loc=%d", i);
8998 					my_css_save.stream_seeds[i].orig_stream = stream;
8999 					my_css_save.stream_seeds[i].stream = curr_stream;
9000 					my_css_save.stream_seeds[i].num_pipes = num_pipes;
9001 					my_css_save.stream_seeds[i].stream_config = *stream_config;
9002 					for (j = 0; j < num_pipes; j++) {
9003 						my_css_save.stream_seeds[i].pipe_config[j] = pipes[j]->config;
9004 						my_css_save.stream_seeds[i].pipes[j] = pipes[j];
9005 						my_css_save.stream_seeds[i].orig_pipes[j] = &pipes[j];
9006 					}
9007 					break;
9008 				}
9009 			}
9010 		} else {
9011 			ia_css_stream_destroy(curr_stream);
9012 		}
9013 	} else {
9014 		ia_css_stream_destroy(curr_stream);
9015 	}
9016 	IA_CSS_LEAVE("return_err=%d mode=%d", err, my_css_save.mode);
9017 	return err;
9018 }
9019 
9020 int
9021 ia_css_stream_destroy(struct ia_css_stream *stream)
9022 {
9023 	int i;
9024 	int err = 0;
9025 
9026 	IA_CSS_ENTER_PRIVATE("stream = %p", stream);
9027 	if (!stream) {
9028 		err = -EINVAL;
9029 		IA_CSS_LEAVE_ERR_PRIVATE(err);
9030 		return err;
9031 	}
9032 
9033 	ia_css_stream_isp_parameters_uninit(stream);
9034 
9035 	if ((stream->last_pipe) &&
9036 	    ia_css_pipeline_is_mapped(stream->last_pipe->pipe_num)) {
9037 #if defined(ISP2401)
9038 		for (i = 0; i < stream->num_pipes; i++) {
9039 			struct ia_css_pipe *entry = stream->pipes[i];
9040 			unsigned int sp_thread_id;
9041 			struct sh_css_sp_pipeline_terminal *sp_pipeline_input_terminal;
9042 
9043 			assert(entry);
9044 			if (entry) {
9045 				/* get the SP thread id */
9046 				if (!ia_css_pipeline_get_sp_thread_id(
9047 					ia_css_pipe_get_pipe_num(entry), &sp_thread_id))
9048 					return -EINVAL;
9049 				/* get the target input terminal */
9050 				sp_pipeline_input_terminal =
9051 				&sh_css_sp_group.pipe_io[sp_thread_id].input;
9052 
9053 				for (i = 0; i < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH; i++) {
9054 					ia_css_isys_stream_h isys_stream =
9055 					&sp_pipeline_input_terminal->context.virtual_input_system_stream[i];
9056 					if (stream->config.isys_config[i].valid && isys_stream->valid)
9057 						ia_css_isys_stream_destroy(isys_stream);
9058 				}
9059 			}
9060 		}
9061 		if (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) {
9062 			for (i = 0; i < stream->num_pipes; i++) {
9063 				struct ia_css_pipe *entry = stream->pipes[i];
9064 				/*
9065 				 * free any mipi frames that are remaining:
9066 				 * some test stream create-destroy cycles do
9067 				 * not generate output frames
9068 				 * and the mipi buffer is not freed in the
9069 				 * deque function
9070 				 */
9071 				if (entry)
9072 					free_mipi_frames(entry);
9073 			}
9074 		}
9075 		stream_unregister_with_csi_rx(stream);
9076 #endif
9077 
9078 		for (i = 0; i < stream->num_pipes; i++) {
9079 			struct ia_css_pipe *curr_pipe = stream->pipes[i];
9080 
9081 			assert(curr_pipe);
9082 			ia_css_pipe_map_queue(curr_pipe, false);
9083 		}
9084 
9085 		err = map_sp_threads(stream, false);
9086 		if (err) {
9087 			IA_CSS_LEAVE_ERR_PRIVATE(err);
9088 			return err;
9089 		}
9090 	}
9091 
9092 	/* remove references from pipes to stream */
9093 	for (i = 0; i < stream->num_pipes; i++) {
9094 		struct ia_css_pipe *entry = stream->pipes[i];
9095 
9096 		assert(entry);
9097 		if (entry) {
9098 			/* clear reference to stream */
9099 			entry->stream = NULL;
9100 			/* check internal copy pipe */
9101 			if (entry->mode == IA_CSS_PIPE_ID_PREVIEW &&
9102 			    entry->pipe_settings.preview.copy_pipe) {
9103 				IA_CSS_LOG("clearing stream on internal preview copy pipe");
9104 				entry->pipe_settings.preview.copy_pipe->stream = NULL;
9105 			}
9106 			if (entry->mode == IA_CSS_PIPE_ID_VIDEO &&
9107 			    entry->pipe_settings.video.copy_pipe) {
9108 				IA_CSS_LOG("clearing stream on internal video copy pipe");
9109 				entry->pipe_settings.video.copy_pipe->stream = NULL;
9110 			}
9111 			err = sh_css_pipe_unload_binaries(entry);
9112 		}
9113 	}
9114 	/* free associated memory of stream struct */
9115 	kfree(stream->pipes);
9116 	stream->pipes = NULL;
9117 	stream->num_pipes = 0;
9118 
9119 	/* working mode: take out of the seed list */
9120 	if (my_css_save.mode == sh_css_mode_working) {
9121 		for (i = 0; i < MAX_ACTIVE_STREAMS; i++) {
9122 			if (my_css_save.stream_seeds[i].stream == stream) {
9123 				IA_CSS_LOG("took out stream %d", i);
9124 				my_css_save.stream_seeds[i].stream = NULL;
9125 				break;
9126 			}
9127 		}
9128 	}
9129 
9130 	kfree(stream);
9131 	IA_CSS_LEAVE_ERR(err);
9132 
9133 	return err;
9134 }
9135 
9136 int
9137 ia_css_stream_get_info(const struct ia_css_stream *stream,
9138 		       struct ia_css_stream_info *stream_info)
9139 {
9140 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_get_info: enter/exit\n");
9141 	assert(stream);
9142 	assert(stream_info);
9143 
9144 	*stream_info = stream->info;
9145 	return 0;
9146 }
9147 
9148 int
9149 ia_css_stream_start(struct ia_css_stream *stream)
9150 {
9151 	int err = 0;
9152 
9153 	IA_CSS_ENTER("stream = %p", stream);
9154 	if ((!stream) || (!stream->last_pipe)) {
9155 		IA_CSS_LEAVE_ERR(-EINVAL);
9156 		return -EINVAL;
9157 	}
9158 	IA_CSS_LOG("starting %d", stream->last_pipe->mode);
9159 
9160 	sh_css_sp_set_disable_continuous_viewfinder(stream->disable_cont_vf);
9161 
9162 	/* Create host side pipeline. */
9163 	err = create_host_pipeline(stream);
9164 	if (err) {
9165 		IA_CSS_LEAVE_ERR(err);
9166 		return err;
9167 	}
9168 
9169 #if defined(ISP2401)
9170 	if ((stream->config.mode == IA_CSS_INPUT_MODE_SENSOR) ||
9171 	    (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR))
9172 		stream_register_with_csi_rx(stream);
9173 #endif
9174 
9175 #if !defined(ISP2401)
9176 	/* Initialize mipi size checks */
9177 	if (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) {
9178 		unsigned int idx;
9179 		unsigned int port = (unsigned int)(stream->config.source.port.port);
9180 
9181 		for (idx = 0; idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT; idx++) {
9182 			sh_css_sp_group.config.mipi_sizes_for_check[port][idx] =
9183 			sh_css_get_mipi_sizes_for_check(port, idx);
9184 		}
9185 	}
9186 #endif
9187 
9188 	if (stream->config.mode != IA_CSS_INPUT_MODE_MEMORY) {
9189 		err = sh_css_config_input_network(stream);
9190 		if (err)
9191 			return err;
9192 	}
9193 
9194 	err = sh_css_pipe_start(stream);
9195 	IA_CSS_LEAVE_ERR(err);
9196 	return err;
9197 }
9198 
9199 int
9200 ia_css_stream_stop(struct ia_css_stream *stream)
9201 {
9202 	int err = 0;
9203 
9204 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_stop() enter/exit\n");
9205 	assert(stream);
9206 	assert(stream->last_pipe);
9207 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_stop: stopping %d\n",
9208 			    stream->last_pipe->mode);
9209 
9210 #if !defined(ISP2401)
9211 	/* De-initialize mipi size checks */
9212 	if (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) {
9213 		unsigned int idx;
9214 		unsigned int port = (unsigned int)(stream->config.source.port.port);
9215 
9216 		for (idx = 0; idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT; idx++)
9217 			sh_css_sp_group.config.mipi_sizes_for_check[port][idx] = 0;
9218 	}
9219 #endif
9220 
9221 	err = ia_css_pipeline_request_stop(&stream->last_pipe->pipeline);
9222 	if (err)
9223 		return err;
9224 
9225 	/*
9226 	 * Ideally, unmapping should happen after pipeline_stop, but current
9227 	 * semantics do not allow that.
9228 	 */
9229 	/* err = map_sp_threads(stream, false); */
9230 
9231 	return err;
9232 }
9233 
9234 bool
9235 ia_css_stream_has_stopped(struct ia_css_stream *stream)
9236 {
9237 	bool stopped;
9238 
9239 	assert(stream);
9240 
9241 	stopped = ia_css_pipeline_has_stopped(&stream->last_pipe->pipeline);
9242 
9243 	return stopped;
9244 }
9245 
9246 /* ISP2400 */
9247 /*
9248  * Destroy the stream and all the pipes related to it.
9249  * The stream handle is used to identify the correct entry in the css_save struct
9250  */
9251 int
9252 ia_css_stream_unload(struct ia_css_stream *stream)
9253 {
9254 	int i;
9255 
9256 	assert(stream);
9257 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,	"ia_css_stream_unload() enter,\n");
9258 	/* some checks */
9259 	assert(stream);
9260 	for (i = 0; i < MAX_ACTIVE_STREAMS; i++)
9261 		if (my_css_save.stream_seeds[i].stream == stream) {
9262 			int j;
9263 
9264 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
9265 					    "ia_css_stream_unload(): unloading %d (%p)\n", i,
9266 					    my_css_save.stream_seeds[i].stream);
9267 			ia_css_stream_destroy(stream);
9268 			for (j = 0; j < my_css_save.stream_seeds[i].num_pipes; j++)
9269 				ia_css_pipe_destroy(my_css_save.stream_seeds[i].pipes[j]);
9270 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
9271 					    "ia_css_stream_unload(): after unloading %d (%p)\n", i,
9272 					    my_css_save.stream_seeds[i].stream);
9273 			break;
9274 		}
9275 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,	"ia_css_stream_unload() exit,\n");
9276 	return 0;
9277 }
9278 
9279 int
9280 ia_css_temp_pipe_to_pipe_id(const struct ia_css_pipe *pipe,
9281 			    enum ia_css_pipe_id *pipe_id)
9282 {
9283 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_temp_pipe_to_pipe_id() enter/exit\n");
9284 	if (pipe)
9285 		*pipe_id = pipe->mode;
9286 	else
9287 		*pipe_id = IA_CSS_PIPE_ID_COPY;
9288 
9289 	return 0;
9290 }
9291 
9292 enum atomisp_input_format
9293 ia_css_stream_get_format(const struct ia_css_stream *stream)
9294 {
9295 	return stream->config.input_config.format;
9296 }
9297 
9298 bool
9299 ia_css_stream_get_two_pixels_per_clock(const struct ia_css_stream *stream)
9300 {
9301 	return (stream->config.pixels_per_clock == 2);
9302 }
9303 
9304 struct ia_css_binary *
9305 ia_css_stream_get_shading_correction_binary(const struct ia_css_stream
9306 	*stream)
9307 {
9308 	struct ia_css_pipe *pipe;
9309 
9310 	assert(stream);
9311 
9312 	pipe = stream->pipes[0];
9313 
9314 	if (stream->num_pipes == 2) {
9315 		assert(stream->pipes[1]);
9316 		if (stream->pipes[1]->config.mode == IA_CSS_PIPE_MODE_VIDEO ||
9317 		    stream->pipes[1]->config.mode == IA_CSS_PIPE_MODE_PREVIEW)
9318 			pipe = stream->pipes[1];
9319 	}
9320 
9321 	return ia_css_pipe_get_shading_correction_binary(pipe);
9322 }
9323 
9324 struct ia_css_binary *
9325 ia_css_stream_get_dvs_binary(const struct ia_css_stream *stream)
9326 {
9327 	int i;
9328 	struct ia_css_pipe *video_pipe = NULL;
9329 
9330 	/* First we find the video pipe */
9331 	for (i = 0; i < stream->num_pipes; i++) {
9332 		struct ia_css_pipe *pipe = stream->pipes[i];
9333 
9334 		if (pipe->config.mode == IA_CSS_PIPE_MODE_VIDEO) {
9335 			video_pipe = pipe;
9336 			break;
9337 		}
9338 	}
9339 	if (video_pipe)
9340 		return &video_pipe->pipe_settings.video.video_binary;
9341 	return NULL;
9342 }
9343 
9344 struct ia_css_binary *
9345 ia_css_stream_get_3a_binary(const struct ia_css_stream *stream)
9346 {
9347 	struct ia_css_pipe *pipe;
9348 	struct ia_css_binary *s3a_binary = NULL;
9349 
9350 	assert(stream);
9351 
9352 	pipe = stream->pipes[0];
9353 
9354 	if (stream->num_pipes == 2) {
9355 		assert(stream->pipes[1]);
9356 		if (stream->pipes[1]->config.mode == IA_CSS_PIPE_MODE_VIDEO ||
9357 		    stream->pipes[1]->config.mode == IA_CSS_PIPE_MODE_PREVIEW)
9358 			pipe = stream->pipes[1];
9359 	}
9360 
9361 	s3a_binary = ia_css_pipe_get_s3a_binary(pipe);
9362 
9363 	return s3a_binary;
9364 }
9365 
9366 int
9367 ia_css_stream_set_output_padded_width(struct ia_css_stream *stream,
9368 				      unsigned int output_padded_width)
9369 {
9370 	struct ia_css_pipe *pipe;
9371 
9372 	assert(stream);
9373 
9374 	pipe = stream->last_pipe;
9375 
9376 	assert(pipe);
9377 
9378 	/* set the config also just in case (redundant info? why do we save config in pipe?) */
9379 	pipe->config.output_info[IA_CSS_PIPE_OUTPUT_STAGE_0].padded_width = output_padded_width;
9380 	pipe->output_info[IA_CSS_PIPE_OUTPUT_STAGE_0].padded_width = output_padded_width;
9381 
9382 	return 0;
9383 }
9384 
9385 static struct ia_css_binary *
9386 ia_css_pipe_get_shading_correction_binary(const struct ia_css_pipe *pipe)
9387 {
9388 	struct ia_css_binary *binary = NULL;
9389 
9390 	assert(pipe);
9391 
9392 	switch (pipe->config.mode) {
9393 	case IA_CSS_PIPE_MODE_PREVIEW:
9394 		binary = (struct ia_css_binary *)&pipe->pipe_settings.preview.preview_binary;
9395 		break;
9396 	case IA_CSS_PIPE_MODE_VIDEO:
9397 		binary = (struct ia_css_binary *)&pipe->pipe_settings.video.video_binary;
9398 		break;
9399 	case IA_CSS_PIPE_MODE_CAPTURE:
9400 		if (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_PRIMARY) {
9401 			unsigned int i;
9402 
9403 			for (i = 0; i < pipe->pipe_settings.capture.num_primary_stage; i++) {
9404 				if (pipe->pipe_settings.capture.primary_binary[i].info->sp.enable.sc) {
9405 					binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.primary_binary[i];
9406 					break;
9407 				}
9408 			}
9409 		} else if (pipe->config.default_capture_config.mode ==
9410 			    IA_CSS_CAPTURE_MODE_BAYER)
9411 			binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.pre_isp_binary;
9412 		else if (pipe->config.default_capture_config.mode ==
9413 			    IA_CSS_CAPTURE_MODE_ADVANCED ||
9414 			    pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT) {
9415 			if (pipe->config.isp_pipe_version == IA_CSS_PIPE_VERSION_1)
9416 				binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.pre_isp_binary;
9417 			else if (pipe->config.isp_pipe_version == IA_CSS_PIPE_VERSION_2_2)
9418 				binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.post_isp_binary;
9419 		}
9420 		break;
9421 	default:
9422 		break;
9423 	}
9424 
9425 	if (binary && binary->info->sp.enable.sc)
9426 		return binary;
9427 
9428 	return NULL;
9429 }
9430 
9431 static struct ia_css_binary *
9432 ia_css_pipe_get_s3a_binary(const struct ia_css_pipe *pipe)
9433 {
9434 	struct ia_css_binary *binary = NULL;
9435 
9436 	assert(pipe);
9437 
9438 	switch (pipe->config.mode) {
9439 	case IA_CSS_PIPE_MODE_PREVIEW:
9440 		binary = (struct ia_css_binary *)&pipe->pipe_settings.preview.preview_binary;
9441 		break;
9442 	case IA_CSS_PIPE_MODE_VIDEO:
9443 		binary = (struct ia_css_binary *)&pipe->pipe_settings.video.video_binary;
9444 		break;
9445 	case IA_CSS_PIPE_MODE_CAPTURE:
9446 		if (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_PRIMARY) {
9447 			unsigned int i;
9448 
9449 			for (i = 0; i < pipe->pipe_settings.capture.num_primary_stage; i++) {
9450 				if (pipe->pipe_settings.capture.primary_binary[i].info->sp.enable.s3a) {
9451 					binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.primary_binary[i];
9452 					break;
9453 				}
9454 			}
9455 		} else if (pipe->config.default_capture_config.mode ==
9456 			    IA_CSS_CAPTURE_MODE_BAYER) {
9457 			binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.pre_isp_binary;
9458 		} else if (pipe->config.default_capture_config.mode ==
9459 			    IA_CSS_CAPTURE_MODE_ADVANCED ||
9460 			    pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT) {
9461 			if (pipe->config.isp_pipe_version == IA_CSS_PIPE_VERSION_1)
9462 				binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.pre_isp_binary;
9463 			else if (pipe->config.isp_pipe_version == IA_CSS_PIPE_VERSION_2_2)
9464 				binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.post_isp_binary;
9465 			else
9466 				assert(0);
9467 		}
9468 		break;
9469 	default:
9470 		break;
9471 	}
9472 
9473 	if (binary && !binary->info->sp.enable.s3a)
9474 		binary = NULL;
9475 
9476 	return binary;
9477 }
9478 
9479 static struct ia_css_binary *
9480 ia_css_pipe_get_sdis_binary(const struct ia_css_pipe *pipe)
9481 {
9482 	struct ia_css_binary *binary = NULL;
9483 
9484 	assert(pipe);
9485 
9486 	switch (pipe->config.mode) {
9487 	case IA_CSS_PIPE_MODE_VIDEO:
9488 		binary = (struct ia_css_binary *)&pipe->pipe_settings.video.video_binary;
9489 		break;
9490 	default:
9491 		break;
9492 	}
9493 
9494 	if (binary && !binary->info->sp.enable.dis)
9495 		binary = NULL;
9496 
9497 	return binary;
9498 }
9499 
9500 struct ia_css_pipeline *
9501 ia_css_pipe_get_pipeline(const struct ia_css_pipe *pipe)
9502 {
9503 	assert(pipe);
9504 
9505 	return (struct ia_css_pipeline *)&pipe->pipeline;
9506 }
9507 
9508 unsigned int
9509 ia_css_pipe_get_pipe_num(const struct ia_css_pipe *pipe)
9510 {
9511 	assert(pipe);
9512 
9513 	/*
9514 	 * KW was not sure this function was not returning a value
9515 	 * that was out of range; so added an assert, and, for the
9516 	 * case when asserts are not enabled, clip to the largest
9517 	 * value; pipe_num is unsigned so the value cannot be too small
9518 	 */
9519 	assert(pipe->pipe_num < IA_CSS_PIPELINE_NUM_MAX);
9520 
9521 	if (pipe->pipe_num >= IA_CSS_PIPELINE_NUM_MAX)
9522 		return (IA_CSS_PIPELINE_NUM_MAX - 1);
9523 
9524 	return pipe->pipe_num;
9525 }
9526 
9527 unsigned int
9528 ia_css_pipe_get_isp_pipe_version(const struct ia_css_pipe *pipe)
9529 {
9530 	assert(pipe);
9531 
9532 	return (unsigned int)pipe->config.isp_pipe_version;
9533 }
9534 
9535 #define SP_START_TIMEOUT_US 30000000
9536 
9537 int
9538 ia_css_start_sp(void)
9539 {
9540 	unsigned long timeout;
9541 	int err = 0;
9542 
9543 	IA_CSS_ENTER("");
9544 	sh_css_sp_start_isp();
9545 
9546 	/* waiting for the SP is completely started */
9547 	timeout = SP_START_TIMEOUT_US;
9548 	while ((ia_css_spctrl_get_state(SP0_ID) != IA_CSS_SP_SW_INITIALIZED) && timeout) {
9549 		timeout--;
9550 		udelay(1);
9551 	}
9552 	if (timeout == 0) {
9553 		IA_CSS_ERROR("timeout during SP initialization");
9554 		return -EINVAL;
9555 	}
9556 
9557 	/* Workaround, in order to run two streams in parallel. See TASK 4271*/
9558 	/* TODO: Fix this. */
9559 
9560 	sh_css_init_host_sp_control_vars();
9561 
9562 	/* buffers should be initialized only when sp is started */
9563 	/* AM: At the moment it will be done only when there is no stream active. */
9564 
9565 	sh_css_setup_queues();
9566 	ia_css_bufq_dump_queue_info();
9567 
9568 	IA_CSS_LEAVE_ERR(err);
9569 	return err;
9570 }
9571 
9572 /*
9573  * Time to wait SP for termincate. Only condition when this can happen
9574  * is a fatal hw failure, but we must be able to detect this and emit
9575  * a proper error trace.
9576  */
9577 #define SP_SHUTDOWN_TIMEOUT_US 200000
9578 
9579 int
9580 ia_css_stop_sp(void)
9581 {
9582 	unsigned long timeout;
9583 	int err = 0;
9584 
9585 	IA_CSS_ENTER("void");
9586 
9587 	if (!sh_css_sp_is_running()) {
9588 		err = -EINVAL;
9589 		IA_CSS_LEAVE("SP already stopped : return_err=%d", err);
9590 
9591 		/* Return an error - stop SP should not have been called by driver */
9592 		return err;
9593 	}
9594 
9595 	/* For now, stop whole SP */
9596 	if (!sh_css_write_host2sp_command(host2sp_cmd_terminate)) {
9597 		IA_CSS_ERROR("Call to 'sh-css_write_host2sp_command()' failed");
9598 		ia_css_debug_dump_sp_sw_debug_info();
9599 		ia_css_debug_dump_debug_info(NULL);
9600 	}
9601 
9602 	sh_css_sp_set_sp_running(false);
9603 
9604 	timeout = SP_SHUTDOWN_TIMEOUT_US;
9605 	while (!ia_css_spctrl_is_idle(SP0_ID) && timeout) {
9606 		timeout--;
9607 		udelay(1);
9608 	}
9609 	if (ia_css_spctrl_get_state(SP0_ID) != IA_CSS_SP_SW_TERMINATED)
9610 		IA_CSS_WARNING("SP has not terminated (SW)");
9611 
9612 	if (timeout == 0) {
9613 		IA_CSS_WARNING("SP is not idle");
9614 		ia_css_debug_dump_sp_sw_debug_info();
9615 	}
9616 	timeout = SP_SHUTDOWN_TIMEOUT_US;
9617 	while (!isp_ctrl_getbit(ISP0_ID, ISP_SC_REG, ISP_IDLE_BIT) && timeout) {
9618 		timeout--;
9619 		udelay(1);
9620 	}
9621 	if (timeout == 0) {
9622 		IA_CSS_WARNING("ISP is not idle");
9623 		ia_css_debug_dump_sp_sw_debug_info();
9624 	}
9625 
9626 	sh_css_hmm_buffer_record_uninit();
9627 
9628 	/* clear pending param sets from refcount */
9629 	sh_css_param_clear_param_sets();
9630 
9631 	IA_CSS_LEAVE_ERR(err);
9632 	return err;
9633 }
9634 
9635 int
9636 ia_css_update_continuous_frames(struct ia_css_stream *stream)
9637 {
9638 	struct ia_css_pipe *pipe;
9639 	unsigned int i;
9640 
9641 	ia_css_debug_dtrace(
9642 	    IA_CSS_DEBUG_TRACE,
9643 	    "sh_css_update_continuous_frames() enter:\n");
9644 
9645 	if (!stream) {
9646 		ia_css_debug_dtrace(
9647 		    IA_CSS_DEBUG_TRACE,
9648 		    "sh_css_update_continuous_frames() leave: invalid stream, return_void\n");
9649 		return -EINVAL;
9650 	}
9651 
9652 	pipe = stream->continuous_pipe;
9653 
9654 	for (i = stream->config.init_num_cont_raw_buf;
9655 		i < stream->config.target_num_cont_raw_buf; i++)
9656 		sh_css_update_host2sp_offline_frame(i,
9657 						    pipe->continuous_frames[i], pipe->cont_md_buffers[i]);
9658 
9659 	sh_css_update_host2sp_cont_num_raw_frames
9660 	(stream->config.target_num_cont_raw_buf, true);
9661 	ia_css_debug_dtrace(
9662 	    IA_CSS_DEBUG_TRACE,
9663 	    "sh_css_update_continuous_frames() leave: return_void\n");
9664 
9665 	return 0;
9666 }
9667 
9668 void ia_css_pipe_map_queue(struct ia_css_pipe *pipe, bool map)
9669 {
9670 	unsigned int thread_id;
9671 	unsigned int pipe_num;
9672 	bool need_input_queue;
9673 
9674 	IA_CSS_ENTER("");
9675 	assert(pipe);
9676 
9677 	pipe_num = pipe->pipe_num;
9678 
9679 	ia_css_pipeline_get_sp_thread_id(pipe_num, &thread_id);
9680 
9681 #if defined(ISP2401)
9682 	need_input_queue = true;
9683 #else
9684 	need_input_queue = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY;
9685 #endif
9686 
9687 	/* map required buffer queues to resources */
9688 	/* TODO: to be improved */
9689 	if (pipe->mode == IA_CSS_PIPE_ID_PREVIEW) {
9690 		if (need_input_queue)
9691 			ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map);
9692 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map);
9693 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map);
9694 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PER_FRAME_PARAMETER_SET, map);
9695 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map);
9696 		if (pipe->pipe_settings.preview.preview_binary.info &&
9697 		    pipe->pipe_settings.preview.preview_binary.info->sp.enable.s3a)
9698 			ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_3A_STATISTICS, map);
9699 	} else if (pipe->mode == IA_CSS_PIPE_ID_CAPTURE) {
9700 		unsigned int i;
9701 
9702 		if (need_input_queue)
9703 			ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map);
9704 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map);
9705 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME, map);
9706 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map);
9707 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PER_FRAME_PARAMETER_SET, map);
9708 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map);
9709 		if (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_PRIMARY) {
9710 			for (i = 0; i < pipe->pipe_settings.capture.num_primary_stage; i++) {
9711 				if (pipe->pipe_settings.capture.primary_binary[i].info &&
9712 				    pipe->pipe_settings.capture.primary_binary[i].info->sp.enable.s3a) {
9713 					ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_3A_STATISTICS, map);
9714 					break;
9715 				}
9716 			}
9717 		} else if (pipe->config.default_capture_config.mode ==
9718 			    IA_CSS_CAPTURE_MODE_ADVANCED ||
9719 			    pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT ||
9720 			    pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER) {
9721 			if (pipe->pipe_settings.capture.pre_isp_binary.info &&
9722 			    pipe->pipe_settings.capture.pre_isp_binary.info->sp.enable.s3a)
9723 				ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_3A_STATISTICS, map);
9724 		}
9725 	} else if (pipe->mode == IA_CSS_PIPE_ID_VIDEO) {
9726 		if (need_input_queue)
9727 			ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map);
9728 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map);
9729 		if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0])
9730 			ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME, map);
9731 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map);
9732 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PER_FRAME_PARAMETER_SET, map);
9733 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map);
9734 		if (pipe->pipe_settings.video.video_binary.info &&
9735 		    pipe->pipe_settings.video.video_binary.info->sp.enable.s3a)
9736 			ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_3A_STATISTICS, map);
9737 		if (pipe->pipe_settings.video.video_binary.info &&
9738 		    (pipe->pipe_settings.video.video_binary.info->sp.enable.dis
9739 		    ))
9740 			ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_DIS_STATISTICS, map);
9741 	} else if (pipe->mode == IA_CSS_PIPE_ID_COPY) {
9742 		if (need_input_queue)
9743 			ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map);
9744 		if (!pipe->stream->config.continuous)
9745 			ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map);
9746 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map);
9747 	} else if (pipe->mode == IA_CSS_PIPE_ID_ACC) {
9748 		if (need_input_queue)
9749 			ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map);
9750 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map);
9751 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map);
9752 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PER_FRAME_PARAMETER_SET, map);
9753 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map);
9754 	} else if (pipe->mode == IA_CSS_PIPE_ID_YUVPP) {
9755 		unsigned int idx;
9756 
9757 		for (idx = 0; idx < IA_CSS_PIPE_MAX_OUTPUT_STAGE; idx++) {
9758 			ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME + idx, map);
9759 			if (pipe->enable_viewfinder[idx])
9760 				ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME + idx, map);
9761 		}
9762 		if (need_input_queue)
9763 			ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map);
9764 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map);
9765 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map);
9766 	}
9767 	IA_CSS_LEAVE("");
9768 }
9769 
9770 
9771 int
9772 ia_css_unlock_raw_frame(struct ia_css_stream *stream, uint32_t exp_id)
9773 {
9774 	int ret;
9775 
9776 	IA_CSS_ENTER("");
9777 
9778 	/*
9779 	 * Only continuous streams have a tagger to which we can send the
9780 	 * unlock message.
9781 	 */
9782 	if (!stream || !stream->config.continuous) {
9783 		IA_CSS_ERROR("invalid stream pointer");
9784 		return -EINVAL;
9785 	}
9786 
9787 	if (exp_id > IA_CSS_ISYS_MAX_EXPOSURE_ID ||
9788 	    exp_id < IA_CSS_ISYS_MIN_EXPOSURE_ID) {
9789 		IA_CSS_ERROR("invalid exposure ID: %d\n", exp_id);
9790 		return -EINVAL;
9791 	}
9792 
9793 	/*
9794 	 * Send the event. Since we verified that the exp_id is valid,
9795 	 * we can safely assign it to an 8-bit argument here.
9796 	 */
9797 	ret = ia_css_bufq_enqueue_psys_event(
9798 	    IA_CSS_PSYS_SW_EVENT_UNLOCK_RAW_BUFFER, exp_id, 0, 0);
9799 
9800 	IA_CSS_LEAVE_ERR(ret);
9801 	return ret;
9802 }
9803 
9804 /*
9805  * @brief	Set the state (Enable or Disable) of the Extension stage in the
9806  *		given pipe.
9807  */
9808 int
9809 ia_css_pipe_set_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle,
9810 			      bool enable)
9811 {
9812 	unsigned int thread_id;
9813 	struct ia_css_pipeline_stage *stage;
9814 	int err = 0;
9815 
9816 	IA_CSS_ENTER("");
9817 
9818 	/* Parameter Check */
9819 	if (!pipe || !pipe->stream) {
9820 		IA_CSS_ERROR("Invalid Pipe.");
9821 		err = -EINVAL;
9822 	} else if (!(pipe->config.acc_extension)) {
9823 		IA_CSS_ERROR("Invalid Pipe(No Extension Firmware)");
9824 		err = -EINVAL;
9825 	} else if (!sh_css_sp_is_running()) {
9826 		IA_CSS_ERROR("Leaving: queue unavailable.");
9827 		err = -EBUSY;
9828 	} else {
9829 		/* Query the threadid and stage_num for the Extension firmware*/
9830 		ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
9831 		err = ia_css_pipeline_get_stage_from_fw(&pipe->pipeline, fw_handle, &stage);
9832 		if (!err) {
9833 			/* Set the Extension State;. TODO: Add check for stage firmware.type (QOS)*/
9834 			err = ia_css_bufq_enqueue_psys_event(
9835 			    (uint8_t)IA_CSS_PSYS_SW_EVENT_STAGE_ENABLE_DISABLE,
9836 			    (uint8_t)thread_id,
9837 			    (uint8_t)stage->stage_num,
9838 			    enable ? 1 : 0);
9839 			if (!err) {
9840 				if (enable)
9841 					SH_CSS_QOS_STAGE_ENABLE(&sh_css_sp_group.pipe[thread_id], stage->stage_num);
9842 				else
9843 					SH_CSS_QOS_STAGE_DISABLE(&sh_css_sp_group.pipe[thread_id], stage->stage_num);
9844 			}
9845 		}
9846 	}
9847 	IA_CSS_LEAVE("err:%d handle:%u enable:%d", err, fw_handle, enable);
9848 	return err;
9849 }
9850 
9851 /*
9852  * @brief	Get the state (Enable or Disable) of the Extension stage in the
9853  * given pipe.
9854  */
9855 int
9856 ia_css_pipe_get_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle,
9857 			      bool *enable)
9858 {
9859 	struct ia_css_pipeline_stage *stage;
9860 	unsigned int thread_id;
9861 	int err = 0;
9862 
9863 	IA_CSS_ENTER("");
9864 
9865 	/* Parameter Check */
9866 	if (!pipe || !pipe->stream) {
9867 		IA_CSS_ERROR("Invalid Pipe.");
9868 		err = -EINVAL;
9869 	} else if (!(pipe->config.acc_extension)) {
9870 		IA_CSS_ERROR("Invalid Pipe (No Extension Firmware).");
9871 		err = -EINVAL;
9872 	} else if (!sh_css_sp_is_running()) {
9873 		IA_CSS_ERROR("Leaving: queue unavailable.");
9874 		err = -EBUSY;
9875 	} else {
9876 		/* Query the threadid and stage_num corresponding to the Extension firmware*/
9877 		ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
9878 		err = ia_css_pipeline_get_stage_from_fw(&pipe->pipeline, fw_handle, &stage);
9879 
9880 		if (!err) {
9881 			/* Get the Extension State */
9882 			*enable = (SH_CSS_QOS_STAGE_IS_ENABLED(&sh_css_sp_group.pipe[thread_id],
9883 								stage->stage_num)) ? true : false;
9884 		}
9885 	}
9886 	IA_CSS_LEAVE("err:%d handle:%u enable:%d", err, fw_handle, *enable);
9887 	return err;
9888 }
9889 
9890 static void
9891 sh_css_hmm_buffer_record_init(void)
9892 {
9893 	int i;
9894 
9895 	for (i = 0; i < MAX_HMM_BUFFER_NUM; i++)
9896 		sh_css_hmm_buffer_record_reset(&hmm_buffer_record[i]);
9897 }
9898 
9899 static void
9900 sh_css_hmm_buffer_record_uninit(void)
9901 {
9902 	int i;
9903 	struct sh_css_hmm_buffer_record *buffer_record = NULL;
9904 
9905 	buffer_record = &hmm_buffer_record[0];
9906 	for (i = 0; i < MAX_HMM_BUFFER_NUM; i++) {
9907 		if (buffer_record->in_use) {
9908 			if (buffer_record->h_vbuf)
9909 				ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &buffer_record->h_vbuf);
9910 			sh_css_hmm_buffer_record_reset(buffer_record);
9911 		}
9912 		buffer_record++;
9913 	}
9914 }
9915 
9916 static void
9917 sh_css_hmm_buffer_record_reset(struct sh_css_hmm_buffer_record *buffer_record)
9918 {
9919 	assert(buffer_record);
9920 	buffer_record->in_use = false;
9921 	buffer_record->type = IA_CSS_BUFFER_TYPE_INVALID;
9922 	buffer_record->h_vbuf = NULL;
9923 	buffer_record->kernel_ptr = 0;
9924 }
9925 
9926 static struct sh_css_hmm_buffer_record
9927 *sh_css_hmm_buffer_record_acquire(struct ia_css_rmgr_vbuf_handle *h_vbuf,
9928 				    enum ia_css_buffer_type type,
9929 				    hrt_address kernel_ptr)
9930 {
9931 	int i;
9932 	struct sh_css_hmm_buffer_record *buffer_record = NULL;
9933 	struct sh_css_hmm_buffer_record *out_buffer_record = NULL;
9934 
9935 	assert(h_vbuf);
9936 	assert((type > IA_CSS_BUFFER_TYPE_INVALID) &&
9937 	       (type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE));
9938 	assert(kernel_ptr != 0);
9939 
9940 	buffer_record = &hmm_buffer_record[0];
9941 	for (i = 0; i < MAX_HMM_BUFFER_NUM; i++) {
9942 		if (!buffer_record->in_use) {
9943 			buffer_record->in_use = true;
9944 			buffer_record->type = type;
9945 			buffer_record->h_vbuf = h_vbuf;
9946 			buffer_record->kernel_ptr = kernel_ptr;
9947 			out_buffer_record = buffer_record;
9948 			break;
9949 		}
9950 		buffer_record++;
9951 	}
9952 
9953 	return out_buffer_record;
9954 }
9955 
9956 static struct sh_css_hmm_buffer_record
9957 *sh_css_hmm_buffer_record_validate(ia_css_ptr ddr_buffer_addr,
9958 				    enum ia_css_buffer_type type)
9959 {
9960 	int i;
9961 	struct sh_css_hmm_buffer_record *buffer_record = NULL;
9962 	bool found_record = false;
9963 
9964 	buffer_record = &hmm_buffer_record[0];
9965 	for (i = 0; i < MAX_HMM_BUFFER_NUM; i++) {
9966 		if ((buffer_record->in_use) &&
9967 		    (buffer_record->type == type) &&
9968 		    (buffer_record->h_vbuf) &&
9969 		    (buffer_record->h_vbuf->vptr == ddr_buffer_addr)) {
9970 			found_record = true;
9971 			break;
9972 		}
9973 		buffer_record++;
9974 	}
9975 
9976 	if (found_record)
9977 		return buffer_record;
9978 	else
9979 		return NULL;
9980 }
9981