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