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