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