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