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