File Index
Files and directories
Sign in
FILE

sh_css.c

File preview with syntax highlighting.

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