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