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