GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / staging / media / atomisp / pci / sh_css_mipi.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Support for Intel Camera Imaging ISP subsystem.
4  * Copyright (c) 2015, Intel Corporation.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  */
15
16 #include "ia_css_mipi.h"
17 #include "sh_css_mipi.h"
18 #include <type_support.h>
19 #include "system_global.h"
20 #include "ia_css_err.h"
21 #include "ia_css_pipe.h"
22 #include "ia_css_stream_format.h"
23 #include "sh_css_stream_format.h"
24 #include "ia_css_stream_public.h"
25 #include "ia_css_frame_public.h"
26 #include "ia_css_input_port.h"
27 #include "ia_css_debug.h"
28 #include "sh_css_struct.h"
29 #include "sh_css_defs.h"
30 #include "sh_css_sp.h" /* sh_css_update_host2sp_mipi_frame sh_css_update_host2sp_num_mipi_frames ... */
31 #include "sw_event_global.h" /* IA_CSS_PSYS_SW_EVENT_MIPI_BUFFERS_READY */
32
33 static u32
34 ref_count_mipi_allocation[N_CSI_PORTS]; /* Initialized in mipi_init */
35
36 /* Assumptions:
37  *      - A line is multiple of 4 bytes = 1 word.
38  *      - Each frame has SOF and EOF (each 1 word).
39  *      - Each line has format header and optionally SOL and EOL (each 1 word).
40  *      - Odd and even lines of YUV420 format are different in bites per pixel size.
41  *      - Custom size of embedded data.
42  *  -- Interleaved frames are not taken into account.
43  *  -- Lines are multiples of 8B, and not necessary of (custom 3B, or 7B
44  *  etc.).
45  * Result is given in DDR mem words, 32B or 256 bits
46  */
47 int
48 ia_css_mipi_frame_calculate_size(const unsigned int width,
49                                  const unsigned int height,
50                                  const enum atomisp_input_format format,
51                                  const bool hasSOLandEOL,
52                                  const unsigned int embedded_data_size_words,
53                                  unsigned int *size_mem_words)
54 {
55         int err = 0;
56
57         unsigned int bits_per_pixel = 0;
58         unsigned int even_line_bytes = 0;
59         unsigned int odd_line_bytes = 0;
60         unsigned int words_per_odd_line = 0;
61         unsigned int words_for_first_line = 0;
62         unsigned int words_per_even_line = 0;
63         unsigned int mem_words_per_even_line = 0;
64         unsigned int mem_words_per_odd_line = 0;
65         unsigned int mem_words_for_first_line = 0;
66         unsigned int mem_words_for_EOF = 0;
67         unsigned int mem_words = 0;
68         unsigned int width_padded = width;
69
70 #if defined(ISP2401)
71         /* The changes will be reverted as soon as RAW
72          * Buffers are deployed by the 2401 Input System
73          * in the non-continuous use scenario.
74          */
75         width_padded += (2 * ISP_VEC_NELEMS);
76 #endif
77
78         IA_CSS_ENTER("padded_width=%d, height=%d, format=%d, hasSOLandEOL=%d, embedded_data_size_words=%d\n",
79                      width_padded, height, format, hasSOLandEOL, embedded_data_size_words);
80
81         switch (format) {
82         case ATOMISP_INPUT_FORMAT_RAW_6:                /* 4p, 3B, 24bits */
83                 bits_per_pixel = 6;
84                 break;
85         case ATOMISP_INPUT_FORMAT_RAW_7:                /* 8p, 7B, 56bits */
86                 bits_per_pixel = 7;
87                 break;
88         case ATOMISP_INPUT_FORMAT_RAW_8:                /* 1p, 1B, 8bits */
89         case ATOMISP_INPUT_FORMAT_BINARY_8:             /*  8bits, TODO: check. */
90         case ATOMISP_INPUT_FORMAT_YUV420_8:             /* odd 2p, 2B, 16bits, even 2p, 4B, 32bits */
91                 bits_per_pixel = 8;
92                 break;
93         case ATOMISP_INPUT_FORMAT_YUV420_10:            /* odd 4p, 5B, 40bits, even 4p, 10B, 80bits */
94         case ATOMISP_INPUT_FORMAT_RAW_10:               /* 4p, 5B, 40bits */
95                 /* The changes will be reverted as soon as RAW
96                  * Buffers are deployed by the 2401 Input System
97                  * in the non-continuous use scenario.
98                  */
99                 bits_per_pixel = 10;
100                 break;
101         case ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY:      /* 2p, 3B, 24bits */
102         case ATOMISP_INPUT_FORMAT_RAW_12:               /* 2p, 3B, 24bits */
103                 bits_per_pixel = 12;
104                 break;
105         case ATOMISP_INPUT_FORMAT_RAW_14:               /* 4p, 7B, 56bits */
106                 bits_per_pixel = 14;
107                 break;
108         case ATOMISP_INPUT_FORMAT_RGB_444:              /* 1p, 2B, 16bits */
109         case ATOMISP_INPUT_FORMAT_RGB_555:              /* 1p, 2B, 16bits */
110         case ATOMISP_INPUT_FORMAT_RGB_565:              /* 1p, 2B, 16bits */
111         case ATOMISP_INPUT_FORMAT_YUV422_8:             /* 2p, 4B, 32bits */
112                 bits_per_pixel = 16;
113                 break;
114         case ATOMISP_INPUT_FORMAT_RGB_666:              /* 4p, 9B, 72bits */
115                 bits_per_pixel = 18;
116                 break;
117         case ATOMISP_INPUT_FORMAT_YUV422_10:            /* 2p, 5B, 40bits */
118                 bits_per_pixel = 20;
119                 break;
120         case ATOMISP_INPUT_FORMAT_RGB_888:              /* 1p, 3B, 24bits */
121                 bits_per_pixel = 24;
122                 break;
123
124         case ATOMISP_INPUT_FORMAT_YUV420_16:            /* Not supported */
125         case ATOMISP_INPUT_FORMAT_YUV422_16:            /* Not supported */
126         case ATOMISP_INPUT_FORMAT_RAW_16:               /* TODO: not specified in MIPI SPEC, check */
127         default:
128                 return -EINVAL;
129         }
130
131         odd_line_bytes = (width_padded * bits_per_pixel + 7) >> 3; /* ceil ( bits per line / 8) */
132
133         /* Even lines for YUV420 formats are double in bits_per_pixel. */
134         if (format == ATOMISP_INPUT_FORMAT_YUV420_8
135             || format == ATOMISP_INPUT_FORMAT_YUV420_10
136             || format == ATOMISP_INPUT_FORMAT_YUV420_16) {
137                 even_line_bytes = (width_padded * 2 * bits_per_pixel + 7) >>
138                         3; /* ceil ( bits per line / 8) */
139         } else {
140                 even_line_bytes = odd_line_bytes;
141         }
142
143         /*  a frame represented in memory:  ()- optional; data - payload words.
144         *  addr         0       1       2       3       4       5       6       7:
145         *  first        SOF     (SOL)   PACK_H  data    data    data    data    data
146         *               data    data    data    data    data    data    data    data
147         *               ...
148         *               data    data    0       0       0       0       0       0
149         *  second       (EOL)   (SOL)   PACK_H  data    data    data    data    data
150         *               data    data    data    data    data    data    data    data
151         *               ...
152         *               data    data    0       0       0       0       0       0
153         *  ...
154         *  last         (EOL)   EOF     0       0       0       0       0       0
155         *
156         *  Embedded lines are regular lines stored before the first and after
157         *  payload lines.
158         */
159
160         words_per_odd_line = (odd_line_bytes + 3) >> 2;
161         /* ceil(odd_line_bytes/4); word = 4 bytes */
162         words_per_even_line  = (even_line_bytes  + 3) >> 2;
163         words_for_first_line = words_per_odd_line + 2 + (hasSOLandEOL ? 1 : 0);
164         /* + SOF +packet header + optionally (SOL), but (EOL) is not in the first line */
165         words_per_odd_line      += (1 + (hasSOLandEOL ? 2 : 0));
166         /* each non-first line has format header, and optionally (SOL) and (EOL). */
167         words_per_even_line += (1 + (hasSOLandEOL ? 2 : 0));
168
169         mem_words_per_odd_line   = (words_per_odd_line + 7) >> 3;
170         /* ceil(words_per_odd_line/8); mem_word = 32 bytes, 8 words */
171         mem_words_for_first_line = (words_for_first_line + 7) >> 3;
172         mem_words_per_even_line  = (words_per_even_line + 7) >> 3;
173         mem_words_for_EOF        = 1; /* last line consisit of the optional (EOL) and EOF */
174
175         mem_words = ((embedded_data_size_words + 7) >> 3) +
176         mem_words_for_first_line +
177         (((height + 1) >> 1) - 1) * mem_words_per_odd_line +
178         /* ceil (height/2) - 1 (first line is calculated separatelly) */
179         (height      >> 1) * mem_words_per_even_line + /* floor(height/2) */
180         mem_words_for_EOF;
181
182         *size_mem_words = mem_words; /* ceil(words/8); mem word is 32B = 8words. */
183         /* Check if the above is still needed. */
184
185         IA_CSS_LEAVE_ERR(err);
186         return err;
187 }
188
189 /*
190  * Check if a source port or TPG/PRBS ID is valid
191  */
192
193 #if !defined(ISP2401)
194 int
195 ia_css_mipi_frame_enable_check_on_size(const enum mipi_port_id port,
196                                        const unsigned int       size_mem_words)
197 {
198         u32 idx;
199
200         int err = -EBUSY;
201
202         OP___assert(port < N_CSI_PORTS);
203         OP___assert(size_mem_words != 0);
204
205         for (idx = 0; idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT &&
206              my_css.mipi_sizes_for_check[port][idx] != 0;
207              idx++) { /* do nothing */
208         }
209         if (idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT) {
210                 my_css.mipi_sizes_for_check[port][idx] = size_mem_words;
211                 err = 0;
212         }
213
214         return err;
215 }
216 #endif
217
218 void
219 mipi_init(void)
220 {
221         unsigned int i;
222
223         for (i = 0; i < N_CSI_PORTS; i++)
224                 ref_count_mipi_allocation[i] = 0;
225 }
226
227 bool mipi_is_free(void)
228 {
229         unsigned int i;
230
231         for (i = 0; i < N_CSI_PORTS; i++)
232                 if (ref_count_mipi_allocation[i])
233                         return false;
234
235         return true;
236 }
237
238 #if defined(ISP2401)
239 /*
240  * @brief Calculate the required MIPI buffer sizes.
241  * Based on the stream configuration, calculate the
242  * required MIPI buffer sizes (in DDR words).
243  *
244  * @param[in]   stream_cfg              Point to the target stream configuration
245  * @param[out]  size_mem_words  MIPI buffer size in DDR words.
246  *
247  * @return
248  */
249 static int calculate_mipi_buff_size(struct ia_css_stream_config *stream_cfg,
250                                     unsigned int *size_mem_words)
251 {
252         unsigned int width;
253         unsigned int height;
254         enum atomisp_input_format format;
255         bool pack_raw_pixels;
256
257         unsigned int width_padded;
258         unsigned int bits_per_pixel = 0;
259
260         unsigned int even_line_bytes = 0;
261         unsigned int odd_line_bytes = 0;
262
263         unsigned int words_per_odd_line = 0;
264         unsigned int words_per_even_line = 0;
265
266         unsigned int mem_words_per_even_line = 0;
267         unsigned int mem_words_per_odd_line = 0;
268
269         unsigned int mem_words_per_buff_line = 0;
270         unsigned int mem_words_per_buff = 0;
271         int err = 0;
272
273         /**
274          * zhengjie.lu@intel.com
275          *
276          * NOTE
277          * - In the struct "ia_css_stream_config", there
278          *   are two members: "input_config" and "isys_config".
279          *   Both of them provide the same information, e.g.
280          *   input_res and format.
281          *
282          *   Question here is that: which one shall be used?
283          */
284         width = stream_cfg->input_config.input_res.width;
285         height = stream_cfg->input_config.input_res.height;
286         format = stream_cfg->input_config.format;
287         pack_raw_pixels = stream_cfg->pack_raw_pixels;
288         /* end of NOTE */
289
290         /**
291          * zhengjie.lu@intel.com
292          *
293          * NOTE
294          * - The following code is derived from the
295          *   existing code "ia_css_mipi_frame_calculate_size()".
296          *
297          *   Question here is: why adding "2 * ISP_VEC_NELEMS"
298          *   to "width_padded", but not making "width_padded"
299          *   aligned with "2 * ISP_VEC_NELEMS"?
300          */
301         /* The changes will be reverted as soon as RAW
302          * Buffers are deployed by the 2401 Input System
303          * in the non-continuous use scenario.
304          */
305         width_padded = width + (2 * ISP_VEC_NELEMS);
306         /* end of NOTE */
307
308         IA_CSS_ENTER("padded_width=%d, height=%d, format=%d\n",
309                      width_padded, height, format);
310
311         bits_per_pixel = sh_css_stream_format_2_bits_per_subpixel(format);
312         bits_per_pixel =
313         (format == ATOMISP_INPUT_FORMAT_RAW_10 && pack_raw_pixels) ? bits_per_pixel : 16;
314         if (bits_per_pixel == 0)
315                 return -EINVAL;
316
317         odd_line_bytes = (width_padded * bits_per_pixel + 7) >> 3; /* ceil ( bits per line / 8) */
318
319         /* Even lines for YUV420 formats are double in bits_per_pixel. */
320         if (format == ATOMISP_INPUT_FORMAT_YUV420_8
321             || format == ATOMISP_INPUT_FORMAT_YUV420_10) {
322                 even_line_bytes = (width_padded * 2 * bits_per_pixel + 7) >>
323                         3; /* ceil ( bits per line / 8) */
324         } else {
325                 even_line_bytes = odd_line_bytes;
326         }
327
328         words_per_odd_line       = (odd_line_bytes   + 3) >> 2;
329         /* ceil(odd_line_bytes/4); word = 4 bytes */
330         words_per_even_line  = (even_line_bytes  + 3) >> 2;
331
332         mem_words_per_odd_line   = (words_per_odd_line + 7) >> 3;
333         /* ceil(words_per_odd_line/8); mem_word = 32 bytes, 8 words */
334         mem_words_per_even_line  = (words_per_even_line + 7) >> 3;
335
336         mem_words_per_buff_line =
337         (mem_words_per_odd_line > mem_words_per_even_line) ? mem_words_per_odd_line : mem_words_per_even_line;
338         mem_words_per_buff = mem_words_per_buff_line * height;
339
340         *size_mem_words = mem_words_per_buff;
341
342         IA_CSS_LEAVE_ERR(err);
343         return err;
344 }
345 #endif
346
347 int
348 allocate_mipi_frames(struct ia_css_pipe *pipe,
349                      struct ia_css_stream_info *info)
350 {
351         int err = -EINVAL;
352         unsigned int port;
353
354         ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
355                             "allocate_mipi_frames(%p) enter:\n", pipe);
356
357         assert(pipe);
358         assert(pipe->stream);
359         if ((!pipe) || (!pipe->stream)) {
360                 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
361                                     "allocate_mipi_frames(%p) exit: pipe or stream is null.\n",
362                                     pipe);
363                 return -EINVAL;
364         }
365
366 #ifdef ISP2401
367         if (pipe->stream->config.online) {
368                 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
369                                     "allocate_mipi_frames(%p) exit: no buffers needed for 2401 pipe mode.\n",
370                                     pipe);
371                 return 0;
372         }
373
374 #endif
375         if (pipe->stream->config.mode != IA_CSS_INPUT_MODE_BUFFERED_SENSOR) {
376                 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
377                                     "allocate_mipi_frames(%p) exit: no buffers needed for pipe mode.\n",
378                                     pipe);
379                 return 0; /* AM TODO: Check  */
380         }
381
382         port = (unsigned int)pipe->stream->config.source.port.port;
383         if (port >= N_CSI_PORTS) {
384                 IA_CSS_ERROR("allocate_mipi_frames(%p) exit: port is not correct (port=%d).",
385                              pipe, port);
386                 return -EINVAL;
387         }
388
389 #ifdef ISP2401
390         err = calculate_mipi_buff_size(&pipe->stream->config,
391                                        &my_css.mipi_frame_size[port]);
392         /*
393          * 2401 system allows multiple streams to use same physical port. This is not
394          * true for 2400 system. Currently 2401 uses MIPI buffers as a temporary solution.
395          * TODO AM: Once that is changed (removed) this code should be removed as well.
396          * In that case only 2400 related code should remain.
397          */
398         if (ref_count_mipi_allocation[port] != 0) {
399                 ref_count_mipi_allocation[port]++;
400                 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
401                                     "allocate_mipi_frames(%p) leave: nothing to do, already allocated for this port (port=%d).\n",
402                                     pipe, port);
403                 return 0;
404         }
405 #else
406         if (ref_count_mipi_allocation[port] != 0) {
407                 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
408                                     "allocate_mipi_frames(%p) exit: already allocated for this port (port=%d).\n",
409                                     pipe, port);
410                 return 0;
411         }
412 #endif
413
414         ref_count_mipi_allocation[port]++;
415
416         /* AM TODO: mipi frames number should come from stream struct. */
417         my_css.num_mipi_frames[port] = NUM_MIPI_FRAMES_PER_STREAM;
418
419         /* Incremental allocation (per stream), not for all streams at once. */
420         { /* limit the scope of i,j */
421                 unsigned int i, j;
422
423                 for (i = 0; i < my_css.num_mipi_frames[port]; i++) {
424                         /* free previous frame */
425                         if (my_css.mipi_frames[port][i]) {
426                                 ia_css_frame_free(my_css.mipi_frames[port][i]);
427                                 my_css.mipi_frames[port][i] = NULL;
428                         }
429                         /* check if new frame is needed */
430                         if (i < my_css.num_mipi_frames[port]) {
431                                 /* allocate new frame */
432                                 err = ia_css_frame_allocate_with_buffer_size(
433                                           &my_css.mipi_frames[port][i],
434                                           my_css.mipi_frame_size[port] * HIVE_ISP_DDR_WORD_BYTES,
435                                           false);
436                                 if (err) {
437                                         for (j = 0; j < i; j++) {
438                                                 if (my_css.mipi_frames[port][j]) {
439                                                         ia_css_frame_free(my_css.mipi_frames[port][j]);
440                                                         my_css.mipi_frames[port][j] = NULL;
441                                                 }
442                                         }
443                                         IA_CSS_ERROR("allocate_mipi_frames(%p, %d) exit: allocation failed.",
444                                                      pipe, port);
445                                         return err;
446                                 }
447                         }
448                         if (info->metadata_info.size > 0) {
449                                 /* free previous metadata buffer */
450                                 if (my_css.mipi_metadata[port][i]) {
451                                         ia_css_metadata_free(my_css.mipi_metadata[port][i]);
452                                         my_css.mipi_metadata[port][i] = NULL;
453                                 }
454                                 /* check if need to allocate a new metadata buffer */
455                                 if (i < my_css.num_mipi_frames[port]) {
456                                         /* allocate new metadata buffer */
457                                         my_css.mipi_metadata[port][i] = ia_css_metadata_allocate(&info->metadata_info);
458                                         if (!my_css.mipi_metadata[port][i]) {
459                                                 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
460                                                                     "allocate_mipi_metadata(%p, %d) failed.\n",
461                                                                     pipe, port);
462                                                 return err;
463                                         }
464                                 }
465                         }
466                 }
467         }
468         ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
469                             "allocate_mipi_frames(%p) exit:\n", pipe);
470
471         return err;
472 }
473
474 int
475 free_mipi_frames(struct ia_css_pipe *pipe)
476 {
477         int err = -EINVAL;
478         unsigned int port;
479
480         ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
481                             "free_mipi_frames(%p) enter:\n", pipe);
482
483         /* assert(pipe != NULL); TEMP: TODO: Should be assert only. */
484         if (pipe) {
485                 assert(pipe->stream);
486                 if ((!pipe) || (!pipe->stream)) {
487                         IA_CSS_ERROR("free_mipi_frames(%p) exit: pipe or stream is null.",
488                                      pipe);
489                         return -EINVAL;
490                 }
491
492                 if (pipe->stream->config.mode != IA_CSS_INPUT_MODE_BUFFERED_SENSOR) {
493                         IA_CSS_ERROR("free_mipi_frames(%p) exit: wrong mode.",
494                                      pipe);
495                         return err;
496                 }
497
498                 port = (unsigned int)pipe->stream->config.source.port.port;
499
500                 if (port >= N_CSI_PORTS) {
501                         IA_CSS_ERROR("free_mipi_frames(%p, %d) exit: pipe port is not correct.",
502                                      pipe, port);
503                         return err;
504                 }
505
506                 if (ref_count_mipi_allocation[port] > 0) {
507 #if !defined(ISP2401)
508                         assert(ref_count_mipi_allocation[port] == 1);
509                         if (ref_count_mipi_allocation[port] != 1) {
510                                 IA_CSS_ERROR("free_mipi_frames(%p) exit: wrong ref_count (ref_count=%d).",
511                                              pipe, ref_count_mipi_allocation[port]);
512                                 return err;
513                         }
514 #endif
515
516                         ref_count_mipi_allocation[port]--;
517
518                         if (ref_count_mipi_allocation[port] == 0) {
519                                 /* no streams are using this buffer, so free it */
520                                 unsigned int i;
521
522                                 for (i = 0; i < my_css.num_mipi_frames[port]; i++) {
523                                         if (my_css.mipi_frames[port][i]) {
524                                                 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
525                                                                     "free_mipi_frames(port=%d, num=%d).\n", port, i);
526                                                 ia_css_frame_free(my_css.mipi_frames[port][i]);
527                                                 my_css.mipi_frames[port][i] = NULL;
528                                         }
529                                         if (my_css.mipi_metadata[port][i]) {
530                                                 ia_css_metadata_free(my_css.mipi_metadata[port][i]);
531                                                 my_css.mipi_metadata[port][i] = NULL;
532                                         }
533                                 }
534
535                                 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
536                                                     "free_mipi_frames(%p) exit (deallocated).\n", pipe);
537                         }
538 #if defined(ISP2401)
539                         else {
540                                 /* 2401 system allows multiple streams to use same physical port. This is not
541                                  * true for 2400 system. Currently 2401 uses MIPI buffers as a temporary solution.
542                                  * TODO AM: Once that is changed (removed) this code should be removed as well.
543                                  * In that case only 2400 related code should remain.
544                                  */
545                                 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
546                                                     "free_mipi_frames(%p) leave: nothing to do, other streams still use this port (port=%d).\n",
547                                                     pipe, port);
548                         }
549 #endif
550                 }
551         } else { /* pipe ==NULL */
552                 /* AM TEMP: free-ing all mipi buffers just like a legacy code. */
553                 for (port = CSI_PORT0_ID; port < N_CSI_PORTS; port++) {
554                         unsigned int i;
555
556                         for (i = 0; i < my_css.num_mipi_frames[port]; i++) {
557                                 if (my_css.mipi_frames[port][i]) {
558                                         ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
559                                                             "free_mipi_frames(port=%d, num=%d).\n", port, i);
560                                         ia_css_frame_free(my_css.mipi_frames[port][i]);
561                                         my_css.mipi_frames[port][i] = NULL;
562                                 }
563                                 if (my_css.mipi_metadata[port][i]) {
564                                         ia_css_metadata_free(my_css.mipi_metadata[port][i]);
565                                         my_css.mipi_metadata[port][i] = NULL;
566                                 }
567                         }
568                         ref_count_mipi_allocation[port] = 0;
569                 }
570         }
571         return 0;
572 }
573
574 int
575 send_mipi_frames(struct ia_css_pipe *pipe)
576 {
577         int err = -EINVAL;
578         unsigned int i;
579         unsigned int port;
580
581         IA_CSS_ENTER_PRIVATE("pipe=%p", pipe);
582
583         assert(pipe);
584         assert(pipe->stream);
585         if (!pipe || !pipe->stream) {
586                 IA_CSS_ERROR("pipe or stream is null");
587                 return -EINVAL;
588         }
589
590         /* multi stream video needs mipi buffers */
591         /* nothing to be done in other cases. */
592         if (pipe->stream->config.mode != IA_CSS_INPUT_MODE_BUFFERED_SENSOR) {
593                 IA_CSS_LOG("nothing to be done for this mode");
594                 return 0;
595                 /* TODO: AM: maybe this should be returning an error. */
596         }
597
598         port = (unsigned int)pipe->stream->config.source.port.port;
599
600         if (port >= N_CSI_PORTS) {
601                 IA_CSS_ERROR("send_mipi_frames(%p) exit: invalid port specified (port=%d).",
602                              pipe, port);
603                 return err;
604         }
605
606         /* Hand-over the SP-internal mipi buffers */
607         for (i = 0; i < my_css.num_mipi_frames[port]; i++) {
608                 /* Need to include the ofset for port. */
609                 sh_css_update_host2sp_mipi_frame(port * NUM_MIPI_FRAMES_PER_STREAM + i,
610                                                  my_css.mipi_frames[port][i]);
611                 sh_css_update_host2sp_mipi_metadata(port * NUM_MIPI_FRAMES_PER_STREAM + i,
612                                                     my_css.mipi_metadata[port][i]);
613         }
614         sh_css_update_host2sp_num_mipi_frames(my_css.num_mipi_frames[port]);
615
616         /**********************************
617          * Send an event to inform the SP
618          * that all MIPI frames are passed.
619          **********************************/
620         if (!sh_css_sp_is_running()) {
621                 /* SP is not running. The queues are not valid */
622                 IA_CSS_ERROR("sp is not running");
623                 return err;
624         }
625
626         ia_css_bufq_enqueue_psys_event(
627             IA_CSS_PSYS_SW_EVENT_MIPI_BUFFERS_READY,
628             (uint8_t)port,
629             (uint8_t)my_css.num_mipi_frames[port],
630             0 /* not used */);
631         IA_CSS_LEAVE_ERR_PRIVATE(0);
632         return 0;
633 }