1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Support for Intel Camera Imaging ISP subsystem.
4 * Copyright (c) 2010 - 2015, Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13 * more details.
14 */
15
16#include "hmm.h"
17
18#include "ia_css_debug.h"
19#include "sw_event_global.h"		/* encode_sw_event */
20#include "sp.h"			/* cnd_sp_irq_enable() */
21#include "assert_support.h"
22#include "sh_css_sp.h"
23#include "ia_css_pipeline.h"
24#include "ia_css_isp_param.h"
25#include "ia_css_bufq.h"
26
27#define PIPELINE_NUM_UNMAPPED                   (~0U)
28#define PIPELINE_SP_THREAD_EMPTY_TOKEN          (0x0)
29#define PIPELINE_SP_THREAD_RESERVED_TOKEN       (0x1)
30
31/*******************************************************
32*** Static variables
33********************************************************/
34static unsigned int pipeline_num_to_sp_thread_map[IA_CSS_PIPELINE_NUM_MAX];
35static unsigned int pipeline_sp_thread_list[SH_CSS_MAX_SP_THREADS];
36
37/*******************************************************
38*** Static functions
39********************************************************/
40static void pipeline_init_sp_thread_map(void);
41static void pipeline_map_num_to_sp_thread(unsigned int pipe_num);
42static void pipeline_unmap_num_to_sp_thread(unsigned int pipe_num);
43static void pipeline_init_defaults(
44    struct ia_css_pipeline *pipeline,
45    enum ia_css_pipe_id pipe_id,
46    unsigned int pipe_num,
47    unsigned int dvs_frame_delay);
48
49static void pipeline_stage_destroy(struct ia_css_pipeline_stage *stage);
50static int pipeline_stage_create(
51    struct ia_css_pipeline_stage_desc *stage_desc,
52    struct ia_css_pipeline_stage **new_stage);
53static void ia_css_pipeline_set_zoom_stage(struct ia_css_pipeline *pipeline);
54static void ia_css_pipeline_configure_inout_port(struct ia_css_pipeline *me,
55	bool continuous);
56
57/*******************************************************
58*** Public functions
59********************************************************/
60void ia_css_pipeline_init(void)
61{
62	pipeline_init_sp_thread_map();
63}
64
65int ia_css_pipeline_create(
66    struct ia_css_pipeline *pipeline,
67    enum ia_css_pipe_id pipe_id,
68    unsigned int pipe_num,
69    unsigned int dvs_frame_delay)
70{
71	assert(pipeline);
72	IA_CSS_ENTER_PRIVATE("pipeline = %p, pipe_id = %d, pipe_num = %d, dvs_frame_delay = %d",
73			     pipeline, pipe_id, pipe_num, dvs_frame_delay);
74	if (!pipeline) {
75		IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL);
76		return -EINVAL;
77	}
78
79	pipeline_init_defaults(pipeline, pipe_id, pipe_num, dvs_frame_delay);
80
81	IA_CSS_LEAVE_ERR_PRIVATE(0);
82	return 0;
83}
84
85void ia_css_pipeline_map(unsigned int pipe_num, bool map)
86{
87	assert(pipe_num < IA_CSS_PIPELINE_NUM_MAX);
88	IA_CSS_ENTER_PRIVATE("pipe_num = %d, map = %d", pipe_num, map);
89
90	if (pipe_num >= IA_CSS_PIPELINE_NUM_MAX) {
91		IA_CSS_ERROR("Invalid pipe number");
92		IA_CSS_LEAVE_PRIVATE("void");
93		return;
94	}
95	if (map)
96		pipeline_map_num_to_sp_thread(pipe_num);
97	else
98		pipeline_unmap_num_to_sp_thread(pipe_num);
99	IA_CSS_LEAVE_PRIVATE("void");
100}
101
102/* @brief destroy a pipeline
103 *
104 * @param[in] pipeline
105 * @return    None
106 *
107 */
108void ia_css_pipeline_destroy(struct ia_css_pipeline *pipeline)
109{
110	assert(pipeline);
111	IA_CSS_ENTER_PRIVATE("pipeline = %p", pipeline);
112
113	if (!pipeline) {
114		IA_CSS_ERROR("NULL input parameter");
115		IA_CSS_LEAVE_PRIVATE("void");
116		return;
117	}
118
119	IA_CSS_LOG("pipe_num = %d", pipeline->pipe_num);
120
121	/* Free the pipeline number */
122	ia_css_pipeline_clean(pipeline);
123
124	IA_CSS_LEAVE_PRIVATE("void");
125}
126
127/* Run a pipeline and wait till it completes. */
128void ia_css_pipeline_start(enum ia_css_pipe_id pipe_id,
129			   struct ia_css_pipeline *pipeline)
130{
131	u8 pipe_num = 0;
132	unsigned int thread_id;
133
134	assert(pipeline);
135	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
136			    "ia_css_pipeline_start() enter: pipe_id=%d, pipeline=%p\n",
137			    pipe_id, pipeline);
138	pipeline->pipe_id = pipe_id;
139	sh_css_sp_init_pipeline(pipeline, pipe_id, pipe_num,
140				false, false, false, true, SH_CSS_BDS_FACTOR_1_00,
141				SH_CSS_PIPE_CONFIG_OVRD_NO_OVRD,
142				IA_CSS_INPUT_MODE_MEMORY, NULL, NULL,
143				(enum mipi_port_id)0);
144
145	ia_css_pipeline_get_sp_thread_id(pipe_num, &thread_id);
146	if (!sh_css_sp_is_running()) {
147		ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
148				    "ia_css_pipeline_start() error,leaving\n");
149		/* queues are invalid*/
150		return;
151	}
152	ia_css_bufq_enqueue_psys_event(IA_CSS_PSYS_SW_EVENT_START_STREAM,
153				       (uint8_t)thread_id,
154				       0,
155				       0);
156
157	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
158			    "ia_css_pipeline_start() leave: return_void\n");
159}
160
161/*
162 * @brief Query the SP thread ID.
163 * Refer to "sh_css_internal.h" for details.
164 */
165bool ia_css_pipeline_get_sp_thread_id(unsigned int key, unsigned int *val)
166{
167	IA_CSS_ENTER("key=%d, val=%p", key, val);
168
169	if ((!val) || (key >= IA_CSS_PIPELINE_NUM_MAX) || (key >= IA_CSS_PIPE_ID_NUM)) {
170		IA_CSS_LEAVE("return value = false");
171		return false;
172	}
173
174	*val = pipeline_num_to_sp_thread_map[key];
175
176	if (*val == (unsigned int)PIPELINE_NUM_UNMAPPED) {
177		IA_CSS_LOG("unmapped pipeline number");
178		IA_CSS_LEAVE("return value = false");
179		return false;
180	}
181	IA_CSS_LEAVE("return value = true");
182	return true;
183}
184
185void ia_css_pipeline_dump_thread_map_info(void)
186{
187	unsigned int i;
188
189	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
190			    "pipeline_num_to_sp_thread_map:\n");
191	for (i = 0; i < IA_CSS_PIPELINE_NUM_MAX; i++) {
192		ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
193				    "pipe_num: %u, tid: 0x%x\n", i, pipeline_num_to_sp_thread_map[i]);
194	}
195}
196
197int ia_css_pipeline_request_stop(struct ia_css_pipeline *pipeline)
198{
199	int err = 0;
200	unsigned int thread_id;
201
202	assert(pipeline);
203
204	if (!pipeline)
205		return -EINVAL;
206
207	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
208			    "ia_css_pipeline_request_stop() enter: pipeline=%p\n",
209			    pipeline);
210	pipeline->stop_requested = true;
211
212	/* Send stop event to the sp*/
213	/* This needs improvement, stop on all the pipes available
214	 * in the stream*/
215	ia_css_pipeline_get_sp_thread_id(pipeline->pipe_num, &thread_id);
216	if (!sh_css_sp_is_running()) {
217		ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
218				    "ia_css_pipeline_request_stop() leaving\n");
219		/* queues are invalid */
220		return -EBUSY;
221	}
222	ia_css_bufq_enqueue_psys_event(IA_CSS_PSYS_SW_EVENT_STOP_STREAM,
223				       (uint8_t)thread_id,
224				       0,
225				       0);
226	sh_css_sp_uninit_pipeline(pipeline->pipe_num);
227
228	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
229			    "ia_css_pipeline_request_stop() leave: return_err=%d\n",
230			    err);
231	return err;
232}
233
234void ia_css_pipeline_clean(struct ia_css_pipeline *pipeline)
235{
236	struct ia_css_pipeline_stage *s;
237
238	assert(pipeline);
239	IA_CSS_ENTER_PRIVATE("pipeline = %p", pipeline);
240
241	if (!pipeline) {
242		IA_CSS_ERROR("NULL input parameter");
243		IA_CSS_LEAVE_PRIVATE("void");
244		return;
245	}
246	s = pipeline->stages;
247
248	while (s) {
249		struct ia_css_pipeline_stage *next = s->next;
250
251		pipeline_stage_destroy(s);
252		s = next;
253	}
254	pipeline_init_defaults(pipeline, pipeline->pipe_id, pipeline->pipe_num,
255			       pipeline->dvs_frame_delay);
256
257	IA_CSS_LEAVE_PRIVATE("void");
258}
259
260/* @brief Add a stage to pipeline.
261 *
262 * @param       pipeline      Pointer to the pipeline to be added to.
263 * @param[in]   stage_desc    The description of the stage
264 * @param[out]	stage         The successor of the stage.
265 * @return      0 or error code upon error.
266 *
267 * Add a new stage to a non-NULL pipeline.
268 * The stage consists of an ISP binary or firmware and input and
269 * output arguments.
270*/
271int ia_css_pipeline_create_and_add_stage(
272    struct ia_css_pipeline *pipeline,
273    struct ia_css_pipeline_stage_desc *stage_desc,
274    struct ia_css_pipeline_stage **stage)
275{
276	struct ia_css_pipeline_stage *last, *new_stage = NULL;
277	int err;
278
279	/* other arguments can be NULL */
280	assert(pipeline);
281	assert(stage_desc);
282	last = pipeline->stages;
283
284	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
285			    "ia_css_pipeline_create_and_add_stage() enter:\n");
286	if (!stage_desc->binary && !stage_desc->firmware
287	    && (stage_desc->sp_func == IA_CSS_PIPELINE_NO_FUNC)) {
288		ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
289				    "ia_css_pipeline_create_and_add_stage() done: Invalid args\n");
290
291		return -EINVAL;
292	}
293
294	/* Find the last stage */
295	while (last && last->next)
296		last = last->next;
297
298	/* if in_frame is not set, we use the out_frame from the previous
299	 * stage, if no previous stage, it's an error.
300	 */
301	if ((stage_desc->sp_func == IA_CSS_PIPELINE_NO_FUNC)
302	    && (!stage_desc->in_frame)
303	    && (!stage_desc->firmware)
304	    && (!stage_desc->binary->online)) {
305		/* Do this only for ISP stages*/
306		if (last && last->args.out_frame[0])
307			stage_desc->in_frame = last->args.out_frame[0];
308
309		if (!stage_desc->in_frame)
310			return -EINVAL;
311	}
312
313	/* Create the new stage */
314	err = pipeline_stage_create(stage_desc, &new_stage);
315	if (err) {
316		ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
317				    "ia_css_pipeline_create_and_add_stage() done: stage_create_failed\n");
318		return err;
319	}
320
321	if (last)
322		last->next = new_stage;
323	else
324		pipeline->stages = new_stage;
325
326	/* Output the new stage */
327	if (stage)
328		*stage = new_stage;
329
330	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
331			    "ia_css_pipeline_create_and_add_stage() done:\n");
332	return 0;
333}
334
335void ia_css_pipeline_finalize_stages(struct ia_css_pipeline *pipeline,
336				     bool continuous)
337{
338	unsigned int i = 0;
339	struct ia_css_pipeline_stage *stage;
340
341	assert(pipeline);
342	for (stage = pipeline->stages; stage; stage = stage->next) {
343		stage->stage_num = i;
344		i++;
345	}
346	pipeline->num_stages = i;
347
348	ia_css_pipeline_set_zoom_stage(pipeline);
349	ia_css_pipeline_configure_inout_port(pipeline, continuous);
350}
351
352int ia_css_pipeline_get_stage(struct ia_css_pipeline *pipeline,
353	int mode,
354	struct ia_css_pipeline_stage **stage)
355{
356	struct ia_css_pipeline_stage *s;
357
358	assert(pipeline);
359	assert(stage);
360	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
361			    "ia_css_pipeline_get_stage() enter:\n");
362	for (s = pipeline->stages; s; s = s->next) {
363		if (s->mode == mode) {
364			*stage = s;
365			return 0;
366		}
367	}
368	return -EINVAL;
369}
370
371int ia_css_pipeline_get_stage_from_fw(struct ia_css_pipeline
372	*pipeline,
373	u32 fw_handle,
374	struct ia_css_pipeline_stage **stage)
375{
376	struct ia_css_pipeline_stage *s;
377
378	assert(pipeline);
379	assert(stage);
380	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "%s()\n", __func__);
381	for (s = pipeline->stages; s; s = s->next) {
382		if ((s->firmware) && (s->firmware->handle == fw_handle)) {
383			*stage = s;
384			return 0;
385		}
386	}
387	return -EINVAL;
388}
389
390int ia_css_pipeline_get_fw_from_stage(struct ia_css_pipeline
391	*pipeline,
392	u32 stage_num,
393	uint32_t *fw_handle)
394{
395	struct ia_css_pipeline_stage *s;
396
397	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "%s()\n", __func__);
398	if ((!pipeline) || (!fw_handle))
399		return -EINVAL;
400
401	for (s = pipeline->stages; s; s = s->next) {
402		if ((s->stage_num == stage_num) && (s->firmware)) {
403			*fw_handle = s->firmware->handle;
404			return 0;
405		}
406	}
407	return -EINVAL;
408}
409
410int ia_css_pipeline_get_output_stage(
411    struct ia_css_pipeline *pipeline,
412    int mode,
413    struct ia_css_pipeline_stage **stage)
414{
415	struct ia_css_pipeline_stage *s;
416
417	assert(pipeline);
418	assert(stage);
419	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
420			    "ia_css_pipeline_get_output_stage() enter:\n");
421
422	*stage = NULL;
423	/* First find acceleration firmware at end of pipe */
424	for (s = pipeline->stages; s; s = s->next) {
425		if (s->firmware && s->mode == mode &&
426		    s->firmware->info.isp.sp.enable.output)
427			*stage = s;
428	}
429	if (*stage)
430		return 0;
431	/* If no firmware, find binary in pipe */
432	return ia_css_pipeline_get_stage(pipeline, mode, stage);
433}
434
435bool ia_css_pipeline_has_stopped(struct ia_css_pipeline *pipeline)
436{
437	/* Android compilation files if made an local variable
438	stack size on android is limited to 2k and this structure
439	is around 2.5K, in place of static malloc can be done but
440	if this call is made too often it will lead to fragment memory
441	versus a fixed allocation */
442	static struct sh_css_sp_group sp_group;
443	unsigned int thread_id;
444	const struct ia_css_fw_info *fw;
445	unsigned int HIVE_ADDR_sp_group;
446
447	fw = &sh_css_sp_fw;
448	HIVE_ADDR_sp_group = fw->info.sp.group;
449
450	ia_css_pipeline_get_sp_thread_id(pipeline->pipe_num, &thread_id);
451	sp_dmem_load(SP0_ID,
452		     (unsigned int)sp_address_of(sp_group),
453		     &sp_group, sizeof(struct sh_css_sp_group));
454	return sp_group.pipe[thread_id].num_stages == 0;
455}
456
457struct sh_css_sp_pipeline_io_status *ia_css_pipeline_get_pipe_io_status(void)
458{
459	return(&sh_css_sp_group.pipe_io_status);
460}
461
462bool ia_css_pipeline_is_mapped(unsigned int key)
463{
464	bool ret = false;
465
466	IA_CSS_ENTER_PRIVATE("key = %d", key);
467
468	if ((key >= IA_CSS_PIPELINE_NUM_MAX) || (key >= IA_CSS_PIPE_ID_NUM)) {
469		IA_CSS_ERROR("Invalid key!!");
470		IA_CSS_LEAVE_PRIVATE("return = %d", false);
471		return false;
472	}
473
474	ret = (bool)(pipeline_num_to_sp_thread_map[key] != (unsigned int)
475		     PIPELINE_NUM_UNMAPPED);
476
477	IA_CSS_LEAVE_PRIVATE("return = %d", ret);
478	return ret;
479}
480
481/*******************************************************
482*** Static functions
483********************************************************/
484
485/* Pipeline:
486 * To organize the several different binaries for each type of mode,
487 * we use a pipeline. A pipeline contains a number of stages, each with
488 * their own binary and frame pointers.
489 * When stages are added to a pipeline, output frames that are not passed
490 * from outside are automatically allocated.
491 * When input frames are not passed from outside, each stage will use the
492 * output frame of the previous stage as input (the full resolution output,
493 * not the viewfinder output).
494 * Pipelines must be cleaned and re-created when settings of the binaries
495 * change.
496 */
497static void pipeline_stage_destroy(struct ia_css_pipeline_stage *stage)
498{
499	unsigned int i;
500
501	for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) {
502		if (stage->out_frame_allocated[i]) {
503			ia_css_frame_free(stage->args.out_frame[i]);
504			stage->args.out_frame[i] = NULL;
505		}
506	}
507	if (stage->vf_frame_allocated) {
508		ia_css_frame_free(stage->args.out_vf_frame);
509		stage->args.out_vf_frame = NULL;
510	}
511	kvfree(stage);
512}
513
514static void pipeline_init_sp_thread_map(void)
515{
516	unsigned int i;
517
518	for (i = 1; i < SH_CSS_MAX_SP_THREADS; i++)
519		pipeline_sp_thread_list[i] = PIPELINE_SP_THREAD_EMPTY_TOKEN;
520
521	for (i = 0; i < IA_CSS_PIPELINE_NUM_MAX; i++)
522		pipeline_num_to_sp_thread_map[i] = PIPELINE_NUM_UNMAPPED;
523}
524
525static void pipeline_map_num_to_sp_thread(unsigned int pipe_num)
526{
527	unsigned int i;
528	bool found_sp_thread = false;
529
530	/* pipe is not mapped to any thread */
531	assert(pipeline_num_to_sp_thread_map[pipe_num]
532	       == (unsigned int)PIPELINE_NUM_UNMAPPED);
533
534	for (i = 0; i < SH_CSS_MAX_SP_THREADS; i++) {
535		if (pipeline_sp_thread_list[i] ==
536		    PIPELINE_SP_THREAD_EMPTY_TOKEN) {
537			pipeline_sp_thread_list[i] =
538			    PIPELINE_SP_THREAD_RESERVED_TOKEN;
539			pipeline_num_to_sp_thread_map[pipe_num] = i;
540			found_sp_thread = true;
541			break;
542		}
543	}
544
545	/* Make sure a mapping is found */
546	/* I could do:
547		assert(i < SH_CSS_MAX_SP_THREADS);
548
549		But the below is more descriptive.
550	*/
551	assert(found_sp_thread);
552}
553
554static void pipeline_unmap_num_to_sp_thread(unsigned int pipe_num)
555{
556	unsigned int thread_id;
557
558	assert(pipeline_num_to_sp_thread_map[pipe_num]
559	       != (unsigned int)PIPELINE_NUM_UNMAPPED);
560
561	thread_id = pipeline_num_to_sp_thread_map[pipe_num];
562	pipeline_num_to_sp_thread_map[pipe_num] = PIPELINE_NUM_UNMAPPED;
563	pipeline_sp_thread_list[thread_id] = PIPELINE_SP_THREAD_EMPTY_TOKEN;
564}
565
566static int pipeline_stage_create(
567    struct ia_css_pipeline_stage_desc *stage_desc,
568    struct ia_css_pipeline_stage **new_stage)
569{
570	int err = 0;
571	struct ia_css_pipeline_stage *stage = NULL;
572	struct ia_css_binary *binary;
573	struct ia_css_frame *vf_frame;
574	struct ia_css_frame *out_frame[IA_CSS_BINARY_MAX_OUTPUT_PORTS];
575	const struct ia_css_fw_info *firmware;
576	unsigned int i;
577
578	/* Verify input parameters*/
579	if (!(stage_desc->in_frame) && !(stage_desc->firmware)
580	    && (stage_desc->binary) && !(stage_desc->binary->online)) {
581		err = -EINVAL;
582		goto ERR;
583	}
584
585	binary = stage_desc->binary;
586	firmware = stage_desc->firmware;
587	vf_frame = stage_desc->vf_frame;
588	for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) {
589		out_frame[i] = stage_desc->out_frame[i];
590	}
591
592	stage = kvzalloc(sizeof(*stage), GFP_KERNEL);
593	if (!stage) {
594		err = -ENOMEM;
595		goto ERR;
596	}
597
598	if (firmware) {
599		stage->binary = NULL;
600		stage->binary_info =
601		    (struct ia_css_binary_info *)&firmware->info.isp;
602	} else {
603		stage->binary = binary;
604		if (binary)
605			stage->binary_info =
606			    (struct ia_css_binary_info *)binary->info;
607		else
608			stage->binary_info = NULL;
609	}
610
611	stage->firmware = firmware;
612	stage->sp_func = stage_desc->sp_func;
613	stage->max_input_width = stage_desc->max_input_width;
614	stage->mode = stage_desc->mode;
615	for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++)
616		stage->out_frame_allocated[i] = false;
617	stage->vf_frame_allocated = false;
618	stage->next = NULL;
619	sh_css_binary_args_reset(&stage->args);
620
621	for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) {
622		if (!(out_frame[i]) && (binary)
623		    && (binary->out_frame_info[i].res.width)) {
624			err = ia_css_frame_allocate_from_info(&out_frame[i],
625							      &binary->out_frame_info[i]);
626			if (err)
627				goto ERR;
628			stage->out_frame_allocated[i] = true;
629		}
630	}
631	/* VF frame is not needed in case of need_pp
632	   However, the capture binary needs a vf frame to write to.
633	 */
634	if (!vf_frame) {
635		if ((binary && binary->vf_frame_info.res.width) ||
636		    (firmware && firmware->info.isp.sp.enable.vf_veceven)
637		   ) {
638			err = ia_css_frame_allocate_from_info(&vf_frame,
639							      &binary->vf_frame_info);
640			if (err)
641				goto ERR;
642			stage->vf_frame_allocated = true;
643		}
644	} else if (vf_frame && binary && binary->vf_frame_info.res.width
645		   && !firmware) {
646		/* only mark as allocated if buffer pointer available */
647		if (vf_frame->data != mmgr_NULL)
648			stage->vf_frame_allocated = true;
649	}
650
651	stage->args.in_frame = stage_desc->in_frame;
652	for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++)
653		stage->args.out_frame[i] = out_frame[i];
654	stage->args.out_vf_frame = vf_frame;
655	*new_stage = stage;
656	return err;
657ERR:
658	if (stage)
659		pipeline_stage_destroy(stage);
660	return err;
661}
662
663static const struct ia_css_frame ia_css_default_frame = DEFAULT_FRAME;
664
665static void pipeline_init_defaults(
666    struct ia_css_pipeline *pipeline,
667    enum ia_css_pipe_id pipe_id,
668    unsigned int pipe_num,
669    unsigned int dvs_frame_delay)
670{
671	unsigned int i;
672
673	pipeline->pipe_id = pipe_id;
674	pipeline->stages = NULL;
675	pipeline->stop_requested = false;
676	pipeline->current_stage = NULL;
677
678	memcpy(&pipeline->in_frame, &ia_css_default_frame,
679	       sizeof(ia_css_default_frame));
680
681	for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) {
682		memcpy(&pipeline->out_frame[i], &ia_css_default_frame,
683		       sizeof(ia_css_default_frame));
684		memcpy(&pipeline->vf_frame[i], &ia_css_default_frame,
685		       sizeof(ia_css_default_frame));
686	}
687	pipeline->num_execs = -1;
688	pipeline->acquire_isp_each_stage = true;
689	pipeline->pipe_num = (uint8_t)pipe_num;
690	pipeline->dvs_frame_delay = dvs_frame_delay;
691}
692
693static void ia_css_pipeline_set_zoom_stage(struct ia_css_pipeline *pipeline)
694{
695	struct ia_css_pipeline_stage *stage = NULL;
696	int err;
697
698	assert(pipeline);
699	if (pipeline->pipe_id == IA_CSS_PIPE_ID_PREVIEW) {
700		/* in preview pipeline, vf_pp stage should do zoom */
701		err = ia_css_pipeline_get_stage(pipeline, IA_CSS_BINARY_MODE_VF_PP, &stage);
702		if (!err)
703			stage->enable_zoom = true;
704	} else if (pipeline->pipe_id == IA_CSS_PIPE_ID_CAPTURE) {
705		/* in capture pipeline, capture_pp stage should do zoom */
706		err = ia_css_pipeline_get_stage(pipeline, IA_CSS_BINARY_MODE_CAPTURE_PP,
707						&stage);
708		if (!err)
709			stage->enable_zoom = true;
710	} else if (pipeline->pipe_id == IA_CSS_PIPE_ID_VIDEO) {
711		/* in video pipeline, video stage should do zoom */
712		err = ia_css_pipeline_get_stage(pipeline, IA_CSS_BINARY_MODE_VIDEO, &stage);
713		if (!err)
714			stage->enable_zoom = true;
715	} else if (pipeline->pipe_id == IA_CSS_PIPE_ID_YUVPP) {
716		/* in yuvpp pipeline, first yuv_scaler stage should do zoom */
717		err = ia_css_pipeline_get_stage(pipeline, IA_CSS_BINARY_MODE_CAPTURE_PP,
718						&stage);
719		if (!err)
720			stage->enable_zoom = true;
721	}
722}
723
724static void
725ia_css_pipeline_configure_inout_port(struct ia_css_pipeline *me,
726				     bool continuous)
727{
728	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
729			    "ia_css_pipeline_configure_inout_port() enter: pipe_id(%d) continuous(%d)\n",
730			    me->pipe_id, continuous);
731	switch (me->pipe_id) {
732	case IA_CSS_PIPE_ID_PREVIEW:
733	case IA_CSS_PIPE_ID_VIDEO:
734		SH_CSS_PIPE_PORT_CONFIG_SET(me->inout_port_config,
735					    (uint8_t)SH_CSS_PORT_INPUT,
736					    (uint8_t)(continuous ? SH_CSS_COPYSINK_TYPE : SH_CSS_HOST_TYPE), 1);
737		SH_CSS_PIPE_PORT_CONFIG_SET(me->inout_port_config,
738					    (uint8_t)SH_CSS_PORT_OUTPUT,
739					    (uint8_t)SH_CSS_HOST_TYPE, 1);
740		break;
741	case IA_CSS_PIPE_ID_COPY: /*Copy pipe ports configured to "offline" mode*/
742		SH_CSS_PIPE_PORT_CONFIG_SET(me->inout_port_config,
743					    (uint8_t)SH_CSS_PORT_INPUT,
744					    (uint8_t)SH_CSS_HOST_TYPE, 1);
745		if (continuous) {
746			SH_CSS_PIPE_PORT_CONFIG_SET(me->inout_port_config,
747						    (uint8_t)SH_CSS_PORT_OUTPUT,
748						    (uint8_t)SH_CSS_COPYSINK_TYPE, 1);
749			SH_CSS_PIPE_PORT_CONFIG_SET(me->inout_port_config,
750						    (uint8_t)SH_CSS_PORT_OUTPUT,
751						    (uint8_t)SH_CSS_TAGGERSINK_TYPE, 1);
752		} else {
753			SH_CSS_PIPE_PORT_CONFIG_SET(me->inout_port_config,
754						    (uint8_t)SH_CSS_PORT_OUTPUT,
755						    (uint8_t)SH_CSS_HOST_TYPE, 1);
756		}
757		break;
758	case IA_CSS_PIPE_ID_CAPTURE:
759		SH_CSS_PIPE_PORT_CONFIG_SET(me->inout_port_config,
760					    (uint8_t)SH_CSS_PORT_INPUT,
761					    (uint8_t)(continuous ? SH_CSS_TAGGERSINK_TYPE : SH_CSS_HOST_TYPE),
762					    1);
763		SH_CSS_PIPE_PORT_CONFIG_SET(me->inout_port_config,
764					    (uint8_t)SH_CSS_PORT_OUTPUT,
765					    (uint8_t)SH_CSS_HOST_TYPE, 1);
766		break;
767	case IA_CSS_PIPE_ID_YUVPP:
768		SH_CSS_PIPE_PORT_CONFIG_SET(me->inout_port_config,
769					    (uint8_t)SH_CSS_PORT_INPUT,
770					    (uint8_t)(SH_CSS_HOST_TYPE), 1);
771		SH_CSS_PIPE_PORT_CONFIG_SET(me->inout_port_config,
772					    (uint8_t)SH_CSS_PORT_OUTPUT,
773					    (uint8_t)SH_CSS_HOST_TYPE, 1);
774		break;
775	default:
776		break;
777	}
778	ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
779			    "ia_css_pipeline_configure_inout_port() leave: inout_port_config(%x)\n",
780			    me->inout_port_config);
781}
782