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(const struct ia_css_stream_config *config)
3228 {
3229 	assert(config);
3230 	if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_BGGR) ||
3231 	    (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG))
3232 		return 1;
3233 
3234 	return 0;
3235 }
3236 
3237 static unsigned int
3238 get_crop_columns_for_bayer_order(const struct ia_css_stream_config *config)
3239 {
3240 	assert(config);
3241 	if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_RGGB) ||
3242 	    (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG))
3243 		return 1;
3244 
3245 	return 0;
3246 }
3247 
3248 /* This function is to get the sum of all extra pixels in addition to the effective
3249  * input, it includes dvs envelop and filter run-in */
3250 static void get_pipe_extra_pixel(struct ia_css_pipe *pipe,
3251 				 unsigned int *extra_row, unsigned int *extra_column)
3252 {
3253 	enum ia_css_pipe_id pipe_id = pipe->mode;
3254 	unsigned int left_cropping = 0, top_cropping = 0;
3255 	unsigned int i;
3256 	struct ia_css_resolution dvs_env = pipe->config.dvs_envelope;
3257 
3258 	/* The dvs envelope info may not be correctly sent down via pipe config
3259 	 * The check is made and the correct value is populated in the binary info
3260 	 * Use this value when computing crop, else excess lines may get trimmed
3261 	 */
3262 	switch (pipe_id) {
3263 	case IA_CSS_PIPE_ID_PREVIEW:
3264 		if (pipe->pipe_settings.preview.preview_binary.info) {
3265 			left_cropping =
3266 			    pipe->pipe_settings.preview.preview_binary.info->sp.pipeline.left_cropping;
3267 			top_cropping =
3268 			    pipe->pipe_settings.preview.preview_binary.info->sp.pipeline.top_cropping;
3269 		}
3270 		dvs_env = pipe->pipe_settings.preview.preview_binary.dvs_envelope;
3271 		break;
3272 	case IA_CSS_PIPE_ID_VIDEO:
3273 		if (pipe->pipe_settings.video.video_binary.info) {
3274 			left_cropping =
3275 			    pipe->pipe_settings.video.video_binary.info->sp.pipeline.left_cropping;
3276 			top_cropping =
3277 			    pipe->pipe_settings.video.video_binary.info->sp.pipeline.top_cropping;
3278 		}
3279 		dvs_env = pipe->pipe_settings.video.video_binary.dvs_envelope;
3280 		break;
3281 	case IA_CSS_PIPE_ID_CAPTURE:
3282 		for (i = 0; i < pipe->pipe_settings.capture.num_primary_stage; i++) {
3283 			if (pipe->pipe_settings.capture.primary_binary[i].info) {
3284 				left_cropping +=
3285 				    pipe->pipe_settings.capture.primary_binary[i].info->sp.pipeline.left_cropping;
3286 				top_cropping +=
3287 				    pipe->pipe_settings.capture.primary_binary[i].info->sp.pipeline.top_cropping;
3288 			}
3289 			dvs_env.width +=
3290 			    pipe->pipe_settings.capture.primary_binary[i].dvs_envelope.width;
3291 			dvs_env.height +=
3292 			    pipe->pipe_settings.capture.primary_binary[i].dvs_envelope.height;
3293 		}
3294 		break;
3295 	default:
3296 		break;
3297 	}
3298 
3299 	*extra_row = top_cropping + dvs_env.height;
3300 	*extra_column = left_cropping + dvs_env.width;
3301 }
3302 
3303 void
3304 ia_css_get_crop_offsets(
3305     struct ia_css_pipe *pipe,
3306     struct ia_css_frame_info *in_frame)
3307 {
3308 	unsigned int row = 0;
3309 	unsigned int column = 0;
3310 	struct ia_css_resolution *input_res;
3311 	struct ia_css_resolution *effective_res;
3312 	unsigned int extra_row = 0, extra_col = 0;
3313 	unsigned int min_reqd_height, min_reqd_width;
3314 
3315 	assert(pipe);
3316 	assert(pipe->stream);
3317 	assert(in_frame);
3318 
3319 	IA_CSS_ENTER_PRIVATE("pipe = %p effective_wd = %u effective_ht = %u",
3320 			     pipe, pipe->config.input_effective_res.width,
3321 			     pipe->config.input_effective_res.height);
3322 
3323 	input_res = &pipe->stream->config.input_config.input_res;
3324 #ifndef ISP2401
3325 	effective_res = &pipe->stream->config.input_config.effective_res;
3326 #else
3327 	effective_res = &pipe->config.input_effective_res;
3328 #endif
3329 
3330 	get_pipe_extra_pixel(pipe, &extra_row, &extra_col);
3331 
3332 	in_frame->raw_bayer_order = pipe->stream->config.input_config.bayer_order;
3333 
3334 	min_reqd_height = effective_res->height + extra_row;
3335 	min_reqd_width = effective_res->width + extra_col;
3336 
3337 	if (input_res->height > min_reqd_height) {
3338 		row = (input_res->height - min_reqd_height) / 2;
3339 		row &= ~0x1;
3340 	}
3341 	if (input_res->width > min_reqd_width) {
3342 		column = (input_res->width - min_reqd_width) / 2;
3343 		column &= ~0x1;
3344 	}
3345 
3346 	/*
3347 	 * TODO:
3348 	 * 1. Require the special support for RAW10 packed mode.
3349 	 * 2. Require the special support for the online use cases.
3350 	 */
3351 
3352 	/* ISP expects GRBG bayer order, we skip one line and/or one row
3353 	 * to correct in case the input bayer order is different.
3354 	 */
3355 	column += get_crop_columns_for_bayer_order(&pipe->stream->config);
3356 	row += get_crop_lines_for_bayer_order(&pipe->stream->config);
3357 
3358 	in_frame->crop_info.start_column = column;
3359 	in_frame->crop_info.start_line = row;
3360 
3361 	IA_CSS_LEAVE_PRIVATE("void start_col: %u start_row: %u", column, row);
3362 
3363 	return;
3364 }
3365 #endif
3366 
3367 static int
3368 init_in_frameinfo_memory_defaults(struct ia_css_pipe *pipe,
3369 				  struct ia_css_frame *frame, enum ia_css_frame_format format)
3370 {
3371 	struct ia_css_frame *in_frame;
3372 	int err = 0;
3373 	unsigned int thread_id;
3374 	enum sh_css_queue_id queue_id;
3375 
3376 	assert(frame);
3377 	in_frame = frame;
3378 
3379 	in_frame->info.format = format;
3380 
3381 #ifdef ISP2401
3382 	if (format == IA_CSS_FRAME_FORMAT_RAW)
3383 		in_frame->info.format = (pipe->stream->config.pack_raw_pixels) ?
3384 		IA_CSS_FRAME_FORMAT_RAW_PACKED : IA_CSS_FRAME_FORMAT_RAW;
3385 #endif
3386 
3387 	in_frame->info.res.width = pipe->stream->config.input_config.input_res.width;
3388 	in_frame->info.res.height = pipe->stream->config.input_config.input_res.height;
3389 	in_frame->info.raw_bit_depth =
3390 	ia_css_pipe_util_pipe_input_format_bpp(pipe);
3391 	ia_css_frame_info_set_width(&in_frame->info, pipe->stream->config.input_config.input_res.width, 0);
3392 	in_frame->contiguous = false;
3393 	in_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
3394 	ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
3395 	ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_INPUT_FRAME, thread_id, &queue_id);
3396 	in_frame->dynamic_queue_id = queue_id;
3397 	in_frame->buf_type = IA_CSS_BUFFER_TYPE_INPUT_FRAME;
3398 #ifdef ISP2401
3399 	ia_css_get_crop_offsets(pipe, &in_frame->info);
3400 #endif
3401 	err = ia_css_frame_init_planes(in_frame);
3402 
3403 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
3404 			    "init_in_frameinfo_memory_defaults() bayer_order = %d:\n", in_frame->info.raw_bayer_order);
3405 
3406 	return err;
3407 }
3408 
3409 static int
3410 init_out_frameinfo_defaults(struct ia_css_pipe *pipe,
3411 			    struct ia_css_frame *out_frame, unsigned int idx)
3412 {
3413 	int err = 0;
3414 	unsigned int thread_id;
3415 	enum sh_css_queue_id queue_id;
3416 
3417 	assert(out_frame);
3418 
3419 	sh_css_pipe_get_output_frame_info(pipe, &out_frame->info, idx);
3420 	out_frame->contiguous = false;
3421 	out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
3422 	ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
3423 	ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_OUTPUT_FRAME + idx, thread_id, &queue_id);
3424 	out_frame->dynamic_queue_id = queue_id;
3425 	out_frame->buf_type = IA_CSS_BUFFER_TYPE_OUTPUT_FRAME + idx;
3426 	err = ia_css_frame_init_planes(out_frame);
3427 
3428 	return err;
3429 }
3430 
3431 /* Create stages for video pipe */
3432 static int create_host_video_pipeline(struct ia_css_pipe *pipe)
3433 {
3434 	struct ia_css_pipeline_stage_desc stage_desc;
3435 	struct ia_css_binary *copy_binary, *video_binary,
3436 		       *yuv_scaler_binary, *vf_pp_binary;
3437 	struct ia_css_pipeline_stage *copy_stage  = NULL;
3438 	struct ia_css_pipeline_stage *video_stage = NULL;
3439 	struct ia_css_pipeline_stage *yuv_scaler_stage  = NULL;
3440 	struct ia_css_pipeline_stage *vf_pp_stage = NULL;
3441 	struct ia_css_pipeline *me;
3442 	struct ia_css_frame *in_frame = NULL;
3443 	struct ia_css_frame *out_frame;
3444 	struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS];
3445 	struct ia_css_frame *vf_frame = NULL;
3446 	int err = 0;
3447 	bool need_copy   = false;
3448 	bool need_vf_pp  = false;
3449 	bool need_yuv_pp = false;
3450 	bool need_in_frameinfo_memory = false;
3451 
3452 	unsigned int i, num_yuv_scaler;
3453 	bool *is_output_stage = NULL;
3454 
3455 	IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
3456 	if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_VIDEO)) {
3457 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
3458 		return -EINVAL;
3459 	}
3460 	ia_css_pipe_util_create_output_frames(out_frames);
3461 	out_frame = &pipe->out_frame_struct;
3462 
3463 	/* pipeline already created as part of create_host_pipeline_structure */
3464 	me = &pipe->pipeline;
3465 	ia_css_pipeline_clean(me);
3466 
3467 	me->dvs_frame_delay = pipe->dvs_frame_delay;
3468 
3469 #ifdef ISP2401
3470 	/* When the input system is 2401, always enable 'in_frameinfo_memory'
3471 	 * except for the following: online or continuous
3472 	 */
3473 	need_in_frameinfo_memory = !(pipe->stream->config.online ||
3474 				     pipe->stream->config.continuous);
3475 #else
3476 	/* Construct in_frame info (only in case we have dynamic input */
3477 	need_in_frameinfo_memory = pipe->stream->config.mode ==
3478 				   IA_CSS_INPUT_MODE_MEMORY;
3479 #endif
3480 
3481 	/* Construct in_frame info (only in case we have dynamic input */
3482 	if (need_in_frameinfo_memory) {
3483 		in_frame = &pipe->in_frame_struct;
3484 		err = init_in_frameinfo_memory_defaults(pipe, in_frame,
3485 							IA_CSS_FRAME_FORMAT_RAW);
3486 		if (err)
3487 			goto ERR;
3488 	}
3489 
3490 	out_frame->data = 0;
3491 	err = init_out_frameinfo_defaults(pipe, out_frame, 0);
3492 	if (err)
3493 		goto ERR;
3494 
3495 	if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) {
3496 		vf_frame = &pipe->vf_frame_struct;
3497 		vf_frame->data = 0;
3498 		err = init_vf_frameinfo_defaults(pipe, vf_frame, 0);
3499 		if (err)
3500 			goto ERR;
3501 	}
3502 
3503 	copy_binary  = &pipe->pipe_settings.video.copy_binary;
3504 	video_binary = &pipe->pipe_settings.video.video_binary;
3505 	vf_pp_binary = &pipe->pipe_settings.video.vf_pp_binary;
3506 
3507 	yuv_scaler_binary = pipe->pipe_settings.video.yuv_scaler_binary;
3508 	num_yuv_scaler  = pipe->pipe_settings.video.num_yuv_scaler;
3509 	is_output_stage = pipe->pipe_settings.video.is_output_stage;
3510 
3511 	need_copy   = (copy_binary && copy_binary->info);
3512 	need_vf_pp  = (vf_pp_binary && vf_pp_binary->info);
3513 	need_yuv_pp = (yuv_scaler_binary && yuv_scaler_binary->info);
3514 
3515 	if (need_copy) {
3516 		ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
3517 		ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary,
3518 						   out_frames, NULL, NULL);
3519 		err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
3520 							   &copy_stage);
3521 		if (err)
3522 			goto ERR;
3523 		in_frame = me->stages->args.out_frame[0];
3524 	} else if (pipe->stream->config.continuous) {
3525 #ifdef ISP2401
3526 		/* When continuous is enabled, configure in_frame with the
3527 		 * last pipe, which is the copy pipe.
3528 		 */
3529 		in_frame = pipe->stream->last_pipe->continuous_frames[0];
3530 #else
3531 		in_frame = pipe->continuous_frames[0];
3532 #endif
3533 	}
3534 
3535 	ia_css_pipe_util_set_output_frames(out_frames, 0,
3536 					   need_yuv_pp ? NULL : out_frame);
3537 
3538 	/* when the video binary supports a second output pin,
3539 	   it can directly produce the vf_frame.  */
3540 	if (need_vf_pp) {
3541 		ia_css_pipe_get_generic_stage_desc(&stage_desc, video_binary,
3542 						   out_frames, in_frame, NULL);
3543 	} else {
3544 		ia_css_pipe_get_generic_stage_desc(&stage_desc, video_binary,
3545 						   out_frames, in_frame, vf_frame);
3546 	}
3547 	err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
3548 						   &video_stage);
3549 	if (err)
3550 		goto ERR;
3551 
3552 	/* If we use copy iso video, the input must be yuv iso raw */
3553 	if (video_stage) {
3554 		video_stage->args.copy_vf =
3555 		    video_binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY;
3556 		video_stage->args.copy_output = video_stage->args.copy_vf;
3557 	}
3558 
3559 	/* when the video binary supports only 1 output pin, vf_pp is needed to
3560 	produce the vf_frame.*/
3561 	if (need_vf_pp && video_stage) {
3562 		in_frame = video_stage->args.out_vf_frame;
3563 		err = add_vf_pp_stage(pipe, in_frame, vf_frame, vf_pp_binary,
3564 				      &vf_pp_stage);
3565 		if (err)
3566 			goto ERR;
3567 	}
3568 	if (video_stage) {
3569 		int frm;
3570 
3571 		for (frm = 0; frm < NUM_TNR_FRAMES; frm++) {
3572 			video_stage->args.tnr_frames[frm] =
3573 			    pipe->pipe_settings.video.tnr_frames[frm];
3574 		}
3575 		for (frm = 0; frm < MAX_NUM_VIDEO_DELAY_FRAMES; frm++) {
3576 			video_stage->args.delay_frames[frm] =
3577 			    pipe->pipe_settings.video.delay_frames[frm];
3578 		}
3579 	}
3580 
3581 	/* Append Extension on Video out, if enabled */
3582 	if (!need_vf_pp && video_stage && pipe->config.acc_extension &&
3583 	    (pipe->config.acc_extension->info.isp.type == IA_CSS_ACC_OUTPUT)) {
3584 		struct ia_css_frame *out = NULL;
3585 		struct ia_css_frame *in = NULL;
3586 
3587 		if ((pipe->config.acc_extension->info.isp.sp.enable.output) &&
3588 		    (pipe->config.acc_extension->info.isp.sp.enable.in_frame) &&
3589 		    (pipe->config.acc_extension->info.isp.sp.enable.out_frame)) {
3590 			/* In/Out Frame mapping to support output frame extension.*/
3591 			out = video_stage->args.out_frame[0];
3592 			err = ia_css_frame_allocate_from_info(&in, &pipe->output_info[0]);
3593 			if (err)
3594 				goto ERR;
3595 			video_stage->args.out_frame[0] = in;
3596 		}
3597 
3598 		err = add_firmwares(me, video_binary, pipe->output_stage,
3599 				    last_output_firmware(pipe->output_stage),
3600 				    IA_CSS_BINARY_MODE_VIDEO,
3601 				    in, out, NULL, &video_stage, NULL);
3602 		if (err)
3603 			goto ERR;
3604 	}
3605 
3606 	if (need_yuv_pp && video_stage) {
3607 		struct ia_css_frame *tmp_in_frame = video_stage->args.out_frame[0];
3608 		struct ia_css_frame *tmp_out_frame = NULL;
3609 
3610 		for (i = 0; i < num_yuv_scaler; i++) {
3611 			tmp_out_frame = is_output_stage[i] ? out_frame : NULL;
3612 
3613 			err = add_yuv_scaler_stage(pipe, me, tmp_in_frame,
3614 						   tmp_out_frame, NULL,
3615 						   &yuv_scaler_binary[i],
3616 						   &yuv_scaler_stage);
3617 
3618 			if (err) {
3619 				IA_CSS_LEAVE_ERR_PRIVATE(err);
3620 				return err;
3621 			}
3622 			/* we use output port 1 as internal output port */
3623 			if (yuv_scaler_stage)
3624 				tmp_in_frame = yuv_scaler_stage->args.out_frame[1];
3625 		}
3626 	}
3627 
3628 	pipe->pipeline.acquire_isp_each_stage = false;
3629 	ia_css_pipeline_finalize_stages(&pipe->pipeline,
3630 					pipe->stream->config.continuous);
3631 
3632 ERR:
3633 	IA_CSS_LEAVE_ERR_PRIVATE(err);
3634 	return err;
3635 }
3636 
3637 static int
3638 create_host_acc_pipeline(struct ia_css_pipe *pipe)
3639 {
3640 	int err = 0;
3641 	const struct ia_css_fw_info *fw;
3642 	unsigned int i;
3643 
3644 	IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
3645 	if ((!pipe) || (!pipe->stream)) {
3646 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
3647 		return -EINVAL;
3648 	}
3649 
3650 	pipe->pipeline.num_execs = pipe->config.acc_num_execs;
3651 	/* Reset pipe_qos_config to default disable all QOS extension stages */
3652 	if (pipe->config.acc_extension)
3653 		pipe->pipeline.pipe_qos_config = 0;
3654 
3655 	fw = pipe->vf_stage;
3656 	for (i = 0; fw; fw = fw->next) {
3657 		err = sh_css_pipeline_add_acc_stage(&pipe->pipeline, fw);
3658 		if (err)
3659 			goto ERR;
3660 	}
3661 
3662 	for (i = 0; i < pipe->config.num_acc_stages; i++) {
3663 		struct ia_css_fw_info *fw = pipe->config.acc_stages[i];
3664 
3665 		err = sh_css_pipeline_add_acc_stage(&pipe->pipeline, fw);
3666 		if (err)
3667 			goto ERR;
3668 	}
3669 
3670 	ia_css_pipeline_finalize_stages(&pipe->pipeline, pipe->stream->config.continuous);
3671 
3672 ERR:
3673 	IA_CSS_LEAVE_ERR_PRIVATE(err);
3674 	return err;
3675 }
3676 
3677 /* Create stages for preview */
3678 static int
3679 create_host_preview_pipeline(struct ia_css_pipe *pipe)
3680 {
3681 	struct ia_css_pipeline_stage *copy_stage = NULL;
3682 	struct ia_css_pipeline_stage *preview_stage = NULL;
3683 	struct ia_css_pipeline_stage *vf_pp_stage = NULL;
3684 	struct ia_css_pipeline_stage_desc stage_desc;
3685 	struct ia_css_pipeline *me = NULL;
3686 	struct ia_css_binary *copy_binary, *preview_binary, *vf_pp_binary = NULL;
3687 	struct ia_css_frame *in_frame = NULL;
3688 	int err = 0;
3689 	struct ia_css_frame *out_frame;
3690 	struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS];
3691 	bool need_in_frameinfo_memory = false;
3692 #ifdef ISP2401
3693 	bool sensor = false;
3694 	bool buffered_sensor = false;
3695 	bool online = false;
3696 	bool continuous = false;
3697 #endif
3698 
3699 	IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
3700 	if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) {
3701 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
3702 		return -EINVAL;
3703 	}
3704 
3705 	ia_css_pipe_util_create_output_frames(out_frames);
3706 	/* pipeline already created as part of create_host_pipeline_structure */
3707 	me = &pipe->pipeline;
3708 	ia_css_pipeline_clean(me);
3709 
3710 #ifdef ISP2401
3711 	/* When the input system is 2401, always enable 'in_frameinfo_memory'
3712 	 * except for the following:
3713 	 * - Direct Sensor Mode Online Preview
3714 	 * - Buffered Sensor Mode Online Preview
3715 	 * - Direct Sensor Mode Continuous Preview
3716 	 * - Buffered Sensor Mode Continuous Preview
3717 	 */
3718 	sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR);
3719 	buffered_sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR);
3720 	online = pipe->stream->config.online;
3721 	continuous = pipe->stream->config.continuous;
3722 	need_in_frameinfo_memory =
3723 	!((sensor && (online || continuous)) || (buffered_sensor && (online || continuous)));
3724 #else
3725 	/* Construct in_frame info (only in case we have dynamic input */
3726 	need_in_frameinfo_memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY;
3727 #endif
3728 	if (need_in_frameinfo_memory) {
3729 		err = init_in_frameinfo_memory_defaults(pipe, &me->in_frame,
3730 							IA_CSS_FRAME_FORMAT_RAW);
3731 		if (err)
3732 			goto ERR;
3733 
3734 		in_frame = &me->in_frame;
3735 	} else {
3736 		in_frame = NULL;
3737 	}
3738 
3739 	err = init_out_frameinfo_defaults(pipe, &me->out_frame[0], 0);
3740 	if (err)
3741 		goto ERR;
3742 	out_frame = &me->out_frame[0];
3743 
3744 	copy_binary    = &pipe->pipe_settings.preview.copy_binary;
3745 	preview_binary = &pipe->pipe_settings.preview.preview_binary;
3746 	if (pipe->pipe_settings.preview.vf_pp_binary.info)
3747 		vf_pp_binary = &pipe->pipe_settings.preview.vf_pp_binary;
3748 
3749 	if (pipe->pipe_settings.preview.copy_binary.info) {
3750 		ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
3751 		ia_css_pipe_get_generic_stage_desc(&stage_desc, copy_binary,
3752 						   out_frames, NULL, NULL);
3753 		err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
3754 							   &copy_stage);
3755 		if (err)
3756 			goto ERR;
3757 		in_frame = me->stages->args.out_frame[0];
3758 	} else if (pipe->stream->config.continuous) {
3759 #ifdef ISP2401
3760 		/* When continuous is enabled, configure in_frame with the
3761 		 * last pipe, which is the copy pipe.
3762 		 */
3763 		if (continuous || !online)
3764 			in_frame = pipe->stream->last_pipe->continuous_frames[0];
3765 
3766 #else
3767 		in_frame = pipe->continuous_frames[0];
3768 #endif
3769 	}
3770 
3771 	if (vf_pp_binary) {
3772 		ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
3773 		ia_css_pipe_get_generic_stage_desc(&stage_desc, preview_binary,
3774 						   out_frames, in_frame, NULL);
3775 	} else {
3776 		ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
3777 		ia_css_pipe_get_generic_stage_desc(&stage_desc, preview_binary,
3778 						   out_frames, in_frame, NULL);
3779 	}
3780 	err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
3781 						   &preview_stage);
3782 	if (err)
3783 		goto ERR;
3784 	/* If we use copy iso preview, the input must be yuv iso raw */
3785 	preview_stage->args.copy_vf =
3786 	    preview_binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY;
3787 	preview_stage->args.copy_output = !preview_stage->args.copy_vf;
3788 	if (preview_stage->args.copy_vf && !preview_stage->args.out_vf_frame) {
3789 		/* in case of copy, use the vf frame as output frame */
3790 		preview_stage->args.out_vf_frame =
3791 		    preview_stage->args.out_frame[0];
3792 	}
3793 	if (vf_pp_binary) {
3794 		if (preview_binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY)
3795 			in_frame = preview_stage->args.out_vf_frame;
3796 		else
3797 			in_frame = preview_stage->args.out_frame[0];
3798 		err = add_vf_pp_stage(pipe, in_frame, out_frame, vf_pp_binary,
3799 				      &vf_pp_stage);
3800 		if (err)
3801 			goto ERR;
3802 	}
3803 
3804 	pipe->pipeline.acquire_isp_each_stage = false;
3805 	ia_css_pipeline_finalize_stages(&pipe->pipeline, pipe->stream->config.continuous);
3806 
3807 ERR:
3808 	IA_CSS_LEAVE_ERR_PRIVATE(err);
3809 	return err;
3810 }
3811 
3812 static void send_raw_frames(struct ia_css_pipe *pipe)
3813 {
3814 	if (pipe->stream->config.continuous) {
3815 		unsigned int i;
3816 
3817 		sh_css_update_host2sp_cont_num_raw_frames
3818 		(pipe->stream->config.init_num_cont_raw_buf, true);
3819 		sh_css_update_host2sp_cont_num_raw_frames
3820 		(pipe->stream->config.target_num_cont_raw_buf, false);
3821 
3822 		/* Hand-over all the SP-internal buffers */
3823 		for (i = 0; i < pipe->stream->config.init_num_cont_raw_buf; i++) {
3824 			sh_css_update_host2sp_offline_frame(i,
3825 							    pipe->continuous_frames[i], pipe->cont_md_buffers[i]);
3826 		}
3827 	}
3828 
3829 	return;
3830 }
3831 
3832 static int
3833 preview_start(struct ia_css_pipe *pipe)
3834 {
3835 	int err = 0;
3836 	struct ia_css_pipe *copy_pipe, *capture_pipe;
3837 	struct ia_css_pipe *acc_pipe;
3838 	enum sh_css_pipe_config_override copy_ovrd;
3839 	enum ia_css_input_mode preview_pipe_input_mode;
3840 	const struct ia_css_coordinate *coord = NULL;
3841 	const struct ia_css_isp_parameters *params = NULL;
3842 
3843 	IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
3844 	if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_PREVIEW)) {
3845 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
3846 		return -EINVAL;
3847 	}
3848 
3849 	preview_pipe_input_mode = pipe->stream->config.mode;
3850 
3851 	copy_pipe    = pipe->pipe_settings.preview.copy_pipe;
3852 	capture_pipe = pipe->pipe_settings.preview.capture_pipe;
3853 	acc_pipe     = pipe->pipe_settings.preview.acc_pipe;
3854 
3855 	sh_css_metrics_start_frame();
3856 
3857 	/* multi stream video needs mipi buffers */
3858 	err = send_mipi_frames(pipe);
3859 	if (err) {
3860 		IA_CSS_LEAVE_ERR_PRIVATE(err);
3861 		return err;
3862 	}
3863 	send_raw_frames(pipe);
3864 
3865 	{
3866 		unsigned int thread_id;
3867 
3868 		ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
3869 		copy_ovrd = 1 << thread_id;
3870 
3871 		if (pipe->stream->cont_capt) {
3872 			ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(capture_pipe),
3873 							 &thread_id);
3874 			copy_ovrd |= 1 << thread_id;
3875 		}
3876 	}
3877 
3878 	if (IS_ISP2401) {
3879 		coord = &pipe->config.internal_frame_origin_bqs_on_sctbl;
3880 		params = pipe->stream->isp_params_configs;
3881 	}
3882 
3883 	/* Construct and load the copy pipe */
3884 	if (pipe->stream->config.continuous) {
3885 		sh_css_sp_init_pipeline(&copy_pipe->pipeline,
3886 					IA_CSS_PIPE_ID_COPY,
3887 					(uint8_t)ia_css_pipe_get_pipe_num(copy_pipe),
3888 					false,
3889 					pipe->stream->config.pixels_per_clock == 2, false,
3890 					false, pipe->required_bds_factor,
3891 					copy_ovrd,
3892 					pipe->stream->config.mode,
3893 					&pipe->stream->config.metadata_config,
3894 					&pipe->stream->info.metadata_info,
3895 					pipe->stream->config.source.port.port,
3896 					coord,
3897 					params);
3898 
3899 		/* make the preview pipe start with mem mode input, copy handles
3900 		   the actual mode */
3901 		preview_pipe_input_mode = IA_CSS_INPUT_MODE_MEMORY;
3902 	}
3903 
3904 	/* Construct and load the capture pipe */
3905 	if (pipe->stream->cont_capt) {
3906 		sh_css_sp_init_pipeline(&capture_pipe->pipeline,
3907 					IA_CSS_PIPE_ID_CAPTURE,
3908 					(uint8_t)ia_css_pipe_get_pipe_num(capture_pipe),
3909 					capture_pipe->config.default_capture_config.enable_xnr != 0,
3910 					capture_pipe->stream->config.pixels_per_clock == 2,
3911 					true, /* continuous */
3912 					false, /* offline */
3913 					capture_pipe->required_bds_factor,
3914 					0,
3915 					IA_CSS_INPUT_MODE_MEMORY,
3916 					&pipe->stream->config.metadata_config,
3917 					&pipe->stream->info.metadata_info,
3918 					(enum mipi_port_id)0,
3919 					coord,
3920 					params);
3921 	}
3922 
3923 	if (acc_pipe) {
3924 		sh_css_sp_init_pipeline(&acc_pipe->pipeline,
3925 					IA_CSS_PIPE_ID_ACC,
3926 					(uint8_t)ia_css_pipe_get_pipe_num(acc_pipe),
3927 					false,
3928 					pipe->stream->config.pixels_per_clock == 2,
3929 					false, /* continuous */
3930 					false, /* offline */
3931 					pipe->required_bds_factor,
3932 					0,
3933 					IA_CSS_INPUT_MODE_MEMORY,
3934 					NULL,
3935 					NULL,
3936 					(enum mipi_port_id)0,
3937 					coord,
3938 					params);
3939 	}
3940 
3941 	start_pipe(pipe, copy_ovrd, preview_pipe_input_mode);
3942 
3943 	IA_CSS_LEAVE_ERR_PRIVATE(err);
3944 	return err;
3945 }
3946 
3947 int
3948 ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe,
3949 			   const struct ia_css_buffer *buffer)
3950 {
3951 	int return_err = 0;
3952 	unsigned int thread_id;
3953 	enum sh_css_queue_id queue_id;
3954 	struct ia_css_pipeline *pipeline;
3955 	struct ia_css_pipeline_stage *stage;
3956 	struct ia_css_rmgr_vbuf_handle p_vbuf;
3957 	struct ia_css_rmgr_vbuf_handle *h_vbuf;
3958 	struct sh_css_hmm_buffer ddr_buffer;
3959 	enum ia_css_buffer_type buf_type;
3960 	enum ia_css_pipe_id pipe_id;
3961 	bool ret_err;
3962 
3963 	IA_CSS_ENTER("pipe=%p, buffer=%p", pipe, buffer);
3964 
3965 	if ((!pipe) || (!buffer)) {
3966 		IA_CSS_LEAVE_ERR(-EINVAL);
3967 		return -EINVAL;
3968 	}
3969 
3970 	buf_type = buffer->type;
3971 	/* following code will be enabled when IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME
3972 	   is removed */
3973 #if 0
3974 	if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) {
3975 		bool found_pipe = false;
3976 
3977 		for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
3978 			if ((buffer->data.frame->info.res.width == pipe->output_info[i].res.width) &&
3979 			    (buffer->data.frame->info.res.height == pipe->output_info[i].res.height)) {
3980 				buf_type += i;
3981 				found_pipe = true;
3982 				break;
3983 			}
3984 		}
3985 		if (!found_pipe)
3986 			return -EINVAL;
3987 	}
3988 	if (buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) {
3989 		bool found_pipe = false;
3990 
3991 		for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
3992 			if ((buffer->data.frame->info.res.width == pipe->vf_output_info[i].res.width) &&
3993 			    (buffer->data.frame->info.res.height == pipe->vf_output_info[i].res.height)) {
3994 				buf_type += i;
3995 				found_pipe = true;
3996 				break;
3997 			}
3998 		}
3999 		if (!found_pipe)
4000 			return -EINVAL;
4001 	}
4002 #endif
4003 	pipe_id = pipe->mode;
4004 
4005 	IA_CSS_LOG("pipe_id=%d, buf_type=%d", pipe_id, buf_type);
4006 
4007 	assert(pipe_id < IA_CSS_PIPE_ID_NUM);
4008 	assert(buf_type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE);
4009 	if (buf_type == IA_CSS_BUFFER_TYPE_INVALID ||
4010 	    buf_type >= IA_CSS_NUM_DYNAMIC_BUFFER_TYPE ||
4011 	    pipe_id >= IA_CSS_PIPE_ID_NUM) {
4012 		IA_CSS_LEAVE_ERR(-EINVAL);
4013 		return -EINVAL;
4014 	}
4015 
4016 	ret_err = ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
4017 	if (!ret_err) {
4018 		IA_CSS_LEAVE_ERR(-EINVAL);
4019 		return -EINVAL;
4020 	}
4021 
4022 	ret_err = ia_css_query_internal_queue_id(buf_type, thread_id, &queue_id);
4023 	if (!ret_err) {
4024 		IA_CSS_LEAVE_ERR(-EINVAL);
4025 		return -EINVAL;
4026 	}
4027 
4028 	if ((queue_id <= SH_CSS_INVALID_QUEUE_ID) || (queue_id >= SH_CSS_MAX_NUM_QUEUES)) {
4029 		IA_CSS_LEAVE_ERR(-EINVAL);
4030 		return -EINVAL;
4031 	}
4032 
4033 	if (!sh_css_sp_is_running()) {
4034 		IA_CSS_LOG("SP is not running!");
4035 		IA_CSS_LEAVE_ERR(-EBUSY);
4036 		/* SP is not running. The queues are not valid */
4037 		return -EBUSY;
4038 	}
4039 
4040 	pipeline = &pipe->pipeline;
4041 
4042 	assert(pipeline ||
4043 	       pipe_id == IA_CSS_PIPE_ID_COPY ||
4044 	       pipe_id == IA_CSS_PIPE_ID_ACC);
4045 
4046 	assert(sizeof(NULL) <= sizeof(ddr_buffer.kernel_ptr));
4047 	ddr_buffer.kernel_ptr = HOST_ADDRESS(NULL);
4048 	ddr_buffer.cookie_ptr = buffer->driver_cookie;
4049 	ddr_buffer.timing_data = buffer->timing_data;
4050 
4051 	if (buf_type == IA_CSS_BUFFER_TYPE_3A_STATISTICS) {
4052 		if (!buffer->data.stats_3a) {
4053 			IA_CSS_LEAVE_ERR(-EINVAL);
4054 			return -EINVAL;
4055 		}
4056 		ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.stats_3a);
4057 		ddr_buffer.payload.s3a = *buffer->data.stats_3a;
4058 	} else if (buf_type == IA_CSS_BUFFER_TYPE_DIS_STATISTICS) {
4059 		if (!buffer->data.stats_dvs) {
4060 			IA_CSS_LEAVE_ERR(-EINVAL);
4061 			return -EINVAL;
4062 		}
4063 		ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.stats_dvs);
4064 		ddr_buffer.payload.dis = *buffer->data.stats_dvs;
4065 	} else if (buf_type == IA_CSS_BUFFER_TYPE_METADATA) {
4066 		if (!buffer->data.metadata) {
4067 			IA_CSS_LEAVE_ERR(-EINVAL);
4068 			return -EINVAL;
4069 		}
4070 		ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.metadata);
4071 		ddr_buffer.payload.metadata = *buffer->data.metadata;
4072 	} else if (buf_type == IA_CSS_BUFFER_TYPE_INPUT_FRAME ||
4073 		   buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME ||
4074 		   buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME ||
4075 		   buf_type == IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME ||
4076 		   buf_type == IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME) {
4077 		if (!buffer->data.frame) {
4078 			IA_CSS_LEAVE_ERR(-EINVAL);
4079 			return -EINVAL;
4080 		}
4081 		ddr_buffer.kernel_ptr = HOST_ADDRESS(buffer->data.frame);
4082 		ddr_buffer.payload.frame.frame_data = buffer->data.frame->data;
4083 		ddr_buffer.payload.frame.flashed = 0;
4084 
4085 		ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
4086 				    "ia_css_pipe_enqueue_buffer() buf_type=%d, data(DDR address)=0x%x\n",
4087 				    buf_type, buffer->data.frame->data);
4088 
4089 #if CONFIG_ON_FRAME_ENQUEUE()
4090 		return_err = set_config_on_frame_enqueue(
4091 				 &buffer->data.frame->info,
4092 				 &ddr_buffer.payload.frame);
4093 		if (return_err) {
4094 			IA_CSS_LEAVE_ERR(return_err);
4095 			return return_err;
4096 		}
4097 #endif
4098 	}
4099 
4100 	/* start of test for using rmgr for acq/rel memory */
4101 	p_vbuf.vptr = 0;
4102 	p_vbuf.count = 0;
4103 	p_vbuf.size = sizeof(struct sh_css_hmm_buffer);
4104 	h_vbuf = &p_vbuf;
4105 	/* TODO: change next to correct pool for optimization */
4106 	ia_css_rmgr_acq_vbuf(hmm_buffer_pool, &h_vbuf);
4107 
4108 	if ((!h_vbuf) || (h_vbuf->vptr == 0x0)) {
4109 		IA_CSS_LEAVE_ERR(-EINVAL);
4110 		return -EINVAL;
4111 	}
4112 
4113 	hmm_store(h_vbuf->vptr,
4114 		  (void *)(&ddr_buffer),
4115 		  sizeof(struct sh_css_hmm_buffer));
4116 	if (buf_type == IA_CSS_BUFFER_TYPE_3A_STATISTICS ||
4117 	    buf_type == IA_CSS_BUFFER_TYPE_DIS_STATISTICS ||
4118 	    buf_type == IA_CSS_BUFFER_TYPE_LACE_STATISTICS) {
4119 		if (!pipeline) {
4120 			ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &h_vbuf);
4121 			IA_CSS_LOG("pipeline is empty!");
4122 			IA_CSS_LEAVE_ERR(-EINVAL);
4123 			return -EINVAL;
4124 		}
4125 
4126 		for (stage = pipeline->stages; stage; stage = stage->next) {
4127 			/* The SP will read the params
4128 				after it got empty 3a and dis */
4129 			if (STATS_ENABLED(stage)) {
4130 				/* there is a stage that needs it */
4131 				return_err = ia_css_bufq_enqueue_buffer(thread_id,
4132 									queue_id,
4133 									(uint32_t)h_vbuf->vptr);
4134 			}
4135 		}
4136 	} else if (buf_type == IA_CSS_BUFFER_TYPE_INPUT_FRAME ||
4137 		   buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME ||
4138 		   buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME ||
4139 		   buf_type == IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME ||
4140 		   buf_type == IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME ||
4141 		   buf_type == IA_CSS_BUFFER_TYPE_METADATA) {
4142 		return_err = ia_css_bufq_enqueue_buffer(thread_id,
4143 							queue_id,
4144 							(uint32_t)h_vbuf->vptr);
4145 #if defined(SH_CSS_ENABLE_PER_FRAME_PARAMS)
4146 		if (!return_err &&
4147 		    buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) {
4148 			IA_CSS_LOG("pfp: enqueued OF %d to q %d thread %d",
4149 				   ddr_buffer.payload.frame.frame_data,
4150 				   queue_id, thread_id);
4151 		}
4152 #endif
4153 	}
4154 
4155 	if (!return_err) {
4156 		if (sh_css_hmm_buffer_record_acquire(
4157 			h_vbuf, buf_type,
4158 			HOST_ADDRESS(ddr_buffer.kernel_ptr))) {
4159 			IA_CSS_LOG("send vbuf=%p", h_vbuf);
4160 		} else {
4161 			return_err = -EINVAL;
4162 			IA_CSS_ERROR("hmm_buffer_record[]: no available slots\n");
4163 		}
4164 	}
4165 
4166 	/*
4167 	 * Tell the SP which queues are not empty,
4168 	 * by sending the software event.
4169 	 */
4170 	if (!return_err) {
4171 		if (!sh_css_sp_is_running()) {
4172 			/* SP is not running. The queues are not valid */
4173 			IA_CSS_LOG("SP is not running!");
4174 			IA_CSS_LEAVE_ERR(-EBUSY);
4175 			return -EBUSY;
4176 		}
4177 		return_err = ia_css_bufq_enqueue_psys_event(
4178 				 IA_CSS_PSYS_SW_EVENT_BUFFER_ENQUEUED,
4179 				 (uint8_t)thread_id,
4180 				 queue_id,
4181 				 0);
4182 	} else {
4183 		ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &h_vbuf);
4184 		IA_CSS_ERROR("buffer not enqueued");
4185 	}
4186 
4187 	IA_CSS_LEAVE("return value = %d", return_err);
4188 
4189 	return return_err;
4190 }
4191 
4192 /*
4193  * TODO: Free up the hmm memory space.
4194 	 */
4195 int
4196 ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe,
4197 			   struct ia_css_buffer *buffer)
4198 {
4199 	int return_err;
4200 	enum sh_css_queue_id queue_id;
4201 	ia_css_ptr ddr_buffer_addr = (ia_css_ptr)0;
4202 	struct sh_css_hmm_buffer ddr_buffer;
4203 	enum ia_css_buffer_type buf_type;
4204 	enum ia_css_pipe_id pipe_id;
4205 	unsigned int thread_id;
4206 	hrt_address kernel_ptr = 0;
4207 	bool ret_err;
4208 
4209 	IA_CSS_ENTER("pipe=%p, buffer=%p", pipe, buffer);
4210 
4211 	if ((!pipe) || (!buffer)) {
4212 		IA_CSS_LEAVE_ERR(-EINVAL);
4213 		return -EINVAL;
4214 	}
4215 
4216 	pipe_id = pipe->mode;
4217 
4218 	buf_type = buffer->type;
4219 
4220 	IA_CSS_LOG("pipe_id=%d, buf_type=%d", pipe_id, buf_type);
4221 
4222 	ddr_buffer.kernel_ptr = 0;
4223 
4224 	ret_err = ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
4225 	if (!ret_err) {
4226 		IA_CSS_LEAVE_ERR(-EINVAL);
4227 		return -EINVAL;
4228 	}
4229 
4230 	ret_err = ia_css_query_internal_queue_id(buf_type, thread_id, &queue_id);
4231 	if (!ret_err) {
4232 		IA_CSS_LEAVE_ERR(-EINVAL);
4233 		return -EINVAL;
4234 	}
4235 
4236 	if ((queue_id <= SH_CSS_INVALID_QUEUE_ID) || (queue_id >= SH_CSS_MAX_NUM_QUEUES)) {
4237 		IA_CSS_LEAVE_ERR(-EINVAL);
4238 		return -EINVAL;
4239 	}
4240 
4241 	if (!sh_css_sp_is_running()) {
4242 		IA_CSS_LOG("SP is not running!");
4243 		IA_CSS_LEAVE_ERR(-EBUSY);
4244 		/* SP is not running. The queues are not valid */
4245 		return -EBUSY;
4246 	}
4247 
4248 	return_err = ia_css_bufq_dequeue_buffer(queue_id,
4249 						(uint32_t *)&ddr_buffer_addr);
4250 
4251 	if (!return_err) {
4252 		struct ia_css_frame *frame;
4253 		struct sh_css_hmm_buffer_record *hmm_buffer_record = NULL;
4254 
4255 		IA_CSS_LOG("receive vbuf=%x", (int)ddr_buffer_addr);
4256 
4257 		/* Validate the ddr_buffer_addr and buf_type */
4258 		hmm_buffer_record = sh_css_hmm_buffer_record_validate(
4259 		    ddr_buffer_addr, buf_type);
4260 		if (hmm_buffer_record) {
4261 			/* valid hmm_buffer_record found. Save the kernel_ptr
4262 			 * for validation after performing hmm_load.  The
4263 			 * vbuf handle and buffer_record can be released.
4264 			 */
4265 			kernel_ptr = hmm_buffer_record->kernel_ptr;
4266 			ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &hmm_buffer_record->h_vbuf);
4267 			sh_css_hmm_buffer_record_reset(hmm_buffer_record);
4268 		} else {
4269 			IA_CSS_ERROR("hmm_buffer_record not found (0x%x) buf_type(%d)",
4270 				     ddr_buffer_addr, buf_type);
4271 			IA_CSS_LEAVE_ERR(-EINVAL);
4272 			return -EINVAL;
4273 		}
4274 
4275 		hmm_load(ddr_buffer_addr,
4276 			 &ddr_buffer,
4277 			 sizeof(struct sh_css_hmm_buffer));
4278 
4279 		/* if the kernel_ptr is 0 or an invalid, return an error.
4280 		 * do not access the buffer via the kernal_ptr.
4281 		 */
4282 		if ((ddr_buffer.kernel_ptr == 0) ||
4283 		    (kernel_ptr != HOST_ADDRESS(ddr_buffer.kernel_ptr))) {
4284 			IA_CSS_ERROR("kernel_ptr invalid");
4285 			IA_CSS_ERROR("expected: (0x%llx)", (u64)kernel_ptr);
4286 			IA_CSS_ERROR("actual: (0x%llx)", (u64)HOST_ADDRESS(ddr_buffer.kernel_ptr));
4287 			IA_CSS_ERROR("buf_type: %d\n", buf_type);
4288 			IA_CSS_LEAVE_ERR(-EINVAL);
4289 			return -EINVAL;
4290 		}
4291 
4292 		if (ddr_buffer.kernel_ptr != 0) {
4293 			/* buffer->exp_id : all instances to be removed later once the driver change
4294 			 * is completed. See patch #5758 for reference */
4295 			buffer->exp_id = 0;
4296 			buffer->driver_cookie = ddr_buffer.cookie_ptr;
4297 			buffer->timing_data = ddr_buffer.timing_data;
4298 
4299 			if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME ||
4300 			    buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) {
4301 				buffer->isys_eof_clock_tick.ticks = ddr_buffer.isys_eof_clock_tick;
4302 			}
4303 
4304 			switch (buf_type) {
4305 			case IA_CSS_BUFFER_TYPE_INPUT_FRAME:
4306 			case IA_CSS_BUFFER_TYPE_OUTPUT_FRAME:
4307 			case IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME:
4308 				if (pipe && pipe->stop_requested) {
4309 #if !defined(ISP2401)
4310 					/* free mipi frames only for old input system
4311 					 * for 2401 it is done in ia_css_stream_destroy call
4312 					 */
4313 					return_err = free_mipi_frames(pipe);
4314 					if (return_err) {
4315 						IA_CSS_LOG("free_mipi_frames() failed");
4316 						IA_CSS_LEAVE_ERR(return_err);
4317 						return return_err;
4318 					}
4319 #endif
4320 					pipe->stop_requested = false;
4321 				}
4322 				fallthrough;
4323 			case IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME:
4324 			case IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME:
4325 				frame = (struct ia_css_frame *)HOST_ADDRESS(ddr_buffer.kernel_ptr);
4326 				buffer->data.frame = frame;
4327 				buffer->exp_id = ddr_buffer.payload.frame.exp_id;
4328 				frame->exp_id = ddr_buffer.payload.frame.exp_id;
4329 				frame->isp_config_id = ddr_buffer.payload.frame.isp_parameters_id;
4330 				if (ddr_buffer.payload.frame.flashed == 1)
4331 					frame->flash_state =
4332 					    IA_CSS_FRAME_FLASH_STATE_PARTIAL;
4333 				if (ddr_buffer.payload.frame.flashed == 2)
4334 					frame->flash_state =
4335 					    IA_CSS_FRAME_FLASH_STATE_FULL;
4336 				frame->valid = pipe->num_invalid_frames == 0;
4337 				if (!frame->valid)
4338 					pipe->num_invalid_frames--;
4339 
4340 				if (frame->info.format == IA_CSS_FRAME_FORMAT_BINARY_8) {
4341 #ifdef ISP2401
4342 					frame->planes.binary.size = frame->data_bytes;
4343 #else
4344 					frame->planes.binary.size =
4345 					    sh_css_sp_get_binary_copy_size();
4346 #endif
4347 				}
4348 #if defined(SH_CSS_ENABLE_PER_FRAME_PARAMS)
4349 				if (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) {
4350 					IA_CSS_LOG("pfp: dequeued OF %d with config id %d thread %d",
4351 						   frame->data, frame->isp_config_id, thread_id);
4352 				}
4353 #endif
4354 
4355 				ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
4356 						    "ia_css_pipe_dequeue_buffer() buf_type=%d, data(DDR address)=0x%x\n",
4357 						    buf_type, buffer->data.frame->data);
4358 
4359 				break;
4360 			case IA_CSS_BUFFER_TYPE_3A_STATISTICS:
4361 				buffer->data.stats_3a =
4362 				    (struct ia_css_isp_3a_statistics *)HOST_ADDRESS(ddr_buffer.kernel_ptr);
4363 				buffer->exp_id = ddr_buffer.payload.s3a.exp_id;
4364 				buffer->data.stats_3a->exp_id = ddr_buffer.payload.s3a.exp_id;
4365 				buffer->data.stats_3a->isp_config_id = ddr_buffer.payload.s3a.isp_config_id;
4366 				break;
4367 			case IA_CSS_BUFFER_TYPE_DIS_STATISTICS:
4368 				buffer->data.stats_dvs =
4369 				    (struct ia_css_isp_dvs_statistics *)
4370 				    HOST_ADDRESS(ddr_buffer.kernel_ptr);
4371 				buffer->exp_id = ddr_buffer.payload.dis.exp_id;
4372 				buffer->data.stats_dvs->exp_id = ddr_buffer.payload.dis.exp_id;
4373 				break;
4374 			case IA_CSS_BUFFER_TYPE_LACE_STATISTICS:
4375 				break;
4376 			case IA_CSS_BUFFER_TYPE_METADATA:
4377 				buffer->data.metadata =
4378 				    (struct ia_css_metadata *)HOST_ADDRESS(ddr_buffer.kernel_ptr);
4379 				buffer->exp_id = ddr_buffer.payload.metadata.exp_id;
4380 				buffer->data.metadata->exp_id = ddr_buffer.payload.metadata.exp_id;
4381 				break;
4382 			default:
4383 				return_err = -EINVAL;
4384 				break;
4385 			}
4386 		}
4387 	}
4388 
4389 	/*
4390 	 * Tell the SP which queues are not full,
4391 	 * by sending the software event.
4392 	 */
4393 	if (!return_err) {
4394 		if (!sh_css_sp_is_running()) {
4395 			IA_CSS_LOG("SP is not running!");
4396 			IA_CSS_LEAVE_ERR(-EBUSY);
4397 			/* SP is not running. The queues are not valid */
4398 			return -EBUSY;
4399 		}
4400 		ia_css_bufq_enqueue_psys_event(
4401 		    IA_CSS_PSYS_SW_EVENT_BUFFER_DEQUEUED,
4402 		    0,
4403 		    queue_id,
4404 		    0);
4405 	}
4406 	IA_CSS_LEAVE("buffer=%p", buffer);
4407 
4408 	return return_err;
4409 }
4410 
4411 /*
4412  * Cannot Move this to event module as it is of ia_css_event_type which is declared in ia_css.h
4413  * TODO: modify and move it if possible.
4414  *
4415  * !!!IMPORTANT!!! KEEP THE FOLLOWING IN SYNC:
4416  * 1) "enum ia_css_event_type"					(ia_css_event_public.h)
4417  * 2) "enum sh_css_sp_event_type"				(sh_css_internal.h)
4418  * 3) "enum ia_css_event_type event_id_2_event_mask"		(event_handler.sp.c)
4419  * 4) "enum ia_css_event_type convert_event_sp_to_host_domain"	(sh_css.c)
4420  */
4421 static enum ia_css_event_type convert_event_sp_to_host_domain[] = {
4422 	IA_CSS_EVENT_TYPE_OUTPUT_FRAME_DONE,	/** Output frame ready. */
4423 	IA_CSS_EVENT_TYPE_SECOND_OUTPUT_FRAME_DONE,	/** Second output frame ready. */
4424 	IA_CSS_EVENT_TYPE_VF_OUTPUT_FRAME_DONE,	/** Viewfinder Output frame ready. */
4425 	IA_CSS_EVENT_TYPE_SECOND_VF_OUTPUT_FRAME_DONE,	/** Second viewfinder Output frame ready. */
4426 	IA_CSS_EVENT_TYPE_3A_STATISTICS_DONE,	/** Indication that 3A statistics are available. */
4427 	IA_CSS_EVENT_TYPE_DIS_STATISTICS_DONE,	/** Indication that DIS statistics are available. */
4428 	IA_CSS_EVENT_TYPE_PIPELINE_DONE,	/** Pipeline Done event, sent after last pipeline stage. */
4429 	IA_CSS_EVENT_TYPE_FRAME_TAGGED,		/** Frame tagged. */
4430 	IA_CSS_EVENT_TYPE_INPUT_FRAME_DONE,	/** Input frame ready. */
4431 	IA_CSS_EVENT_TYPE_METADATA_DONE,	/** Metadata ready. */
4432 	IA_CSS_EVENT_TYPE_LACE_STATISTICS_DONE,	/** Indication that LACE statistics are available. */
4433 	IA_CSS_EVENT_TYPE_ACC_STAGE_COMPLETE,	/** Extension stage executed. */
4434 	IA_CSS_EVENT_TYPE_TIMER,		/** Timing measurement data. */
4435 	IA_CSS_EVENT_TYPE_PORT_EOF,		/** End Of Frame event, sent when in buffered sensor mode. */
4436 	IA_CSS_EVENT_TYPE_FW_WARNING,		/** Performance warning encountered by FW */
4437 	IA_CSS_EVENT_TYPE_FW_ASSERT,		/** Assertion hit by FW */
4438 	0,					/* error if sp passes  SH_CSS_SP_EVENT_NR_OF_TYPES as a valid event. */
4439 };
4440 
4441 int
4442 ia_css_dequeue_event(struct ia_css_event *event)
4443 {
4444 	return ia_css_dequeue_psys_event(event);
4445 }
4446 
4447 int
4448 ia_css_dequeue_psys_event(struct ia_css_event *event)
4449 {
4450 	enum ia_css_pipe_id pipe_id = 0;
4451 	u8 payload[4] = {0, 0, 0, 0};
4452 	int ret_err;
4453 
4454 	/*TODO:
4455 	 * a) use generic decoding function , same as the one used by sp.
4456 	 * b) group decode and dequeue into eventQueue module
4457 	 *
4458 	 * We skip the IA_CSS_ENTER logging call
4459 	 * to avoid flooding the logs when the host application
4460 	 * uses polling. */
4461 	if (!event)
4462 		return -EINVAL;
4463 
4464 	/* SP is not running. The queues are not valid */
4465 	if (!sh_css_sp_is_running())
4466 		return -EBUSY;
4467 
4468 	/* dequeue the event (if any) from the psys event queue */
4469 	ret_err = ia_css_bufq_dequeue_psys_event(payload);
4470 	if (ret_err)
4471 		return ret_err;
4472 
4473 	IA_CSS_LOG("event dequeued from psys event queue");
4474 
4475 	/* Tell the SP that we dequeued an event from the event queue. */
4476 	ia_css_bufq_enqueue_psys_event(
4477 	    IA_CSS_PSYS_SW_EVENT_EVENT_DEQUEUED, 0, 0, 0);
4478 
4479 	/* Events are decoded into 4 bytes of payload, the first byte
4480 	 * contains the sp event type. This is converted to a host enum.
4481 	 * TODO: can this enum conversion be eliminated */
4482 	event->type = convert_event_sp_to_host_domain[payload[0]];
4483 	/* Some sane default values since not all events use all fields. */
4484 	event->pipe = NULL;
4485 	event->port = MIPI_PORT0_ID;
4486 	event->exp_id = 0;
4487 	event->fw_warning = IA_CSS_FW_WARNING_NONE;
4488 	event->fw_handle = 0;
4489 	event->timer_data = 0;
4490 	event->timer_code = 0;
4491 	event->timer_subcode = 0;
4492 
4493 	if (event->type == IA_CSS_EVENT_TYPE_TIMER) {
4494 		/* timer event ??? get the 2nd event and decode the data into the event struct */
4495 		u32 tmp_data;
4496 		/* 1st event: LSB 16-bit timer data and code */
4497 		event->timer_data = ((payload[1] & 0xFF) | ((payload[3] & 0xFF) << 8));
4498 		event->timer_code = payload[2];
4499 		payload[0] = payload[1] = payload[2] = payload[3] = 0;
4500 		ret_err = ia_css_bufq_dequeue_psys_event(payload);
4501 		if (ret_err) {
4502 			/* no 2nd event ??? an error */
4503 			/* Putting IA_CSS_ERROR is resulting in failures in
4504 			 * Merrifield smoke testing  */
4505 			IA_CSS_WARNING("Timer: Error de-queuing the 2nd TIMER event!!!\n");
4506 			return ret_err;
4507 		}
4508 		ia_css_bufq_enqueue_psys_event(
4509 		    IA_CSS_PSYS_SW_EVENT_EVENT_DEQUEUED, 0, 0, 0);
4510 		event->type = convert_event_sp_to_host_domain[payload[0]];
4511 		/* It's a timer */
4512 		if (event->type == IA_CSS_EVENT_TYPE_TIMER) {
4513 			/* 2nd event data: MSB 16-bit timer and subcode */
4514 			tmp_data = ((payload[1] & 0xFF) | ((payload[3] & 0xFF) << 8));
4515 			event->timer_data |= (tmp_data << 16);
4516 			event->timer_subcode = payload[2];
4517 		} else {
4518 		/* It's a non timer event. So clear first half of the timer event data.
4519 		* If the second part of the TIMER event is not received, we discard
4520 		* the first half of the timer data and process the non timer event without
4521 		* affecting the flow. So the non timer event falls through
4522 		* the code. */
4523 			event->timer_data = 0;
4524 			event->timer_code = 0;
4525 			event->timer_subcode = 0;
4526 			IA_CSS_ERROR("Missing 2nd timer event. Timer event discarded");
4527 		}
4528 	}
4529 	if (event->type == IA_CSS_EVENT_TYPE_PORT_EOF) {
4530 		event->port = (enum mipi_port_id)payload[1];
4531 		event->exp_id = payload[3];
4532 	} else if (event->type == IA_CSS_EVENT_TYPE_FW_WARNING) {
4533 		event->fw_warning = (enum ia_css_fw_warning)payload[1];
4534 		/* exp_id is only available in these warning types */
4535 		if (event->fw_warning == IA_CSS_FW_WARNING_EXP_ID_LOCKED ||
4536 		    event->fw_warning == IA_CSS_FW_WARNING_TAG_EXP_ID_FAILED)
4537 			event->exp_id = payload[3];
4538 	} else if (event->type == IA_CSS_EVENT_TYPE_FW_ASSERT) {
4539 		event->fw_assert_module_id = payload[1]; /* module */
4540 		event->fw_assert_line_no = (payload[2] << 8) + payload[3];
4541 		/* payload[2] is line_no>>8, payload[3] is line_no&0xff */
4542 	} else if (event->type != IA_CSS_EVENT_TYPE_TIMER) {
4543 		/* pipe related events.
4544 		 * payload[1] contains the pipe_num,
4545 		 * payload[2] contains the pipe_id. These are different. */
4546 		event->pipe = find_pipe_by_num(payload[1]);
4547 		pipe_id = (enum ia_css_pipe_id)payload[2];
4548 		/* Check to see if pipe still exists */
4549 		if (!event->pipe)
4550 			return -EBUSY;
4551 
4552 		if (event->type == IA_CSS_EVENT_TYPE_FRAME_TAGGED) {
4553 			/* find the capture pipe that goes with this */
4554 			int i, n;
4555 
4556 			n = event->pipe->stream->num_pipes;
4557 			for (i = 0; i < n; i++) {
4558 				struct ia_css_pipe *p =
4559 					    event->pipe->stream->pipes[i];
4560 				if (p->config.mode == IA_CSS_PIPE_MODE_CAPTURE) {
4561 					event->pipe = p;
4562 					break;
4563 				}
4564 			}
4565 			event->exp_id = payload[3];
4566 		}
4567 		if (event->type == IA_CSS_EVENT_TYPE_ACC_STAGE_COMPLETE) {
4568 			/* payload[3] contains the acc fw handle. */
4569 			u32 stage_num = (uint32_t)payload[3];
4570 
4571 			ret_err = ia_css_pipeline_get_fw_from_stage(
4572 				      &event->pipe->pipeline,
4573 				      stage_num,
4574 				      &event->fw_handle);
4575 			if (ret_err) {
4576 				IA_CSS_ERROR("Invalid stage num received for ACC event. stage_num:%u",
4577 					     stage_num);
4578 				return ret_err;
4579 			}
4580 		}
4581 	}
4582 
4583 	if (event->pipe)
4584 		IA_CSS_LEAVE("event_id=%d, pipe_id=%d", event->type, pipe_id);
4585 	else
4586 		IA_CSS_LEAVE("event_id=%d", event->type);
4587 
4588 	return 0;
4589 }
4590 
4591 int
4592 ia_css_dequeue_isys_event(struct ia_css_event *event)
4593 {
4594 	u8 payload[4] = {0, 0, 0, 0};
4595 	int err = 0;
4596 
4597 	/* We skip the IA_CSS_ENTER logging call
4598 	 * to avoid flooding the logs when the host application
4599 	 * uses polling. */
4600 	if (!event)
4601 		return -EINVAL;
4602 
4603 	/* SP is not running. The queues are not valid */
4604 	if (!sh_css_sp_is_running())
4605 		return -EBUSY;
4606 
4607 	err = ia_css_bufq_dequeue_isys_event(payload);
4608 	if (err)
4609 		return err;
4610 
4611 	IA_CSS_LOG("event dequeued from isys event queue");
4612 
4613 	/* Update SP state to indicate that element was dequeued. */
4614 	ia_css_bufq_enqueue_isys_event(IA_CSS_ISYS_SW_EVENT_EVENT_DEQUEUED);
4615 
4616 	/* Fill return struct with appropriate info */
4617 	event->type = IA_CSS_EVENT_TYPE_PORT_EOF;
4618 	/* EOF events are associated with a CSI port, not with a pipe */
4619 	event->pipe = NULL;
4620 	event->port = payload[1];
4621 	event->exp_id = payload[3];
4622 
4623 	IA_CSS_LEAVE_ERR(err);
4624 	return err;
4625 }
4626 
4627 static void
4628 acc_start(struct ia_css_pipe *pipe)
4629 {
4630 	assert(pipe);
4631 	assert(pipe->stream);
4632 
4633 	start_pipe(pipe, SH_CSS_PIPE_CONFIG_OVRD_NO_OVRD,
4634 		   pipe->stream->config.mode);
4635 }
4636 
4637 static int
4638 sh_css_pipe_start(struct ia_css_stream *stream)
4639 {
4640 	int err = 0;
4641 
4642 	struct ia_css_pipe *pipe;
4643 	enum ia_css_pipe_id pipe_id;
4644 	unsigned int thread_id;
4645 
4646 	IA_CSS_ENTER_PRIVATE("stream = %p", stream);
4647 
4648 	if (!stream) {
4649 		IA_CSS_LEAVE_ERR(-EINVAL);
4650 		return -EINVAL;
4651 	}
4652 	pipe = stream->last_pipe;
4653 	if (!pipe) {
4654 		IA_CSS_LEAVE_ERR(-EINVAL);
4655 		return -EINVAL;
4656 	}
4657 
4658 	pipe_id = pipe->mode;
4659 
4660 	if (stream->started) {
4661 		IA_CSS_WARNING("Cannot start stream that is already started");
4662 		IA_CSS_LEAVE_ERR(err);
4663 		return err;
4664 	}
4665 
4666 	pipe->stop_requested = false;
4667 
4668 	switch (pipe_id) {
4669 	case IA_CSS_PIPE_ID_PREVIEW:
4670 		err = preview_start(pipe);
4671 		break;
4672 	case IA_CSS_PIPE_ID_VIDEO:
4673 		err = video_start(pipe);
4674 		break;
4675 	case IA_CSS_PIPE_ID_CAPTURE:
4676 		err = capture_start(pipe);
4677 		break;
4678 	case IA_CSS_PIPE_ID_YUVPP:
4679 		err = yuvpp_start(pipe);
4680 		break;
4681 	case IA_CSS_PIPE_ID_ACC:
4682 		acc_start(pipe);
4683 		break;
4684 	default:
4685 		err = -EINVAL;
4686 	}
4687 	/* DH regular multi pipe - not continuous mode: start the next pipes too */
4688 	if (!stream->config.continuous) {
4689 		int i;
4690 
4691 		for (i = 1; i < stream->num_pipes && 0 == err ; i++) {
4692 			switch (stream->pipes[i]->mode) {
4693 			case IA_CSS_PIPE_ID_PREVIEW:
4694 				stream->pipes[i]->stop_requested = false;
4695 				err = preview_start(stream->pipes[i]);
4696 				break;
4697 			case IA_CSS_PIPE_ID_VIDEO:
4698 				stream->pipes[i]->stop_requested = false;
4699 				err = video_start(stream->pipes[i]);
4700 				break;
4701 			case IA_CSS_PIPE_ID_CAPTURE:
4702 				stream->pipes[i]->stop_requested = false;
4703 				err = capture_start(stream->pipes[i]);
4704 				break;
4705 			case IA_CSS_PIPE_ID_YUVPP:
4706 				stream->pipes[i]->stop_requested = false;
4707 				err = yuvpp_start(stream->pipes[i]);
4708 				break;
4709 			case IA_CSS_PIPE_ID_ACC:
4710 				stream->pipes[i]->stop_requested = false;
4711 				acc_start(stream->pipes[i]);
4712 				break;
4713 			default:
4714 				err = -EINVAL;
4715 			}
4716 		}
4717 	}
4718 	if (err) {
4719 		IA_CSS_LEAVE_ERR_PRIVATE(err);
4720 		return err;
4721 	}
4722 
4723 	/* Force ISP parameter calculation after a mode change
4724 	 * Acceleration API examples pass NULL for stream but they
4725 	 * don't use ISP parameters anyway. So this should be okay.
4726 	 * The SP binary (jpeg) copy does not use any parameters.
4727 	 */
4728 	if (!copy_on_sp(pipe)) {
4729 		sh_css_invalidate_params(stream);
4730 		err = sh_css_param_update_isp_params(pipe,
4731 						     stream->isp_params_configs, true, NULL);
4732 		if (err) {
4733 			IA_CSS_LEAVE_ERR_PRIVATE(err);
4734 			return err;
4735 		}
4736 	}
4737 
4738 	ia_css_debug_pipe_graph_dump_epilogue();
4739 
4740 	ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
4741 
4742 	if (!sh_css_sp_is_running()) {
4743 		IA_CSS_LEAVE_ERR_PRIVATE(-EBUSY);
4744 		/* SP is not running. The queues are not valid */
4745 		return -EBUSY;
4746 	}
4747 	ia_css_bufq_enqueue_psys_event(IA_CSS_PSYS_SW_EVENT_START_STREAM,
4748 				       (uint8_t)thread_id, 0, 0);
4749 
4750 	/* DH regular multi pipe - not continuous mode: enqueue event to the next pipes too */
4751 	if (!stream->config.continuous) {
4752 		int i;
4753 
4754 		for (i = 1; i < stream->num_pipes; i++) {
4755 			ia_css_pipeline_get_sp_thread_id(
4756 			    ia_css_pipe_get_pipe_num(stream->pipes[i]),
4757 			    &thread_id);
4758 			ia_css_bufq_enqueue_psys_event(
4759 			    IA_CSS_PSYS_SW_EVENT_START_STREAM,
4760 			    (uint8_t)thread_id, 0, 0);
4761 		}
4762 	}
4763 
4764 	/* in case of continuous capture mode, we also start capture thread and copy thread*/
4765 	if (pipe->stream->config.continuous) {
4766 		struct ia_css_pipe *copy_pipe = NULL;
4767 
4768 		if (pipe_id == IA_CSS_PIPE_ID_PREVIEW)
4769 			copy_pipe = pipe->pipe_settings.preview.copy_pipe;
4770 		else if (pipe_id == IA_CSS_PIPE_ID_VIDEO)
4771 			copy_pipe = pipe->pipe_settings.video.copy_pipe;
4772 
4773 		if (!copy_pipe) {
4774 			IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
4775 			return -EINVAL;
4776 		}
4777 		ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(copy_pipe),
4778 						 &thread_id);
4779 		/* by the time we reach here q is initialized and handle is available.*/
4780 		ia_css_bufq_enqueue_psys_event(
4781 		    IA_CSS_PSYS_SW_EVENT_START_STREAM,
4782 		    (uint8_t)thread_id, 0,  0);
4783 	}
4784 	if (pipe->stream->cont_capt) {
4785 		struct ia_css_pipe *capture_pipe = NULL;
4786 
4787 		if (pipe_id == IA_CSS_PIPE_ID_PREVIEW)
4788 			capture_pipe = pipe->pipe_settings.preview.capture_pipe;
4789 		else if (pipe_id == IA_CSS_PIPE_ID_VIDEO)
4790 			capture_pipe = pipe->pipe_settings.video.capture_pipe;
4791 
4792 		if (!capture_pipe) {
4793 			IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
4794 			return -EINVAL;
4795 		}
4796 		ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(capture_pipe),
4797 						 &thread_id);
4798 		/* by the time we reach here q is initialized and handle is available.*/
4799 		ia_css_bufq_enqueue_psys_event(
4800 		    IA_CSS_PSYS_SW_EVENT_START_STREAM,
4801 		    (uint8_t)thread_id, 0,  0);
4802 	}
4803 
4804 	/* in case of PREVIEW mode, check whether QOS acc_pipe is available, then start the qos pipe */
4805 	if (pipe_id == IA_CSS_PIPE_ID_PREVIEW) {
4806 		struct ia_css_pipe *acc_pipe = NULL;
4807 
4808 		acc_pipe = pipe->pipe_settings.preview.acc_pipe;
4809 
4810 		if (acc_pipe) {
4811 			ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(acc_pipe),
4812 							 &thread_id);
4813 			/* by the time we reach here q is initialized and handle is available.*/
4814 			ia_css_bufq_enqueue_psys_event(
4815 			    IA_CSS_PSYS_SW_EVENT_START_STREAM,
4816 			    (uint8_t)thread_id, 0, 0);
4817 		}
4818 	}
4819 
4820 	stream->started = true;
4821 
4822 	IA_CSS_LEAVE_ERR_PRIVATE(err);
4823 	return err;
4824 }
4825 
4826 /* ISP2400 */
4827 void
4828 sh_css_enable_cont_capt(bool enable, bool stop_copy_preview)
4829 {
4830 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
4831 			    "sh_css_enable_cont_capt() enter: enable=%d\n", enable);
4832 //my_css.cont_capt = enable;
4833 	my_css.stop_copy_preview = stop_copy_preview;
4834 }
4835 
4836 bool
4837 sh_css_continuous_is_enabled(uint8_t pipe_num)
4838 {
4839 	struct ia_css_pipe *pipe;
4840 	bool continuous;
4841 
4842 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
4843 			    "sh_css_continuous_is_enabled() enter: pipe_num=%d\n", pipe_num);
4844 
4845 	pipe = find_pipe_by_num(pipe_num);
4846 	continuous = pipe && pipe->stream->config.continuous;
4847 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
4848 			    "sh_css_continuous_is_enabled() leave: enable=%d\n",
4849 			    continuous);
4850 	return continuous;
4851 }
4852 
4853 /* ISP2400 */
4854 int
4855 ia_css_stream_get_max_buffer_depth(struct ia_css_stream *stream,
4856 				   int *buffer_depth)
4857 {
4858 	if (!buffer_depth)
4859 		return -EINVAL;
4860 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_get_max_buffer_depth() enter: void\n");
4861 	(void)stream;
4862 	*buffer_depth = NUM_CONTINUOUS_FRAMES;
4863 	return 0;
4864 }
4865 
4866 int
4867 ia_css_stream_set_buffer_depth(struct ia_css_stream *stream, int buffer_depth)
4868 {
4869 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_set_buffer_depth() enter: num_frames=%d\n", buffer_depth);
4870 	(void)stream;
4871 	if (buffer_depth > NUM_CONTINUOUS_FRAMES || buffer_depth < 1)
4872 		return -EINVAL;
4873 	/* ok, value allowed */
4874 	stream->config.target_num_cont_raw_buf = buffer_depth;
4875 	/* TODO: check what to regarding initialization */
4876 	return 0;
4877 }
4878 
4879 /* ISP2401 */
4880 int
4881 ia_css_stream_get_buffer_depth(struct ia_css_stream *stream,
4882 			       int *buffer_depth)
4883 {
4884 	if (!buffer_depth)
4885 		return -EINVAL;
4886 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_get_buffer_depth() enter: void\n");
4887 	(void)stream;
4888 	*buffer_depth = stream->config.target_num_cont_raw_buf;
4889 	return 0;
4890 }
4891 
4892 /*
4893  * @brief Stop all "ia_css_pipe" instances in the target
4894  * "ia_css_stream" instance.
4895  *
4896  * Refer to "Local prototypes" for more info.
4897  */
4898 /* ISP2401 */
4899 static int
4900 sh_css_pipes_stop(struct ia_css_stream *stream)
4901 {
4902 	int err = 0;
4903 	struct ia_css_pipe *main_pipe;
4904 	enum ia_css_pipe_id main_pipe_id;
4905 	int i;
4906 
4907 	if (!stream) {
4908 		IA_CSS_LOG("stream does NOT exist!");
4909 		err = -EINVAL;
4910 		goto ERR;
4911 	}
4912 
4913 	main_pipe = stream->last_pipe;
4914 	if (!main_pipe) {
4915 		IA_CSS_LOG("main_pipe does NOT exist!");
4916 		err = -EINVAL;
4917 		goto ERR;
4918 	}
4919 
4920 	main_pipe_id = main_pipe->mode;
4921 	IA_CSS_ENTER_PRIVATE("main_pipe_id=%d", main_pipe_id);
4922 
4923 	/*
4924 	 * Stop all "ia_css_pipe" instances in this target
4925 	 * "ia_css_stream" instance.
4926 	 */
4927 	for (i = 0; i < stream->num_pipes; i++) {
4928 		/* send the "stop" request to the "ia_css_pipe" instance */
4929 		IA_CSS_LOG("Send the stop-request to the pipe: pipe_id=%d",
4930 			   stream->pipes[i]->pipeline.pipe_id);
4931 		err = ia_css_pipeline_request_stop(&stream->pipes[i]->pipeline);
4932 
4933 		/*
4934 		* Exit this loop if "ia_css_pipeline_request_stop()"
4935 		* returns the error code.
4936 		*
4937 		* The error code would be generated in the following
4938 		* two cases:
4939 		* (1) The Scalar Processor has already been stopped.
4940 		* (2) The "Host->SP" event queue is full.
4941 		*
4942 		* As the convention of using CSS API 2.0/2.1, such CSS
4943 		* error code would be propogated from the CSS-internal
4944 		* API returned value to the CSS API returned value. Then
4945 		* the CSS driver should capture these error code and
4946 		* handle it in the driver exception handling mechanism.
4947 		*/
4948 		if (err)
4949 			goto ERR;
4950 	}
4951 
4952 	/*
4953 	 * In the CSS firmware use scenario "Continuous Preview"
4954 	 * as well as "Continuous Video", the "ia_css_pipe" instance
4955 	 * "Copy Pipe" is activated. This "Copy Pipe" is private to
4956 	 * the CSS firmware so that it is not listed in the target
4957 	 * "ia_css_stream" instance.
4958 	 *
4959 	 * We need to stop this "Copy Pipe", as well.
4960 	 */
4961 	if (main_pipe->stream->config.continuous) {
4962 		struct ia_css_pipe *copy_pipe = NULL;
4963 
4964 		/* get the reference to "Copy Pipe" */
4965 		if (main_pipe_id == IA_CSS_PIPE_ID_PREVIEW)
4966 			copy_pipe = main_pipe->pipe_settings.preview.copy_pipe;
4967 		else if (main_pipe_id == IA_CSS_PIPE_ID_VIDEO)
4968 			copy_pipe = main_pipe->pipe_settings.video.copy_pipe;
4969 
4970 		/* return the error code if "Copy Pipe" does NOT exist */
4971 		if (!copy_pipe) {
4972 			IA_CSS_LOG("Copy Pipe does NOT exist!");
4973 			err = -EINVAL;
4974 			goto ERR;
4975 		}
4976 
4977 		/* send the "stop" request to "Copy Pipe" */
4978 		IA_CSS_LOG("Send the stop-request to the pipe: pipe_id=%d",
4979 			   copy_pipe->pipeline.pipe_id);
4980 		err = ia_css_pipeline_request_stop(&copy_pipe->pipeline);
4981 	}
4982 
4983 ERR:
4984 	IA_CSS_LEAVE_ERR_PRIVATE(err);
4985 	return err;
4986 }
4987 
4988 /*
4989  * @brief Check if all "ia_css_pipe" instances in the target
4990  * "ia_css_stream" instance have stopped.
4991  *
4992  * Refer to "Local prototypes" for more info.
4993  */
4994 /* ISP2401 */
4995 static bool
4996 sh_css_pipes_have_stopped(struct ia_css_stream *stream)
4997 {
4998 	bool rval = true;
4999 
5000 	struct ia_css_pipe *main_pipe;
5001 	enum ia_css_pipe_id main_pipe_id;
5002 
5003 	int i;
5004 
5005 	if (!stream) {
5006 		IA_CSS_LOG("stream does NOT exist!");
5007 		rval = false;
5008 		goto RET;
5009 	}
5010 
5011 	main_pipe = stream->last_pipe;
5012 
5013 	if (!main_pipe) {
5014 		IA_CSS_LOG("main_pipe does NOT exist!");
5015 		rval = false;
5016 		goto RET;
5017 	}
5018 
5019 	main_pipe_id = main_pipe->mode;
5020 	IA_CSS_ENTER_PRIVATE("main_pipe_id=%d", main_pipe_id);
5021 
5022 	/*
5023 	 * Check if every "ia_css_pipe" instance in this target
5024 	 * "ia_css_stream" instance has stopped.
5025 	 */
5026 	for (i = 0; i < stream->num_pipes; i++) {
5027 		rval = rval && ia_css_pipeline_has_stopped(&stream->pipes[i]->pipeline);
5028 		IA_CSS_LOG("Pipe has stopped: pipe_id=%d, stopped=%d",
5029 			   stream->pipes[i]->pipeline.pipe_id,
5030 			   rval);
5031 	}
5032 
5033 	/*
5034 	 * In the CSS firmware use scenario "Continuous Preview"
5035 	 * as well as "Continuous Video", the "ia_css_pipe" instance
5036 	 * "Copy Pipe" is activated. This "Copy Pipe" is private to
5037 	 * the CSS firmware so that it is not listed in the target
5038 	 * "ia_css_stream" instance.
5039 	 *
5040 	 * We need to check if this "Copy Pipe" has stopped, as well.
5041 	 */
5042 	if (main_pipe->stream->config.continuous) {
5043 		struct ia_css_pipe *copy_pipe = NULL;
5044 
5045 		/* get the reference to "Copy Pipe" */
5046 		if (main_pipe_id == IA_CSS_PIPE_ID_PREVIEW)
5047 			copy_pipe = main_pipe->pipe_settings.preview.copy_pipe;
5048 		else if (main_pipe_id == IA_CSS_PIPE_ID_VIDEO)
5049 			copy_pipe = main_pipe->pipe_settings.video.copy_pipe;
5050 
5051 		/* return if "Copy Pipe" does NOT exist */
5052 		if (!copy_pipe) {
5053 			IA_CSS_LOG("Copy Pipe does NOT exist!");
5054 
5055 			rval = false;
5056 			goto RET;
5057 		}
5058 
5059 		/* check if "Copy Pipe" has stopped or not */
5060 		rval = rval && ia_css_pipeline_has_stopped(&copy_pipe->pipeline);
5061 		IA_CSS_LOG("Pipe has stopped: pipe_id=%d, stopped=%d",
5062 			   copy_pipe->pipeline.pipe_id,
5063 			   rval);
5064 	}
5065 
5066 RET:
5067 	IA_CSS_LEAVE_PRIVATE("rval=%d", rval);
5068 	return rval;
5069 }
5070 
5071 #if !defined(ISP2401)
5072 unsigned int
5073 sh_css_get_mipi_sizes_for_check(const unsigned int port, const unsigned int idx)
5074 {
5075 	OP___assert(port < N_CSI_PORTS);
5076 	OP___assert(idx  < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT);
5077 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
5078 			    "sh_css_get_mipi_sizes_for_check(port %d, idx %d): %d\n",
5079 			    port, idx, my_css.mipi_sizes_for_check[port][idx]);
5080 	return my_css.mipi_sizes_for_check[port][idx];
5081 }
5082 #endif
5083 
5084 static int sh_css_pipe_configure_output(
5085     struct ia_css_pipe *pipe,
5086     unsigned int width,
5087     unsigned int height,
5088     unsigned int padded_width,
5089     enum ia_css_frame_format format,
5090     unsigned int idx)
5091 {
5092 	int err = 0;
5093 
5094 	IA_CSS_ENTER_PRIVATE("pipe = %p, width = %d, height = %d, padded width = %d, format = %d, idx = %d",
5095 			     pipe, width, height, padded_width, format, idx);
5096 	if (!pipe) {
5097 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
5098 		return -EINVAL;
5099 	}
5100 
5101 	err = ia_css_util_check_res(width, height);
5102 	if (err) {
5103 		IA_CSS_LEAVE_ERR_PRIVATE(err);
5104 		return err;
5105 	}
5106 	if (pipe->output_info[idx].res.width != width ||
5107 	    pipe->output_info[idx].res.height != height ||
5108 	    pipe->output_info[idx].format != format) {
5109 		ia_css_frame_info_init(
5110 		    &pipe->output_info[idx],
5111 		    width,
5112 		    height,
5113 		    format,
5114 		    padded_width);
5115 	}
5116 	IA_CSS_LEAVE_ERR_PRIVATE(0);
5117 	return 0;
5118 }
5119 
5120 static int
5121 sh_css_pipe_get_shading_info(struct ia_css_pipe *pipe,
5122 			     struct ia_css_shading_info *shading_info,
5123 			     struct ia_css_pipe_config *pipe_config)
5124 {
5125 	int err = 0;
5126 	struct ia_css_binary *binary = NULL;
5127 
5128 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
5129 			    "sh_css_pipe_get_shading_info() enter:\n");
5130 
5131 	binary = ia_css_pipe_get_shading_correction_binary(pipe);
5132 
5133 	if (binary) {
5134 		err = ia_css_binary_get_shading_info(binary,
5135 						     IA_CSS_SHADING_CORRECTION_TYPE_1,
5136 						     pipe->required_bds_factor,
5137 						     (const struct ia_css_stream_config *)&pipe->stream->config,
5138 						     shading_info, pipe_config);
5139 
5140 		/* Other function calls can be added here when other shading correction types will be added
5141 		 * in the future.
5142 		 */
5143 	} else {
5144 		/* When the pipe does not have a binary which has the shading
5145 		 * correction, this function does not need to fill the shading
5146 		 * information. It is not a error case, and then
5147 		 * this function should return 0.
5148 		 */
5149 		memset(shading_info, 0, sizeof(*shading_info));
5150 	}
5151 	return err;
5152 }
5153 
5154 static int
5155 sh_css_pipe_get_grid_info(struct ia_css_pipe *pipe,
5156 			  struct ia_css_grid_info *info)
5157 {
5158 	int err = 0;
5159 	struct ia_css_binary *binary = NULL;
5160 
5161 	assert(pipe);
5162 	assert(info);
5163 
5164 	IA_CSS_ENTER_PRIVATE("");
5165 
5166 	binary = ia_css_pipe_get_s3a_binary(pipe);
5167 
5168 	if (binary) {
5169 		err = ia_css_binary_3a_grid_info(binary, info, pipe);
5170 		if (err)
5171 			goto err;
5172 	} else {
5173 		memset(&info->s3a_grid, 0, sizeof(info->s3a_grid));
5174 	}
5175 
5176 	binary = ia_css_pipe_get_sdis_binary(pipe);
5177 
5178 	if (binary) {
5179 		ia_css_binary_dvs_grid_info(binary, info, pipe);
5180 		ia_css_binary_dvs_stat_grid_info(binary, info, pipe);
5181 	} else {
5182 		memset(&info->dvs_grid, 0, sizeof(info->dvs_grid));
5183 	}
5184 
5185 	if (binary) {
5186 		/* copy pipe does not have ISP binary*/
5187 		info->isp_in_width = binary->internal_frame_info.res.width;
5188 		info->isp_in_height = binary->internal_frame_info.res.height;
5189 	}
5190 
5191 	info->vamem_type = IA_CSS_VAMEM_TYPE_2;
5192 
5193 err:
5194 	IA_CSS_LEAVE_ERR_PRIVATE(err);
5195 	return err;
5196 }
5197 
5198 /* ISP2401 */
5199 /*
5200  * @brief Check if a format is supported by the pipe.
5201  *
5202  */
5203 static int
5204 ia_css_pipe_check_format(struct ia_css_pipe *pipe,
5205 			 enum ia_css_frame_format format)
5206 {
5207 	const enum ia_css_frame_format *supported_formats;
5208 	int number_of_formats;
5209 	int found = 0;
5210 	int i;
5211 
5212 	IA_CSS_ENTER_PRIVATE("");
5213 
5214 	if (NULL == pipe || NULL == pipe->pipe_settings.video.video_binary.info) {
5215 		IA_CSS_ERROR("Pipe or binary info is not set");
5216 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
5217 		return -EINVAL;
5218 	}
5219 
5220 	supported_formats = pipe->pipe_settings.video.video_binary.info->output_formats;
5221 	number_of_formats = sizeof(pipe->pipe_settings.video.video_binary.info->output_formats) / sizeof(enum ia_css_frame_format);
5222 
5223 	for (i = 0; i < number_of_formats && !found; i++) {
5224 		if (supported_formats[i] == format) {
5225 			found = 1;
5226 			break;
5227 		}
5228 	}
5229 	if (!found) {
5230 		IA_CSS_ERROR("Requested format is not supported by binary");
5231 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
5232 		return -EINVAL;
5233 	}
5234 	IA_CSS_LEAVE_ERR_PRIVATE(0);
5235 	return 0;
5236 }
5237 
5238 static int load_video_binaries(struct ia_css_pipe *pipe)
5239 {
5240 	struct ia_css_frame_info video_in_info, tnr_info,
5241 		       *video_vf_info, video_bds_out_info, *pipe_out_info, *pipe_vf_out_info;
5242 	bool online;
5243 	int err = 0;
5244 	bool continuous = pipe->stream->config.continuous;
5245 	unsigned int i;
5246 	unsigned int num_output_pins;
5247 	struct ia_css_frame_info video_bin_out_info;
5248 	bool need_scaler = false;
5249 	bool vf_res_different_than_output = false;
5250 	bool need_vf_pp = false;
5251 	int vf_ds_log2;
5252 	struct ia_css_video_settings *mycs  = &pipe->pipe_settings.video;
5253 
5254 	IA_CSS_ENTER_PRIVATE("");
5255 	assert(pipe);
5256 	assert(pipe->mode == IA_CSS_PIPE_ID_VIDEO);
5257 	/* we only test the video_binary because offline video doesn't need a
5258 	 * vf_pp binary and online does not (always use) the copy_binary.
5259 	 * All are always reset at the same time anyway.
5260 	 */
5261 	if (mycs->video_binary.info)
5262 		return 0;
5263 
5264 	online = pipe->stream->config.online;
5265 	pipe_out_info = &pipe->output_info[0];
5266 	pipe_vf_out_info = &pipe->vf_output_info[0];
5267 
5268 	assert(pipe_out_info);
5269 
5270 	/*
5271 	 * There is no explicit input format requirement for raw or yuv
5272 	 * What matters is that there is a binary that supports the stream format.
5273 	 * This is checked in the binary_find(), so no need to check it here
5274 	 */
5275 	err = ia_css_util_check_input(&pipe->stream->config, false, false);
5276 	if (err)
5277 		return err;
5278 	/* cannot have online video and input_mode memory */
5279 	if (online && pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY)
5280 		return -EINVAL;
5281 	if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) {
5282 		err = ia_css_util_check_vf_out_info(pipe_out_info,
5283 						    pipe_vf_out_info);
5284 		if (err)
5285 			return err;
5286 	} else {
5287 		err = ia_css_frame_check_info(pipe_out_info);
5288 		if (err)
5289 			return err;
5290 	}
5291 
5292 	if (pipe->out_yuv_ds_input_info.res.width)
5293 		video_bin_out_info = pipe->out_yuv_ds_input_info;
5294 	else
5295 		video_bin_out_info = *pipe_out_info;
5296 
5297 	/* Video */
5298 	if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) {
5299 		video_vf_info = pipe_vf_out_info;
5300 		vf_res_different_than_output = (video_vf_info->res.width !=
5301 						video_bin_out_info.res.width) ||
5302 					       (video_vf_info->res.height != video_bin_out_info.res.height);
5303 	} else {
5304 		video_vf_info = NULL;
5305 	}
5306 
5307 	need_scaler = need_downscaling(video_bin_out_info.res, pipe_out_info->res);
5308 
5309 	/* we build up the pipeline starting at the end */
5310 	/* YUV post-processing if needed */
5311 	if (need_scaler) {
5312 		struct ia_css_cas_binary_descr cas_scaler_descr = { };
5313 
5314 		/* NV12 is the common format that is supported by both */
5315 		/* yuv_scaler and the video_xx_isp2_min binaries. */
5316 		video_bin_out_info.format = IA_CSS_FRAME_FORMAT_NV12;
5317 
5318 		err = ia_css_pipe_create_cas_scaler_desc_single_output(
5319 			  &video_bin_out_info,
5320 			  pipe_out_info,
5321 			  NULL,
5322 			  &cas_scaler_descr);
5323 		if (err)
5324 			return err;
5325 		mycs->num_yuv_scaler = cas_scaler_descr.num_stage;
5326 		mycs->yuv_scaler_binary = kcalloc(cas_scaler_descr.num_stage,
5327 						  sizeof(struct ia_css_binary),
5328 						  GFP_KERNEL);
5329 		if (!mycs->yuv_scaler_binary) {
5330 			err = -ENOMEM;
5331 			return err;
5332 		}
5333 		mycs->is_output_stage = kcalloc(cas_scaler_descr.num_stage,
5334 						sizeof(bool), GFP_KERNEL);
5335 		if (!mycs->is_output_stage) {
5336 			err = -ENOMEM;
5337 			return err;
5338 		}
5339 		for (i = 0; i < cas_scaler_descr.num_stage; i++) {
5340 			struct ia_css_binary_descr yuv_scaler_descr;
5341 
5342 			mycs->is_output_stage[i] = cas_scaler_descr.is_output_stage[i];
5343 			ia_css_pipe_get_yuvscaler_binarydesc(pipe,
5344 							     &yuv_scaler_descr, &cas_scaler_descr.in_info[i],
5345 							     &cas_scaler_descr.out_info[i],
5346 							     &cas_scaler_descr.internal_out_info[i],
5347 							     &cas_scaler_descr.vf_info[i]);
5348 			err = ia_css_binary_find(&yuv_scaler_descr,
5349 						 &mycs->yuv_scaler_binary[i]);
5350 			if (err) {
5351 				kfree(mycs->is_output_stage);
5352 				mycs->is_output_stage = NULL;
5353 				return err;
5354 			}
5355 		}
5356 		ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr);
5357 	}
5358 
5359 	{
5360 		struct ia_css_binary_descr video_descr;
5361 		enum ia_css_frame_format vf_info_format;
5362 
5363 		err = ia_css_pipe_get_video_binarydesc(pipe,
5364 						       &video_descr, &video_in_info, &video_bds_out_info, &video_bin_out_info,
5365 						       video_vf_info,
5366 						       pipe->stream->config.left_padding);
5367 		if (err)
5368 			return err;
5369 
5370 		/* In the case where video_vf_info is not NULL, this allows
5371 		 * us to find a potential video library with desired vf format.
5372 		 * If success, no vf_pp binary is needed.
5373 		 * If failed, we will look up video binary with YUV_LINE vf format
5374 		 */
5375 		err = ia_css_binary_find(&video_descr,
5376 					 &mycs->video_binary);
5377 
5378 		if (err) {
5379 			/* This will do another video binary lookup later for YUV_LINE format*/
5380 			if (video_vf_info)
5381 				need_vf_pp = true;
5382 			else
5383 				return err;
5384 		} else if (video_vf_info) {
5385 			/* The first video binary lookup is successful, but we may
5386 			 * still need vf_pp binary based on additiona check */
5387 			num_output_pins = mycs->video_binary.info->num_output_pins;
5388 			vf_ds_log2 = mycs->video_binary.vf_downscale_log2;
5389 
5390 			/* If the binary has dual output pins, we need vf_pp if the resolution
5391 			* is different. */
5392 			need_vf_pp |= ((num_output_pins == 2) && vf_res_different_than_output);
5393 
5394 			/* If the binary has single output pin, we need vf_pp if additional
5395 			* scaling is needed for vf */
5396 			need_vf_pp |= ((num_output_pins == 1) &&
5397 				       ((video_vf_info->res.width << vf_ds_log2 != pipe_out_info->res.width) ||
5398 					(video_vf_info->res.height << vf_ds_log2 != pipe_out_info->res.height)));
5399 		}
5400 
5401 		if (need_vf_pp) {
5402 			/* save the current vf_info format for restoration later */
5403 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
5404 					    "load_video_binaries() need_vf_pp; find video binary with YUV_LINE again\n");
5405 
5406 			vf_info_format = video_vf_info->format;
5407 
5408 			if (!pipe->config.enable_vfpp_bci)
5409 				ia_css_frame_info_set_format(video_vf_info,
5410 							     IA_CSS_FRAME_FORMAT_YUV_LINE);
5411 
5412 			ia_css_binary_destroy_isp_parameters(&mycs->video_binary);
5413 
5414 			err = ia_css_binary_find(&video_descr,
5415 						 &mycs->video_binary);
5416 
5417 			/* restore original vf_info format */
5418 			ia_css_frame_info_set_format(video_vf_info,
5419 						     vf_info_format);
5420 			if (err)
5421 				return err;
5422 		}
5423 	}
5424 
5425 	/* If a video binary does not use a ref_frame, we set the frame delay
5426 	 * to 0. This is the case for the 1-stage low-power video binary. */
5427 	if (!mycs->video_binary.info->sp.enable.ref_frame)
5428 		pipe->dvs_frame_delay = 0;
5429 
5430 	/* The delay latency determines the number of invalid frames after
5431 	 * a stream is started. */
5432 	pipe->num_invalid_frames = pipe->dvs_frame_delay;
5433 	pipe->info.num_invalid_frames = pipe->num_invalid_frames;
5434 
5435 	/* Viewfinder frames also decrement num_invalid_frames. If the pipe
5436 	 * outputs a viewfinder output, then we need double the number of
5437 	 * invalid frames */
5438 	if (video_vf_info)
5439 		pipe->num_invalid_frames *= 2;
5440 
5441 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
5442 			    "load_video_binaries() num_invalid_frames=%d dvs_frame_delay=%d\n",
5443 			    pipe->num_invalid_frames, pipe->dvs_frame_delay);
5444 
5445 	/* pqiao TODO: temp hack for PO, should be removed after offline YUVPP is enabled */
5446 #if !defined(ISP2401)
5447 	/* Copy */
5448 	if (!online && !continuous) {
5449 		/* TODO: what exactly needs doing, prepend the copy binary to
5450 		 *	 video base this only on !online?
5451 		 */
5452 		err = load_copy_binary(pipe,
5453 				       &mycs->copy_binary,
5454 				       &mycs->video_binary);
5455 		if (err)
5456 			return err;
5457 	}
5458 #else
5459 	(void)continuous;
5460 #endif
5461 
5462 #if !defined(HAS_OUTPUT_SYSTEM)
5463 	if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0] && need_vf_pp) {
5464 		struct ia_css_binary_descr vf_pp_descr;
5465 
5466 		if (mycs->video_binary.vf_frame_info.format
5467 		    == IA_CSS_FRAME_FORMAT_YUV_LINE) {
5468 			ia_css_pipe_get_vfpp_binarydesc(pipe, &vf_pp_descr,
5469 							&mycs->video_binary.vf_frame_info,
5470 							pipe_vf_out_info);
5471 		} else {
5472 			/* output from main binary is not yuv line. currently this is
5473 			 * possible only when bci is enabled on vfpp output */
5474 			assert(pipe->config.enable_vfpp_bci);
5475 			ia_css_pipe_get_yuvscaler_binarydesc(pipe, &vf_pp_descr,
5476 							     &mycs->video_binary.vf_frame_info,
5477 							     pipe_vf_out_info, NULL, NULL);
5478 		}
5479 
5480 		err = ia_css_binary_find(&vf_pp_descr,
5481 					 &mycs->vf_pp_binary);
5482 		if (err)
5483 			return err;
5484 	}
5485 #endif
5486 
5487 	err = allocate_delay_frames(pipe);
5488 
5489 	if (err)
5490 		return err;
5491 
5492 	if (mycs->video_binary.info->sp.enable.block_output) {
5493 		unsigned int tnr_width;
5494 		unsigned int tnr_height;
5495 
5496 		tnr_info = mycs->video_binary.out_frame_info[0];
5497 
5498 		if (IS_ISP2401) {
5499 			/* Select resolution for TNR. If
5500 			* output_system_in_resolution(GDC_out_resolution) is
5501 			* being used, then select that as it will also be in resolution for
5502 			* TNR. At present, it only make sense for Skycam */
5503 			if (pipe->config.output_system_in_res.width &&
5504 			    pipe->config.output_system_in_res.height) {
5505 				tnr_width = pipe->config.output_system_in_res.width;
5506 				tnr_height = pipe->config.output_system_in_res.height;
5507 			} else {
5508 				tnr_width = tnr_info.res.width;
5509 				tnr_height = tnr_info.res.height;
5510 			}
5511 
5512 			/* Make tnr reference buffers output block width(in pix) align */
5513 			tnr_info.res.width  = CEIL_MUL(tnr_width,
5514 						       (mycs->video_binary.info->sp.block.block_width * ISP_NWAY));
5515 			tnr_info.padded_width = tnr_info.res.width;
5516 		} else {
5517 			tnr_height = tnr_info.res.height;
5518 		}
5519 
5520 		/* Make tnr reference buffers output block height align */
5521 		tnr_info.res.height = CEIL_MUL(tnr_height,
5522 					       mycs->video_binary.info->sp.block.output_block_height);
5523 	} else {
5524 		tnr_info = mycs->video_binary.internal_frame_info;
5525 	}
5526 	tnr_info.format = IA_CSS_FRAME_FORMAT_YUV_LINE;
5527 	tnr_info.raw_bit_depth = SH_CSS_TNR_BIT_DEPTH;
5528 
5529 	for (i = 0; i < NUM_TNR_FRAMES; i++) {
5530 		if (mycs->tnr_frames[i]) {
5531 			ia_css_frame_free(mycs->tnr_frames[i]);
5532 			mycs->tnr_frames[i] = NULL;
5533 		}
5534 		err = ia_css_frame_allocate_from_info(
5535 			  &mycs->tnr_frames[i],
5536 			  &tnr_info);
5537 		if (err)
5538 			return err;
5539 	}
5540 	IA_CSS_LEAVE_PRIVATE("");
5541 	return 0;
5542 }
5543 
5544 static int
5545 unload_video_binaries(struct ia_css_pipe *pipe)
5546 {
5547 	unsigned int i;
5548 
5549 	IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
5550 
5551 	if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_VIDEO)) {
5552 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
5553 		return -EINVAL;
5554 	}
5555 	ia_css_binary_unload(&pipe->pipe_settings.video.copy_binary);
5556 	ia_css_binary_unload(&pipe->pipe_settings.video.video_binary);
5557 	ia_css_binary_unload(&pipe->pipe_settings.video.vf_pp_binary);
5558 
5559 	for (i = 0; i < pipe->pipe_settings.video.num_yuv_scaler; i++)
5560 		ia_css_binary_unload(&pipe->pipe_settings.video.yuv_scaler_binary[i]);
5561 
5562 	kfree(pipe->pipe_settings.video.is_output_stage);
5563 	pipe->pipe_settings.video.is_output_stage = NULL;
5564 	kfree(pipe->pipe_settings.video.yuv_scaler_binary);
5565 	pipe->pipe_settings.video.yuv_scaler_binary = NULL;
5566 
5567 	IA_CSS_LEAVE_ERR_PRIVATE(0);
5568 	return 0;
5569 }
5570 
5571 static int video_start(struct ia_css_pipe *pipe)
5572 {
5573 	int err = 0;
5574 	struct ia_css_pipe *copy_pipe, *capture_pipe;
5575 	enum sh_css_pipe_config_override copy_ovrd;
5576 	enum ia_css_input_mode video_pipe_input_mode;
5577 
5578 	const struct ia_css_coordinate *coord = NULL;
5579 	const struct ia_css_isp_parameters *params = NULL;
5580 
5581 	IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
5582 	if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_VIDEO)) {
5583 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
5584 		return -EINVAL;
5585 	}
5586 
5587 	video_pipe_input_mode = pipe->stream->config.mode;
5588 
5589 	copy_pipe    = pipe->pipe_settings.video.copy_pipe;
5590 	capture_pipe = pipe->pipe_settings.video.capture_pipe;
5591 
5592 	sh_css_metrics_start_frame();
5593 
5594 	/* multi stream video needs mipi buffers */
5595 
5596 	err = send_mipi_frames(pipe);
5597 	if (err)
5598 		return err;
5599 
5600 	send_raw_frames(pipe);
5601 	{
5602 		unsigned int thread_id;
5603 
5604 		ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
5605 		copy_ovrd = 1 << thread_id;
5606 
5607 		if (pipe->stream->cont_capt) {
5608 			ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(capture_pipe),
5609 							 &thread_id);
5610 			copy_ovrd |= 1 << thread_id;
5611 		}
5612 	}
5613 
5614 	if (IS_ISP2401) {
5615 		coord = &pipe->config.internal_frame_origin_bqs_on_sctbl;
5616 		params = pipe->stream->isp_params_configs;
5617 	}
5618 
5619 	/* Construct and load the copy pipe */
5620 	if (pipe->stream->config.continuous) {
5621 		sh_css_sp_init_pipeline(&copy_pipe->pipeline,
5622 					IA_CSS_PIPE_ID_COPY,
5623 					(uint8_t)ia_css_pipe_get_pipe_num(copy_pipe),
5624 					false,
5625 					pipe->stream->config.pixels_per_clock == 2, false,
5626 					false, pipe->required_bds_factor,
5627 					copy_ovrd,
5628 					pipe->stream->config.mode,
5629 					&pipe->stream->config.metadata_config,
5630 					&pipe->stream->info.metadata_info,
5631 					pipe->stream->config.source.port.port,
5632 					coord,
5633 					params);
5634 
5635 		/* make the video pipe start with mem mode input, copy handles
5636 		   the actual mode */
5637 		video_pipe_input_mode = IA_CSS_INPUT_MODE_MEMORY;
5638 	}
5639 
5640 	/* Construct and load the capture pipe */
5641 	if (pipe->stream->cont_capt) {
5642 		sh_css_sp_init_pipeline(&capture_pipe->pipeline,
5643 					IA_CSS_PIPE_ID_CAPTURE,
5644 					(uint8_t)ia_css_pipe_get_pipe_num(capture_pipe),
5645 					capture_pipe->config.default_capture_config.enable_xnr != 0,
5646 					capture_pipe->stream->config.pixels_per_clock == 2,
5647 					true, /* continuous */
5648 					false, /* offline */
5649 					capture_pipe->required_bds_factor,
5650 					0,
5651 					IA_CSS_INPUT_MODE_MEMORY,
5652 					&pipe->stream->config.metadata_config,
5653 					&pipe->stream->info.metadata_info,
5654 					(enum mipi_port_id)0,
5655 					coord,
5656 					params);
5657 	}
5658 
5659 	start_pipe(pipe, copy_ovrd, video_pipe_input_mode);
5660 
5661 	IA_CSS_LEAVE_ERR_PRIVATE(err);
5662 	return err;
5663 }
5664 
5665 static
5666 int sh_css_pipe_get_viewfinder_frame_info(
5667     struct ia_css_pipe *pipe,
5668     struct ia_css_frame_info *info,
5669     unsigned int idx)
5670 {
5671 	assert(pipe);
5672 	assert(info);
5673 
5674 	/* We could print the pointer as input arg, and the values as output */
5675 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
5676 			    "sh_css_pipe_get_viewfinder_frame_info() enter: void\n");
5677 
5678 	if (pipe->mode == IA_CSS_PIPE_ID_CAPTURE &&
5679 	    (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_RAW ||
5680 	     pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER))
5681 		return -EINVAL;
5682 	/* offline video does not generate viewfinder output */
5683 	*info = pipe->vf_output_info[idx];
5684 
5685 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
5686 			    "sh_css_pipe_get_viewfinder_frame_info() leave: \
5687 		info.res.width=%d, info.res.height=%d, \
5688 		info.padded_width=%d, info.format=%d, \
5689 		info.raw_bit_depth=%d, info.raw_bayer_order=%d\n",
5690 			    info->res.width, info->res.height,
5691 			    info->padded_width, info->format,
5692 			    info->raw_bit_depth, info->raw_bayer_order);
5693 
5694 	return 0;
5695 }
5696 
5697 static int
5698 sh_css_pipe_configure_viewfinder(struct ia_css_pipe *pipe, unsigned int width,
5699 				 unsigned int height, unsigned int min_width,
5700 				 enum ia_css_frame_format format,
5701 				 unsigned int idx)
5702 {
5703 	int err = 0;
5704 
5705 	IA_CSS_ENTER_PRIVATE("pipe = %p, width = %d, height = %d, min_width = %d, format = %d, idx = %d\n",
5706 			     pipe, width, height, min_width, format, idx);
5707 
5708 	if (!pipe) {
5709 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
5710 		return -EINVAL;
5711 	}
5712 
5713 	err = ia_css_util_check_res(width, height);
5714 	if (err) {
5715 		IA_CSS_LEAVE_ERR_PRIVATE(err);
5716 		return err;
5717 	}
5718 	if (pipe->vf_output_info[idx].res.width != width ||
5719 	    pipe->vf_output_info[idx].res.height != height ||
5720 	    pipe->vf_output_info[idx].format != format)
5721 		ia_css_frame_info_init(&pipe->vf_output_info[idx], width, height,
5722 				       format, min_width);
5723 
5724 	IA_CSS_LEAVE_ERR_PRIVATE(0);
5725 	return 0;
5726 }
5727 
5728 static int load_copy_binaries(struct ia_css_pipe *pipe)
5729 {
5730 	int err = 0;
5731 
5732 	assert(pipe);
5733 	IA_CSS_ENTER_PRIVATE("");
5734 
5735 	assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
5736 	       pipe->mode == IA_CSS_PIPE_ID_COPY);
5737 	if (pipe->pipe_settings.capture.copy_binary.info)
5738 		return 0;
5739 
5740 	err = ia_css_frame_check_info(&pipe->output_info[0]);
5741 	if (err)
5742 		goto ERR;
5743 
5744 	err = verify_copy_out_frame_format(pipe);
5745 	if (err)
5746 		goto ERR;
5747 
5748 	err = load_copy_binary(pipe,
5749 			       &pipe->pipe_settings.capture.copy_binary,
5750 			       NULL);
5751 
5752 ERR:
5753 	IA_CSS_LEAVE_ERR_PRIVATE(err);
5754 	return err;
5755 }
5756 
5757 static bool need_capture_pp(
5758     const struct ia_css_pipe *pipe)
5759 {
5760 	const struct ia_css_frame_info *out_info = &pipe->output_info[0];
5761 
5762 	IA_CSS_ENTER_LEAVE_PRIVATE("");
5763 	assert(pipe);
5764 	assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE);
5765 
5766 	if (IS_ISP2401) {
5767 		/* ldc and capture_pp are not supported in the same pipeline */
5768 		if (need_capt_ldc(pipe))
5769 			return false;
5770 	}
5771 
5772 	/* determine whether we need to use the capture_pp binary.
5773 	 * This is needed for:
5774 	 *   1. XNR or
5775 	 *   2. Digital Zoom or
5776 	 *   3. YUV downscaling
5777 	 */
5778 	if (pipe->out_yuv_ds_input_info.res.width &&
5779 	    ((pipe->out_yuv_ds_input_info.res.width != out_info->res.width) ||
5780 	     (pipe->out_yuv_ds_input_info.res.height != out_info->res.height)))
5781 		return true;
5782 
5783 	if (pipe->config.default_capture_config.enable_xnr != 0)
5784 		return true;
5785 
5786 	if ((pipe->stream->isp_params_configs->dz_config.dx < HRT_GDC_N) ||
5787 	    (pipe->stream->isp_params_configs->dz_config.dy < HRT_GDC_N) ||
5788 	    pipe->config.enable_dz)
5789 		return true;
5790 
5791 	return false;
5792 }
5793 
5794 static bool need_capt_ldc(
5795     const struct ia_css_pipe *pipe)
5796 {
5797 	IA_CSS_ENTER_LEAVE_PRIVATE("");
5798 	assert(pipe);
5799 	assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE);
5800 	return (pipe->extra_config.enable_dvs_6axis) ? true : false;
5801 }
5802 
5803 static int set_num_primary_stages(unsigned int *num,
5804 				  enum ia_css_pipe_version version)
5805 {
5806 	int err = 0;
5807 
5808 	if (!num)
5809 		return -EINVAL;
5810 
5811 	switch (version) {
5812 	case IA_CSS_PIPE_VERSION_2_6_1:
5813 		*num = NUM_PRIMARY_HQ_STAGES;
5814 		break;
5815 	case IA_CSS_PIPE_VERSION_2_2:
5816 	case IA_CSS_PIPE_VERSION_1:
5817 		*num = NUM_PRIMARY_STAGES;
5818 		break;
5819 	default:
5820 		err = -EINVAL;
5821 		break;
5822 	}
5823 
5824 	return err;
5825 }
5826 
5827 static int load_primary_binaries(
5828     struct ia_css_pipe *pipe)
5829 {
5830 	bool online = false;
5831 	bool need_pp = false;
5832 	bool need_isp_copy_binary = false;
5833 	bool need_ldc = false;
5834 #ifdef ISP2401
5835 	bool sensor = false;
5836 #else
5837 	bool memory, continuous;
5838 #endif
5839 	struct ia_css_frame_info prim_in_info,
5840 		       prim_out_info,
5841 		       capt_pp_out_info, vf_info,
5842 		       *vf_pp_in_info, *pipe_out_info,
5843 		       *pipe_vf_out_info, *capt_pp_in_info,
5844 		       capt_ldc_out_info;
5845 	int err = 0;
5846 	struct ia_css_capture_settings *mycs;
5847 	unsigned int i;
5848 	bool need_extra_yuv_scaler = false;
5849 	struct ia_css_binary_descr prim_descr[MAX_NUM_PRIMARY_STAGES];
5850 
5851 	IA_CSS_ENTER_PRIVATE("");
5852 	assert(pipe);
5853 	assert(pipe->stream);
5854 	assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
5855 	       pipe->mode == IA_CSS_PIPE_ID_COPY);
5856 
5857 	online = pipe->stream->config.online;
5858 #ifdef ISP2401
5859 	sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR);
5860 #else
5861 	memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY;
5862 	continuous = pipe->stream->config.continuous;
5863 #endif
5864 
5865 	mycs = &pipe->pipe_settings.capture;
5866 	pipe_out_info = &pipe->output_info[0];
5867 	pipe_vf_out_info = &pipe->vf_output_info[0];
5868 
5869 	if (mycs->primary_binary[0].info)
5870 		return 0;
5871 
5872 	err = set_num_primary_stages(&mycs->num_primary_stage,
5873 				     pipe->config.isp_pipe_version);
5874 	if (err) {
5875 		IA_CSS_LEAVE_ERR_PRIVATE(err);
5876 		return err;
5877 	}
5878 
5879 	if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) {
5880 		err = ia_css_util_check_vf_out_info(pipe_out_info, pipe_vf_out_info);
5881 		if (err) {
5882 			IA_CSS_LEAVE_ERR_PRIVATE(err);
5883 			return err;
5884 		}
5885 	} else {
5886 		err = ia_css_frame_check_info(pipe_out_info);
5887 		if (err) {
5888 			IA_CSS_LEAVE_ERR_PRIVATE(err);
5889 			return err;
5890 		}
5891 	}
5892 	need_pp = need_capture_pp(pipe);
5893 
5894 	/* we use the vf output info to get the primary/capture_pp binary
5895 	   configured for vf_veceven. It will select the closest downscaling
5896 	   factor. */
5897 	vf_info = *pipe_vf_out_info;
5898 
5899 	/*
5900 	 * WARNING: The #if def flag has been added below as a
5901 	 * temporary solution to solve the problem of enabling the
5902 	 * view finder in a single binary in a capture flow. The
5903 	 * vf-pp stage has been removed for Skycam in the solution
5904 	 * provided. The vf-pp stage should be re-introduced when
5905 	 * required. This should not be considered as a clean solution.
5906 	 * Proper investigation should be done to come up with the clean
5907 	 * solution.
5908 	 * */
5909 	ia_css_frame_info_set_format(&vf_info, IA_CSS_FRAME_FORMAT_YUV_LINE);
5910 
5911 	/* TODO: All this yuv_scaler and capturepp calculation logic
5912 	 * can be shared later. Capture_pp is also a yuv_scale binary
5913 	 * with extra XNR funcionality. Therefore, it can be made as the
5914 	 * first step of the cascade. */
5915 	capt_pp_out_info = pipe->out_yuv_ds_input_info;
5916 	capt_pp_out_info.format = IA_CSS_FRAME_FORMAT_YUV420;
5917 	capt_pp_out_info.res.width  /= MAX_PREFERRED_YUV_DS_PER_STEP;
5918 	capt_pp_out_info.res.height /= MAX_PREFERRED_YUV_DS_PER_STEP;
5919 	ia_css_frame_info_set_width(&capt_pp_out_info, capt_pp_out_info.res.width, 0);
5920 
5921 	need_extra_yuv_scaler = need_downscaling(capt_pp_out_info.res,
5922 						 pipe_out_info->res);
5923 
5924 	if (need_extra_yuv_scaler) {
5925 		struct ia_css_cas_binary_descr cas_scaler_descr = { };
5926 
5927 		err = ia_css_pipe_create_cas_scaler_desc_single_output(
5928 			  &capt_pp_out_info,
5929 			  pipe_out_info,
5930 			  NULL,
5931 			  &cas_scaler_descr);
5932 		if (err) {
5933 			IA_CSS_LEAVE_ERR_PRIVATE(err);
5934 			return err;
5935 		}
5936 		mycs->num_yuv_scaler = cas_scaler_descr.num_stage;
5937 		mycs->yuv_scaler_binary = kcalloc(cas_scaler_descr.num_stage,
5938 						  sizeof(struct ia_css_binary),
5939 						  GFP_KERNEL);
5940 		if (!mycs->yuv_scaler_binary) {
5941 			err = -ENOMEM;
5942 			IA_CSS_LEAVE_ERR_PRIVATE(err);
5943 			return err;
5944 		}
5945 		mycs->is_output_stage = kcalloc(cas_scaler_descr.num_stage,
5946 						sizeof(bool), GFP_KERNEL);
5947 		if (!mycs->is_output_stage) {
5948 			err = -ENOMEM;
5949 			IA_CSS_LEAVE_ERR_PRIVATE(err);
5950 			return err;
5951 		}
5952 		for (i = 0; i < cas_scaler_descr.num_stage; i++) {
5953 			struct ia_css_binary_descr yuv_scaler_descr;
5954 
5955 			mycs->is_output_stage[i] = cas_scaler_descr.is_output_stage[i];
5956 			ia_css_pipe_get_yuvscaler_binarydesc(pipe,
5957 							     &yuv_scaler_descr, &cas_scaler_descr.in_info[i],
5958 							     &cas_scaler_descr.out_info[i],
5959 							     &cas_scaler_descr.internal_out_info[i],
5960 							     &cas_scaler_descr.vf_info[i]);
5961 			err = ia_css_binary_find(&yuv_scaler_descr,
5962 						 &mycs->yuv_scaler_binary[i]);
5963 			if (err) {
5964 				IA_CSS_LEAVE_ERR_PRIVATE(err);
5965 				return err;
5966 			}
5967 		}
5968 		ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr);
5969 
5970 	} else {
5971 		capt_pp_out_info = pipe->output_info[0];
5972 	}
5973 
5974 	/* TODO Do we disable ldc for skycam */
5975 	need_ldc = need_capt_ldc(pipe);
5976 	if (IS_ISP2401 && need_ldc) {
5977 		/* ldc and capt_pp are not supported in the same pipeline */
5978 		struct ia_css_binary_descr capt_ldc_descr;
5979 
5980 		ia_css_pipe_get_ldc_binarydesc(pipe,
5981 					       &capt_ldc_descr, &prim_out_info,
5982 					       &capt_pp_out_info);
5983 
5984 		err = ia_css_binary_find(&capt_ldc_descr,
5985 					 &mycs->capture_ldc_binary);
5986 		if (err) {
5987 			IA_CSS_LEAVE_ERR_PRIVATE(err);
5988 			return err;
5989 		}
5990 		need_pp = false;
5991 		need_ldc = false;
5992 	}
5993 
5994 	/* we build up the pipeline starting at the end */
5995 	/* Capture post-processing */
5996 	if (need_pp) {
5997 		struct ia_css_binary_descr capture_pp_descr;
5998 
5999 		if (!IS_ISP2401)
6000 			capt_pp_in_info = need_ldc ? &capt_ldc_out_info : &prim_out_info;
6001 		else
6002 			capt_pp_in_info = &prim_out_info;
6003 
6004 		ia_css_pipe_get_capturepp_binarydesc(pipe,
6005 						     &capture_pp_descr,
6006 						     capt_pp_in_info,
6007 						     &capt_pp_out_info,
6008 						     &vf_info);
6009 
6010 		err = ia_css_binary_find(&capture_pp_descr,
6011 					 &mycs->capture_pp_binary);
6012 		if (err) {
6013 			IA_CSS_LEAVE_ERR_PRIVATE(err);
6014 			return err;
6015 		}
6016 
6017 		if (need_ldc) {
6018 			struct ia_css_binary_descr capt_ldc_descr;
6019 
6020 			ia_css_pipe_get_ldc_binarydesc(pipe,
6021 						       &capt_ldc_descr,
6022 						       &prim_out_info,
6023 						       &capt_ldc_out_info);
6024 
6025 			err = ia_css_binary_find(&capt_ldc_descr,
6026 						 &mycs->capture_ldc_binary);
6027 			if (err) {
6028 				IA_CSS_LEAVE_ERR_PRIVATE(err);
6029 				return err;
6030 			}
6031 		}
6032 	} else {
6033 		prim_out_info = *pipe_out_info;
6034 	}
6035 
6036 	/* Primary */
6037 	for (i = 0; i < mycs->num_primary_stage; i++) {
6038 		struct ia_css_frame_info *local_vf_info = NULL;
6039 
6040 		if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0] &&
6041 		    (i == mycs->num_primary_stage - 1))
6042 			local_vf_info = &vf_info;
6043 		ia_css_pipe_get_primary_binarydesc(pipe, &prim_descr[i],
6044 						   &prim_in_info, &prim_out_info,
6045 						   local_vf_info, i);
6046 		err = ia_css_binary_find(&prim_descr[i], &mycs->primary_binary[i]);
6047 		if (err) {
6048 			IA_CSS_LEAVE_ERR_PRIVATE(err);
6049 			return err;
6050 		}
6051 	}
6052 
6053 	/* Viewfinder post-processing */
6054 	if (need_pp)
6055 		vf_pp_in_info = &mycs->capture_pp_binary.vf_frame_info;
6056 	else
6057 		vf_pp_in_info = &mycs->primary_binary[mycs->num_primary_stage - 1].vf_frame_info;
6058 
6059 	/*
6060 	    * WARNING: The #if def flag has been added below as a
6061 	    * temporary solution to solve the problem of enabling the
6062 	    * view finder in a single binary in a capture flow. The
6063 	    * vf-pp stage has been removed for Skycam in the solution
6064 	    * provided. The vf-pp stage should be re-introduced when
6065 	    * required. Thisshould not be considered as a clean solution.
6066 	    * Proper  * investigation should be done to come up with the clean
6067 	    * solution.
6068 	    * */
6069 	if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) {
6070 		struct ia_css_binary_descr vf_pp_descr;
6071 
6072 		ia_css_pipe_get_vfpp_binarydesc(pipe,
6073 						&vf_pp_descr, vf_pp_in_info, pipe_vf_out_info);
6074 		err = ia_css_binary_find(&vf_pp_descr, &mycs->vf_pp_binary);
6075 		if (err) {
6076 			IA_CSS_LEAVE_ERR_PRIVATE(err);
6077 			return err;
6078 		}
6079 	}
6080 	err = allocate_delay_frames(pipe);
6081 
6082 	if (err)
6083 		return err;
6084 
6085 #ifdef ISP2401
6086 	/* When the input system is 2401, only the Direct Sensor Mode
6087 	    * Offline Capture uses the ISP copy binary.
6088 	    */
6089 	need_isp_copy_binary = !online && sensor;
6090 #else
6091 	need_isp_copy_binary = !online && !continuous && !memory;
6092 #endif
6093 
6094 	/* ISP Copy */
6095 	if (need_isp_copy_binary) {
6096 		err = load_copy_binary(pipe,
6097 				       &mycs->copy_binary,
6098 				       &mycs->primary_binary[0]);
6099 		if (err) {
6100 			IA_CSS_LEAVE_ERR_PRIVATE(err);
6101 			return err;
6102 		}
6103 	}
6104 
6105 	return 0;
6106 }
6107 
6108 static int
6109 allocate_delay_frames(struct ia_css_pipe *pipe)
6110 {
6111 	unsigned int num_delay_frames = 0, i = 0;
6112 	unsigned int dvs_frame_delay = 0;
6113 	struct ia_css_frame_info ref_info;
6114 	int err = 0;
6115 	enum ia_css_pipe_id mode = IA_CSS_PIPE_ID_VIDEO;
6116 	struct ia_css_frame **delay_frames = NULL;
6117 
6118 	IA_CSS_ENTER_PRIVATE("");
6119 
6120 	if (!pipe) {
6121 		IA_CSS_ERROR("Invalid args - pipe %p", pipe);
6122 		return -EINVAL;
6123 	}
6124 
6125 	mode = pipe->mode;
6126 	dvs_frame_delay = pipe->dvs_frame_delay;
6127 
6128 	if (dvs_frame_delay > 0)
6129 		num_delay_frames = dvs_frame_delay + 1;
6130 
6131 	switch (mode) {
6132 	case IA_CSS_PIPE_ID_CAPTURE: {
6133 		struct ia_css_capture_settings *mycs_capture = &pipe->pipe_settings.capture;
6134 		(void)mycs_capture;
6135 		return err;
6136 	}
6137 	break;
6138 	case IA_CSS_PIPE_ID_VIDEO: {
6139 		struct ia_css_video_settings *mycs_video = &pipe->pipe_settings.video;
6140 
6141 		ref_info = mycs_video->video_binary.internal_frame_info;
6142 		/*The ref frame expects
6143 		    *	1. Y plane
6144 		    *	2. UV plane with line interleaving, like below
6145 		    *		UUUUUU(width/2 times) VVVVVVVV..(width/2 times)
6146 		    *
6147 		    *	This format is not YUV420(which has Y, U and V planes).
6148 		    *	Its closer to NV12, except that the UV plane has UV
6149 		    *	interleaving, like UVUVUVUVUVUVUVUVU...
6150 		    *
6151 		    *	TODO: make this ref_frame format as a separate frame format
6152 		    */
6153 		ref_info.format        = IA_CSS_FRAME_FORMAT_NV12;
6154 		delay_frames = mycs_video->delay_frames;
6155 	}
6156 	break;
6157 	case IA_CSS_PIPE_ID_PREVIEW: {
6158 		struct ia_css_preview_settings *mycs_preview = &pipe->pipe_settings.preview;
6159 
6160 		ref_info = mycs_preview->preview_binary.internal_frame_info;
6161 		/*The ref frame expects
6162 		    *	1. Y plane
6163 		    *	2. UV plane with line interleaving, like below
6164 		    *		UUUUUU(width/2 times) VVVVVVVV..(width/2 times)
6165 		    *
6166 		    *	This format is not YUV420(which has Y, U and V planes).
6167 		    *	Its closer to NV12, except that the UV plane has UV
6168 		    *	interleaving, like UVUVUVUVUVUVUVUVU...
6169 		    *
6170 		    *	TODO: make this ref_frame format as a separate frame format
6171 		    */
6172 		ref_info.format        = IA_CSS_FRAME_FORMAT_NV12;
6173 		delay_frames = mycs_preview->delay_frames;
6174 	}
6175 	break;
6176 	default:
6177 		return -EINVAL;
6178 	}
6179 
6180 	ref_info.raw_bit_depth = SH_CSS_REF_BIT_DEPTH;
6181 
6182 	assert(num_delay_frames <= MAX_NUM_VIDEO_DELAY_FRAMES);
6183 	for (i = 0; i < num_delay_frames; i++) {
6184 		err = ia_css_frame_allocate_from_info(&delay_frames[i],	&ref_info);
6185 		if (err)
6186 			return err;
6187 	}
6188 	IA_CSS_LEAVE_PRIVATE("");
6189 	return 0;
6190 }
6191 
6192 static int load_advanced_binaries(struct ia_css_pipe *pipe)
6193 {
6194 	struct ia_css_frame_info pre_in_info, gdc_in_info,
6195 			post_in_info, post_out_info,
6196 			vf_info, *vf_pp_in_info, *pipe_out_info,
6197 			*pipe_vf_out_info;
6198 	bool need_pp;
6199 	bool need_isp_copy = true;
6200 	int err = 0;
6201 
6202 	IA_CSS_ENTER_PRIVATE("");
6203 
6204 	assert(pipe);
6205 	assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
6206 	       pipe->mode == IA_CSS_PIPE_ID_COPY);
6207 	if (pipe->pipe_settings.capture.pre_isp_binary.info)
6208 		return 0;
6209 	pipe_out_info = &pipe->output_info[0];
6210 	pipe_vf_out_info = &pipe->vf_output_info[0];
6211 
6212 	vf_info = *pipe_vf_out_info;
6213 	err = ia_css_util_check_vf_out_info(pipe_out_info, &vf_info);
6214 	if (err)
6215 		return err;
6216 	need_pp = need_capture_pp(pipe);
6217 
6218 	ia_css_frame_info_set_format(&vf_info,
6219 				     IA_CSS_FRAME_FORMAT_YUV_LINE);
6220 
6221 	/* we build up the pipeline starting at the end */
6222 	/* Capture post-processing */
6223 	if (need_pp) {
6224 		struct ia_css_binary_descr capture_pp_descr;
6225 
6226 		ia_css_pipe_get_capturepp_binarydesc(pipe, &capture_pp_descr,
6227 						     &post_out_info,
6228 						     pipe_out_info, &vf_info);
6229 		err = ia_css_binary_find(&capture_pp_descr,
6230 					 &pipe->pipe_settings.capture.capture_pp_binary);
6231 		if (err)
6232 			return err;
6233 	} else {
6234 		post_out_info = *pipe_out_info;
6235 	}
6236 
6237 	/* Post-gdc */
6238 	{
6239 		struct ia_css_binary_descr post_gdc_descr;
6240 
6241 		ia_css_pipe_get_post_gdc_binarydesc(pipe, &post_gdc_descr,
6242 						    &post_in_info,
6243 						    &post_out_info, &vf_info);
6244 		err = ia_css_binary_find(&post_gdc_descr,
6245 					 &pipe->pipe_settings.capture.post_isp_binary);
6246 		if (err)
6247 			return err;
6248 	}
6249 
6250 	/* Gdc */
6251 	{
6252 		struct ia_css_binary_descr gdc_descr;
6253 
6254 		ia_css_pipe_get_gdc_binarydesc(pipe, &gdc_descr, &gdc_in_info,
6255 					       &pipe->pipe_settings.capture.post_isp_binary.in_frame_info);
6256 		err = ia_css_binary_find(&gdc_descr,
6257 					 &pipe->pipe_settings.capture.anr_gdc_binary);
6258 		if (err)
6259 			return err;
6260 	}
6261 	pipe->pipe_settings.capture.anr_gdc_binary.left_padding =
6262 	    pipe->pipe_settings.capture.post_isp_binary.left_padding;
6263 
6264 	/* Pre-gdc */
6265 	{
6266 		struct ia_css_binary_descr pre_gdc_descr;
6267 
6268 		ia_css_pipe_get_pre_gdc_binarydesc(pipe, &pre_gdc_descr, &pre_in_info,
6269 						   &pipe->pipe_settings.capture.anr_gdc_binary.in_frame_info);
6270 		err = ia_css_binary_find(&pre_gdc_descr,
6271 					 &pipe->pipe_settings.capture.pre_isp_binary);
6272 		if (err)
6273 			return err;
6274 	}
6275 	pipe->pipe_settings.capture.pre_isp_binary.left_padding =
6276 	    pipe->pipe_settings.capture.anr_gdc_binary.left_padding;
6277 
6278 	/* Viewfinder post-processing */
6279 	if (need_pp) {
6280 		vf_pp_in_info =
6281 		    &pipe->pipe_settings.capture.capture_pp_binary.vf_frame_info;
6282 	} else {
6283 		vf_pp_in_info =
6284 		    &pipe->pipe_settings.capture.post_isp_binary.vf_frame_info;
6285 	}
6286 
6287 	{
6288 		struct ia_css_binary_descr vf_pp_descr;
6289 
6290 		ia_css_pipe_get_vfpp_binarydesc(pipe,
6291 						&vf_pp_descr, vf_pp_in_info, pipe_vf_out_info);
6292 		err = ia_css_binary_find(&vf_pp_descr,
6293 					 &pipe->pipe_settings.capture.vf_pp_binary);
6294 		if (err)
6295 			return err;
6296 	}
6297 
6298 	/* Copy */
6299 #ifdef ISP2401
6300 	/* For CSI2+, only the direct sensor mode/online requires ISP copy */
6301 	need_isp_copy = pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR;
6302 #endif
6303 	if (need_isp_copy)
6304 		load_copy_binary(pipe,
6305 				 &pipe->pipe_settings.capture.copy_binary,
6306 				 &pipe->pipe_settings.capture.pre_isp_binary);
6307 
6308 	return err;
6309 }
6310 
6311 static int load_bayer_isp_binaries(struct ia_css_pipe *pipe)
6312 {
6313 	struct ia_css_frame_info pre_isp_in_info, *pipe_out_info;
6314 	int err = 0;
6315 	struct ia_css_binary_descr pre_de_descr;
6316 
6317 	IA_CSS_ENTER_PRIVATE("");
6318 	assert(pipe);
6319 	assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
6320 	       pipe->mode == IA_CSS_PIPE_ID_COPY);
6321 	pipe_out_info = &pipe->output_info[0];
6322 
6323 	if (pipe->pipe_settings.capture.pre_isp_binary.info)
6324 		return 0;
6325 
6326 	err = ia_css_frame_check_info(pipe_out_info);
6327 	if (err)
6328 		return err;
6329 
6330 	ia_css_pipe_get_pre_de_binarydesc(pipe, &pre_de_descr,
6331 					  &pre_isp_in_info,
6332 					  pipe_out_info);
6333 
6334 	err = ia_css_binary_find(&pre_de_descr,
6335 				 &pipe->pipe_settings.capture.pre_isp_binary);
6336 
6337 	return err;
6338 }
6339 
6340 static int load_low_light_binaries(struct ia_css_pipe *pipe)
6341 {
6342 	struct ia_css_frame_info pre_in_info, anr_in_info,
6343 			post_in_info, post_out_info,
6344 			vf_info, *pipe_vf_out_info, *pipe_out_info,
6345 			*vf_pp_in_info;
6346 	bool need_pp;
6347 	bool need_isp_copy = true;
6348 	int err = 0;
6349 
6350 	IA_CSS_ENTER_PRIVATE("");
6351 	assert(pipe);
6352 	assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
6353 	       pipe->mode == IA_CSS_PIPE_ID_COPY);
6354 
6355 	if (pipe->pipe_settings.capture.pre_isp_binary.info)
6356 		return 0;
6357 	pipe_vf_out_info = &pipe->vf_output_info[0];
6358 	pipe_out_info = &pipe->output_info[0];
6359 
6360 	vf_info = *pipe_vf_out_info;
6361 	err = ia_css_util_check_vf_out_info(pipe_out_info,
6362 					    &vf_info);
6363 	if (err)
6364 		return err;
6365 	need_pp = need_capture_pp(pipe);
6366 
6367 	ia_css_frame_info_set_format(&vf_info,
6368 				     IA_CSS_FRAME_FORMAT_YUV_LINE);
6369 
6370 	/* we build up the pipeline starting at the end */
6371 	/* Capture post-processing */
6372 	if (need_pp) {
6373 		struct ia_css_binary_descr capture_pp_descr;
6374 
6375 		ia_css_pipe_get_capturepp_binarydesc(pipe, &capture_pp_descr,
6376 						     &post_out_info,
6377 						     pipe_out_info, &vf_info);
6378 		err = ia_css_binary_find(&capture_pp_descr,
6379 					 &pipe->pipe_settings.capture.capture_pp_binary);
6380 		if (err)
6381 			return err;
6382 	} else {
6383 		post_out_info = *pipe_out_info;
6384 	}
6385 
6386 	/* Post-anr */
6387 	{
6388 		struct ia_css_binary_descr post_anr_descr;
6389 
6390 		ia_css_pipe_get_post_anr_binarydesc(pipe,
6391 						    &post_anr_descr, &post_in_info, &post_out_info, &vf_info);
6392 		err = ia_css_binary_find(&post_anr_descr,
6393 					 &pipe->pipe_settings.capture.post_isp_binary);
6394 		if (err)
6395 			return err;
6396 	}
6397 
6398 	/* Anr */
6399 	{
6400 		struct ia_css_binary_descr anr_descr;
6401 
6402 		ia_css_pipe_get_anr_binarydesc(pipe, &anr_descr, &anr_in_info,
6403 					       &pipe->pipe_settings.capture.post_isp_binary.in_frame_info);
6404 		err = ia_css_binary_find(&anr_descr,
6405 					 &pipe->pipe_settings.capture.anr_gdc_binary);
6406 		if (err)
6407 			return err;
6408 	}
6409 	pipe->pipe_settings.capture.anr_gdc_binary.left_padding =
6410 	    pipe->pipe_settings.capture.post_isp_binary.left_padding;
6411 
6412 	/* Pre-anr */
6413 	{
6414 		struct ia_css_binary_descr pre_anr_descr;
6415 
6416 		ia_css_pipe_get_pre_anr_binarydesc(pipe, &pre_anr_descr, &pre_in_info,
6417 						   &pipe->pipe_settings.capture.anr_gdc_binary.in_frame_info);
6418 		err = ia_css_binary_find(&pre_anr_descr,
6419 					 &pipe->pipe_settings.capture.pre_isp_binary);
6420 		if (err)
6421 			return err;
6422 	}
6423 	pipe->pipe_settings.capture.pre_isp_binary.left_padding =
6424 	    pipe->pipe_settings.capture.anr_gdc_binary.left_padding;
6425 
6426 	/* Viewfinder post-processing */
6427 	if (need_pp) {
6428 		vf_pp_in_info =
6429 		    &pipe->pipe_settings.capture.capture_pp_binary.vf_frame_info;
6430 	} else {
6431 		vf_pp_in_info =
6432 		    &pipe->pipe_settings.capture.post_isp_binary.vf_frame_info;
6433 	}
6434 
6435 	{
6436 		struct ia_css_binary_descr vf_pp_descr;
6437 
6438 		ia_css_pipe_get_vfpp_binarydesc(pipe, &vf_pp_descr,
6439 						vf_pp_in_info, pipe_vf_out_info);
6440 		err = ia_css_binary_find(&vf_pp_descr,
6441 					 &pipe->pipe_settings.capture.vf_pp_binary);
6442 		if (err)
6443 			return err;
6444 	}
6445 
6446 	/* Copy */
6447 #ifdef ISP2401
6448 	/* For CSI2+, only the direct sensor mode/online requires ISP copy */
6449 	need_isp_copy = pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR;
6450 #endif
6451 	if (need_isp_copy)
6452 		err = load_copy_binary(pipe,
6453 				       &pipe->pipe_settings.capture.copy_binary,
6454 				       &pipe->pipe_settings.capture.pre_isp_binary);
6455 
6456 	return err;
6457 }
6458 
6459 static bool copy_on_sp(struct ia_css_pipe *pipe)
6460 {
6461 	bool rval;
6462 
6463 	assert(pipe);
6464 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "copy_on_sp() enter:\n");
6465 
6466 	rval = true;
6467 
6468 	rval &=	(pipe->mode == IA_CSS_PIPE_ID_CAPTURE);
6469 
6470 	rval &= (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_RAW);
6471 
6472 	rval &= ((pipe->stream->config.input_config.format ==
6473 		    ATOMISP_INPUT_FORMAT_BINARY_8) ||
6474 		    (pipe->config.mode == IA_CSS_PIPE_MODE_COPY));
6475 
6476 	return rval;
6477 }
6478 
6479 static int load_capture_binaries(struct ia_css_pipe *pipe)
6480 {
6481 	int err = 0;
6482 	bool must_be_raw;
6483 
6484 	IA_CSS_ENTER_PRIVATE("");
6485 	assert(pipe);
6486 	assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
6487 	       pipe->mode == IA_CSS_PIPE_ID_COPY);
6488 
6489 	if (pipe->pipe_settings.capture.primary_binary[0].info) {
6490 		IA_CSS_LEAVE_ERR_PRIVATE(0);
6491 		return 0;
6492 	}
6493 
6494 	/* in primary, advanced,low light or bayer,
6495 						the input format must be raw */
6496 	must_be_raw =
6497 	    pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_ADVANCED ||
6498 	    pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER ||
6499 	    pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT;
6500 	err = ia_css_util_check_input(&pipe->stream->config, must_be_raw, false);
6501 	if (err) {
6502 		IA_CSS_LEAVE_ERR_PRIVATE(err);
6503 		return err;
6504 	}
6505 	if (copy_on_sp(pipe) &&
6506 	    pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8) {
6507 		ia_css_frame_info_init(
6508 		    &pipe->output_info[0],
6509 		    JPEG_BYTES,
6510 		    1,
6511 		    IA_CSS_FRAME_FORMAT_BINARY_8,
6512 		    0);
6513 		IA_CSS_LEAVE_ERR_PRIVATE(0);
6514 		return 0;
6515 	}
6516 
6517 	switch (pipe->config.default_capture_config.mode) {
6518 	case IA_CSS_CAPTURE_MODE_RAW:
6519 		err = load_copy_binaries(pipe);
6520 #if defined(ISP2401)
6521 		if (!err)
6522 			pipe->pipe_settings.capture.copy_binary.online = pipe->stream->config.online;
6523 #endif
6524 		break;
6525 	case IA_CSS_CAPTURE_MODE_BAYER:
6526 		err = load_bayer_isp_binaries(pipe);
6527 		break;
6528 	case IA_CSS_CAPTURE_MODE_PRIMARY:
6529 		err = load_primary_binaries(pipe);
6530 		break;
6531 	case IA_CSS_CAPTURE_MODE_ADVANCED:
6532 		err = load_advanced_binaries(pipe);
6533 		break;
6534 	case IA_CSS_CAPTURE_MODE_LOW_LIGHT:
6535 		err = load_low_light_binaries(pipe);
6536 		break;
6537 	}
6538 	if (err) {
6539 		IA_CSS_LEAVE_ERR_PRIVATE(err);
6540 		return err;
6541 	}
6542 
6543 	IA_CSS_LEAVE_ERR_PRIVATE(err);
6544 	return err;
6545 }
6546 
6547 static int
6548 unload_capture_binaries(struct ia_css_pipe *pipe)
6549 {
6550 	unsigned int i;
6551 
6552 	IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
6553 
6554 	if (!pipe || (pipe->mode != IA_CSS_PIPE_ID_CAPTURE &&
6555 		      pipe->mode != IA_CSS_PIPE_ID_COPY)) {
6556 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
6557 		return -EINVAL;
6558 	}
6559 	ia_css_binary_unload(&pipe->pipe_settings.capture.copy_binary);
6560 	for (i = 0; i < MAX_NUM_PRIMARY_STAGES; i++)
6561 		ia_css_binary_unload(&pipe->pipe_settings.capture.primary_binary[i]);
6562 	ia_css_binary_unload(&pipe->pipe_settings.capture.pre_isp_binary);
6563 	ia_css_binary_unload(&pipe->pipe_settings.capture.anr_gdc_binary);
6564 	ia_css_binary_unload(&pipe->pipe_settings.capture.post_isp_binary);
6565 	ia_css_binary_unload(&pipe->pipe_settings.capture.capture_pp_binary);
6566 	ia_css_binary_unload(&pipe->pipe_settings.capture.capture_ldc_binary);
6567 	ia_css_binary_unload(&pipe->pipe_settings.capture.vf_pp_binary);
6568 
6569 	for (i = 0; i < pipe->pipe_settings.capture.num_yuv_scaler; i++)
6570 		ia_css_binary_unload(&pipe->pipe_settings.capture.yuv_scaler_binary[i]);
6571 
6572 	kfree(pipe->pipe_settings.capture.is_output_stage);
6573 	pipe->pipe_settings.capture.is_output_stage = NULL;
6574 	kfree(pipe->pipe_settings.capture.yuv_scaler_binary);
6575 	pipe->pipe_settings.capture.yuv_scaler_binary = NULL;
6576 
6577 	IA_CSS_LEAVE_ERR_PRIVATE(0);
6578 	return 0;
6579 }
6580 
6581 static bool
6582 need_downscaling(const struct ia_css_resolution in_res,
6583 		 const struct ia_css_resolution out_res)
6584 {
6585 	if (in_res.width > out_res.width || in_res.height > out_res.height)
6586 		return true;
6587 
6588 	return false;
6589 }
6590 
6591 static bool
6592 need_yuv_scaler_stage(const struct ia_css_pipe *pipe)
6593 {
6594 	unsigned int i;
6595 	struct ia_css_resolution in_res, out_res;
6596 
6597 	bool need_format_conversion = false;
6598 
6599 	IA_CSS_ENTER_PRIVATE("");
6600 	assert(pipe);
6601 	assert(pipe->mode == IA_CSS_PIPE_ID_YUVPP);
6602 
6603 	/* TODO: make generic function */
6604 	need_format_conversion =
6605 	    ((pipe->stream->config.input_config.format ==
6606 		ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY) &&
6607 		(pipe->output_info[0].format != IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8));
6608 
6609 	in_res = pipe->config.input_effective_res;
6610 
6611 	if (pipe->config.enable_dz)
6612 		return true;
6613 
6614 	if ((pipe->output_info[0].res.width != 0) && need_format_conversion)
6615 		return true;
6616 
6617 	for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
6618 		out_res = pipe->output_info[i].res;
6619 
6620 		/* A non-zero width means it is a valid output port */
6621 		if ((out_res.width != 0) && need_downscaling(in_res, out_res))
6622 			return true;
6623 	}
6624 
6625 	return false;
6626 }
6627 
6628 /* TODO: it is temporarily created from ia_css_pipe_create_cas_scaler_desc */
6629 /* which has some hard-coded knowledge which prevents reuse of the function. */
6630 /* Later, merge this with ia_css_pipe_create_cas_scaler_desc */
6631 static int ia_css_pipe_create_cas_scaler_desc_single_output(
6632 	    struct ia_css_frame_info *cas_scaler_in_info,
6633 	    struct ia_css_frame_info *cas_scaler_out_info,
6634 	    struct ia_css_frame_info *cas_scaler_vf_info,
6635 	    struct ia_css_cas_binary_descr *descr)
6636 {
6637 	unsigned int i;
6638 	unsigned int hor_ds_factor = 0, ver_ds_factor = 0;
6639 	int err = 0;
6640 	struct ia_css_frame_info tmp_in_info;
6641 
6642 	unsigned int max_scale_factor_per_stage = MAX_PREFERRED_YUV_DS_PER_STEP;
6643 
6644 	assert(cas_scaler_in_info);
6645 	assert(cas_scaler_out_info);
6646 
6647 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
6648 			    "ia_css_pipe_create_cas_scaler_desc() enter:\n");
6649 
6650 	/* We assume that this function is used only for single output port case. */
6651 	descr->num_output_stage = 1;
6652 
6653 	hor_ds_factor = CEIL_DIV(cas_scaler_in_info->res.width,
6654 				 cas_scaler_out_info->res.width);
6655 	ver_ds_factor = CEIL_DIV(cas_scaler_in_info->res.height,
6656 				 cas_scaler_out_info->res.height);
6657 	/* use the same horizontal and vertical downscaling factor for simplicity */
6658 	assert(hor_ds_factor == ver_ds_factor);
6659 
6660 	i = 1;
6661 	while (i < hor_ds_factor) {
6662 		descr->num_stage++;
6663 		i *= max_scale_factor_per_stage;
6664 	}
6665 
6666 	descr->in_info = kmalloc(descr->num_stage *
6667 				 sizeof(struct ia_css_frame_info),
6668 				 GFP_KERNEL);
6669 	if (!descr->in_info) {
6670 		err = -ENOMEM;
6671 		goto ERR;
6672 	}
6673 	descr->internal_out_info = kmalloc(descr->num_stage *
6674 					   sizeof(struct ia_css_frame_info),
6675 					   GFP_KERNEL);
6676 	if (!descr->internal_out_info) {
6677 		err = -ENOMEM;
6678 		goto ERR;
6679 	}
6680 	descr->out_info = kmalloc(descr->num_stage *
6681 				  sizeof(struct ia_css_frame_info),
6682 				  GFP_KERNEL);
6683 	if (!descr->out_info) {
6684 		err = -ENOMEM;
6685 		goto ERR;
6686 	}
6687 	descr->vf_info = kmalloc(descr->num_stage *
6688 				 sizeof(struct ia_css_frame_info),
6689 				 GFP_KERNEL);
6690 	if (!descr->vf_info) {
6691 		err = -ENOMEM;
6692 		goto ERR;
6693 	}
6694 	descr->is_output_stage = kmalloc(descr->num_stage * sizeof(bool),
6695 					 GFP_KERNEL);
6696 	if (!descr->is_output_stage) {
6697 		err = -ENOMEM;
6698 		goto ERR;
6699 	}
6700 
6701 	tmp_in_info = *cas_scaler_in_info;
6702 	for (i = 0; i < descr->num_stage; i++) {
6703 		descr->in_info[i] = tmp_in_info;
6704 		if ((tmp_in_info.res.width / max_scale_factor_per_stage) <=
6705 		    cas_scaler_out_info->res.width) {
6706 			descr->is_output_stage[i] = true;
6707 			if ((descr->num_output_stage > 1) && (i != (descr->num_stage - 1))) {
6708 				descr->internal_out_info[i].res.width = cas_scaler_out_info->res.width;
6709 				descr->internal_out_info[i].res.height = cas_scaler_out_info->res.height;
6710 				descr->internal_out_info[i].padded_width = cas_scaler_out_info->padded_width;
6711 				descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420;
6712 			} else {
6713 				assert(i == (descr->num_stage - 1));
6714 				descr->internal_out_info[i].res.width = 0;
6715 				descr->internal_out_info[i].res.height = 0;
6716 			}
6717 			descr->out_info[i].res.width = cas_scaler_out_info->res.width;
6718 			descr->out_info[i].res.height = cas_scaler_out_info->res.height;
6719 			descr->out_info[i].padded_width = cas_scaler_out_info->padded_width;
6720 			descr->out_info[i].format = cas_scaler_out_info->format;
6721 			if (cas_scaler_vf_info) {
6722 				descr->vf_info[i].res.width = cas_scaler_vf_info->res.width;
6723 				descr->vf_info[i].res.height = cas_scaler_vf_info->res.height;
6724 				descr->vf_info[i].padded_width = cas_scaler_vf_info->padded_width;
6725 				ia_css_frame_info_set_format(&descr->vf_info[i], IA_CSS_FRAME_FORMAT_YUV_LINE);
6726 			} else {
6727 				descr->vf_info[i].res.width = 0;
6728 				descr->vf_info[i].res.height = 0;
6729 				descr->vf_info[i].padded_width = 0;
6730 			}
6731 		} else {
6732 			descr->is_output_stage[i] = false;
6733 			descr->internal_out_info[i].res.width = tmp_in_info.res.width /
6734 								max_scale_factor_per_stage;
6735 			descr->internal_out_info[i].res.height = tmp_in_info.res.height /
6736 				max_scale_factor_per_stage;
6737 			descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420;
6738 			ia_css_frame_info_init(&descr->internal_out_info[i],
6739 					       tmp_in_info.res.width / max_scale_factor_per_stage,
6740 					       tmp_in_info.res.height / max_scale_factor_per_stage,
6741 					       IA_CSS_FRAME_FORMAT_YUV420, 0);
6742 			descr->out_info[i].res.width = 0;
6743 			descr->out_info[i].res.height = 0;
6744 			descr->vf_info[i].res.width = 0;
6745 			descr->vf_info[i].res.height = 0;
6746 		}
6747 		tmp_in_info = descr->internal_out_info[i];
6748 	}
6749 ERR:
6750 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
6751 			    "ia_css_pipe_create_cas_scaler_desc() leave, err=%d\n",
6752 			    err);
6753 	return err;
6754 }
6755 
6756 /* FIXME: merge most of this and single output version */
6757 static int
6758 ia_css_pipe_create_cas_scaler_desc(struct ia_css_pipe *pipe,
6759 				   struct ia_css_cas_binary_descr *descr)
6760 {
6761 	struct ia_css_frame_info in_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO;
6762 	struct ia_css_frame_info *out_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE];
6763 	struct ia_css_frame_info *vf_out_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE];
6764 	struct ia_css_frame_info tmp_in_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO;
6765 	unsigned int i, j;
6766 	unsigned int hor_scale_factor[IA_CSS_PIPE_MAX_OUTPUT_STAGE],
6767 		    ver_scale_factor[IA_CSS_PIPE_MAX_OUTPUT_STAGE],
6768 		    scale_factor = 0;
6769 	unsigned int num_stages = 0;
6770 	int err = 0;
6771 
6772 	unsigned int max_scale_factor_per_stage = MAX_PREFERRED_YUV_DS_PER_STEP;
6773 
6774 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
6775 			    "ia_css_pipe_create_cas_scaler_desc() enter:\n");
6776 
6777 	for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
6778 		out_info[i] = NULL;
6779 		vf_out_info[i] = NULL;
6780 		hor_scale_factor[i] = 0;
6781 		ver_scale_factor[i] = 0;
6782 	}
6783 
6784 	in_info.res = pipe->config.input_effective_res;
6785 	in_info.padded_width = in_info.res.width;
6786 	descr->num_output_stage = 0;
6787 	/* Find out how much scaling we need for each output */
6788 	for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
6789 		if (pipe->output_info[i].res.width != 0) {
6790 			out_info[i] = &pipe->output_info[i];
6791 			if (pipe->vf_output_info[i].res.width != 0)
6792 				vf_out_info[i] = &pipe->vf_output_info[i];
6793 			descr->num_output_stage += 1;
6794 		}
6795 
6796 		if (out_info[i]) {
6797 			hor_scale_factor[i] = CEIL_DIV(in_info.res.width, out_info[i]->res.width);
6798 			ver_scale_factor[i] = CEIL_DIV(in_info.res.height, out_info[i]->res.height);
6799 			/* use the same horizontal and vertical scaling factor for simplicity */
6800 			assert(hor_scale_factor[i] == ver_scale_factor[i]);
6801 			scale_factor = 1;
6802 			do {
6803 				num_stages++;
6804 				scale_factor *= max_scale_factor_per_stage;
6805 			} while (scale_factor < hor_scale_factor[i]);
6806 
6807 			in_info.res = out_info[i]->res;
6808 		}
6809 	}
6810 
6811 	if (need_yuv_scaler_stage(pipe) && (num_stages == 0))
6812 		num_stages = 1;
6813 
6814 	descr->num_stage = num_stages;
6815 
6816 	descr->in_info = kmalloc_array(descr->num_stage,
6817 				       sizeof(struct ia_css_frame_info),
6818 				       GFP_KERNEL);
6819 	if (!descr->in_info) {
6820 		err = -ENOMEM;
6821 		goto ERR;
6822 	}
6823 	descr->internal_out_info = kmalloc(descr->num_stage *
6824 					   sizeof(struct ia_css_frame_info),
6825 					   GFP_KERNEL);
6826 	if (!descr->internal_out_info) {
6827 		err = -ENOMEM;
6828 		goto ERR;
6829 	}
6830 	descr->out_info = kmalloc(descr->num_stage *
6831 				  sizeof(struct ia_css_frame_info),
6832 				  GFP_KERNEL);
6833 	if (!descr->out_info) {
6834 		err = -ENOMEM;
6835 		goto ERR;
6836 	}
6837 	descr->vf_info = kmalloc(descr->num_stage *
6838 				 sizeof(struct ia_css_frame_info),
6839 				 GFP_KERNEL);
6840 	if (!descr->vf_info) {
6841 		err = -ENOMEM;
6842 		goto ERR;
6843 	}
6844 	descr->is_output_stage = kmalloc(descr->num_stage * sizeof(bool),
6845 					 GFP_KERNEL);
6846 	if (!descr->is_output_stage) {
6847 		err = -ENOMEM;
6848 		goto ERR;
6849 	}
6850 
6851 	for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
6852 		if (out_info[i]) {
6853 			if (i > 0) {
6854 				assert((out_info[i - 1]->res.width >= out_info[i]->res.width) &&
6855 				       (out_info[i - 1]->res.height >= out_info[i]->res.height));
6856 			}
6857 		}
6858 	}
6859 
6860 	tmp_in_info.res = pipe->config.input_effective_res;
6861 	tmp_in_info.format = IA_CSS_FRAME_FORMAT_YUV420;
6862 	for (i = 0, j = 0; i < descr->num_stage; i++) {
6863 		assert(j < 2);
6864 		assert(out_info[j]);
6865 
6866 		descr->in_info[i] = tmp_in_info;
6867 		if ((tmp_in_info.res.width / max_scale_factor_per_stage) <=
6868 		    out_info[j]->res.width) {
6869 			descr->is_output_stage[i] = true;
6870 			if ((descr->num_output_stage > 1) && (i != (descr->num_stage - 1))) {
6871 				descr->internal_out_info[i].res.width = out_info[j]->res.width;
6872 				descr->internal_out_info[i].res.height = out_info[j]->res.height;
6873 				descr->internal_out_info[i].padded_width = out_info[j]->padded_width;
6874 				descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420;
6875 			} else {
6876 				assert(i == (descr->num_stage - 1));
6877 				descr->internal_out_info[i].res.width = 0;
6878 				descr->internal_out_info[i].res.height = 0;
6879 			}
6880 			descr->out_info[i].res.width = out_info[j]->res.width;
6881 			descr->out_info[i].res.height = out_info[j]->res.height;
6882 			descr->out_info[i].padded_width = out_info[j]->padded_width;
6883 			descr->out_info[i].format = out_info[j]->format;
6884 			if (vf_out_info[j]) {
6885 				descr->vf_info[i].res.width = vf_out_info[j]->res.width;
6886 				descr->vf_info[i].res.height = vf_out_info[j]->res.height;
6887 				descr->vf_info[i].padded_width = vf_out_info[j]->padded_width;
6888 				ia_css_frame_info_set_format(&descr->vf_info[i], IA_CSS_FRAME_FORMAT_YUV_LINE);
6889 			} else {
6890 				descr->vf_info[i].res.width = 0;
6891 				descr->vf_info[i].res.height = 0;
6892 				descr->vf_info[i].padded_width = 0;
6893 			}
6894 			j++;
6895 		} else {
6896 			descr->is_output_stage[i] = false;
6897 			descr->internal_out_info[i].res.width = tmp_in_info.res.width /
6898 								max_scale_factor_per_stage;
6899 			descr->internal_out_info[i].res.height = tmp_in_info.res.height /
6900 				max_scale_factor_per_stage;
6901 			descr->internal_out_info[i].format = IA_CSS_FRAME_FORMAT_YUV420;
6902 			ia_css_frame_info_init(&descr->internal_out_info[i],
6903 					       tmp_in_info.res.width / max_scale_factor_per_stage,
6904 					       tmp_in_info.res.height / max_scale_factor_per_stage,
6905 					       IA_CSS_FRAME_FORMAT_YUV420, 0);
6906 			descr->out_info[i].res.width = 0;
6907 			descr->out_info[i].res.height = 0;
6908 			descr->vf_info[i].res.width = 0;
6909 			descr->vf_info[i].res.height = 0;
6910 		}
6911 		tmp_in_info = descr->internal_out_info[i];
6912 	}
6913 ERR:
6914 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
6915 			    "ia_css_pipe_create_cas_scaler_desc() leave, err=%d\n",
6916 			    err);
6917 	return err;
6918 }
6919 
6920 static void ia_css_pipe_destroy_cas_scaler_desc(struct ia_css_cas_binary_descr
6921 	*descr)
6922 {
6923 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
6924 			    "ia_css_pipe_destroy_cas_scaler_desc() enter:\n");
6925 	kfree(descr->in_info);
6926 	descr->in_info = NULL;
6927 	kfree(descr->internal_out_info);
6928 	descr->internal_out_info = NULL;
6929 	kfree(descr->out_info);
6930 	descr->out_info = NULL;
6931 	kfree(descr->vf_info);
6932 	descr->vf_info = NULL;
6933 	kfree(descr->is_output_stage);
6934 	descr->is_output_stage = NULL;
6935 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
6936 			    "ia_css_pipe_destroy_cas_scaler_desc() leave\n");
6937 }
6938 
6939 static int
6940 load_yuvpp_binaries(struct ia_css_pipe *pipe)
6941 {
6942 	int err = 0;
6943 	bool need_scaler = false;
6944 	struct ia_css_frame_info *vf_pp_in_info[IA_CSS_PIPE_MAX_OUTPUT_STAGE];
6945 	struct ia_css_yuvpp_settings *mycs;
6946 	struct ia_css_binary *next_binary;
6947 	struct ia_css_cas_binary_descr cas_scaler_descr = { };
6948 	unsigned int i, j;
6949 	bool need_isp_copy_binary = false;
6950 
6951 	IA_CSS_ENTER_PRIVATE("");
6952 	assert(pipe);
6953 	assert(pipe->stream);
6954 	assert(pipe->mode == IA_CSS_PIPE_ID_YUVPP);
6955 
6956 	if (pipe->pipe_settings.yuvpp.copy_binary.info)
6957 		goto ERR;
6958 
6959 	/* Set both must_be_raw and must_be_yuv to false then yuvpp can take rgb inputs */
6960 	err = ia_css_util_check_input(&pipe->stream->config, false, false);
6961 	if (err)
6962 		goto ERR;
6963 
6964 	mycs = &pipe->pipe_settings.yuvpp;
6965 
6966 	for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
6967 		if (pipe->vf_output_info[i].res.width != 0) {
6968 			err = ia_css_util_check_vf_out_info(&pipe->output_info[i],
6969 							    &pipe->vf_output_info[i]);
6970 			if (err)
6971 				goto ERR;
6972 		}
6973 		vf_pp_in_info[i] = NULL;
6974 	}
6975 
6976 	need_scaler = need_yuv_scaler_stage(pipe);
6977 
6978 	/* we build up the pipeline starting at the end */
6979 	/* Capture post-processing */
6980 	if (need_scaler) {
6981 		struct ia_css_binary_descr yuv_scaler_descr;
6982 
6983 		err = ia_css_pipe_create_cas_scaler_desc(pipe,
6984 							 &cas_scaler_descr);
6985 		if (err)
6986 			goto ERR;
6987 		mycs->num_output = cas_scaler_descr.num_output_stage;
6988 		mycs->num_yuv_scaler = cas_scaler_descr.num_stage;
6989 		mycs->yuv_scaler_binary = kcalloc(cas_scaler_descr.num_stage,
6990 						  sizeof(struct ia_css_binary),
6991 						  GFP_KERNEL);
6992 		if (!mycs->yuv_scaler_binary) {
6993 			err = -ENOMEM;
6994 			goto ERR;
6995 		}
6996 		mycs->is_output_stage = kcalloc(cas_scaler_descr.num_stage,
6997 						sizeof(bool), GFP_KERNEL);
6998 		if (!mycs->is_output_stage) {
6999 			err = -ENOMEM;
7000 			goto ERR;
7001 		}
7002 		for (i = 0; i < cas_scaler_descr.num_stage; i++) {
7003 			mycs->is_output_stage[i] = cas_scaler_descr.is_output_stage[i];
7004 			ia_css_pipe_get_yuvscaler_binarydesc(pipe,
7005 							     &yuv_scaler_descr,
7006 							     &cas_scaler_descr.in_info[i],
7007 							     &cas_scaler_descr.out_info[i],
7008 							     &cas_scaler_descr.internal_out_info[i],
7009 							     &cas_scaler_descr.vf_info[i]);
7010 			err = ia_css_binary_find(&yuv_scaler_descr,
7011 						 &mycs->yuv_scaler_binary[i]);
7012 			if (err)
7013 				goto ERR;
7014 		}
7015 		ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr);
7016 	} else {
7017 		mycs->num_output = 1;
7018 	}
7019 
7020 	if (need_scaler)
7021 		next_binary = &mycs->yuv_scaler_binary[0];
7022 	else
7023 		next_binary = NULL;
7024 
7025 #if defined(ISP2401)
7026 	/*
7027 	    * NOTES
7028 	    * - Why does the "yuvpp" pipe needs "isp_copy_binary" (i.e. ISP Copy) when
7029 	    *   its input is "ATOMISP_INPUT_FORMAT_YUV422_8"?
7030 	    *
7031 	    *   In most use cases, the first stage in the "yuvpp" pipe is the "yuv_scale_
7032 	    *   binary". However, the "yuv_scale_binary" does NOT support the input-frame
7033 	    *   format as "IA_CSS_STREAM _FORMAT_YUV422_8".
7034 	    *
7035 	    *   Hence, the "isp_copy_binary" is required to be present in front of the "yuv
7036 	    *   _scale_binary". It would translate the input-frame to the frame formats that
7037 	    *   are supported by the "yuv_scale_binary".
7038 	    *
7039 	    *   Please refer to "FrameWork/css/isp/pipes/capture_pp/capture_pp_1.0/capture_
7040 	    *   pp_defs.h" for the list of input-frame formats that are supported by the
7041 	    *   "yuv_scale_binary".
7042 	    */
7043 	need_isp_copy_binary =
7044 	    (pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_YUV422_8);
7045 #else  /* !ISP2401 */
7046 	need_isp_copy_binary = true;
7047 #endif /*  ISP2401 */
7048 
7049 	if (need_isp_copy_binary) {
7050 		err = load_copy_binary(pipe,
7051 				       &mycs->copy_binary,
7052 				       next_binary);
7053 
7054 		if (err)
7055 			goto ERR;
7056 
7057 		/*
7058 		    * NOTES
7059 		    * - Why is "pipe->pipe_settings.capture.copy_binary.online" specified?
7060 		    *
7061 		    *   In some use cases, the first stage in the "yuvpp" pipe is the
7062 		    *   "isp_copy_binary". The "isp_copy_binary" is designed to process
7063 		    *   the input from either the system DDR or from the IPU internal VMEM.
7064 		    *   So it provides the flag "online" to specify where its input is from,
7065 		    *   i.e.:
7066 		    *
7067 		    *      (1) "online <= true", the input is from the IPU internal VMEM.
7068 		    *      (2) "online <= false", the input is from the system DDR.
7069 		    *
7070 		    *   In other use cases, the first stage in the "yuvpp" pipe is the
7071 		    *   "yuv_scale_binary". "The "yuv_scale_binary" is designed to process the
7072 		    *   input ONLY from the system DDR. So it does not provide the flag "online"
7073 		    *   to specify where its input is from.
7074 		    */
7075 		pipe->pipe_settings.capture.copy_binary.online = pipe->stream->config.online;
7076 	}
7077 
7078 	/* Viewfinder post-processing */
7079 	if (need_scaler) {
7080 		for (i = 0, j = 0; i < mycs->num_yuv_scaler; i++) {
7081 			if (mycs->is_output_stage[i]) {
7082 				assert(j < 2);
7083 				vf_pp_in_info[j] =
7084 				    &mycs->yuv_scaler_binary[i].vf_frame_info;
7085 				j++;
7086 			}
7087 		}
7088 		mycs->num_vf_pp = j;
7089 	} else {
7090 		vf_pp_in_info[0] =
7091 		    &mycs->copy_binary.vf_frame_info;
7092 		for (i = 1; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++)
7093 			vf_pp_in_info[i] = NULL;
7094 
7095 		mycs->num_vf_pp = 1;
7096 	}
7097 	mycs->vf_pp_binary = kcalloc(mycs->num_vf_pp,
7098 				     sizeof(struct ia_css_binary),
7099 				     GFP_KERNEL);
7100 	if (!mycs->vf_pp_binary) {
7101 		err = -ENOMEM;
7102 		goto ERR;
7103 	}
7104 
7105 	{
7106 		struct ia_css_binary_descr vf_pp_descr;
7107 
7108 		for (i = 0; i < mycs->num_vf_pp; i++) {
7109 			if (pipe->vf_output_info[i].res.width != 0) {
7110 				ia_css_pipe_get_vfpp_binarydesc(pipe,
7111 								&vf_pp_descr, vf_pp_in_info[i], &pipe->vf_output_info[i]);
7112 				err = ia_css_binary_find(&vf_pp_descr, &mycs->vf_pp_binary[i]);
7113 				if (err)
7114 					goto ERR;
7115 			}
7116 		}
7117 	}
7118 
7119 	if (err)
7120 		goto ERR;
7121 
7122 ERR:
7123 	if (need_scaler)
7124 		ia_css_pipe_destroy_cas_scaler_desc(&cas_scaler_descr);
7125 
7126 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "load_yuvpp_binaries() leave, err=%d\n",
7127 			    err);
7128 	return err;
7129 }
7130 
7131 static int
7132 unload_yuvpp_binaries(struct ia_css_pipe *pipe)
7133 {
7134 	unsigned int i;
7135 
7136 	IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
7137 
7138 	if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP)) {
7139 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
7140 		return -EINVAL;
7141 	}
7142 	ia_css_binary_unload(&pipe->pipe_settings.yuvpp.copy_binary);
7143 	for (i = 0; i < pipe->pipe_settings.yuvpp.num_yuv_scaler; i++)
7144 		ia_css_binary_unload(&pipe->pipe_settings.yuvpp.yuv_scaler_binary[i]);
7145 
7146 	for (i = 0; i < pipe->pipe_settings.yuvpp.num_vf_pp; i++)
7147 		ia_css_binary_unload(&pipe->pipe_settings.yuvpp.vf_pp_binary[i]);
7148 
7149 	kfree(pipe->pipe_settings.yuvpp.is_output_stage);
7150 	pipe->pipe_settings.yuvpp.is_output_stage = NULL;
7151 	kfree(pipe->pipe_settings.yuvpp.yuv_scaler_binary);
7152 	pipe->pipe_settings.yuvpp.yuv_scaler_binary = NULL;
7153 	kfree(pipe->pipe_settings.yuvpp.vf_pp_binary);
7154 	pipe->pipe_settings.yuvpp.vf_pp_binary = NULL;
7155 
7156 	IA_CSS_LEAVE_ERR_PRIVATE(0);
7157 	return 0;
7158 }
7159 
7160 static int yuvpp_start(struct ia_css_pipe *pipe)
7161 {
7162 	int err = 0;
7163 	enum sh_css_pipe_config_override copy_ovrd;
7164 	enum ia_css_input_mode yuvpp_pipe_input_mode;
7165 
7166 	IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
7167 	if ((!pipe) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP)) {
7168 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
7169 		return -EINVAL;
7170 	}
7171 
7172 	yuvpp_pipe_input_mode = pipe->stream->config.mode;
7173 
7174 	sh_css_metrics_start_frame();
7175 
7176 	/* multi stream video needs mipi buffers */
7177 
7178 	err = send_mipi_frames(pipe);
7179 	if (err) {
7180 		IA_CSS_LEAVE_ERR_PRIVATE(err);
7181 		return err;
7182 	}
7183 
7184 	{
7185 		unsigned int thread_id;
7186 
7187 		ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
7188 		copy_ovrd = 1 << thread_id;
7189 	}
7190 
7191 	start_pipe(pipe, copy_ovrd, yuvpp_pipe_input_mode);
7192 
7193 	IA_CSS_LEAVE_ERR_PRIVATE(err);
7194 	return err;
7195 }
7196 
7197 static int
7198 sh_css_pipe_unload_binaries(struct ia_css_pipe *pipe)
7199 {
7200 	int err = 0;
7201 
7202 	IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
7203 
7204 	if (!pipe) {
7205 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
7206 		return -EINVAL;
7207 	}
7208 	/* PIPE_MODE_COPY has no binaries, but has output frames to outside*/
7209 	if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY) {
7210 		IA_CSS_LEAVE_ERR_PRIVATE(0);
7211 		return 0;
7212 	}
7213 
7214 	switch (pipe->mode) {
7215 	case IA_CSS_PIPE_ID_PREVIEW:
7216 		err = unload_preview_binaries(pipe);
7217 		break;
7218 	case IA_CSS_PIPE_ID_VIDEO:
7219 		err = unload_video_binaries(pipe);
7220 		break;
7221 	case IA_CSS_PIPE_ID_CAPTURE:
7222 		err = unload_capture_binaries(pipe);
7223 		break;
7224 	case IA_CSS_PIPE_ID_YUVPP:
7225 		err = unload_yuvpp_binaries(pipe);
7226 		break;
7227 	default:
7228 		break;
7229 	}
7230 	IA_CSS_LEAVE_ERR_PRIVATE(err);
7231 	return err;
7232 }
7233 
7234 static int
7235 sh_css_pipe_load_binaries(struct ia_css_pipe *pipe)
7236 {
7237 	int err = 0;
7238 
7239 	assert(pipe);
7240 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "sh_css_pipe_load_binaries() enter:\n");
7241 
7242 	/* PIPE_MODE_COPY has no binaries, but has output frames to outside*/
7243 	if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY)
7244 		return err;
7245 
7246 	switch (pipe->mode) {
7247 	case IA_CSS_PIPE_ID_PREVIEW:
7248 		err = load_preview_binaries(pipe);
7249 		break;
7250 	case IA_CSS_PIPE_ID_VIDEO:
7251 		err = load_video_binaries(pipe);
7252 		break;
7253 	case IA_CSS_PIPE_ID_CAPTURE:
7254 		err = load_capture_binaries(pipe);
7255 		break;
7256 	case IA_CSS_PIPE_ID_YUVPP:
7257 		err = load_yuvpp_binaries(pipe);
7258 		break;
7259 	case IA_CSS_PIPE_ID_ACC:
7260 		break;
7261 	default:
7262 		err = -EINVAL;
7263 		break;
7264 	}
7265 	if (err) {
7266 		if (sh_css_pipe_unload_binaries(pipe)) {
7267 			/* currently css does not support multiple error returns in a single function,
7268 			    * using -EINVAL in this case */
7269 			err = -EINVAL;
7270 		}
7271 	}
7272 	return err;
7273 }
7274 
7275 static int
7276 create_host_yuvpp_pipeline(struct ia_css_pipe *pipe)
7277 {
7278 	struct ia_css_pipeline *me;
7279 	int err = 0;
7280 	struct ia_css_pipeline_stage *vf_pp_stage = NULL,
7281 		*copy_stage = NULL,
7282 		*yuv_scaler_stage = NULL;
7283 	struct ia_css_binary *copy_binary,
7284 		*vf_pp_binary,
7285 		*yuv_scaler_binary;
7286 	bool need_scaler = false;
7287 	unsigned int num_stage, num_output_stage;
7288 	unsigned int i, j;
7289 
7290 	struct ia_css_frame *in_frame = NULL;
7291 	struct ia_css_frame *out_frame[IA_CSS_PIPE_MAX_OUTPUT_STAGE];
7292 	struct ia_css_frame *bin_out_frame[IA_CSS_BINARY_MAX_OUTPUT_PORTS];
7293 	struct ia_css_frame *vf_frame[IA_CSS_PIPE_MAX_OUTPUT_STAGE];
7294 	struct ia_css_pipeline_stage_desc stage_desc;
7295 	bool need_in_frameinfo_memory = false;
7296 #ifdef ISP2401
7297 	bool sensor = false;
7298 	bool buffered_sensor = false;
7299 	bool online = false;
7300 	bool continuous = false;
7301 #endif
7302 
7303 	IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
7304 	if ((!pipe) || (!pipe->stream) || (pipe->mode != IA_CSS_PIPE_ID_YUVPP)) {
7305 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
7306 		return -EINVAL;
7307 	}
7308 	me = &pipe->pipeline;
7309 	ia_css_pipeline_clean(me);
7310 	for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
7311 		out_frame[i] = NULL;
7312 		vf_frame[i] = NULL;
7313 	}
7314 	ia_css_pipe_util_create_output_frames(bin_out_frame);
7315 	num_stage  = pipe->pipe_settings.yuvpp.num_yuv_scaler;
7316 	num_output_stage   = pipe->pipe_settings.yuvpp.num_output;
7317 
7318 #ifdef ISP2401
7319 	/* When the input system is 2401, always enable 'in_frameinfo_memory'
7320 	    * except for the following:
7321 	    * - Direct Sensor Mode Online Capture
7322 	    * - Direct Sensor Mode Continuous Capture
7323 	    * - Buffered Sensor Mode Continuous Capture
7324 	    */
7325 	sensor = pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR;
7326 	buffered_sensor = pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR;
7327 	online = pipe->stream->config.online;
7328 	continuous = pipe->stream->config.continuous;
7329 	need_in_frameinfo_memory =
7330 	!((sensor && (online || continuous)) || (buffered_sensor && continuous));
7331 #else
7332 	/* Construct in_frame info (only in case we have dynamic input */
7333 	need_in_frameinfo_memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY;
7334 #endif
7335 	/* the input frame can come from:
7336 	    *  a) memory: connect yuvscaler to me->in_frame
7337 	    *  b) sensor, via copy binary: connect yuvscaler to copy binary later on */
7338 	if (need_in_frameinfo_memory) {
7339 		/* TODO: improve for different input formats. */
7340 
7341 		/*
7342 		    * "pipe->stream->config.input_config.format" represents the sensor output
7343 		    * frame format, e.g. YUV422 8-bit.
7344 		    *
7345 		    * "in_frame_format" represents the imaging pipe's input frame format, e.g.
7346 		    * Bayer-Quad RAW.
7347 		    */
7348 		int in_frame_format;
7349 
7350 		if (pipe->stream->config.input_config.format ==
7351 		    ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY) {
7352 			in_frame_format = IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8;
7353 		} else if (pipe->stream->config.input_config.format ==
7354 			    ATOMISP_INPUT_FORMAT_YUV422_8) {
7355 			/*
7356 			    * When the sensor output frame format is "ATOMISP_INPUT_FORMAT_YUV422_8",
7357 			    * the "isp_copy_var" binary is selected as the first stage in the yuvpp
7358 			    * pipe.
7359 			    *
7360 			    * For the "isp_copy_var" binary, it reads the YUV422-8 pixels from
7361 			    * the frame buffer (at DDR) to the frame-line buffer (at VMEM).
7362 			    *
7363 			    * By now, the "isp_copy_var" binary does NOT provide a separated
7364 			    * frame-line buffer to store the YUV422-8 pixels. Instead, it stores
7365 			    * the YUV422-8 pixels in the frame-line buffer which is designed to
7366 			    * store the Bayer-Quad RAW pixels.
7367 			    *
7368 			    * To direct the "isp_copy_var" binary reading from the RAW frame-line
7369 			    * buffer, its input frame format must be specified as "IA_CSS_FRAME_
7370 			    * FORMAT_RAW".
7371 			    */
7372 			in_frame_format = IA_CSS_FRAME_FORMAT_RAW;
7373 		} else {
7374 			in_frame_format = IA_CSS_FRAME_FORMAT_NV12;
7375 		}
7376 
7377 		err = init_in_frameinfo_memory_defaults(pipe,
7378 							&me->in_frame,
7379 							in_frame_format);
7380 
7381 		if (err) {
7382 			IA_CSS_LEAVE_ERR_PRIVATE(err);
7383 			return err;
7384 		}
7385 
7386 		in_frame = &me->in_frame;
7387 	} else {
7388 		in_frame = NULL;
7389 	}
7390 
7391 	for (i = 0; i < num_output_stage; i++) {
7392 		assert(i < IA_CSS_PIPE_MAX_OUTPUT_STAGE);
7393 		if (pipe->output_info[i].res.width != 0) {
7394 			err = init_out_frameinfo_defaults(pipe, &me->out_frame[i], i);
7395 			if (err) {
7396 				IA_CSS_LEAVE_ERR_PRIVATE(err);
7397 				return err;
7398 			}
7399 			out_frame[i] = &me->out_frame[i];
7400 		}
7401 
7402 		/* Construct vf_frame info (only in case we have VF) */
7403 		if (pipe->vf_output_info[i].res.width != 0) {
7404 			err = init_vf_frameinfo_defaults(pipe, &me->vf_frame[i], i);
7405 			if (err) {
7406 				IA_CSS_LEAVE_ERR_PRIVATE(err);
7407 				return err;
7408 			}
7409 			vf_frame[i] = &me->vf_frame[i];
7410 		}
7411 	}
7412 
7413 	copy_binary       = &pipe->pipe_settings.yuvpp.copy_binary;
7414 	vf_pp_binary      = pipe->pipe_settings.yuvpp.vf_pp_binary;
7415 	yuv_scaler_binary = pipe->pipe_settings.yuvpp.yuv_scaler_binary;
7416 	need_scaler = need_yuv_scaler_stage(pipe);
7417 
7418 	if (pipe->pipe_settings.yuvpp.copy_binary.info) {
7419 		struct ia_css_frame *in_frame_local = NULL;
7420 
7421 #ifdef ISP2401
7422 		/* After isp copy is enabled in_frame needs to be passed. */
7423 		if (!online)
7424 			in_frame_local = in_frame;
7425 #endif
7426 
7427 		if (need_scaler) {
7428 			ia_css_pipe_util_set_output_frames(bin_out_frame,
7429 							   0, NULL);
7430 			ia_css_pipe_get_generic_stage_desc(&stage_desc,
7431 							   copy_binary,
7432 							   bin_out_frame,
7433 							   in_frame_local,
7434 							   NULL);
7435 		} else {
7436 			ia_css_pipe_util_set_output_frames(bin_out_frame,
7437 							   0, out_frame[0]);
7438 			ia_css_pipe_get_generic_stage_desc(&stage_desc,
7439 							   copy_binary,
7440 							   bin_out_frame,
7441 							   in_frame_local,
7442 							   NULL);
7443 		}
7444 
7445 		err = ia_css_pipeline_create_and_add_stage(me,
7446 							   &stage_desc,
7447 							   &copy_stage);
7448 
7449 		if (err) {
7450 			IA_CSS_LEAVE_ERR_PRIVATE(err);
7451 			return err;
7452 		}
7453 
7454 		if (copy_stage) {
7455 			/* if we use yuv scaler binary, vf output should be from there */
7456 			copy_stage->args.copy_vf = !need_scaler;
7457 			/* for yuvpp pipe, it should always be enabled */
7458 			copy_stage->args.copy_output = true;
7459 			/* connect output of copy binary to input of yuv scaler */
7460 			in_frame = copy_stage->args.out_frame[0];
7461 		}
7462 	}
7463 
7464 	if (need_scaler) {
7465 		struct ia_css_frame *tmp_out_frame = NULL;
7466 		struct ia_css_frame *tmp_vf_frame = NULL;
7467 		struct ia_css_frame *tmp_in_frame = in_frame;
7468 
7469 		for (i = 0, j = 0; i < num_stage; i++) {
7470 			assert(j < num_output_stage);
7471 			if (pipe->pipe_settings.yuvpp.is_output_stage[i]) {
7472 				tmp_out_frame = out_frame[j];
7473 				tmp_vf_frame = vf_frame[j];
7474 			} else {
7475 				tmp_out_frame = NULL;
7476 				tmp_vf_frame = NULL;
7477 			}
7478 
7479 			err = add_yuv_scaler_stage(pipe, me, tmp_in_frame,
7480 						   tmp_out_frame,
7481 						   NULL,
7482 						   &yuv_scaler_binary[i],
7483 						   &yuv_scaler_stage);
7484 
7485 			if (err) {
7486 				IA_CSS_LEAVE_ERR_PRIVATE(err);
7487 				return err;
7488 			}
7489 			/* we use output port 1 as internal output port */
7490 			tmp_in_frame = yuv_scaler_stage->args.out_frame[1];
7491 			if (pipe->pipe_settings.yuvpp.is_output_stage[i]) {
7492 				if (tmp_vf_frame && (tmp_vf_frame->info.res.width != 0)) {
7493 					in_frame = yuv_scaler_stage->args.out_vf_frame;
7494 					err = add_vf_pp_stage(pipe, in_frame,
7495 							      tmp_vf_frame,
7496 							      &vf_pp_binary[j],
7497 							      &vf_pp_stage);
7498 
7499 					if (err) {
7500 						IA_CSS_LEAVE_ERR_PRIVATE(err);
7501 						return err;
7502 					}
7503 				}
7504 				j++;
7505 			}
7506 		}
7507 	} else if (copy_stage) {
7508 		if (vf_frame[0] && vf_frame[0]->info.res.width != 0) {
7509 			in_frame = copy_stage->args.out_vf_frame;
7510 			err = add_vf_pp_stage(pipe, in_frame, vf_frame[0],
7511 					      &vf_pp_binary[0], &vf_pp_stage);
7512 		}
7513 		if (err) {
7514 			IA_CSS_LEAVE_ERR_PRIVATE(err);
7515 			return err;
7516 		}
7517 	}
7518 
7519 	ia_css_pipeline_finalize_stages(&pipe->pipeline,
7520 					pipe->stream->config.continuous);
7521 
7522 	IA_CSS_LEAVE_ERR_PRIVATE(0);
7523 
7524 	return 0;
7525 }
7526 
7527 static int
7528 create_host_copy_pipeline(struct ia_css_pipe *pipe,
7529 			  unsigned int max_input_width,
7530 			  struct ia_css_frame *out_frame)
7531 {
7532 	struct ia_css_pipeline *me;
7533 	int err = 0;
7534 	struct ia_css_pipeline_stage_desc stage_desc;
7535 
7536 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
7537 			    "create_host_copy_pipeline() enter:\n");
7538 
7539 	/* pipeline already created as part of create_host_pipeline_structure */
7540 	me = &pipe->pipeline;
7541 	ia_css_pipeline_clean(me);
7542 
7543 	/* Construct out_frame info */
7544 	out_frame->contiguous = false;
7545 	out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
7546 
7547 	if (copy_on_sp(pipe) &&
7548 	    pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8) {
7549 		ia_css_frame_info_init(&out_frame->info, JPEG_BYTES, 1,
7550 				       IA_CSS_FRAME_FORMAT_BINARY_8, 0);
7551 	} else if (out_frame->info.format == IA_CSS_FRAME_FORMAT_RAW) {
7552 		out_frame->info.raw_bit_depth =
7553 		ia_css_pipe_util_pipe_input_format_bpp(pipe);
7554 	}
7555 
7556 	me->num_stages = 1;
7557 	me->pipe_id = IA_CSS_PIPE_ID_COPY;
7558 	pipe->mode  = IA_CSS_PIPE_ID_COPY;
7559 
7560 	ia_css_pipe_get_sp_func_stage_desc(&stage_desc, out_frame,
7561 					   IA_CSS_PIPELINE_RAW_COPY,
7562 					   max_input_width);
7563 	err = ia_css_pipeline_create_and_add_stage(me, &stage_desc, NULL);
7564 
7565 	ia_css_pipeline_finalize_stages(&pipe->pipeline,
7566 					pipe->stream->config.continuous);
7567 
7568 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
7569 			    "create_host_copy_pipeline() leave:\n");
7570 
7571 	return err;
7572 }
7573 
7574 static int
7575 create_host_isyscopy_capture_pipeline(struct ia_css_pipe *pipe)
7576 {
7577 	struct ia_css_pipeline *me = &pipe->pipeline;
7578 	int err = 0;
7579 	struct ia_css_pipeline_stage_desc stage_desc;
7580 	struct ia_css_frame *out_frame = &me->out_frame[0];
7581 	struct ia_css_pipeline_stage *out_stage = NULL;
7582 	unsigned int thread_id;
7583 	enum sh_css_queue_id queue_id;
7584 	unsigned int max_input_width = MAX_VECTORS_PER_INPUT_LINE_CONT * ISP_VEC_NELEMS;
7585 
7586 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
7587 			    "create_host_isyscopy_capture_pipeline() enter:\n");
7588 	ia_css_pipeline_clean(me);
7589 
7590 	/* Construct out_frame info */
7591 	err = sh_css_pipe_get_output_frame_info(pipe, &out_frame->info, 0);
7592 	if (err)
7593 		return err;
7594 	out_frame->contiguous = false;
7595 	out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
7596 	ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
7597 	ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, thread_id, &queue_id);
7598 	out_frame->dynamic_queue_id = queue_id;
7599 	out_frame->buf_type = IA_CSS_BUFFER_TYPE_OUTPUT_FRAME;
7600 
7601 	me->num_stages = 1;
7602 	me->pipe_id = IA_CSS_PIPE_ID_CAPTURE;
7603 	pipe->mode  = IA_CSS_PIPE_ID_CAPTURE;
7604 	ia_css_pipe_get_sp_func_stage_desc(&stage_desc, out_frame,
7605 					   IA_CSS_PIPELINE_ISYS_COPY,
7606 					   max_input_width);
7607 	err = ia_css_pipeline_create_and_add_stage(me,
7608 						   &stage_desc, &out_stage);
7609 	if (err)
7610 		return err;
7611 
7612 	ia_css_pipeline_finalize_stages(me, pipe->stream->config.continuous);
7613 
7614 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
7615 			    "create_host_isyscopy_capture_pipeline() leave:\n");
7616 
7617 	return err;
7618 }
7619 
7620 static int
7621 create_host_regular_capture_pipeline(struct ia_css_pipe *pipe)
7622 {
7623 	struct ia_css_pipeline *me;
7624 	int err = 0;
7625 	enum ia_css_capture_mode mode;
7626 	struct ia_css_pipeline_stage *current_stage = NULL;
7627 	struct ia_css_pipeline_stage *yuv_scaler_stage = NULL;
7628 	struct ia_css_binary *copy_binary,
7629 		*primary_binary[MAX_NUM_PRIMARY_STAGES],
7630 		*vf_pp_binary,
7631 		*pre_isp_binary,
7632 		*anr_gdc_binary,
7633 		*post_isp_binary,
7634 		*yuv_scaler_binary,
7635 		*capture_pp_binary,
7636 		*capture_ldc_binary;
7637 	bool need_pp = false;
7638 	bool raw;
7639 
7640 	struct ia_css_frame *in_frame;
7641 	struct ia_css_frame *out_frame;
7642 	struct ia_css_frame *out_frames[IA_CSS_BINARY_MAX_OUTPUT_PORTS];
7643 	struct ia_css_frame *vf_frame;
7644 	struct ia_css_pipeline_stage_desc stage_desc;
7645 	bool need_in_frameinfo_memory = false;
7646 #ifdef ISP2401
7647 	bool sensor = false;
7648 	bool buffered_sensor = false;
7649 	bool online = false;
7650 	bool continuous = false;
7651 #endif
7652 	unsigned int i, num_yuv_scaler, num_primary_stage;
7653 	bool need_yuv_pp = false;
7654 	bool *is_output_stage = NULL;
7655 	bool need_ldc = false;
7656 
7657 	IA_CSS_ENTER_PRIVATE("");
7658 	assert(pipe);
7659 	assert(pipe->stream);
7660 	assert(pipe->mode == IA_CSS_PIPE_ID_CAPTURE ||
7661 	       pipe->mode == IA_CSS_PIPE_ID_COPY);
7662 
7663 	me = &pipe->pipeline;
7664 	mode = pipe->config.default_capture_config.mode;
7665 	raw = (mode == IA_CSS_CAPTURE_MODE_RAW);
7666 	ia_css_pipeline_clean(me);
7667 	ia_css_pipe_util_create_output_frames(out_frames);
7668 
7669 #ifdef ISP2401
7670 	/* When the input system is 2401, always enable 'in_frameinfo_memory'
7671 	    * except for the following:
7672 	    * - Direct Sensor Mode Online Capture
7673 	    * - Direct Sensor Mode Online Capture
7674 	    * - Direct Sensor Mode Continuous Capture
7675 	    * - Buffered Sensor Mode Continuous Capture
7676 	    */
7677 	sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_SENSOR);
7678 	buffered_sensor = (pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR);
7679 	online = pipe->stream->config.online;
7680 	continuous = pipe->stream->config.continuous;
7681 	need_in_frameinfo_memory =
7682 	!((sensor && (online || continuous)) || (buffered_sensor && (online || continuous)));
7683 #else
7684 	/* Construct in_frame info (only in case we have dynamic input */
7685 	need_in_frameinfo_memory = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY;
7686 #endif
7687 	if (need_in_frameinfo_memory) {
7688 		err = init_in_frameinfo_memory_defaults(pipe, &me->in_frame,
7689 							IA_CSS_FRAME_FORMAT_RAW);
7690 		if (err) {
7691 			IA_CSS_LEAVE_ERR_PRIVATE(err);
7692 			return err;
7693 		}
7694 
7695 		in_frame = &me->in_frame;
7696 	} else {
7697 		in_frame = NULL;
7698 	}
7699 
7700 	err = init_out_frameinfo_defaults(pipe, &me->out_frame[0], 0);
7701 	if (err) {
7702 		IA_CSS_LEAVE_ERR_PRIVATE(err);
7703 		return err;
7704 	}
7705 	out_frame = &me->out_frame[0];
7706 
7707 	/* Construct vf_frame info (only in case we have VF) */
7708 	if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0]) {
7709 		if (mode == IA_CSS_CAPTURE_MODE_RAW || mode == IA_CSS_CAPTURE_MODE_BAYER) {
7710 			/* These modes don't support viewfinder output */
7711 			vf_frame = NULL;
7712 		} else {
7713 			init_vf_frameinfo_defaults(pipe, &me->vf_frame[0], 0);
7714 			vf_frame = &me->vf_frame[0];
7715 		}
7716 	} else {
7717 		vf_frame = NULL;
7718 	}
7719 
7720 	copy_binary       = &pipe->pipe_settings.capture.copy_binary;
7721 	num_primary_stage = pipe->pipe_settings.capture.num_primary_stage;
7722 	if ((num_primary_stage == 0) && (mode == IA_CSS_CAPTURE_MODE_PRIMARY)) {
7723 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
7724 		return -EINVAL;
7725 	}
7726 
7727 	for (i = 0; i < num_primary_stage; i++)
7728 		primary_binary[i] = &pipe->pipe_settings.capture.primary_binary[i];
7729 
7730 	vf_pp_binary      = &pipe->pipe_settings.capture.vf_pp_binary;
7731 	pre_isp_binary    = &pipe->pipe_settings.capture.pre_isp_binary;
7732 	anr_gdc_binary    = &pipe->pipe_settings.capture.anr_gdc_binary;
7733 	post_isp_binary   = &pipe->pipe_settings.capture.post_isp_binary;
7734 	capture_pp_binary = &pipe->pipe_settings.capture.capture_pp_binary;
7735 	yuv_scaler_binary = pipe->pipe_settings.capture.yuv_scaler_binary;
7736 	num_yuv_scaler	  = pipe->pipe_settings.capture.num_yuv_scaler;
7737 	is_output_stage   = pipe->pipe_settings.capture.is_output_stage;
7738 	capture_ldc_binary = &pipe->pipe_settings.capture.capture_ldc_binary;
7739 
7740 	need_pp = (need_capture_pp(pipe) || pipe->output_stage) &&
7741 		    mode != IA_CSS_CAPTURE_MODE_RAW &&
7742 		    mode != IA_CSS_CAPTURE_MODE_BAYER;
7743 	need_yuv_pp = (yuv_scaler_binary && yuv_scaler_binary->info);
7744 	need_ldc = (capture_ldc_binary && capture_ldc_binary->info);
7745 
7746 	if (pipe->pipe_settings.capture.copy_binary.info) {
7747 		if (raw) {
7748 			ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
7749 #if defined(ISP2401)
7750 			if (!continuous) {
7751 				ia_css_pipe_get_generic_stage_desc(&stage_desc,
7752 								   copy_binary,
7753 								   out_frames,
7754 								   in_frame,
7755 								   NULL);
7756 			} else {
7757 				in_frame = pipe->stream->last_pipe->continuous_frames[0];
7758 				ia_css_pipe_get_generic_stage_desc(&stage_desc,
7759 								   copy_binary,
7760 								   out_frames,
7761 								   in_frame,
7762 								   NULL);
7763 			}
7764 #else
7765 			ia_css_pipe_get_generic_stage_desc(&stage_desc,
7766 							   copy_binary,
7767 							   out_frames,
7768 							   NULL, NULL);
7769 #endif
7770 		} else {
7771 			ia_css_pipe_util_set_output_frames(out_frames, 0,
7772 							   in_frame);
7773 			ia_css_pipe_get_generic_stage_desc(&stage_desc,
7774 							   copy_binary,
7775 							   out_frames,
7776 							   NULL, NULL);
7777 		}
7778 
7779 		err = ia_css_pipeline_create_and_add_stage(me,
7780 							   &stage_desc,
7781 							   &current_stage);
7782 		if (err) {
7783 			IA_CSS_LEAVE_ERR_PRIVATE(err);
7784 			return err;
7785 		}
7786 	} else if (pipe->stream->config.continuous) {
7787 		in_frame = pipe->stream->last_pipe->continuous_frames[0];
7788 	}
7789 
7790 	if (mode == IA_CSS_CAPTURE_MODE_PRIMARY) {
7791 		struct ia_css_frame *local_in_frame = NULL;
7792 		struct ia_css_frame *local_out_frame = NULL;
7793 
7794 		for (i = 0; i < num_primary_stage; i++) {
7795 			if (i == 0)
7796 				local_in_frame = in_frame;
7797 			else
7798 				local_in_frame = NULL;
7799 #ifndef ISP2401
7800 			if (!need_pp && (i == num_primary_stage - 1))
7801 #else
7802 			if (!need_pp && (i == num_primary_stage - 1) && !need_ldc)
7803 #endif
7804 				local_out_frame = out_frame;
7805 			else
7806 				local_out_frame = NULL;
7807 			ia_css_pipe_util_set_output_frames(out_frames, 0, local_out_frame);
7808 			/*
7809 			    * WARNING: The #if def flag has been added below as a
7810 			    * temporary solution to solve the problem of enabling the
7811 			    * view finder in a single binary in a capture flow. The
7812 			    * vf-pp stage has been removed from Skycam in the solution
7813 			    * provided. The vf-pp stage should be re-introduced when
7814 			    * required. This  * should not be considered as a clean solution.
7815 			    * Proper investigation should be done to come up with the clean
7816 			    * solution.
7817 			    * */
7818 			ia_css_pipe_get_generic_stage_desc(&stage_desc,
7819 							   primary_binary[i],
7820 							   out_frames,
7821 							   local_in_frame,
7822 							   NULL);
7823 			err = ia_css_pipeline_create_and_add_stage(me,
7824 								   &stage_desc,
7825 								   &current_stage);
7826 			if (err) {
7827 				IA_CSS_LEAVE_ERR_PRIVATE(err);
7828 				return err;
7829 			}
7830 		}
7831 		/* If we use copy iso primary,
7832 		    the input must be yuv iso raw */
7833 		current_stage->args.copy_vf =
7834 		    primary_binary[0]->info->sp.pipeline.mode ==
7835 		    IA_CSS_BINARY_MODE_COPY;
7836 		current_stage->args.copy_output = current_stage->args.copy_vf;
7837 	} else if (mode == IA_CSS_CAPTURE_MODE_ADVANCED ||
7838 		    mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT) {
7839 		ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
7840 		ia_css_pipe_get_generic_stage_desc(&stage_desc, pre_isp_binary,
7841 						   out_frames, in_frame, NULL);
7842 		err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
7843 							   NULL);
7844 		if (err) {
7845 			IA_CSS_LEAVE_ERR_PRIVATE(err);
7846 			return err;
7847 		}
7848 		ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
7849 		ia_css_pipe_get_generic_stage_desc(&stage_desc, anr_gdc_binary,
7850 						   out_frames, NULL, NULL);
7851 		err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
7852 							   NULL);
7853 		if (err) {
7854 			IA_CSS_LEAVE_ERR_PRIVATE(err);
7855 			return err;
7856 		}
7857 
7858 		if (need_pp) {
7859 			ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
7860 			ia_css_pipe_get_generic_stage_desc(&stage_desc,
7861 							   post_isp_binary,
7862 							   out_frames,
7863 							   NULL, NULL);
7864 		} else {
7865 			ia_css_pipe_util_set_output_frames(out_frames, 0,
7866 							   out_frame);
7867 			ia_css_pipe_get_generic_stage_desc(&stage_desc,
7868 							   post_isp_binary,
7869 							   out_frames,
7870 							   NULL, NULL);
7871 		}
7872 
7873 		err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
7874 							   &current_stage);
7875 		if (err) {
7876 			IA_CSS_LEAVE_ERR_PRIVATE(err);
7877 			return err;
7878 		}
7879 	} else if (mode == IA_CSS_CAPTURE_MODE_BAYER) {
7880 		ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
7881 		ia_css_pipe_get_generic_stage_desc(&stage_desc, pre_isp_binary,
7882 						   out_frames, in_frame, NULL);
7883 		err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
7884 							   NULL);
7885 		if (err) {
7886 			IA_CSS_LEAVE_ERR_PRIVATE(err);
7887 			return err;
7888 		}
7889 	}
7890 
7891 #ifndef ISP2401
7892 	if (need_pp && current_stage) {
7893 		struct ia_css_frame *local_in_frame = NULL;
7894 
7895 		local_in_frame = current_stage->args.out_frame[0];
7896 
7897 		if (need_ldc) {
7898 			ia_css_pipe_util_set_output_frames(out_frames, 0, NULL);
7899 			ia_css_pipe_get_generic_stage_desc(&stage_desc,
7900 							   capture_ldc_binary,
7901 							   out_frames,
7902 							   local_in_frame,
7903 							   NULL);
7904 			err = ia_css_pipeline_create_and_add_stage(me,
7905 								   &stage_desc,
7906 								   &current_stage);
7907 			local_in_frame = current_stage->args.out_frame[0];
7908 		}
7909 		err = add_capture_pp_stage(pipe, me, local_in_frame,
7910 					   need_yuv_pp ? NULL : out_frame,
7911 #else
7912 	/* ldc and capture_pp not supported in same pipeline */
7913 	if (need_ldc && current_stage) {
7914 		in_frame = current_stage->args.out_frame[0];
7915 		ia_css_pipe_util_set_output_frames(out_frames, 0, out_frame);
7916 		ia_css_pipe_get_generic_stage_desc(&stage_desc, capture_ldc_binary,
7917 						   out_frames, in_frame, NULL);
7918 		err = ia_css_pipeline_create_and_add_stage(me, &stage_desc,
7919 							   NULL);
7920 	} else if (need_pp && current_stage) {
7921 		in_frame = current_stage->args.out_frame[0];
7922 		err = add_capture_pp_stage(pipe, me, in_frame,
7923 					   need_yuv_pp ? NULL : out_frame,
7924 #endif
7925 					   capture_pp_binary,
7926 					   &current_stage);
7927 		if (err) {
7928 			IA_CSS_LEAVE_ERR_PRIVATE(err);
7929 			return err;
7930 		}
7931 	}
7932 
7933 	if (need_yuv_pp && current_stage) {
7934 		struct ia_css_frame *tmp_in_frame = current_stage->args.out_frame[0];
7935 		struct ia_css_frame *tmp_out_frame = NULL;
7936 
7937 		for (i = 0; i < num_yuv_scaler; i++) {
7938 			if (is_output_stage[i])
7939 				tmp_out_frame = out_frame;
7940 			else
7941 				tmp_out_frame = NULL;
7942 
7943 			err = add_yuv_scaler_stage(pipe, me, tmp_in_frame,
7944 						   tmp_out_frame, NULL,
7945 						   &yuv_scaler_binary[i],
7946 						   &yuv_scaler_stage);
7947 			if (err) {
7948 				IA_CSS_LEAVE_ERR_PRIVATE(err);
7949 				return err;
7950 			}
7951 			/* we use output port 1 as internal output port */
7952 			tmp_in_frame = yuv_scaler_stage->args.out_frame[1];
7953 		}
7954 	}
7955 
7956 	/*
7957 	    * WARNING: The #if def flag has been added below as a
7958 	    * temporary solution to solve the problem of enabling the
7959 	    * view finder in a single binary in a capture flow. The vf-pp
7960 	    * stage has been removed from Skycam in the solution provided.
7961 	    * The vf-pp stage should be re-introduced when required. This
7962 	    * should not be considered as a clean solution. Proper
7963 	    * investigation should be done to come up with the clean solution.
7964 	    * */
7965 	if (mode != IA_CSS_CAPTURE_MODE_RAW &&
7966 	    mode != IA_CSS_CAPTURE_MODE_BAYER &&
7967 	    current_stage && vf_frame) {
7968 		in_frame = current_stage->args.out_vf_frame;
7969 		err = add_vf_pp_stage(pipe, in_frame, vf_frame, vf_pp_binary,
7970 				      &current_stage);
7971 		if (err) {
7972 			IA_CSS_LEAVE_ERR_PRIVATE(err);
7973 			return err;
7974 		}
7975 	}
7976 	ia_css_pipeline_finalize_stages(&pipe->pipeline, pipe->stream->config.continuous);
7977 
7978 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
7979 			    "create_host_regular_capture_pipeline() leave:\n");
7980 
7981 	return 0;
7982 }
7983 
7984 static int
7985 create_host_capture_pipeline(struct ia_css_pipe *pipe)
7986 {
7987 	int err = 0;
7988 
7989 	IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
7990 
7991 	if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY)
7992 		err = create_host_isyscopy_capture_pipeline(pipe);
7993 	else
7994 		err = create_host_regular_capture_pipeline(pipe);
7995 	if (err) {
7996 		IA_CSS_LEAVE_ERR_PRIVATE(err);
7997 		return err;
7998 	}
7999 
8000 	IA_CSS_LEAVE_ERR_PRIVATE(err);
8001 
8002 	return err;
8003 }
8004 
8005 static int capture_start(struct ia_css_pipe *pipe)
8006 {
8007 	struct ia_css_pipeline *me;
8008 
8009 	int err = 0;
8010 	enum sh_css_pipe_config_override copy_ovrd;
8011 
8012 	IA_CSS_ENTER_PRIVATE("pipe = %p", pipe);
8013 	if (!pipe) {
8014 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
8015 		return -EINVAL;
8016 	}
8017 
8018 	me = &pipe->pipeline;
8019 
8020 	if ((pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_RAW   ||
8021 	     pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER) &&
8022 	    (pipe->config.mode != IA_CSS_PIPE_MODE_COPY)) {
8023 		if (copy_on_sp(pipe)) {
8024 			err = start_copy_on_sp(pipe, &me->out_frame[0]);
8025 			IA_CSS_LEAVE_ERR_PRIVATE(err);
8026 			return err;
8027 		}
8028 	}
8029 
8030 #if !defined(ISP2401)
8031 	/* old isys: need to send_mipi_frames() in all pipe modes */
8032 	err = send_mipi_frames(pipe);
8033 	if (err) {
8034 		IA_CSS_LEAVE_ERR_PRIVATE(err);
8035 		return err;
8036 	}
8037 #elif defined(ISP2401)
8038 	if (pipe->config.mode != IA_CSS_PIPE_MODE_COPY) {
8039 		err = send_mipi_frames(pipe);
8040 		if (err) {
8041 			IA_CSS_LEAVE_ERR_PRIVATE(err);
8042 			return err;
8043 		}
8044 	}
8045 
8046 #endif
8047 
8048 	{
8049 		unsigned int thread_id;
8050 
8051 		ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
8052 		copy_ovrd = 1 << thread_id;
8053 	}
8054 	start_pipe(pipe, copy_ovrd, pipe->stream->config.mode);
8055 
8056 #if !defined(ISP2401)
8057 	/*
8058 	    * old isys: for IA_CSS_PIPE_MODE_COPY pipe, isys rx has to be configured,
8059 	    * which is currently done in start_binary(); but COPY pipe contains no binary,
8060 	    * and does not call start_binary(); so we need to configure the rx here.
8061 	    */
8062 	if (pipe->config.mode == IA_CSS_PIPE_MODE_COPY &&
8063 	    pipe->stream->reconfigure_css_rx) {
8064 		ia_css_isys_rx_configure(&pipe->stream->csi_rx_config,
8065 					 pipe->stream->config.mode);
8066 		pipe->stream->reconfigure_css_rx = false;
8067 	}
8068 #endif
8069 
8070 	IA_CSS_LEAVE_ERR_PRIVATE(err);
8071 	return err;
8072 }
8073 
8074 static int
8075 sh_css_pipe_get_output_frame_info(struct ia_css_pipe *pipe,
8076 				  struct ia_css_frame_info *info,
8077 				  unsigned int idx)
8078 {
8079 	assert(pipe);
8080 	assert(info);
8081 
8082 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
8083 			    "sh_css_pipe_get_output_frame_info() enter:\n");
8084 
8085 	*info = pipe->output_info[idx];
8086 	if (copy_on_sp(pipe) &&
8087 	    pipe->stream->config.input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8) {
8088 		ia_css_frame_info_init(
8089 		    info,
8090 		    JPEG_BYTES,
8091 		    1,
8092 		    IA_CSS_FRAME_FORMAT_BINARY_8,
8093 		    0);
8094 	} else if (info->format == IA_CSS_FRAME_FORMAT_RAW ||
8095 		   info->format == IA_CSS_FRAME_FORMAT_RAW_PACKED) {
8096 		info->raw_bit_depth =
8097 		ia_css_pipe_util_pipe_input_format_bpp(pipe);
8098 	}
8099 
8100 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
8101 			    "sh_css_pipe_get_output_frame_info() leave:\n");
8102 	return 0;
8103 }
8104 
8105 void
8106 ia_css_stream_send_input_frame(const struct ia_css_stream *stream,
8107 			       const unsigned short *data,
8108 			       unsigned int width,
8109 			       unsigned int height)
8110 {
8111 	assert(stream);
8112 
8113 	ia_css_inputfifo_send_input_frame(
8114 	    data, width, height,
8115 	    stream->config.channel_id,
8116 	    stream->config.input_config.format,
8117 	    stream->config.pixels_per_clock == 2);
8118 }
8119 
8120 void
8121 ia_css_stream_start_input_frame(const struct ia_css_stream *stream)
8122 {
8123 	assert(stream);
8124 
8125 	ia_css_inputfifo_start_frame(
8126 	    stream->config.channel_id,
8127 	    stream->config.input_config.format,
8128 	    stream->config.pixels_per_clock == 2);
8129 }
8130 
8131 void
8132 ia_css_stream_send_input_line(const struct ia_css_stream *stream,
8133 			      const unsigned short *data,
8134 			      unsigned int width,
8135 			      const unsigned short *data2,
8136 			      unsigned int width2)
8137 {
8138 	assert(stream);
8139 
8140 	ia_css_inputfifo_send_line(stream->config.channel_id,
8141 				   data, width, data2, width2);
8142 }
8143 
8144 void
8145 ia_css_stream_send_input_embedded_line(const struct ia_css_stream *stream,
8146 				       enum atomisp_input_format format,
8147 				       const unsigned short *data,
8148 				       unsigned int width)
8149 {
8150 	assert(stream);
8151 	if (!data || width == 0)
8152 		return;
8153 	ia_css_inputfifo_send_embedded_line(stream->config.channel_id,
8154 					    format, data, width);
8155 }
8156 
8157 void
8158 ia_css_stream_end_input_frame(const struct ia_css_stream *stream)
8159 {
8160 	assert(stream);
8161 
8162 	ia_css_inputfifo_end_frame(stream->config.channel_id);
8163 }
8164 
8165 static void
8166 append_firmware(struct ia_css_fw_info **l, struct ia_css_fw_info *firmware)
8167 {
8168 	IA_CSS_ENTER_PRIVATE("l = %p, firmware = %p", l, firmware);
8169 	if (!l) {
8170 		IA_CSS_ERROR("NULL fw_info");
8171 		IA_CSS_LEAVE_PRIVATE("");
8172 		return;
8173 	}
8174 	while (*l)
8175 		l = &(*l)->next;
8176 	*l = firmware;
8177 	/*firmware->next = NULL;*/ /* when multiple acc extensions are loaded, 'next' can be not NULL */
8178 	IA_CSS_LEAVE_PRIVATE("");
8179 }
8180 
8181 static void
8182 remove_firmware(struct ia_css_fw_info **l, struct ia_css_fw_info *firmware)
8183 {
8184 	assert(*l);
8185 	assert(firmware);
8186 	(void)l;
8187 	(void)firmware;
8188 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "remove_firmware() enter:\n");
8189 
8190 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "remove_firmware() leave:\n");
8191 	return; /* removing single and multiple firmware is handled in acc_unload_extension() */
8192 }
8193 
8194 static int upload_isp_code(struct ia_css_fw_info *firmware)
8195 {
8196 	ia_css_ptr binary;
8197 
8198 	if (!firmware) {
8199 		IA_CSS_ERROR("NULL input parameter");
8200 		return -EINVAL;
8201 	}
8202 	binary = firmware->info.isp.xmem_addr;
8203 
8204 	if (!binary) {
8205 		unsigned int size = firmware->blob.size;
8206 		const unsigned char *blob;
8207 		const unsigned char *binary_name;
8208 
8209 		binary_name =
8210 		    (const unsigned char *)(IA_CSS_EXT_ISP_PROG_NAME(
8211 						firmware));
8212 		blob = binary_name +
8213 			strlen((const char *)binary_name) +
8214 			1;
8215 		binary = sh_css_load_blob(blob, size);
8216 		firmware->info.isp.xmem_addr = binary;
8217 	}
8218 
8219 	if (!binary)
8220 		return -ENOMEM;
8221 	return 0;
8222 }
8223 
8224 static int
8225 acc_load_extension(struct ia_css_fw_info *firmware)
8226 {
8227 	int err;
8228 	struct ia_css_fw_info *hd = firmware;
8229 
8230 	while (hd) {
8231 		err = upload_isp_code(hd);
8232 		if (err)
8233 			return err;
8234 		hd = hd->next;
8235 	}
8236 
8237 	if (!firmware)
8238 		return -EINVAL;
8239 	firmware->loaded = true;
8240 	return 0;
8241 }
8242 
8243 static void
8244 acc_unload_extension(struct ia_css_fw_info *firmware)
8245 {
8246 	struct ia_css_fw_info *hd = firmware;
8247 	struct ia_css_fw_info *hdn = NULL;
8248 
8249 	if (!firmware) /* should not happen */
8250 		return;
8251 	/* unload and remove multiple firmwares */
8252 	while (hd) {
8253 		hdn = (hd->next) ? &(*hd->next) : NULL;
8254 		if (hd->info.isp.xmem_addr) {
8255 			hmm_free(hd->info.isp.xmem_addr);
8256 			hd->info.isp.xmem_addr = mmgr_NULL;
8257 		}
8258 		hd->isp_code = NULL;
8259 		hd->next = NULL;
8260 		hd = hdn;
8261 	}
8262 
8263 	firmware->loaded = false;
8264 }
8265 
8266 /* Load firmware for extension */
8267 static int
8268 ia_css_pipe_load_extension(struct ia_css_pipe *pipe,
8269 			   struct ia_css_fw_info *firmware)
8270 {
8271 	int err = 0;
8272 
8273 	IA_CSS_ENTER_PRIVATE("fw = %p pipe = %p", firmware, pipe);
8274 
8275 	if ((!firmware) || (!pipe)) {
8276 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
8277 		return -EINVAL;
8278 	}
8279 
8280 	if (firmware->info.isp.type == IA_CSS_ACC_OUTPUT)
8281 		append_firmware(&pipe->output_stage, firmware);
8282 	else if (firmware->info.isp.type == IA_CSS_ACC_VIEWFINDER)
8283 		append_firmware(&pipe->vf_stage, firmware);
8284 	err = acc_load_extension(firmware);
8285 
8286 	IA_CSS_LEAVE_ERR_PRIVATE(err);
8287 	return err;
8288 }
8289 
8290 /* Unload firmware for extension */
8291 static void
8292 ia_css_pipe_unload_extension(struct ia_css_pipe *pipe,
8293 			     struct ia_css_fw_info *firmware)
8294 {
8295 	IA_CSS_ENTER_PRIVATE("fw = %p pipe = %p", firmware, pipe);
8296 
8297 	if ((!firmware) || (!pipe)) {
8298 		IA_CSS_ERROR("NULL input parameters");
8299 		IA_CSS_LEAVE_PRIVATE("");
8300 		return;
8301 	}
8302 
8303 	if (firmware->info.isp.type == IA_CSS_ACC_OUTPUT)
8304 		remove_firmware(&pipe->output_stage, firmware);
8305 	else if (firmware->info.isp.type == IA_CSS_ACC_VIEWFINDER)
8306 		remove_firmware(&pipe->vf_stage, firmware);
8307 	acc_unload_extension(firmware);
8308 
8309 	IA_CSS_LEAVE_PRIVATE("");
8310 }
8311 
8312 bool
8313 ia_css_pipeline_uses_params(struct ia_css_pipeline *me)
8314 {
8315 	struct ia_css_pipeline_stage *stage;
8316 
8317 	assert(me);
8318 
8319 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8320 			    "ia_css_pipeline_uses_params() enter: me=%p\n", me);
8321 
8322 	for (stage = me->stages; stage; stage = stage->next)
8323 		if (stage->binary_info && stage->binary_info->enable.params) {
8324 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8325 					    "ia_css_pipeline_uses_params() leave: return_bool=true\n");
8326 			return true;
8327 		}
8328 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8329 			    "ia_css_pipeline_uses_params() leave: return_bool=false\n");
8330 	return false;
8331 }
8332 
8333 static int
8334 sh_css_pipeline_add_acc_stage(struct ia_css_pipeline *pipeline,
8335 			      const void *acc_fw)
8336 {
8337 	struct ia_css_fw_info *fw = (struct ia_css_fw_info *)acc_fw;
8338 	/* In QoS case, load_extension already called, so skipping */
8339 	int	err = 0;
8340 
8341 	if (!fw->loaded)
8342 		err = acc_load_extension(fw);
8343 
8344 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8345 			    "sh_css_pipeline_add_acc_stage() enter: pipeline=%p, acc_fw=%p\n",
8346 			    pipeline, acc_fw);
8347 
8348 	if (!err) {
8349 		struct ia_css_pipeline_stage_desc stage_desc;
8350 
8351 		ia_css_pipe_get_acc_stage_desc(&stage_desc, NULL, fw);
8352 		err = ia_css_pipeline_create_and_add_stage(pipeline,
8353 							   &stage_desc,
8354 							   NULL);
8355 	}
8356 
8357 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8358 			    "sh_css_pipeline_add_acc_stage() leave: return_err=%d\n", err);
8359 	return err;
8360 }
8361 
8362 /*
8363     * @brief Tag a specific frame in continuous capture.
8364     * Refer to "sh_css_internal.h" for details.
8365     */
8366 int ia_css_stream_capture_frame(struct ia_css_stream *stream,
8367 				unsigned int exp_id)
8368 {
8369 	struct sh_css_tag_descr tag_descr;
8370 	u32 encoded_tag_descr;
8371 	int err;
8372 
8373 	assert(stream);
8374 	IA_CSS_ENTER("exp_id=%d", exp_id);
8375 
8376 	/* Only continuous streams have a tagger */
8377 	if (exp_id == 0 || !stream->config.continuous) {
8378 		IA_CSS_LEAVE_ERR(-EINVAL);
8379 		return -EINVAL;
8380 	}
8381 
8382 	if (!sh_css_sp_is_running()) {
8383 		/* SP is not running. The queues are not valid */
8384 		IA_CSS_LEAVE_ERR(-EBUSY);
8385 		return -EBUSY;
8386 	}
8387 
8388 	/* Create the tag descriptor from the parameters */
8389 	sh_css_create_tag_descr(0, 0, 0, exp_id, &tag_descr);
8390 	/* Encode the tag descriptor into a 32-bit value */
8391 	encoded_tag_descr = sh_css_encode_tag_descr(&tag_descr);
8392 	/* Enqueue the encoded tag to the host2sp queue.
8393 	    * Note: The pipe and stage IDs for tag_cmd queue are hard-coded to 0
8394 	    * on both host and the SP side.
8395 	    * It is mainly because it is enough to have only one tag_cmd queue */
8396 	err = ia_css_bufq_enqueue_tag_cmd(encoded_tag_descr);
8397 
8398 	IA_CSS_LEAVE_ERR(err);
8399 	return err;
8400 }
8401 
8402 /*
8403     * @brief Configure the continuous capture.
8404     * Refer to "sh_css_internal.h" for details.
8405     */
8406 int ia_css_stream_capture(struct ia_css_stream *stream, int num_captures,
8407 			  unsigned int skip, int offset)
8408 {
8409 	struct sh_css_tag_descr tag_descr;
8410 	unsigned int encoded_tag_descr;
8411 	int return_err;
8412 
8413 	if (!stream)
8414 		return -EINVAL;
8415 
8416 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8417 			    "ia_css_stream_capture() enter: num_captures=%d, skip=%d, offset=%d\n",
8418 			    num_captures, skip, offset);
8419 
8420 	/* Check if the tag descriptor is valid */
8421 	if (num_captures < SH_CSS_MINIMUM_TAG_ID) {
8422 		ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8423 				    "ia_css_stream_capture() leave: return_err=%d\n",
8424 				    -EINVAL);
8425 		return -EINVAL;
8426 	}
8427 
8428 	/* Create the tag descriptor from the parameters */
8429 	sh_css_create_tag_descr(num_captures, skip, offset, 0, &tag_descr);
8430 
8431 	/* Encode the tag descriptor into a 32-bit value */
8432 	encoded_tag_descr = sh_css_encode_tag_descr(&tag_descr);
8433 
8434 	if (!sh_css_sp_is_running()) {
8435 		/* SP is not running. The queues are not valid */
8436 		ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8437 				    "ia_css_stream_capture() leaving:queues unavailable\n");
8438 		return -EBUSY;
8439 	}
8440 
8441 	/* Enqueue the encoded tag to the host2sp queue.
8442 	    * Note: The pipe and stage IDs for tag_cmd queue are hard-coded to 0
8443 	    * on both host and the SP side.
8444 	    * It is mainly because it is enough to have only one tag_cmd queue */
8445 	return_err = ia_css_bufq_enqueue_tag_cmd((uint32_t)encoded_tag_descr);
8446 
8447 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8448 			    "ia_css_stream_capture() leave: return_err=%d\n",
8449 			    return_err);
8450 
8451 	return return_err;
8452 }
8453 
8454 void ia_css_stream_request_flash(struct ia_css_stream *stream)
8455 {
8456 	(void)stream;
8457 
8458 	assert(stream);
8459 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8460 			    "ia_css_stream_request_flash() enter: void\n");
8461 
8462 #ifndef ISP2401
8463 	sh_css_write_host2sp_command(host2sp_cmd_start_flash);
8464 #else
8465 	if (sh_css_sp_is_running()) {
8466 		if (!sh_css_write_host2sp_command(host2sp_cmd_start_flash)) {
8467 			IA_CSS_ERROR("Call to 'sh-css_write_host2sp_command()' failed");
8468 			ia_css_debug_dump_sp_sw_debug_info();
8469 			ia_css_debug_dump_debug_info(NULL);
8470 		}
8471 	} else {
8472 		IA_CSS_LOG("SP is not running!");
8473 	}
8474 
8475 #endif
8476 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8477 			    "ia_css_stream_request_flash() leave: return_void\n");
8478 }
8479 
8480 static void
8481 sh_css_init_host_sp_control_vars(void)
8482 {
8483 	const struct ia_css_fw_info *fw;
8484 	unsigned int HIVE_ADDR_ia_css_ispctrl_sp_isp_started;
8485 
8486 	unsigned int HIVE_ADDR_host_sp_queues_initialized;
8487 	unsigned int HIVE_ADDR_sp_sleep_mode;
8488 	unsigned int HIVE_ADDR_ia_css_dmaproxy_sp_invalidate_tlb;
8489 #ifndef ISP2401
8490 	unsigned int HIVE_ADDR_sp_stop_copy_preview;
8491 #endif
8492 	unsigned int HIVE_ADDR_host_sp_com;
8493 	unsigned int o = offsetof(struct host_sp_communication, host2sp_command)
8494 			    / sizeof(int);
8495 
8496 	unsigned int i;
8497 
8498 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
8499 			    "sh_css_init_host_sp_control_vars() enter: void\n");
8500 
8501 	fw = &sh_css_sp_fw;
8502 	HIVE_ADDR_ia_css_ispctrl_sp_isp_started = fw->info.sp.isp_started;
8503 
8504 	HIVE_ADDR_host_sp_queues_initialized =
8505 	    fw->info.sp.host_sp_queues_initialized;
8506 	HIVE_ADDR_sp_sleep_mode = fw->info.sp.sleep_mode;
8507 	HIVE_ADDR_ia_css_dmaproxy_sp_invalidate_tlb = fw->info.sp.invalidate_tlb;
8508 #ifndef ISP2401
8509 	HIVE_ADDR_sp_stop_copy_preview = fw->info.sp.stop_copy_preview;
8510 #endif
8511 	HIVE_ADDR_host_sp_com = fw->info.sp.host_sp_com;
8512 
8513 	(void)HIVE_ADDR_ia_css_ispctrl_sp_isp_started; /* Suppres warnings in CRUN */
8514 
8515 	(void)HIVE_ADDR_sp_sleep_mode;
8516 	(void)HIVE_ADDR_ia_css_dmaproxy_sp_invalidate_tlb;
8517 #ifndef ISP2401
8518 	(void)HIVE_ADDR_sp_stop_copy_preview;
8519 #endif
8520 	(void)HIVE_ADDR_host_sp_com;
8521 
8522 	sp_dmem_store_uint32(SP0_ID,
8523 			     (unsigned int)sp_address_of(ia_css_ispctrl_sp_isp_started),
8524 			     (uint32_t)(0));
8525 
8526 	sp_dmem_store_uint32(SP0_ID,
8527 			     (unsigned int)sp_address_of(host_sp_queues_initialized),
8528 			     (uint32_t)(0));
8529 	sp_dmem_store_uint32(SP0_ID,
8530 			     (unsigned int)sp_address_of(sp_sleep_mode),
8531 			     (uint32_t)(0));
8532 	sp_dmem_store_uint32(SP0_ID,
8533 			     (unsigned int)sp_address_of(ia_css_dmaproxy_sp_invalidate_tlb),
8534 			     (uint32_t)(false));
8535 #ifndef ISP2401
8536 	sp_dmem_store_uint32(SP0_ID,
8537 			     (unsigned int)sp_address_of(sp_stop_copy_preview),
8538 			     my_css.stop_copy_preview ? (uint32_t)(1) : (uint32_t)(0));
8539 #endif
8540 	store_sp_array_uint(host_sp_com, o, host2sp_cmd_ready);
8541 
8542 	for (i = 0; i < N_CSI_PORTS; i++) {
8543 		sh_css_update_host2sp_num_mipi_frames
8544 		(my_css.num_mipi_frames[i]);
8545 	}
8546 
8547 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
8548 			    "sh_css_init_host_sp_control_vars() leave: return_void\n");
8549 }
8550 
8551 /*
8552  * create the internal structures and fill in the configuration data
8553  */
8554 
8555 static const struct
8556 ia_css_pipe_config ia_css_pipe_default_config = DEFAULT_PIPE_CONFIG;
8557 
8558 void ia_css_pipe_config_defaults(struct ia_css_pipe_config *pipe_config)
8559 {
8560 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_pipe_config_defaults()\n");
8561 	memcpy(pipe_config, &ia_css_pipe_default_config, sizeof(*pipe_config));
8562 }
8563 
8564 void
8565 ia_css_pipe_extra_config_defaults(struct ia_css_pipe_extra_config *extra_config)
8566 {
8567 	if (!extra_config) {
8568 		IA_CSS_ERROR("NULL input parameter");
8569 		return;
8570 	}
8571 
8572 	extra_config->enable_raw_binning = false;
8573 	extra_config->enable_yuv_ds = false;
8574 	extra_config->enable_high_speed = false;
8575 	extra_config->enable_dvs_6axis = false;
8576 	extra_config->enable_reduced_pipe = false;
8577 	extra_config->disable_vf_pp = false;
8578 	extra_config->enable_fractional_ds = false;
8579 }
8580 
8581 void ia_css_stream_config_defaults(struct ia_css_stream_config *stream_config)
8582 {
8583 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_config_defaults()\n");
8584 	assert(stream_config);
8585 	memset(stream_config, 0, sizeof(*stream_config));
8586 	stream_config->online = true;
8587 	stream_config->left_padding = -1;
8588 	stream_config->pixels_per_clock = 1;
8589 	/* temporary default value for backwards compatibility.
8590 	    * This field used to be hardcoded within CSS but this has now
8591 	    * been moved to the stream_config struct. */
8592 	stream_config->source.port.rxcount = 0x04040404;
8593 }
8594 
8595 static int
8596 ia_css_acc_pipe_create(struct ia_css_pipe *pipe)
8597 {
8598 	int err = 0;
8599 
8600 	if (!pipe) {
8601 		IA_CSS_ERROR("NULL input parameter");
8602 		return -EINVAL;
8603 	}
8604 
8605 	/* There is not meaning for num_execs = 0 semantically. Run atleast once. */
8606 	if (pipe->config.acc_num_execs == 0)
8607 		pipe->config.acc_num_execs = 1;
8608 
8609 	if (pipe->config.acc_extension)
8610 		err = ia_css_pipe_load_extension(pipe, pipe->config.acc_extension);
8611 
8612 	return err;
8613 }
8614 
8615 int ia_css_pipe_create(const struct ia_css_pipe_config *config,
8616 		       struct ia_css_pipe **pipe)
8617 {
8618 	int err = 0;
8619 
8620 	IA_CSS_ENTER_PRIVATE("config = %p, pipe = %p", config, pipe);
8621 
8622 	if (!config || !pipe) {
8623 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
8624 		return -EINVAL;
8625 	}
8626 
8627 	err = ia_css_pipe_create_extra(config, NULL, pipe);
8628 
8629 	if (err == 0)
8630 		IA_CSS_LOG("pipe created successfully = %p", *pipe);
8631 
8632 	IA_CSS_LEAVE_ERR_PRIVATE(err);
8633 
8634 	return err;
8635 }
8636 
8637 int
8638 ia_css_pipe_create_extra(const struct ia_css_pipe_config *config,
8639 			 const struct ia_css_pipe_extra_config *extra_config,
8640 			 struct ia_css_pipe **pipe)
8641 {
8642 	int err = -EINVAL;
8643 	struct ia_css_pipe *internal_pipe = NULL;
8644 	unsigned int i;
8645 
8646 	IA_CSS_ENTER_PRIVATE("config = %p, extra_config = %p and pipe = %p", config, extra_config, pipe);
8647 
8648 	/* do not allow to create more than the maximum limit */
8649 	if (my_css.pipe_counter >= IA_CSS_PIPELINE_NUM_MAX) {
8650 		IA_CSS_LEAVE_ERR_PRIVATE(-ENOSPC);
8651 		return -EINVAL;
8652 	}
8653 
8654 	if ((!pipe) || (!config)) {
8655 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
8656 		return -EINVAL;
8657 	}
8658 
8659 	ia_css_debug_dump_pipe_config(config);
8660 	ia_css_debug_dump_pipe_extra_config(extra_config);
8661 
8662 	err = create_pipe(config->mode, &internal_pipe, false);
8663 	if (err) {
8664 		IA_CSS_LEAVE_ERR_PRIVATE(err);
8665 		return err;
8666 	}
8667 
8668 	/* now we have a pipe structure to fill */
8669 	internal_pipe->config = *config;
8670 	if (extra_config)
8671 		internal_pipe->extra_config = *extra_config;
8672 	else
8673 		ia_css_pipe_extra_config_defaults(&internal_pipe->extra_config);
8674 
8675 	if (config->mode == IA_CSS_PIPE_MODE_ACC) {
8676 		/* Temporary hack to migrate acceleration to CSS 2.0.
8677 		    * In the future the code for all pipe types should be
8678 		    * unified. */
8679 		*pipe = internal_pipe;
8680 		if (!internal_pipe->config.acc_extension &&
8681 		    internal_pipe->config.num_acc_stages ==
8682 		    0) { /* if no acc binary and no standalone stage */
8683 			*pipe = NULL;
8684 			IA_CSS_LEAVE_ERR_PRIVATE(0);
8685 			return 0;
8686 		}
8687 		return ia_css_acc_pipe_create(internal_pipe);
8688 	}
8689 
8690 	/* Use config value when dvs_frame_delay setting equal to 2, otherwise always 1 by default */
8691 	if (internal_pipe->config.dvs_frame_delay == IA_CSS_FRAME_DELAY_2)
8692 		internal_pipe->dvs_frame_delay = 2;
8693 	else
8694 		internal_pipe->dvs_frame_delay = 1;
8695 
8696 	/* we still keep enable_raw_binning for backward compatibility, for any new
8697 	    fractional bayer downscaling, we should use bayer_ds_out_res. if both are
8698 	    specified, bayer_ds_out_res will take precedence.if none is specified, we
8699 	    set bayer_ds_out_res equal to IF output resolution(IF may do cropping on
8700 	    sensor output) or use default decimation factor 1. */
8701 	if (internal_pipe->extra_config.enable_raw_binning &&
8702 	    internal_pipe->config.bayer_ds_out_res.width) {
8703 		/* fill some code here, if no code is needed, please remove it during integration */
8704 	}
8705 
8706 	/* YUV downscaling */
8707 	if ((internal_pipe->config.vf_pp_in_res.width ||
8708 	     internal_pipe->config.capt_pp_in_res.width)) {
8709 		enum ia_css_frame_format format;
8710 
8711 		if (internal_pipe->config.vf_pp_in_res.width) {
8712 			format = IA_CSS_FRAME_FORMAT_YUV_LINE;
8713 			ia_css_frame_info_init(
8714 			    &internal_pipe->vf_yuv_ds_input_info,
8715 			    internal_pipe->config.vf_pp_in_res.width,
8716 			    internal_pipe->config.vf_pp_in_res.height,
8717 			    format, 0);
8718 		}
8719 		if (internal_pipe->config.capt_pp_in_res.width) {
8720 			format = IA_CSS_FRAME_FORMAT_YUV420;
8721 			ia_css_frame_info_init(
8722 			    &internal_pipe->out_yuv_ds_input_info,
8723 			    internal_pipe->config.capt_pp_in_res.width,
8724 			    internal_pipe->config.capt_pp_in_res.height,
8725 			    format, 0);
8726 		}
8727 	}
8728 	if (internal_pipe->config.vf_pp_in_res.width &&
8729 	    internal_pipe->config.mode == IA_CSS_PIPE_MODE_PREVIEW) {
8730 		ia_css_frame_info_init(
8731 		    &internal_pipe->vf_yuv_ds_input_info,
8732 		    internal_pipe->config.vf_pp_in_res.width,
8733 		    internal_pipe->config.vf_pp_in_res.height,
8734 		    IA_CSS_FRAME_FORMAT_YUV_LINE, 0);
8735 	}
8736 	/* handle bayer downscaling output info */
8737 	if (internal_pipe->config.bayer_ds_out_res.width) {
8738 		ia_css_frame_info_init(
8739 		    &internal_pipe->bds_output_info,
8740 		    internal_pipe->config.bayer_ds_out_res.width,
8741 		    internal_pipe->config.bayer_ds_out_res.height,
8742 		    IA_CSS_FRAME_FORMAT_RAW, 0);
8743 	}
8744 
8745 	/* handle output info, assume always needed */
8746 	for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
8747 		if (internal_pipe->config.output_info[i].res.width) {
8748 			err = sh_css_pipe_configure_output(
8749 				    internal_pipe,
8750 				    internal_pipe->config.output_info[i].res.width,
8751 				    internal_pipe->config.output_info[i].res.height,
8752 				    internal_pipe->config.output_info[i].padded_width,
8753 				    internal_pipe->config.output_info[i].format,
8754 				    i);
8755 			if (err) {
8756 				IA_CSS_LEAVE_ERR_PRIVATE(err);
8757 				kvfree(internal_pipe);
8758 				internal_pipe = NULL;
8759 				return err;
8760 			}
8761 		}
8762 
8763 		/* handle vf output info, when configured */
8764 		internal_pipe->enable_viewfinder[i] =
8765 		    (internal_pipe->config.vf_output_info[i].res.width != 0);
8766 		if (internal_pipe->config.vf_output_info[i].res.width) {
8767 			err = sh_css_pipe_configure_viewfinder(
8768 				    internal_pipe,
8769 				    internal_pipe->config.vf_output_info[i].res.width,
8770 				    internal_pipe->config.vf_output_info[i].res.height,
8771 				    internal_pipe->config.vf_output_info[i].padded_width,
8772 				    internal_pipe->config.vf_output_info[i].format,
8773 				    i);
8774 			if (err) {
8775 				IA_CSS_LEAVE_ERR_PRIVATE(err);
8776 				kvfree(internal_pipe);
8777 				internal_pipe = NULL;
8778 				return err;
8779 			}
8780 		}
8781 	}
8782 	if (internal_pipe->config.acc_extension) {
8783 		err = ia_css_pipe_load_extension(internal_pipe,
8784 						 internal_pipe->config.acc_extension);
8785 		if (err) {
8786 			IA_CSS_LEAVE_ERR_PRIVATE(err);
8787 			kvfree(internal_pipe);
8788 			return err;
8789 		}
8790 	}
8791 	/* set all info to zeroes first */
8792 	memset(&internal_pipe->info, 0, sizeof(internal_pipe->info));
8793 
8794 	/* all went well, return the pipe */
8795 	*pipe = internal_pipe;
8796 	IA_CSS_LEAVE_ERR_PRIVATE(0);
8797 	return 0;
8798 }
8799 
8800 int
8801 ia_css_pipe_get_info(const struct ia_css_pipe *pipe,
8802 		     struct ia_css_pipe_info *pipe_info)
8803 {
8804 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
8805 			    "ia_css_pipe_get_info()\n");
8806 	if (!pipe_info) {
8807 		ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR,
8808 				    "ia_css_pipe_get_info: pipe_info cannot be NULL\n");
8809 		return -EINVAL;
8810 	}
8811 	if (!pipe || !pipe->stream) {
8812 		ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR,
8813 				    "ia_css_pipe_get_info: ia_css_stream_create needs to be called before ia_css_[stream/pipe]_get_info\n");
8814 		return -EINVAL;
8815 	}
8816 	/* we succeeded return the info */
8817 	*pipe_info = pipe->info;
8818 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_pipe_get_info() leave\n");
8819 	return 0;
8820 }
8821 
8822 bool ia_css_pipe_has_dvs_stats(struct ia_css_pipe_info *pipe_info)
8823 {
8824 	unsigned int i;
8825 
8826 	if (pipe_info) {
8827 		for (i = 0; i < IA_CSS_DVS_STAT_NUM_OF_LEVELS; i++) {
8828 			if (pipe_info->grid_info.dvs_grid.dvs_stat_grid_info.grd_cfg[i].grd_start.enable)
8829 				return true;
8830 		}
8831 	}
8832 
8833 	return false;
8834 }
8835 
8836 int
8837 ia_css_pipe_override_frame_format(struct ia_css_pipe *pipe,
8838 				  int pin_index,
8839 				  enum ia_css_frame_format new_format)
8840 {
8841 	int err = 0;
8842 
8843 	IA_CSS_ENTER_PRIVATE("pipe = %p, pin_index = %d, new_formats = %d", pipe, pin_index, new_format);
8844 
8845 	if (!pipe) {
8846 		IA_CSS_ERROR("pipe is not set");
8847 		err = -EINVAL;
8848 		IA_CSS_LEAVE_ERR_PRIVATE(err);
8849 		return err;
8850 	}
8851 	if (0 != pin_index && 1 != pin_index) {
8852 		IA_CSS_ERROR("pin index is not valid");
8853 		err = -EINVAL;
8854 		IA_CSS_LEAVE_ERR_PRIVATE(err);
8855 		return err;
8856 	}
8857 	if (new_format != IA_CSS_FRAME_FORMAT_NV12_TILEY) {
8858 		IA_CSS_ERROR("new format is not valid");
8859 		err = -EINVAL;
8860 		IA_CSS_LEAVE_ERR_PRIVATE(err);
8861 		return err;
8862 	} else {
8863 		err = ia_css_pipe_check_format(pipe, new_format);
8864 		if (!err) {
8865 			if (pin_index == 0)
8866 				pipe->output_info[0].format = new_format;
8867 			else
8868 				pipe->vf_output_info[0].format = new_format;
8869 		}
8870 	}
8871 	IA_CSS_LEAVE_ERR_PRIVATE(err);
8872 	return err;
8873 }
8874 
8875 #if !defined(ISP2401)
8876 /* Configuration of INPUT_SYSTEM_VERSION_2401 is done on SP */
8877 static int
8878 ia_css_stream_configure_rx(struct ia_css_stream *stream)
8879 {
8880 	struct ia_css_input_port *config;
8881 
8882 	assert(stream);
8883 
8884 	config = &stream->config.source.port;
8885 	/* AM: this code is not reliable, especially for 2400 */
8886 	if (config->num_lanes == 1)
8887 		stream->csi_rx_config.mode = MONO_1L_1L_0L;
8888 	else if (config->num_lanes == 2)
8889 		stream->csi_rx_config.mode = MONO_2L_1L_0L;
8890 	else if (config->num_lanes == 3)
8891 		stream->csi_rx_config.mode = MONO_3L_1L_0L;
8892 	else if (config->num_lanes == 4)
8893 		stream->csi_rx_config.mode = MONO_4L_1L_0L;
8894 	else if (config->num_lanes != 0)
8895 		return -EINVAL;
8896 
8897 	if (config->port > MIPI_PORT2_ID)
8898 		return -EINVAL;
8899 	stream->csi_rx_config.port =
8900 	ia_css_isys_port_to_mipi_port(config->port);
8901 	stream->csi_rx_config.timeout    = config->timeout;
8902 	stream->csi_rx_config.initcount  = 0;
8903 	stream->csi_rx_config.synccount  = 0x28282828;
8904 	stream->csi_rx_config.rxcount    = config->rxcount;
8905 	if (config->compression.type == IA_CSS_CSI2_COMPRESSION_TYPE_NONE)
8906 		stream->csi_rx_config.comp = MIPI_PREDICTOR_NONE;
8907 	else
8908 		/* not implemented yet, requires extension of the rx_cfg_t
8909 		    * struct */
8910 		return -EINVAL;
8911 
8912 	stream->csi_rx_config.is_two_ppc = (stream->config.pixels_per_clock == 2);
8913 	stream->reconfigure_css_rx = true;
8914 	return 0;
8915 }
8916 #endif
8917 
8918 static struct ia_css_pipe *
8919 find_pipe(struct ia_css_pipe *pipes[], unsigned int num_pipes,
8920 	  enum ia_css_pipe_mode mode, bool copy_pipe)
8921 {
8922 	unsigned int i;
8923 
8924 	assert(pipes);
8925 	for (i = 0; i < num_pipes; i++) {
8926 		assert(pipes[i]);
8927 		if (pipes[i]->config.mode != mode)
8928 			continue;
8929 		if (copy_pipe && pipes[i]->mode != IA_CSS_PIPE_ID_COPY)
8930 			continue;
8931 		return pipes[i];
8932 	}
8933 	return NULL;
8934 }
8935 
8936 static int
8937 ia_css_acc_stream_create(struct ia_css_stream *stream)
8938 {
8939 	int i;
8940 	int err = 0;
8941 
8942 	IA_CSS_ENTER_PRIVATE("stream = %p", stream);
8943 
8944 	if (!stream) {
8945 		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
8946 		return -EINVAL;
8947 	}
8948 
8949 	for (i = 0;  i < stream->num_pipes; i++) {
8950 		struct ia_css_pipe *pipe = stream->pipes[i];
8951 
8952 		if (!pipe) {
8953 			IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
8954 			return -EINVAL;
8955 		}
8956 
8957 		pipe->stream = stream;
8958 	}
8959 
8960 	/* Map SP threads before doing anything. */
8961 	err = map_sp_threads(stream, true);
8962 	if (err) {
8963 		IA_CSS_LEAVE_ERR_PRIVATE(err);
8964 		return err;
8965 	}
8966 
8967 	for (i = 0;  i < stream->num_pipes; i++) {
8968 		struct ia_css_pipe *pipe = stream->pipes[i];
8969 
8970 		assert(pipe);
8971 		ia_css_pipe_map_queue(pipe, true);
8972 	}
8973 
8974 	err = create_host_pipeline_structure(stream);
8975 	if (err) {
8976 		IA_CSS_LEAVE_ERR_PRIVATE(err);
8977 		return err;
8978 	}
8979 
8980 	stream->started = false;
8981 
8982 	IA_CSS_LEAVE_ERR_PRIVATE(0);
8983 
8984 	return 0;
8985 }
8986 
8987 static int
8988 metadata_info_init(const struct ia_css_metadata_config *mdc,
8989 		   struct ia_css_metadata_info *md)
8990 {
8991 	/* Either both width and height should be set or neither */
8992 	if ((mdc->resolution.height > 0) ^ (mdc->resolution.width > 0))
8993 		return -EINVAL;
8994 
8995 	md->resolution = mdc->resolution;
8996 	/* We round up the stride to a multiple of the width
8997 	    * of the port going to DDR, this is a HW requirements (DMA). */
8998 	md->stride = CEIL_MUL(mdc->resolution.width, HIVE_ISP_DDR_WORD_BYTES);
8999 	md->size = mdc->resolution.height * md->stride;
9000 	return 0;
9001 }
9002 
9003 /* ISP2401 */
9004 static int check_pipe_resolutions(const struct ia_css_pipe *pipe)
9005 {
9006 	int err = 0;
9007 
9008 	IA_CSS_ENTER_PRIVATE("");
9009 
9010 	if (!pipe || !pipe->stream) {
9011 		IA_CSS_ERROR("null arguments");
9012 		err = -EINVAL;
9013 		goto EXIT;
9014 	}
9015 
9016 	if (ia_css_util_check_res(pipe->config.input_effective_res.width,
9017 				  pipe->config.input_effective_res.height) != 0) {
9018 		IA_CSS_ERROR("effective resolution not supported");
9019 		err = -EINVAL;
9020 		goto EXIT;
9021 	}
9022 	if (!ia_css_util_resolution_is_zero(
9023 		pipe->stream->config.input_config.input_res)) {
9024 		if (!ia_css_util_res_leq(pipe->config.input_effective_res,
9025 					 pipe->stream->config.input_config.input_res)) {
9026 			IA_CSS_ERROR("effective resolution is larger than input resolution");
9027 			err = -EINVAL;
9028 			goto EXIT;
9029 		}
9030 	}
9031 	if (!ia_css_util_resolution_is_even(pipe->config.output_info[0].res)) {
9032 		IA_CSS_ERROR("output resolution must be even");
9033 		err = -EINVAL;
9034 		goto EXIT;
9035 	}
9036 	if (!ia_css_util_resolution_is_even(pipe->config.vf_output_info[0].res)) {
9037 		IA_CSS_ERROR("VF resolution must be even");
9038 		err = -EINVAL;
9039 		goto EXIT;
9040 	}
9041 EXIT:
9042 	IA_CSS_LEAVE_ERR_PRIVATE(err);
9043 	return err;
9044 }
9045 
9046 int
9047 ia_css_stream_create(const struct ia_css_stream_config *stream_config,
9048 		     int num_pipes,
9049 		     struct ia_css_pipe *pipes[],
9050 		     struct ia_css_stream **stream)
9051 {
9052 	struct ia_css_pipe *curr_pipe;
9053 	struct ia_css_stream *curr_stream = NULL;
9054 	bool spcopyonly;
9055 	bool sensor_binning_changed;
9056 	int i, j;
9057 	int err = -EINVAL;
9058 	struct ia_css_metadata_info md_info;
9059 	struct ia_css_resolution effective_res;
9060 #ifdef ISP2401
9061 	bool aspect_ratio_crop_enabled = false;
9062 #endif
9063 
9064 	IA_CSS_ENTER("num_pipes=%d", num_pipes);
9065 	ia_css_debug_dump_stream_config(stream_config, num_pipes);
9066 
9067 	/* some checks */
9068 	if (num_pipes == 0 ||
9069 	    !stream ||
9070 	    !pipes) {
9071 		err = -EINVAL;
9072 		IA_CSS_LEAVE_ERR(err);
9073 		return err;
9074 	}
9075 
9076 #if !defined(ISP2401)
9077 	/* We don't support metadata for JPEG stream, since they both use str2mem */
9078 	if (stream_config->input_config.format == ATOMISP_INPUT_FORMAT_BINARY_8 &&
9079 	    stream_config->metadata_config.resolution.height > 0) {
9080 		err = -EINVAL;
9081 		IA_CSS_LEAVE_ERR(err);
9082 		return err;
9083 	}
9084 #endif
9085 
9086 #ifdef ISP2401
9087 	if (stream_config->online && stream_config->pack_raw_pixels) {
9088 		IA_CSS_LOG("online and pack raw is invalid on input system 2401");
9089 		err = -EINVAL;
9090 		IA_CSS_LEAVE_ERR(err);
9091 		return err;
9092 	}
9093 #endif
9094 
9095 	ia_css_debug_pipe_graph_dump_stream_config(stream_config);
9096 
9097 	/* check if mipi size specified */
9098 	if (stream_config->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR)
9099 #ifdef ISP2401
9100 		if (!stream_config->online)
9101 #endif
9102 		{
9103 			unsigned int port = (unsigned int)stream_config->source.port.port;
9104 
9105 			if (port >= N_MIPI_PORT_ID) {
9106 				err = -EINVAL;
9107 				IA_CSS_LEAVE_ERR(err);
9108 				return err;
9109 			}
9110 
9111 			if (my_css.size_mem_words != 0) {
9112 				my_css.mipi_frame_size[port] = my_css.size_mem_words;
9113 			} else if (stream_config->mipi_buffer_config.size_mem_words != 0) {
9114 				my_css.mipi_frame_size[port] = stream_config->mipi_buffer_config.size_mem_words;
9115 			} else {
9116 				ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
9117 						    "ia_css_stream_create() exit: error, need to set mipi frame size.\n");
9118 				assert(stream_config->mipi_buffer_config.size_mem_words != 0);
9119 				err = -EINVAL;
9120 				IA_CSS_LEAVE_ERR(err);
9121 				return err;
9122 			}
9123 
9124 			if (my_css.size_mem_words != 0) {
9125 				my_css.num_mipi_frames[port] =
9126 				    2; /* Temp change: Default for backwards compatibility. */
9127 			} else if (stream_config->mipi_buffer_config.nof_mipi_buffers != 0) {
9128 				my_css.num_mipi_frames[port] =
9129 				    stream_config->mipi_buffer_config.nof_mipi_buffers;
9130 			} else {
9131 				ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
9132 						    "ia_css_stream_create() exit: error, need to set number of mipi frames.\n");
9133 				assert(stream_config->mipi_buffer_config.nof_mipi_buffers != 0);
9134 				err = -EINVAL;
9135 				IA_CSS_LEAVE_ERR(err);
9136 				return err;
9137 			}
9138 		}
9139 
9140 	/* Currently we only supported metadata up to a certain size. */
9141 	err = metadata_info_init(&stream_config->metadata_config, &md_info);
9142 	if (err) {
9143 		IA_CSS_LEAVE_ERR(err);
9144 		return err;
9145 	}
9146 
9147 	/* allocate the stream instance */
9148 	curr_stream = kzalloc(sizeof(struct ia_css_stream), GFP_KERNEL);
9149 	if (!curr_stream) {
9150 		err = -ENOMEM;
9151 		IA_CSS_LEAVE_ERR(err);
9152 		return err;
9153 	}
9154 	/* default all to 0 */
9155 	curr_stream->info.metadata_info = md_info;
9156 
9157 	/* allocate pipes */
9158 	curr_stream->num_pipes = num_pipes;
9159 	curr_stream->pipes = kcalloc(num_pipes, sizeof(struct ia_css_pipe *), GFP_KERNEL);
9160 	if (!curr_stream->pipes) {
9161 		curr_stream->num_pipes = 0;
9162 		kfree(curr_stream);
9163 		curr_stream = NULL;
9164 		err = -ENOMEM;
9165 		IA_CSS_LEAVE_ERR(err);
9166 		return err;
9167 	}
9168 	/* store pipes */
9169 	spcopyonly = (num_pipes == 1) && (pipes[0]->config.mode == IA_CSS_PIPE_MODE_COPY);
9170 	for (i = 0; i < num_pipes; i++)
9171 		curr_stream->pipes[i] = pipes[i];
9172 	curr_stream->last_pipe = curr_stream->pipes[0];
9173 	/* take over stream config */
9174 	curr_stream->config = *stream_config;
9175 
9176 #if defined(ISP2401)
9177 	if (stream_config->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR &&
9178 	    stream_config->online)
9179 		curr_stream->config.online = false;
9180 #endif
9181 
9182 #ifdef ISP2401
9183 	if (curr_stream->config.online) {
9184 		curr_stream->config.source.port.num_lanes =
9185 		    stream_config->source.port.num_lanes;
9186 		curr_stream->config.mode =  IA_CSS_INPUT_MODE_BUFFERED_SENSOR;
9187 	}
9188 #endif
9189 	/* in case driver doesn't configure init number of raw buffers, configure it here */
9190 	if (curr_stream->config.target_num_cont_raw_buf == 0)
9191 		curr_stream->config.target_num_cont_raw_buf = NUM_CONTINUOUS_FRAMES;
9192 	if (curr_stream->config.init_num_cont_raw_buf == 0)
9193 		curr_stream->config.init_num_cont_raw_buf = curr_stream->config.target_num_cont_raw_buf;
9194 
9195 	/* Enable locking & unlocking of buffers in RAW buffer pool */
9196 	if (curr_stream->config.ia_css_enable_raw_buffer_locking)
9197 		sh_css_sp_configure_enable_raw_pool_locking(
9198 		    curr_stream->config.lock_all);
9199 
9200 	/* copy mode specific stuff */
9201 	switch (curr_stream->config.mode) {
9202 	case IA_CSS_INPUT_MODE_SENSOR:
9203 	case IA_CSS_INPUT_MODE_BUFFERED_SENSOR:
9204 #if !defined(ISP2401)
9205 		ia_css_stream_configure_rx(curr_stream);
9206 #endif
9207 		break;
9208 	case IA_CSS_INPUT_MODE_TPG:
9209 #if !defined(ISP2401)
9210 		IA_CSS_LOG("tpg_configuration: x_mask=%d, y_mask=%d, x_delta=%d, y_delta=%d, xy_mask=%d",
9211 			   curr_stream->config.source.tpg.x_mask,
9212 			   curr_stream->config.source.tpg.y_mask,
9213 			   curr_stream->config.source.tpg.x_delta,
9214 			   curr_stream->config.source.tpg.y_delta,
9215 			   curr_stream->config.source.tpg.xy_mask);
9216 
9217 		sh_css_sp_configure_tpg(
9218 		    curr_stream->config.source.tpg.x_mask,
9219 		    curr_stream->config.source.tpg.y_mask,
9220 		    curr_stream->config.source.tpg.x_delta,
9221 		    curr_stream->config.source.tpg.y_delta,
9222 		    curr_stream->config.source.tpg.xy_mask);
9223 #endif
9224 		break;
9225 	case IA_CSS_INPUT_MODE_PRBS:
9226 #if !defined(ISP2401)
9227 		IA_CSS_LOG("mode prbs");
9228 		sh_css_sp_configure_prbs(curr_stream->config.source.prbs.seed);
9229 #endif
9230 		break;
9231 	case IA_CSS_INPUT_MODE_MEMORY:
9232 		IA_CSS_LOG("mode memory");
9233 		curr_stream->reconfigure_css_rx = false;
9234 		break;
9235 	default:
9236 		IA_CSS_LOG("mode sensor/default");
9237 	}
9238 
9239 #ifdef ISP2401
9240 	err = aspect_ratio_crop_init(curr_stream, pipes,
9241 				     &aspect_ratio_crop_enabled);
9242 	if (err) {
9243 		IA_CSS_LEAVE_ERR(err);
9244 		goto ERR;
9245 	}
9246 #endif
9247 	for (i = 0; i < num_pipes; i++) {
9248 		struct ia_css_resolution effective_res;
9249 
9250 		curr_pipe = pipes[i];
9251 		/* set current stream */
9252 		curr_pipe->stream = curr_stream;
9253 		/* take over effective info */
9254 
9255 		effective_res = curr_pipe->config.input_effective_res;
9256 		if (effective_res.height == 0 || effective_res.width == 0) {
9257 			effective_res = curr_pipe->stream->config.input_config.effective_res;
9258 
9259 #if defined(ISP2401)
9260 			/* The aspect ratio cropping is currently only
9261 			    * supported on the new input system. */
9262 			if (aspect_ratio_crop_check(aspect_ratio_crop_enabled, curr_pipe)) {
9263 				struct ia_css_resolution crop_res;
9264 
9265 				err = aspect_ratio_crop(curr_pipe, &crop_res);
9266 				if (!err) {
9267 					effective_res = crop_res;
9268 				} else {
9269 					/* in case of error fallback to default
9270 					    * effective resolution from driver. */
9271 					IA_CSS_LOG("aspect_ratio_crop() failed with err(%d)", err);
9272 				}
9273 			}
9274 #endif
9275 			curr_pipe->config.input_effective_res = effective_res;
9276 		}
9277 		IA_CSS_LOG("effective_res=%dx%d",
9278 			   effective_res.width,
9279 			   effective_res.height);
9280 	}
9281 
9282 	if (IS_ISP2401) {
9283 		for (i = 0; i < num_pipes; i++) {
9284 			if (pipes[i]->config.mode != IA_CSS_PIPE_MODE_ACC &&
9285 			    pipes[i]->config.mode != IA_CSS_PIPE_MODE_COPY) {
9286 				err = check_pipe_resolutions(pipes[i]);
9287 				if (err)
9288 					goto ERR;
9289 			}
9290 		}
9291 	}
9292 
9293 	err = ia_css_stream_isp_parameters_init(curr_stream);
9294 	if (err)
9295 		goto ERR;
9296 	IA_CSS_LOG("isp_params_configs: %p", curr_stream->isp_params_configs);
9297 
9298 	if (num_pipes == 1 && pipes[0]->config.mode == IA_CSS_PIPE_MODE_ACC) {
9299 		*stream = curr_stream;
9300 		err = ia_css_acc_stream_create(curr_stream);
9301 		goto ERR;
9302 	}
9303 	/* sensor binning */
9304 	if (!spcopyonly) {
9305 		sensor_binning_changed =
9306 		    sh_css_params_set_binning_factor(curr_stream,
9307 						     curr_stream->config.sensor_binning_factor);
9308 	} else {
9309 		sensor_binning_changed = false;
9310 	}
9311 
9312 	IA_CSS_LOG("sensor_binning=%d, changed=%d",
9313 		   curr_stream->config.sensor_binning_factor, sensor_binning_changed);
9314 	/* loop over pipes */
9315 	IA_CSS_LOG("num_pipes=%d", num_pipes);
9316 	curr_stream->cont_capt = false;
9317 	/* Temporary hack: we give the preview pipe a reference to the capture
9318 	    * pipe in continuous capture mode. */
9319 	if (curr_stream->config.continuous) {
9320 		/* Search for the preview pipe and create the copy pipe */
9321 		struct ia_css_pipe *preview_pipe;
9322 		struct ia_css_pipe *video_pipe;
9323 		struct ia_css_pipe *acc_pipe;
9324 		struct ia_css_pipe *capture_pipe = NULL;
9325 		struct ia_css_pipe *copy_pipe = NULL;
9326 
9327 		if (num_pipes >= 2) {
9328 			curr_stream->cont_capt = true;
9329 			curr_stream->disable_cont_vf = curr_stream->config.disable_cont_viewfinder;
9330 
9331 			if (!IS_ISP2401)
9332 				curr_stream->stop_copy_preview = my_css.stop_copy_preview;
9333 		}
9334 
9335 		/* Create copy pipe here, since it may not be exposed to the driver */
9336 		preview_pipe = find_pipe(pipes, num_pipes,
9337 					 IA_CSS_PIPE_MODE_PREVIEW, false);
9338 		video_pipe = find_pipe(pipes, num_pipes,
9339 				       IA_CSS_PIPE_MODE_VIDEO, false);
9340 		acc_pipe = find_pipe(pipes, num_pipes, IA_CSS_PIPE_MODE_ACC,
9341 				     false);
9342 		if (acc_pipe && num_pipes == 2 && curr_stream->cont_capt)
9343 			curr_stream->cont_capt =
9344 			    false; /* preview + QoS case will not need cont_capt switch */
9345 		if (curr_stream->cont_capt) {
9346 			capture_pipe = find_pipe(pipes, num_pipes,
9347 						 IA_CSS_PIPE_MODE_CAPTURE,
9348 						 false);
9349 			if (!capture_pipe) {
9350 				err = -EINVAL;
9351 				goto ERR;
9352 			}
9353 		}
9354 		/* We do not support preview and video pipe at the same time */
9355 		if (preview_pipe && video_pipe) {
9356 			err = -EINVAL;
9357 			goto ERR;
9358 		}
9359 
9360 		if (preview_pipe && !preview_pipe->pipe_settings.preview.copy_pipe) {
9361 			err = create_pipe(IA_CSS_PIPE_MODE_CAPTURE, &copy_pipe, true);
9362 			if (err)
9363 				goto ERR;
9364 			ia_css_pipe_config_defaults(&copy_pipe->config);
9365 			preview_pipe->pipe_settings.preview.copy_pipe = copy_pipe;
9366 			copy_pipe->stream = curr_stream;
9367 		}
9368 		if (preview_pipe && curr_stream->cont_capt)
9369 			preview_pipe->pipe_settings.preview.capture_pipe = capture_pipe;
9370 
9371 		if (video_pipe && !video_pipe->pipe_settings.video.copy_pipe) {
9372 			err = create_pipe(IA_CSS_PIPE_MODE_CAPTURE, &copy_pipe, true);
9373 			if (err)
9374 				goto ERR;
9375 			ia_css_pipe_config_defaults(&copy_pipe->config);
9376 			video_pipe->pipe_settings.video.copy_pipe = copy_pipe;
9377 			copy_pipe->stream = curr_stream;
9378 		}
9379 		if (video_pipe && curr_stream->cont_capt)
9380 			video_pipe->pipe_settings.video.capture_pipe = capture_pipe;
9381 
9382 		if (preview_pipe && acc_pipe)
9383 			preview_pipe->pipe_settings.preview.acc_pipe = acc_pipe;
9384 	}
9385 	for (i = 0; i < num_pipes; i++) {
9386 		curr_pipe = pipes[i];
9387 		/* set current stream */
9388 		curr_pipe->stream = curr_stream;
9389 
9390 		if (!IS_ISP2401) {
9391 			/* take over effective info */
9392 
9393 			effective_res = curr_pipe->config.input_effective_res;
9394 			err = ia_css_util_check_res(
9395 				effective_res.width,
9396 				effective_res.height);
9397 			if (err)
9398 				goto ERR;
9399 		}
9400 		/* sensor binning per pipe */
9401 		if (sensor_binning_changed)
9402 			sh_css_pipe_free_shading_table(curr_pipe);
9403 	}
9404 
9405 	/* now pipes have been configured, info should be available */
9406 	for (i = 0; i < num_pipes; i++) {
9407 		struct ia_css_pipe_info *pipe_info = NULL;
9408 
9409 		curr_pipe = pipes[i];
9410 
9411 		err = sh_css_pipe_load_binaries(curr_pipe);
9412 		if (err)
9413 			goto ERR;
9414 
9415 		/* handle each pipe */
9416 		pipe_info = &curr_pipe->info;
9417 		for (j = 0; j < IA_CSS_PIPE_MAX_OUTPUT_STAGE; j++) {
9418 			err = sh_css_pipe_get_output_frame_info(curr_pipe,
9419 								&pipe_info->output_info[j], j);
9420 			if (err)
9421 				goto ERR;
9422 		}
9423 
9424 		if (IS_ISP2401)
9425 			pipe_info->output_system_in_res_info = curr_pipe->config.output_system_in_res;
9426 
9427 		if (!spcopyonly) {
9428 			if (!IS_ISP2401)
9429 				err = sh_css_pipe_get_shading_info(curr_pipe,
9430 								   &pipe_info->shading_info,
9431 								   NULL);
9432 			else
9433 				err = sh_css_pipe_get_shading_info(curr_pipe,
9434 								   &pipe_info->shading_info,
9435 								   &curr_pipe->config);
9436 
9437 			if (err)
9438 				goto ERR;
9439 			err = sh_css_pipe_get_grid_info(curr_pipe,
9440 							&pipe_info->grid_info);
9441 			if (err)
9442 				goto ERR;
9443 			for (j = 0; j < IA_CSS_PIPE_MAX_OUTPUT_STAGE; j++) {
9444 				sh_css_pipe_get_viewfinder_frame_info(curr_pipe,
9445 								      &pipe_info->vf_output_info[j],
9446 								      j);
9447 				if (err)
9448 					goto ERR;
9449 			}
9450 		}
9451 
9452 		my_css.active_pipes[ia_css_pipe_get_pipe_num(curr_pipe)] = curr_pipe;
9453 	}
9454 
9455 	curr_stream->started = false;
9456 
9457 	/* Map SP threads before doing anything. */
9458 	err = map_sp_threads(curr_stream, true);
9459 	if (err) {
9460 		IA_CSS_LOG("map_sp_threads: return_err=%d", err);
9461 		goto ERR;
9462 	}
9463 
9464 	for (i = 0; i < num_pipes; i++) {
9465 		curr_pipe = pipes[i];
9466 		ia_css_pipe_map_queue(curr_pipe, true);
9467 	}
9468 
9469 	/* Create host side pipeline objects without stages */
9470 	err = create_host_pipeline_structure(curr_stream);
9471 	if (err) {
9472 		IA_CSS_LOG("create_host_pipeline_structure: return_err=%d", err);
9473 		goto ERR;
9474 	}
9475 
9476 	/* assign curr_stream */
9477 	*stream = curr_stream;
9478 
9479 ERR:
9480 	if (!err) {
9481 		/* working mode: enter into the seed list */
9482 		if (my_css_save.mode == sh_css_mode_working) {
9483 			for (i = 0; i < MAX_ACTIVE_STREAMS; i++) {
9484 				if (!my_css_save.stream_seeds[i].stream) {
9485 					IA_CSS_LOG("entered stream into loc=%d", i);
9486 					my_css_save.stream_seeds[i].orig_stream = stream;
9487 					my_css_save.stream_seeds[i].stream = curr_stream;
9488 					my_css_save.stream_seeds[i].num_pipes = num_pipes;
9489 					my_css_save.stream_seeds[i].stream_config = *stream_config;
9490 					for (j = 0; j < num_pipes; j++) {
9491 						my_css_save.stream_seeds[i].pipe_config[j] = pipes[j]->config;
9492 						my_css_save.stream_seeds[i].pipes[j] = pipes[j];
9493 						my_css_save.stream_seeds[i].orig_pipes[j] = &pipes[j];
9494 					}
9495 					break;
9496 				}
9497 			}
9498 		} else {
9499 			ia_css_stream_destroy(curr_stream);
9500 		}
9501 	} else {
9502 		ia_css_stream_destroy(curr_stream);
9503 	}
9504 	IA_CSS_LEAVE("return_err=%d mode=%d", err, my_css_save.mode);
9505 	return err;
9506 }
9507 
9508 int
9509 ia_css_stream_destroy(struct ia_css_stream *stream)
9510 {
9511 	int i;
9512 	int err = 0;
9513 
9514 	IA_CSS_ENTER_PRIVATE("stream = %p", stream);
9515 	if (!stream) {
9516 		err = -EINVAL;
9517 		IA_CSS_LEAVE_ERR_PRIVATE(err);
9518 		return err;
9519 	}
9520 
9521 	ia_css_stream_isp_parameters_uninit(stream);
9522 
9523 	if ((stream->last_pipe) &&
9524 	    ia_css_pipeline_is_mapped(stream->last_pipe->pipe_num)) {
9525 #if defined(ISP2401)
9526 		bool free_mpi;
9527 
9528 		for (i = 0; i < stream->num_pipes; i++) {
9529 			struct ia_css_pipe *entry = stream->pipes[i];
9530 			unsigned int sp_thread_id;
9531 			struct sh_css_sp_pipeline_terminal *sp_pipeline_input_terminal;
9532 
9533 			assert(entry);
9534 			if (entry) {
9535 				/* get the SP thread id */
9536 				if (!ia_css_pipeline_get_sp_thread_id(
9537 					ia_css_pipe_get_pipe_num(entry), &sp_thread_id))
9538 					return -EINVAL;
9539 				/* get the target input terminal */
9540 				sp_pipeline_input_terminal =
9541 				&sh_css_sp_group.pipe_io[sp_thread_id].input;
9542 
9543 				for (i = 0; i < IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH; i++) {
9544 					ia_css_isys_stream_h isys_stream =
9545 					&sp_pipeline_input_terminal->context.virtual_input_system_stream[i];
9546 					if (stream->config.isys_config[i].valid && isys_stream->valid)
9547 						ia_css_isys_stream_destroy(isys_stream);
9548 				}
9549 			}
9550 		}
9551 		free_mpi = stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR;
9552 		if (IS_ISP2401) {
9553 			free_mpi |= stream->config.mode == IA_CSS_INPUT_MODE_TPG;
9554 			free_mpi |= stream->config.mode == IA_CSS_INPUT_MODE_PRBS;
9555 		}
9556 
9557 		if (free_mpi) {
9558 			for (i = 0; i < stream->num_pipes; i++) {
9559 				struct ia_css_pipe *entry = stream->pipes[i];
9560 				/* free any mipi frames that are remaining:
9561 				    * some test stream create-destroy cycles do not generate output frames
9562 				    * and the mipi buffer is not freed in the deque function
9563 				    */
9564 				if (entry)
9565 					free_mipi_frames(entry);
9566 			}
9567 		}
9568 		stream_unregister_with_csi_rx(stream);
9569 #endif
9570 
9571 		for (i = 0; i < stream->num_pipes; i++) {
9572 			struct ia_css_pipe *curr_pipe = stream->pipes[i];
9573 
9574 			assert(curr_pipe);
9575 			ia_css_pipe_map_queue(curr_pipe, false);
9576 		}
9577 
9578 		err = map_sp_threads(stream, false);
9579 		if (err) {
9580 			IA_CSS_LEAVE_ERR_PRIVATE(err);
9581 			return err;
9582 		}
9583 	}
9584 
9585 	/* remove references from pipes to stream */
9586 	for (i = 0; i < stream->num_pipes; i++) {
9587 		struct ia_css_pipe *entry = stream->pipes[i];
9588 
9589 		assert(entry);
9590 		if (entry) {
9591 			/* clear reference to stream */
9592 			entry->stream = NULL;
9593 			/* check internal copy pipe */
9594 			if (entry->mode == IA_CSS_PIPE_ID_PREVIEW &&
9595 			    entry->pipe_settings.preview.copy_pipe) {
9596 				IA_CSS_LOG("clearing stream on internal preview copy pipe");
9597 				entry->pipe_settings.preview.copy_pipe->stream = NULL;
9598 			}
9599 			if (entry->mode == IA_CSS_PIPE_ID_VIDEO &&
9600 			    entry->pipe_settings.video.copy_pipe) {
9601 				IA_CSS_LOG("clearing stream on internal video copy pipe");
9602 				entry->pipe_settings.video.copy_pipe->stream = NULL;
9603 			}
9604 			err = sh_css_pipe_unload_binaries(entry);
9605 		}
9606 	}
9607 	/* free associated memory of stream struct */
9608 	kfree(stream->pipes);
9609 	stream->pipes = NULL;
9610 	stream->num_pipes = 0;
9611 
9612 	/* working mode: take out of the seed list */
9613 	if (my_css_save.mode == sh_css_mode_working) {
9614 		for (i = 0; i < MAX_ACTIVE_STREAMS; i++) {
9615 			if (my_css_save.stream_seeds[i].stream == stream) {
9616 				IA_CSS_LOG("took out stream %d", i);
9617 				my_css_save.stream_seeds[i].stream = NULL;
9618 				break;
9619 			}
9620 		}
9621 	}
9622 
9623 	kfree(stream);
9624 	IA_CSS_LEAVE_ERR(err);
9625 
9626 	return err;
9627 }
9628 
9629 int
9630 ia_css_stream_get_info(const struct ia_css_stream *stream,
9631 		       struct ia_css_stream_info *stream_info)
9632 {
9633 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_get_info: enter/exit\n");
9634 	assert(stream);
9635 	assert(stream_info);
9636 
9637 	*stream_info = stream->info;
9638 	return 0;
9639 }
9640 
9641 /*
9642     * Rebuild a stream, including allocating structs, setting configuration and
9643     * building the required pipes.
9644     * The data is taken from the css_save struct updated upon stream creation.
9645     * The stream handle is used to identify the correct entry in the css_save struct
9646     */
9647 int
9648 ia_css_stream_load(struct ia_css_stream *stream)
9649 {
9650 	int i, j, err;
9651 
9652 	if (IS_ISP2401) {
9653 		/* TODO remove function - DEPRECATED */
9654 		(void)stream;
9655 		return -ENOTSUPP;
9656 	}
9657 
9658 	assert(stream);
9659 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,	"ia_css_stream_load() enter,\n");
9660 	for (i = 0; i < MAX_ACTIVE_STREAMS; i++) {
9661 		if (my_css_save.stream_seeds[i].stream != stream)
9662 			continue;
9663 
9664 		for (j = 0; j < my_css_save.stream_seeds[i].num_pipes; j++) {
9665 			int k;
9666 
9667 			err = ia_css_pipe_create(&my_css_save.stream_seeds[i].pipe_config[j],
9668 						 &my_css_save.stream_seeds[i].pipes[j]);
9669 			if (!err)
9670 				continue;
9671 
9672 			for (k = 0; k < j; k++)
9673 				ia_css_pipe_destroy(my_css_save.stream_seeds[i].pipes[k]);
9674 			return err;
9675 		}
9676 		err = ia_css_stream_create(&my_css_save.stream_seeds[i].stream_config,
9677 					   my_css_save.stream_seeds[i].num_pipes,
9678 					   my_css_save.stream_seeds[i].pipes,
9679 					   &my_css_save.stream_seeds[i].stream);
9680 		if (!err)
9681 			break;
9682 
9683 		ia_css_stream_destroy(stream);
9684 		for (j = 0; j < my_css_save.stream_seeds[i].num_pipes; j++)
9685 			ia_css_pipe_destroy(my_css_save.stream_seeds[i].pipes[j]);
9686 		return err;
9687 	}
9688 
9689 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,	"ia_css_stream_load() exit,\n");
9690 	return 0;
9691 }
9692 
9693 int
9694 ia_css_stream_start(struct ia_css_stream *stream)
9695 {
9696 	int err = 0;
9697 
9698 	IA_CSS_ENTER("stream = %p", stream);
9699 	if ((!stream) || (!stream->last_pipe)) {
9700 		IA_CSS_LEAVE_ERR(-EINVAL);
9701 		return -EINVAL;
9702 	}
9703 	IA_CSS_LOG("starting %d", stream->last_pipe->mode);
9704 
9705 	sh_css_sp_set_disable_continuous_viewfinder(stream->disable_cont_vf);
9706 
9707 	/* Create host side pipeline. */
9708 	err = create_host_pipeline(stream);
9709 	if (err) {
9710 		IA_CSS_LEAVE_ERR(err);
9711 		return err;
9712 	}
9713 
9714 #if defined(ISP2401)
9715 	if ((stream->config.mode == IA_CSS_INPUT_MODE_SENSOR) ||
9716 	    (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR))
9717 		stream_register_with_csi_rx(stream);
9718 #endif
9719 
9720 #if !defined(ISP2401)
9721 	/* Initialize mipi size checks */
9722 	if (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) {
9723 		unsigned int idx;
9724 		unsigned int port = (unsigned int)(stream->config.source.port.port);
9725 
9726 		for (idx = 0; idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT; idx++) {
9727 			sh_css_sp_group.config.mipi_sizes_for_check[port][idx] =
9728 			sh_css_get_mipi_sizes_for_check(port, idx);
9729 		}
9730 	}
9731 #endif
9732 
9733 	if (stream->config.mode != IA_CSS_INPUT_MODE_MEMORY) {
9734 		err = sh_css_config_input_network(stream);
9735 		if (err)
9736 			return err;
9737 	}
9738 
9739 	err = sh_css_pipe_start(stream);
9740 	IA_CSS_LEAVE_ERR(err);
9741 	return err;
9742 }
9743 
9744 int
9745 ia_css_stream_stop(struct ia_css_stream *stream)
9746 {
9747 	int err = 0;
9748 
9749 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_stop() enter/exit\n");
9750 	assert(stream);
9751 	assert(stream->last_pipe);
9752 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_stop: stopping %d\n",
9753 			    stream->last_pipe->mode);
9754 
9755 #if !defined(ISP2401)
9756 	/* De-initialize mipi size checks */
9757 	if (stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) {
9758 		unsigned int idx;
9759 		unsigned int port = (unsigned int)(stream->config.source.port.port);
9760 
9761 		for (idx = 0; idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT; idx++)
9762 			sh_css_sp_group.config.mipi_sizes_for_check[port][idx] = 0;
9763 	}
9764 #endif
9765 
9766 	if (!IS_ISP2401)
9767 		err = ia_css_pipeline_request_stop(&stream->last_pipe->pipeline);
9768 	else
9769 		err = sh_css_pipes_stop(stream);
9770 
9771 	if (err)
9772 		return err;
9773 
9774 	/* Ideally, unmapping should happen after pipeline_stop, but current
9775 	    * semantics do not allow that. */
9776 	/* err = map_sp_threads(stream, false); */
9777 
9778 	return err;
9779 }
9780 
9781 bool
9782 ia_css_stream_has_stopped(struct ia_css_stream *stream)
9783 {
9784 	bool stopped;
9785 
9786 	assert(stream);
9787 
9788 	if (!IS_ISP2401)
9789 		stopped = ia_css_pipeline_has_stopped(&stream->last_pipe->pipeline);
9790 	else
9791 		stopped = sh_css_pipes_have_stopped(stream);
9792 
9793 	return stopped;
9794 }
9795 
9796 /* ISP2400 */
9797 /*
9798     * Destroy the stream and all the pipes related to it.
9799     * The stream handle is used to identify the correct entry in the css_save struct
9800     */
9801 int
9802 ia_css_stream_unload(struct ia_css_stream *stream)
9803 {
9804 	int i;
9805 
9806 	assert(stream);
9807 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,	"ia_css_stream_unload() enter,\n");
9808 	/* some checks */
9809 	assert(stream);
9810 	for (i = 0; i < MAX_ACTIVE_STREAMS; i++)
9811 		if (my_css_save.stream_seeds[i].stream == stream) {
9812 			int j;
9813 
9814 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
9815 					    "ia_css_stream_unload(): unloading %d (%p)\n", i,
9816 					    my_css_save.stream_seeds[i].stream);
9817 			ia_css_stream_destroy(stream);
9818 			for (j = 0; j < my_css_save.stream_seeds[i].num_pipes; j++)
9819 				ia_css_pipe_destroy(my_css_save.stream_seeds[i].pipes[j]);
9820 			ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
9821 					    "ia_css_stream_unload(): after unloading %d (%p)\n", i,
9822 					    my_css_save.stream_seeds[i].stream);
9823 			break;
9824 		}
9825 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,	"ia_css_stream_unload() exit,\n");
9826 	return 0;
9827 }
9828 
9829 int
9830 ia_css_temp_pipe_to_pipe_id(const struct ia_css_pipe *pipe,
9831 			    enum ia_css_pipe_id *pipe_id)
9832 {
9833 	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_temp_pipe_to_pipe_id() enter/exit\n");
9834 	if (pipe)
9835 		*pipe_id = pipe->mode;
9836 	else
9837 		*pipe_id = IA_CSS_PIPE_ID_COPY;
9838 
9839 	return 0;
9840 }
9841 
9842 enum atomisp_input_format
9843 ia_css_stream_get_format(const struct ia_css_stream *stream)
9844 {
9845 	return stream->config.input_config.format;
9846 }
9847 
9848 bool
9849 ia_css_stream_get_two_pixels_per_clock(const struct ia_css_stream *stream)
9850 {
9851 	return (stream->config.pixels_per_clock == 2);
9852 }
9853 
9854 struct ia_css_binary *
9855 ia_css_stream_get_shading_correction_binary(const struct ia_css_stream
9856 	*stream)
9857 {
9858 	struct ia_css_pipe *pipe;
9859 
9860 	assert(stream);
9861 
9862 	pipe = stream->pipes[0];
9863 
9864 	if (stream->num_pipes == 2) {
9865 		assert(stream->pipes[1]);
9866 		if (stream->pipes[1]->config.mode == IA_CSS_PIPE_MODE_VIDEO ||
9867 		    stream->pipes[1]->config.mode == IA_CSS_PIPE_MODE_PREVIEW)
9868 			pipe = stream->pipes[1];
9869 	}
9870 
9871 	return ia_css_pipe_get_shading_correction_binary(pipe);
9872 }
9873 
9874 struct ia_css_binary *
9875 ia_css_stream_get_dvs_binary(const struct ia_css_stream *stream)
9876 {
9877 	int i;
9878 	struct ia_css_pipe *video_pipe = NULL;
9879 
9880 	/* First we find the video pipe */
9881 	for (i = 0; i < stream->num_pipes; i++) {
9882 		struct ia_css_pipe *pipe = stream->pipes[i];
9883 
9884 		if (pipe->config.mode == IA_CSS_PIPE_MODE_VIDEO) {
9885 			video_pipe = pipe;
9886 			break;
9887 		}
9888 	}
9889 	if (video_pipe)
9890 		return &video_pipe->pipe_settings.video.video_binary;
9891 	return NULL;
9892 }
9893 
9894 struct ia_css_binary *
9895 ia_css_stream_get_3a_binary(const struct ia_css_stream *stream)
9896 {
9897 	struct ia_css_pipe *pipe;
9898 	struct ia_css_binary *s3a_binary = NULL;
9899 
9900 	assert(stream);
9901 
9902 	pipe = stream->pipes[0];
9903 
9904 	if (stream->num_pipes == 2) {
9905 		assert(stream->pipes[1]);
9906 		if (stream->pipes[1]->config.mode == IA_CSS_PIPE_MODE_VIDEO ||
9907 		    stream->pipes[1]->config.mode == IA_CSS_PIPE_MODE_PREVIEW)
9908 			pipe = stream->pipes[1];
9909 	}
9910 
9911 	s3a_binary = ia_css_pipe_get_s3a_binary(pipe);
9912 
9913 	return s3a_binary;
9914 }
9915 
9916 int
9917 ia_css_stream_set_output_padded_width(struct ia_css_stream *stream,
9918 				      unsigned int output_padded_width)
9919 {
9920 	struct ia_css_pipe *pipe;
9921 
9922 	assert(stream);
9923 
9924 	pipe = stream->last_pipe;
9925 
9926 	assert(pipe);
9927 
9928 	/* set the config also just in case (redundant info? why do we save config in pipe?) */
9929 	pipe->config.output_info[IA_CSS_PIPE_OUTPUT_STAGE_0].padded_width = output_padded_width;
9930 	pipe->output_info[IA_CSS_PIPE_OUTPUT_STAGE_0].padded_width = output_padded_width;
9931 
9932 	return 0;
9933 }
9934 
9935 static struct ia_css_binary *
9936 ia_css_pipe_get_shading_correction_binary(const struct ia_css_pipe *pipe)
9937 {
9938 	struct ia_css_binary *binary = NULL;
9939 
9940 	assert(pipe);
9941 
9942 	switch (pipe->config.mode) {
9943 	case IA_CSS_PIPE_MODE_PREVIEW:
9944 		binary = (struct ia_css_binary *)&pipe->pipe_settings.preview.preview_binary;
9945 		break;
9946 	case IA_CSS_PIPE_MODE_VIDEO:
9947 		binary = (struct ia_css_binary *)&pipe->pipe_settings.video.video_binary;
9948 		break;
9949 	case IA_CSS_PIPE_MODE_CAPTURE:
9950 		if (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_PRIMARY) {
9951 			unsigned int i;
9952 
9953 			for (i = 0; i < pipe->pipe_settings.capture.num_primary_stage; i++) {
9954 				if (pipe->pipe_settings.capture.primary_binary[i].info->sp.enable.sc) {
9955 					binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.primary_binary[i];
9956 					break;
9957 				}
9958 			}
9959 		} else if (pipe->config.default_capture_config.mode ==
9960 			    IA_CSS_CAPTURE_MODE_BAYER)
9961 			binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.pre_isp_binary;
9962 		else if (pipe->config.default_capture_config.mode ==
9963 			    IA_CSS_CAPTURE_MODE_ADVANCED ||
9964 			    pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT) {
9965 			if (pipe->config.isp_pipe_version == IA_CSS_PIPE_VERSION_1)
9966 				binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.pre_isp_binary;
9967 			else if (pipe->config.isp_pipe_version == IA_CSS_PIPE_VERSION_2_2)
9968 				binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.post_isp_binary;
9969 		}
9970 		break;
9971 	default:
9972 		break;
9973 	}
9974 
9975 	if (binary && binary->info->sp.enable.sc)
9976 		return binary;
9977 
9978 	return NULL;
9979 }
9980 
9981 static struct ia_css_binary *
9982 ia_css_pipe_get_s3a_binary(const struct ia_css_pipe *pipe)
9983 {
9984 	struct ia_css_binary *binary = NULL;
9985 
9986 	assert(pipe);
9987 
9988 	switch (pipe->config.mode) {
9989 	case IA_CSS_PIPE_MODE_PREVIEW:
9990 		binary = (struct ia_css_binary *)&pipe->pipe_settings.preview.preview_binary;
9991 		break;
9992 	case IA_CSS_PIPE_MODE_VIDEO:
9993 		binary = (struct ia_css_binary *)&pipe->pipe_settings.video.video_binary;
9994 		break;
9995 	case IA_CSS_PIPE_MODE_CAPTURE:
9996 		if (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_PRIMARY) {
9997 			unsigned int i;
9998 
9999 			for (i = 0; i < pipe->pipe_settings.capture.num_primary_stage; i++) {
10000 				if (pipe->pipe_settings.capture.primary_binary[i].info->sp.enable.s3a) {
10001 					binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.primary_binary[i];
10002 					break;
10003 				}
10004 			}
10005 		} else if (pipe->config.default_capture_config.mode ==
10006 			    IA_CSS_CAPTURE_MODE_BAYER) {
10007 			binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.pre_isp_binary;
10008 		} else if (pipe->config.default_capture_config.mode ==
10009 			    IA_CSS_CAPTURE_MODE_ADVANCED ||
10010 			    pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT) {
10011 			if (pipe->config.isp_pipe_version == IA_CSS_PIPE_VERSION_1)
10012 				binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.pre_isp_binary;
10013 			else if (pipe->config.isp_pipe_version == IA_CSS_PIPE_VERSION_2_2)
10014 				binary = (struct ia_css_binary *)&pipe->pipe_settings.capture.post_isp_binary;
10015 			else
10016 				assert(0);
10017 		}
10018 		break;
10019 	default:
10020 		break;
10021 	}
10022 
10023 	if (binary && !binary->info->sp.enable.s3a)
10024 		binary = NULL;
10025 
10026 	return binary;
10027 }
10028 
10029 static struct ia_css_binary *
10030 ia_css_pipe_get_sdis_binary(const struct ia_css_pipe *pipe)
10031 {
10032 	struct ia_css_binary *binary = NULL;
10033 
10034 	assert(pipe);
10035 
10036 	switch (pipe->config.mode) {
10037 	case IA_CSS_PIPE_MODE_VIDEO:
10038 		binary = (struct ia_css_binary *)&pipe->pipe_settings.video.video_binary;
10039 		break;
10040 	default:
10041 		break;
10042 	}
10043 
10044 	if (binary && !binary->info->sp.enable.dis)
10045 		binary = NULL;
10046 
10047 	return binary;
10048 }
10049 
10050 struct ia_css_pipeline *
10051 ia_css_pipe_get_pipeline(const struct ia_css_pipe *pipe)
10052 {
10053 	assert(pipe);
10054 
10055 	return (struct ia_css_pipeline *)&pipe->pipeline;
10056 }
10057 
10058 unsigned int
10059 ia_css_pipe_get_pipe_num(const struct ia_css_pipe *pipe)
10060 {
10061 	assert(pipe);
10062 
10063 	/* KW was not sure this function was not returning a value
10064 	    that was out of range; so added an assert, and, for the
10065 	    case when asserts are not enabled, clip to the largest
10066 	    value; pipe_num is unsigned so the value cannot be too small
10067 	*/
10068 	assert(pipe->pipe_num < IA_CSS_PIPELINE_NUM_MAX);
10069 
10070 	if (pipe->pipe_num >= IA_CSS_PIPELINE_NUM_MAX)
10071 		return (IA_CSS_PIPELINE_NUM_MAX - 1);
10072 
10073 	return pipe->pipe_num;
10074 }
10075 
10076 unsigned int
10077 ia_css_pipe_get_isp_pipe_version(const struct ia_css_pipe *pipe)
10078 {
10079 	assert(pipe);
10080 
10081 	return (unsigned int)pipe->config.isp_pipe_version;
10082 }
10083 
10084 #define SP_START_TIMEOUT_US 30000000
10085 
10086 int
10087 ia_css_start_sp(void)
10088 {
10089 	unsigned long timeout;
10090 	int err = 0;
10091 
10092 	IA_CSS_ENTER("");
10093 	sh_css_sp_start_isp();
10094 
10095 	/* waiting for the SP is completely started */
10096 	timeout = SP_START_TIMEOUT_US;
10097 	while ((ia_css_spctrl_get_state(SP0_ID) != IA_CSS_SP_SW_INITIALIZED) && timeout) {
10098 		timeout--;
10099 		udelay(1);
10100 	}
10101 	if (timeout == 0) {
10102 		IA_CSS_ERROR("timeout during SP initialization");
10103 		return -EINVAL;
10104 	}
10105 
10106 	/* Workaround, in order to run two streams in parallel. See TASK 4271*/
10107 	/* TODO: Fix this. */
10108 
10109 	sh_css_init_host_sp_control_vars();
10110 
10111 	/* buffers should be initialized only when sp is started */
10112 	/* AM: At the moment it will be done only when there is no stream active. */
10113 
10114 	sh_css_setup_queues();
10115 	ia_css_bufq_dump_queue_info();
10116 
10117 	IA_CSS_LEAVE_ERR(err);
10118 	return err;
10119 }
10120 
10121 /*
10122     *	Time to wait SP for termincate. Only condition when this can happen
10123     *	is a fatal hw failure, but we must be able to detect this and emit
10124     *	a proper error trace.
10125     */
10126 #define SP_SHUTDOWN_TIMEOUT_US 200000
10127 
10128 int
10129 ia_css_stop_sp(void)
10130 {
10131 	unsigned long timeout;
10132 	int err = 0;
10133 
10134 	IA_CSS_ENTER("void");
10135 
10136 	if (!sh_css_sp_is_running()) {
10137 		err = -EINVAL;
10138 		IA_CSS_LEAVE("SP already stopped : return_err=%d", err);
10139 
10140 		/* Return an error - stop SP should not have been called by driver */
10141 		return err;
10142 	}
10143 
10144 	/* For now, stop whole SP */
10145 	if (!IS_ISP2401) {
10146 		sh_css_write_host2sp_command(host2sp_cmd_terminate);
10147 	} else {
10148 		if (!sh_css_write_host2sp_command(host2sp_cmd_terminate)) {
10149 			IA_CSS_ERROR("Call to 'sh-css_write_host2sp_command()' failed");
10150 			ia_css_debug_dump_sp_sw_debug_info();
10151 			ia_css_debug_dump_debug_info(NULL);
10152 		}
10153 	}
10154 
10155 	sh_css_sp_set_sp_running(false);
10156 
10157 	timeout = SP_SHUTDOWN_TIMEOUT_US;
10158 	while (!ia_css_spctrl_is_idle(SP0_ID) && timeout) {
10159 		timeout--;
10160 		udelay(1);
10161 	}
10162 	if (ia_css_spctrl_get_state(SP0_ID) != IA_CSS_SP_SW_TERMINATED)
10163 		IA_CSS_WARNING("SP has not terminated (SW)");
10164 
10165 	if (timeout == 0) {
10166 		IA_CSS_WARNING("SP is not idle");
10167 		ia_css_debug_dump_sp_sw_debug_info();
10168 	}
10169 	timeout = SP_SHUTDOWN_TIMEOUT_US;
10170 	while (!isp_ctrl_getbit(ISP0_ID, ISP_SC_REG, ISP_IDLE_BIT) && timeout) {
10171 		timeout--;
10172 		udelay(1);
10173 	}
10174 	if (timeout == 0) {
10175 		IA_CSS_WARNING("ISP is not idle");
10176 		ia_css_debug_dump_sp_sw_debug_info();
10177 	}
10178 
10179 	sh_css_hmm_buffer_record_uninit();
10180 
10181 	/* clear pending param sets from refcount */
10182 	sh_css_param_clear_param_sets();
10183 
10184 	IA_CSS_LEAVE_ERR(err);
10185 	return err;
10186 }
10187 
10188 int
10189 ia_css_update_continuous_frames(struct ia_css_stream *stream)
10190 {
10191 	struct ia_css_pipe *pipe;
10192 	unsigned int i;
10193 
10194 	ia_css_debug_dtrace(
10195 	    IA_CSS_DEBUG_TRACE,
10196 	    "sh_css_update_continuous_frames() enter:\n");
10197 
10198 	if (!stream) {
10199 		ia_css_debug_dtrace(
10200 		    IA_CSS_DEBUG_TRACE,
10201 		    "sh_css_update_continuous_frames() leave: invalid stream, return_void\n");
10202 		return -EINVAL;
10203 	}
10204 
10205 	pipe = stream->continuous_pipe;
10206 
10207 	for (i = stream->config.init_num_cont_raw_buf;
10208 		i < stream->config.target_num_cont_raw_buf; i++)
10209 		sh_css_update_host2sp_offline_frame(i,
10210 						    pipe->continuous_frames[i], pipe->cont_md_buffers[i]);
10211 
10212 	sh_css_update_host2sp_cont_num_raw_frames
10213 	(stream->config.target_num_cont_raw_buf, true);
10214 	ia_css_debug_dtrace(
10215 	    IA_CSS_DEBUG_TRACE,
10216 	    "sh_css_update_continuous_frames() leave: return_void\n");
10217 
10218 	return 0;
10219 }
10220 
10221 void ia_css_pipe_map_queue(struct ia_css_pipe *pipe, bool map)
10222 {
10223 	unsigned int thread_id;
10224 	unsigned int pipe_num;
10225 	bool need_input_queue;
10226 
10227 	IA_CSS_ENTER("");
10228 	assert(pipe);
10229 
10230 	pipe_num = pipe->pipe_num;
10231 
10232 	ia_css_pipeline_get_sp_thread_id(pipe_num, &thread_id);
10233 
10234 #if defined(ISP2401)
10235 	need_input_queue = true;
10236 #else
10237 	need_input_queue = pipe->stream->config.mode == IA_CSS_INPUT_MODE_MEMORY;
10238 #endif
10239 
10240 	/* map required buffer queues to resources */
10241 	/* TODO: to be improved */
10242 	if (pipe->mode == IA_CSS_PIPE_ID_PREVIEW) {
10243 		if (need_input_queue)
10244 			ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map);
10245 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map);
10246 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map);
10247 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PER_FRAME_PARAMETER_SET, map);
10248 #if defined SH_CSS_ENABLE_METADATA
10249 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map);
10250 #endif
10251 		if (pipe->pipe_settings.preview.preview_binary.info &&
10252 		    pipe->pipe_settings.preview.preview_binary.info->sp.enable.s3a)
10253 			ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_3A_STATISTICS, map);
10254 	} else if (pipe->mode == IA_CSS_PIPE_ID_CAPTURE) {
10255 		unsigned int i;
10256 
10257 		if (need_input_queue)
10258 			ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map);
10259 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map);
10260 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME, map);
10261 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map);
10262 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PER_FRAME_PARAMETER_SET, map);
10263 #if defined SH_CSS_ENABLE_METADATA
10264 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map);
10265 #endif
10266 		if (pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_PRIMARY) {
10267 			for (i = 0; i < pipe->pipe_settings.capture.num_primary_stage; i++) {
10268 				if (pipe->pipe_settings.capture.primary_binary[i].info &&
10269 				    pipe->pipe_settings.capture.primary_binary[i].info->sp.enable.s3a) {
10270 					ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_3A_STATISTICS, map);
10271 					break;
10272 				}
10273 			}
10274 		} else if (pipe->config.default_capture_config.mode ==
10275 			    IA_CSS_CAPTURE_MODE_ADVANCED ||
10276 			    pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_LOW_LIGHT ||
10277 			    pipe->config.default_capture_config.mode == IA_CSS_CAPTURE_MODE_BAYER) {
10278 			if (pipe->pipe_settings.capture.pre_isp_binary.info &&
10279 			    pipe->pipe_settings.capture.pre_isp_binary.info->sp.enable.s3a)
10280 				ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_3A_STATISTICS, map);
10281 		}
10282 	} else if (pipe->mode == IA_CSS_PIPE_ID_VIDEO) {
10283 		if (need_input_queue)
10284 			ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map);
10285 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map);
10286 		if (pipe->enable_viewfinder[IA_CSS_PIPE_OUTPUT_STAGE_0])
10287 			ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME, map);
10288 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map);
10289 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PER_FRAME_PARAMETER_SET, map);
10290 #if defined SH_CSS_ENABLE_METADATA
10291 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map);
10292 #endif
10293 		if (pipe->pipe_settings.video.video_binary.info &&
10294 		    pipe->pipe_settings.video.video_binary.info->sp.enable.s3a)
10295 			ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_3A_STATISTICS, map);
10296 		if (pipe->pipe_settings.video.video_binary.info &&
10297 		    (pipe->pipe_settings.video.video_binary.info->sp.enable.dis
10298 		    ))
10299 			ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_DIS_STATISTICS, map);
10300 	} else if (pipe->mode == IA_CSS_PIPE_ID_COPY) {
10301 		if (need_input_queue)
10302 			ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map);
10303 		if (!pipe->stream->config.continuous)
10304 			ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map);
10305 #if defined SH_CSS_ENABLE_METADATA
10306 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map);
10307 #endif
10308 	} else if (pipe->mode == IA_CSS_PIPE_ID_ACC) {
10309 		if (need_input_queue)
10310 			ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map);
10311 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, map);
10312 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map);
10313 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PER_FRAME_PARAMETER_SET, map);
10314 #if defined SH_CSS_ENABLE_METADATA
10315 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map);
10316 #endif
10317 	} else if (pipe->mode == IA_CSS_PIPE_ID_YUVPP) {
10318 		unsigned int idx;
10319 
10320 		for (idx = 0; idx < IA_CSS_PIPE_MAX_OUTPUT_STAGE; idx++) {
10321 			ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME + idx, map);
10322 			if (pipe->enable_viewfinder[idx])
10323 				ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME + idx, map);
10324 		}
10325 		if (need_input_queue)
10326 			ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_INPUT_FRAME, map);
10327 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_PARAMETER_SET, map);
10328 #if defined SH_CSS_ENABLE_METADATA
10329 		ia_css_queue_map(thread_id, IA_CSS_BUFFER_TYPE_METADATA, map);
10330 #endif
10331 	}
10332 	IA_CSS_LEAVE("");
10333 }
10334 
10335 #if CONFIG_ON_FRAME_ENQUEUE()
10336 static int set_config_on_frame_enqueue(struct ia_css_frame_info
10337 	*info, struct frame_data_wrapper *frame)
10338 {
10339 	frame->config_on_frame_enqueue.padded_width = 0;
10340 
10341 	/* currently we support configuration on frame enqueue only on YUV formats */
10342 	/* on other formats the padded_width is zeroed for no configuration override */
10343 	switch (info->format) {
10344 	case IA_CSS_FRAME_FORMAT_YUV420:
10345 	case IA_CSS_FRAME_FORMAT_NV12:
10346 		if (info->padded_width > info->res.width)
10347 			frame->config_on_frame_enqueue.padded_width = info->padded_width;
10348 		else if ((info->padded_width < info->res.width) && (info->padded_width > 0))
10349 			return -EINVAL;
10350 
10351 		/* nothing to do if width == padded width or padded width is zeroed (the same) */
10352 		break;
10353 	default:
10354 		break;
10355 	}
10356 
10357 	return 0;
10358 }
10359 #endif
10360 
10361 int
10362 ia_css_unlock_raw_frame(struct ia_css_stream *stream, uint32_t exp_id)
10363 {
10364 	int ret;
10365 
10366 	IA_CSS_ENTER("");
10367 
10368 	/* Only continuous streams have a tagger to which we can send the
10369 	    * unlock message. */
10370 	if (!stream || !stream->config.continuous) {
10371 		IA_CSS_ERROR("invalid stream pointer");
10372 		return -EINVAL;
10373 	}
10374 
10375 	if (exp_id > IA_CSS_ISYS_MAX_EXPOSURE_ID ||
10376 	    exp_id < IA_CSS_ISYS_MIN_EXPOSURE_ID) {
10377 		IA_CSS_ERROR("invalid exposure ID: %d\n", exp_id);
10378 		return -EINVAL;
10379 	}
10380 
10381 	/* Send the event. Since we verified that the exp_id is valid,
10382 	    * we can safely assign it to an 8-bit argument here. */
10383 	ret = ia_css_bufq_enqueue_psys_event(
10384 	    IA_CSS_PSYS_SW_EVENT_UNLOCK_RAW_BUFFER, exp_id, 0, 0);
10385 
10386 	IA_CSS_LEAVE_ERR(ret);
10387 	return ret;
10388 }
10389 
10390 /* @brief	Set the state (Enable or Disable) of the Extension stage in the
10391     *		given pipe.
10392     */
10393 int
10394 ia_css_pipe_set_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle,
10395 			      bool enable)
10396 {
10397 	unsigned int thread_id;
10398 	struct ia_css_pipeline_stage *stage;
10399 	int err = 0;
10400 
10401 	IA_CSS_ENTER("");
10402 
10403 	/* Parameter Check */
10404 	if (!pipe || !pipe->stream) {
10405 		IA_CSS_ERROR("Invalid Pipe.");
10406 		err = -EINVAL;
10407 	} else if (!(pipe->config.acc_extension)) {
10408 		IA_CSS_ERROR("Invalid Pipe(No Extension Firmware)");
10409 		err = -EINVAL;
10410 	} else if (!sh_css_sp_is_running()) {
10411 		IA_CSS_ERROR("Leaving: queue unavailable.");
10412 		err = -EBUSY;
10413 	} else {
10414 		/* Query the threadid and stage_num for the Extension firmware*/
10415 		ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
10416 		err = ia_css_pipeline_get_stage_from_fw(&pipe->pipeline, fw_handle, &stage);
10417 		if (!err) {
10418 			/* Set the Extension State;. TODO: Add check for stage firmware.type (QOS)*/
10419 			err = ia_css_bufq_enqueue_psys_event(
10420 			    (uint8_t)IA_CSS_PSYS_SW_EVENT_STAGE_ENABLE_DISABLE,
10421 			    (uint8_t)thread_id,
10422 			    (uint8_t)stage->stage_num,
10423 			    enable ? 1 : 0);
10424 			if (!err) {
10425 				if (enable)
10426 					SH_CSS_QOS_STAGE_ENABLE(&sh_css_sp_group.pipe[thread_id], stage->stage_num);
10427 				else
10428 					SH_CSS_QOS_STAGE_DISABLE(&sh_css_sp_group.pipe[thread_id], stage->stage_num);
10429 			}
10430 		}
10431 	}
10432 	IA_CSS_LEAVE("err:%d handle:%u enable:%d", err, fw_handle, enable);
10433 	return err;
10434 }
10435 
10436 /*	@brief	Get the state (Enable or Disable) of the Extension stage in the
10437     *	given pipe.
10438     */
10439 int
10440 ia_css_pipe_get_qos_ext_state(struct ia_css_pipe *pipe, uint32_t fw_handle,
10441 			      bool *enable)
10442 {
10443 	struct ia_css_pipeline_stage *stage;
10444 	unsigned int thread_id;
10445 	int err = 0;
10446 
10447 	IA_CSS_ENTER("");
10448 
10449 	/* Parameter Check */
10450 	if (!pipe || !pipe->stream) {
10451 		IA_CSS_ERROR("Invalid Pipe.");
10452 		err = -EINVAL;
10453 	} else if (!(pipe->config.acc_extension)) {
10454 		IA_CSS_ERROR("Invalid Pipe (No Extension Firmware).");
10455 		err = -EINVAL;
10456 	} else if (!sh_css_sp_is_running()) {
10457 		IA_CSS_ERROR("Leaving: queue unavailable.");
10458 		err = -EBUSY;
10459 	} else {
10460 		/* Query the threadid and stage_num corresponding to the Extension firmware*/
10461 		ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
10462 		err = ia_css_pipeline_get_stage_from_fw(&pipe->pipeline, fw_handle, &stage);
10463 
10464 		if (!err) {
10465 			/* Get the Extension State */
10466 			*enable = (SH_CSS_QOS_STAGE_IS_ENABLED(&sh_css_sp_group.pipe[thread_id],
10467 								stage->stage_num)) ? true : false;
10468 		}
10469 	}
10470 	IA_CSS_LEAVE("err:%d handle:%u enable:%d", err, fw_handle, *enable);
10471 	return err;
10472 }
10473 
10474 /* ISP2401 */
10475 int
10476 ia_css_pipe_update_qos_ext_mapped_arg(struct ia_css_pipe *pipe,
10477 				      u32 fw_handle,
10478 				      struct ia_css_isp_param_css_segments *css_seg,
10479 				      struct ia_css_isp_param_isp_segments *isp_seg)
10480 {
10481 	unsigned int HIVE_ADDR_sp_group;
10482 	static struct sh_css_sp_group sp_group;
10483 	static struct sh_css_sp_stage sp_stage;
10484 	static struct sh_css_isp_stage isp_stage;
10485 	const struct ia_css_fw_info *fw;
10486 	unsigned int thread_id;
10487 	struct ia_css_pipeline_stage *stage;
10488 	int err = 0;
10489 	int stage_num = 0;
10490 	enum ia_css_isp_memories mem;
10491 	bool enabled;
10492 
10493 	IA_CSS_ENTER("");
10494 
10495 	fw = &sh_css_sp_fw;
10496 
10497 	/* Parameter Check */
10498 	if (!pipe || !pipe->stream) {
10499 		IA_CSS_ERROR("Invalid Pipe.");
10500 		err = -EINVAL;
10501 	} else if (!(pipe->config.acc_extension)) {
10502 		IA_CSS_ERROR("Invalid Pipe (No Extension Firmware).");
10503 		err = -EINVAL;
10504 	} else if (!sh_css_sp_is_running()) {
10505 		IA_CSS_ERROR("Leaving: queue unavailable.");
10506 		err = -EBUSY;
10507 	} else {
10508 		/* Query the thread_id and stage_num corresponding to the Extension firmware */
10509 		ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
10510 		err = ia_css_pipeline_get_stage_from_fw(&pipe->pipeline, fw_handle, &stage);
10511 		if (!err) {
10512 			/* Get the Extension State */
10513 			enabled = (SH_CSS_QOS_STAGE_IS_ENABLED(&sh_css_sp_group.pipe[thread_id],
10514 							       stage->stage_num)) ? true : false;
10515 			/* Update mapped arg only when extension stage is not enabled */
10516 			if (enabled) {
10517 				IA_CSS_ERROR("Leaving: cannot update when stage is enabled.");
10518 				err = -EBUSY;
10519 			} else {
10520 				stage_num = stage->stage_num;
10521 
10522 				HIVE_ADDR_sp_group = fw->info.sp.group;
10523 				sp_dmem_load(SP0_ID,
10524 					     (unsigned int)sp_address_of(sp_group),
10525 					     &sp_group,
10526 					     sizeof(struct sh_css_sp_group));
10527 				hmm_load(sp_group.pipe[thread_id].sp_stage_addr[stage_num],
10528 					 &sp_stage, sizeof(struct sh_css_sp_stage));
10529 
10530 				hmm_load(sp_stage.isp_stage_addr,
10531 					 &isp_stage, sizeof(struct sh_css_isp_stage));
10532 
10533 				for (mem = 0; mem < N_IA_CSS_ISP_MEMORIES; mem++) {
10534 					isp_stage.mem_initializers.params[IA_CSS_PARAM_CLASS_PARAM][mem].address =
10535 					    css_seg->params[IA_CSS_PARAM_CLASS_PARAM][mem].address;
10536 					isp_stage.mem_initializers.params[IA_CSS_PARAM_CLASS_PARAM][mem].size =
10537 					    css_seg->params[IA_CSS_PARAM_CLASS_PARAM][mem].size;
10538 					isp_stage.binary_info.mem_initializers.params[IA_CSS_PARAM_CLASS_PARAM][mem].address
10539 					    =
10540 						isp_seg->params[IA_CSS_PARAM_CLASS_PARAM][mem].address;
10541 					isp_stage.binary_info.mem_initializers.params[IA_CSS_PARAM_CLASS_PARAM][mem].size
10542 					    =
10543 						isp_seg->params[IA_CSS_PARAM_CLASS_PARAM][mem].size;
10544 				}
10545 
10546 				hmm_store(sp_stage.isp_stage_addr,
10547 					  &isp_stage,
10548 					  sizeof(struct sh_css_isp_stage));
10549 			}
10550 		}
10551 	}
10552 	IA_CSS_LEAVE("err:%d handle:%u", err, fw_handle);
10553 	return err;
10554 }
10555 
10556 #ifdef ISP2401
10557 static int
10558 aspect_ratio_crop_init(struct ia_css_stream *curr_stream,
10559 		       struct ia_css_pipe *pipes[],
10560 		       bool *do_crop_status)
10561 {
10562 	int err = 0;
10563 	int i;
10564 	struct ia_css_pipe *curr_pipe;
10565 	u32 pipe_mask = 0;
10566 
10567 	if ((!curr_stream) ||
10568 	    (curr_stream->num_pipes == 0) ||
10569 	    (!pipes) ||
10570 	    (!do_crop_status)) {
10571 		err = -EINVAL;
10572 		IA_CSS_LEAVE_ERR(err);
10573 		return err;
10574 	}
10575 
10576 	for (i = 0; i < curr_stream->num_pipes; i++) {
10577 		curr_pipe = pipes[i];
10578 		pipe_mask |= (1 << curr_pipe->config.mode);
10579 	}
10580 
10581 	*do_crop_status =
10582 	(((pipe_mask & (1 << IA_CSS_PIPE_MODE_PREVIEW)) ||
10583 	    (pipe_mask & (1 << IA_CSS_PIPE_MODE_VIDEO))) &&
10584 	    (pipe_mask & (1 << IA_CSS_PIPE_MODE_CAPTURE)) &&
10585 	    curr_stream->config.continuous);
10586 	return 0;
10587 }
10588 
10589 static bool
10590 aspect_ratio_crop_check(bool enabled, struct ia_css_pipe *curr_pipe)
10591 {
10592 	bool status = false;
10593 
10594 	if ((curr_pipe) && enabled) {
10595 		if ((curr_pipe->config.mode == IA_CSS_PIPE_MODE_PREVIEW) ||
10596 		    (curr_pipe->config.mode == IA_CSS_PIPE_MODE_VIDEO) ||
10597 		    (curr_pipe->config.mode == IA_CSS_PIPE_MODE_CAPTURE))
10598 			status = true;
10599 	}
10600 
10601 	return status;
10602 }
10603 
10604 static int
10605 aspect_ratio_crop(struct ia_css_pipe *curr_pipe,
10606 		  struct ia_css_resolution *effective_res)
10607 {
10608 	int err = 0;
10609 	struct ia_css_resolution crop_res;
10610 	struct ia_css_resolution *in_res = NULL;
10611 	struct ia_css_resolution *out_res = NULL;
10612 	bool use_bds_output_info = false;
10613 	bool use_vf_pp_in_res = false;
10614 	bool use_capt_pp_in_res = false;
10615 
10616 	if ((!curr_pipe) ||
10617 	    (!effective_res)) {
10618 		err = -EINVAL;
10619 		IA_CSS_LEAVE_ERR(err);
10620 		return err;
10621 	}
10622 
10623 	if ((curr_pipe->config.mode != IA_CSS_PIPE_MODE_PREVIEW) &&
10624 	    (curr_pipe->config.mode != IA_CSS_PIPE_MODE_VIDEO) &&
10625 	    (curr_pipe->config.mode != IA_CSS_PIPE_MODE_CAPTURE)) {
10626 		err = -EINVAL;
10627 		IA_CSS_LEAVE_ERR(err);
10628 		return err;
10629 	}
10630 
10631 	use_bds_output_info =
10632 	((curr_pipe->bds_output_info.res.width != 0) &&
10633 	    (curr_pipe->bds_output_info.res.height != 0));
10634 
10635 	use_vf_pp_in_res =
10636 	((curr_pipe->config.vf_pp_in_res.width != 0) &&
10637 	    (curr_pipe->config.vf_pp_in_res.height != 0));
10638 
10639 	use_capt_pp_in_res =
10640 	((curr_pipe->config.capt_pp_in_res.width != 0) &&
10641 	    (curr_pipe->config.capt_pp_in_res.height != 0));
10642 
10643 	in_res = &curr_pipe->stream->config.input_config.effective_res;
10644 	out_res = &curr_pipe->output_info[0].res;
10645 
10646 	switch (curr_pipe->config.mode) {
10647 	case IA_CSS_PIPE_MODE_PREVIEW:
10648 		if (use_bds_output_info)
10649 			out_res = &curr_pipe->bds_output_info.res;
10650 		else if (use_vf_pp_in_res)
10651 			out_res = &curr_pipe->config.vf_pp_in_res;
10652 		break;
10653 	case IA_CSS_PIPE_MODE_VIDEO:
10654 		if (use_bds_output_info)
10655 			out_res = &curr_pipe->bds_output_info.res;
10656 		break;
10657 	case IA_CSS_PIPE_MODE_CAPTURE:
10658 		if (use_capt_pp_in_res)
10659 			out_res = &curr_pipe->config.capt_pp_in_res;
10660 		break;
10661 	case IA_CSS_PIPE_MODE_ACC:
10662 	case IA_CSS_PIPE_MODE_COPY:
10663 	case IA_CSS_PIPE_MODE_YUVPP:
10664 	default:
10665 		IA_CSS_ERROR("aspect ratio cropping invalid args: mode[%d]\n",
10666 			     curr_pipe->config.mode);
10667 		assert(0);
10668 		break;
10669 	}
10670 
10671 	err = ia_css_frame_find_crop_resolution(in_res, out_res, &crop_res);
10672 	if (!err)
10673 		*effective_res = crop_res;
10674 	else
10675 		/* in case of error fallback to default
10676 		    * effective resolution from driver. */
10677 		IA_CSS_LOG("ia_css_frame_find_crop_resolution() failed with err(%d)", err);
10678 
10679 	return err;
10680 }
10681 #endif
10682 
10683 static void
10684 sh_css_hmm_buffer_record_init(void)
10685 {
10686 	int i;
10687 
10688 	for (i = 0; i < MAX_HMM_BUFFER_NUM; i++)
10689 		sh_css_hmm_buffer_record_reset(&hmm_buffer_record[i]);
10690 }
10691 
10692 static void
10693 sh_css_hmm_buffer_record_uninit(void)
10694 {
10695 	int i;
10696 	struct sh_css_hmm_buffer_record *buffer_record = NULL;
10697 
10698 	buffer_record = &hmm_buffer_record[0];
10699 	for (i = 0; i < MAX_HMM_BUFFER_NUM; i++) {
10700 		if (buffer_record->in_use) {
10701 			if (buffer_record->h_vbuf)
10702 				ia_css_rmgr_rel_vbuf(hmm_buffer_pool, &buffer_record->h_vbuf);
10703 			sh_css_hmm_buffer_record_reset(buffer_record);
10704 		}
10705 		buffer_record++;
10706 	}
10707 }
10708 
10709 static void
10710 sh_css_hmm_buffer_record_reset(struct sh_css_hmm_buffer_record *buffer_record)
10711 {
10712 	assert(buffer_record);
10713 	buffer_record->in_use = false;
10714 	buffer_record->type = IA_CSS_BUFFER_TYPE_INVALID;
10715 	buffer_record->h_vbuf = NULL;
10716 	buffer_record->kernel_ptr = 0;
10717 }
10718 
10719 static struct sh_css_hmm_buffer_record
10720 *sh_css_hmm_buffer_record_acquire(struct ia_css_rmgr_vbuf_handle *h_vbuf,
10721 				    enum ia_css_buffer_type type,
10722 				    hrt_address kernel_ptr)
10723 {
10724 	int i;
10725 	struct sh_css_hmm_buffer_record *buffer_record = NULL;
10726 	struct sh_css_hmm_buffer_record *out_buffer_record = NULL;
10727 
10728 	assert(h_vbuf);
10729 	assert((type > IA_CSS_BUFFER_TYPE_INVALID) &&
10730 	       (type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE));
10731 	assert(kernel_ptr != 0);
10732 
10733 	buffer_record = &hmm_buffer_record[0];
10734 	for (i = 0; i < MAX_HMM_BUFFER_NUM; i++) {
10735 		if (!buffer_record->in_use) {
10736 			buffer_record->in_use = true;
10737 			buffer_record->type = type;
10738 			buffer_record->h_vbuf = h_vbuf;
10739 			buffer_record->kernel_ptr = kernel_ptr;
10740 			out_buffer_record = buffer_record;
10741 			break;
10742 		}
10743 		buffer_record++;
10744 	}
10745 
10746 	return out_buffer_record;
10747 }
10748 
10749 static struct sh_css_hmm_buffer_record
10750 *sh_css_hmm_buffer_record_validate(ia_css_ptr ddr_buffer_addr,
10751 				    enum ia_css_buffer_type type)
10752 {
10753 	int i;
10754 	struct sh_css_hmm_buffer_record *buffer_record = NULL;
10755 	bool found_record = false;
10756 
10757 	buffer_record = &hmm_buffer_record[0];
10758 	for (i = 0; i < MAX_HMM_BUFFER_NUM; i++) {
10759 		if ((buffer_record->in_use) &&
10760 		    (buffer_record->type == type) &&
10761 		    (buffer_record->h_vbuf) &&
10762 		    (buffer_record->h_vbuf->vptr == ddr_buffer_addr)) {
10763 			found_record = true;
10764 			break;
10765 		}
10766 		buffer_record++;
10767 	}
10768 
10769 	if (found_record)
10770 		return buffer_record;
10771 	else
10772 		return NULL;
10773 }
10774