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