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