media: atomisp: change the detection of ISP2401 at runtime
[linux-2.6-microblaze.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 #if defined(USE_INPUT_SYSTEM_VERSION_2) || defined(USE_INPUT_SYSTEM_VERSION_2401)
34 static u32
35 ref_count_mipi_allocation[N_CSI_PORTS]; /* Initialized in mipi_init */
36 #endif
37
38 int
39 ia_css_mipi_frame_specify(const unsigned int size_mem_words,
40                           const bool contiguous) {
41         int err = 0;
42
43         my_css.size_mem_words = size_mem_words;
44         (void)contiguous;
45
46         return err;
47 }
48
49 /*
50  * Check if a source port or TPG/PRBS ID is valid
51  */
52 static bool ia_css_mipi_is_source_port_valid(struct ia_css_pipe *pipe,
53         unsigned int *pport)
54 {
55         bool ret = true;
56         unsigned int port = 0;
57         unsigned int max_ports = 0;
58
59         switch (pipe->stream->config.mode) {
60         case IA_CSS_INPUT_MODE_BUFFERED_SENSOR:
61                 port = (unsigned int)pipe->stream->config.source.port.port;
62                 max_ports = N_CSI_PORTS;
63                 break;
64         case IA_CSS_INPUT_MODE_TPG:
65                 port = (unsigned int)pipe->stream->config.source.tpg.id;
66                 max_ports = N_CSS_TPG_IDS;
67                 break;
68         case IA_CSS_INPUT_MODE_PRBS:
69                 port = (unsigned int)pipe->stream->config.source.prbs.id;
70                 max_ports = N_CSS_PRBS_IDS;
71                 break;
72         default:
73                 assert(false);
74                 ret = false;
75                 break;
76         }
77
78         if (ret) {
79                 assert(port < max_ports);
80
81                 if (port >= max_ports)
82                         ret = false;
83         }
84
85         *pport = port;
86
87         return ret;
88 }
89
90 /* Assumptions:
91  *      - A line is multiple of 4 bytes = 1 word.
92  *      - Each frame has SOF and EOF (each 1 word).
93  *      - Each line has format header and optionally SOL and EOL (each 1 word).
94  *      - Odd and even lines of YUV420 format are different in bites per pixel size.
95  *      - Custom size of embedded data.
96  *  -- Interleaved frames are not taken into account.
97  *  -- Lines are multiples of 8B, and not necessary of (custom 3B, or 7B
98  *  etc.).
99  * Result is given in DDR mem words, 32B or 256 bits
100  */
101 int
102 ia_css_mipi_frame_calculate_size(const unsigned int width,
103                                  const unsigned int height,
104                                  const enum atomisp_input_format format,
105                                  const bool hasSOLandEOL,
106                                  const unsigned int embedded_data_size_words,
107                                  unsigned int *size_mem_words) {
108         int err = 0;
109
110         unsigned int bits_per_pixel = 0;
111         unsigned int even_line_bytes = 0;
112         unsigned int odd_line_bytes = 0;
113         unsigned int words_per_odd_line = 0;
114         unsigned int words_for_first_line = 0;
115         unsigned int words_per_even_line = 0;
116         unsigned int mem_words_per_even_line = 0;
117         unsigned int mem_words_per_odd_line = 0;
118         unsigned int mem_words_for_first_line = 0;
119         unsigned int mem_words_for_EOF = 0;
120         unsigned int mem_words = 0;
121         unsigned int width_padded = width;
122
123 #if defined(USE_INPUT_SYSTEM_VERSION_2401)
124         /* The changes will be reverted as soon as RAW
125          * Buffers are deployed by the 2401 Input System
126          * in the non-continuous use scenario.
127          */
128         width_padded += (2 * ISP_VEC_NELEMS);
129 #endif
130
131         IA_CSS_ENTER("padded_width=%d, height=%d, format=%d, hasSOLandEOL=%d, embedded_data_size_words=%d\n",
132                      width_padded, height, format, hasSOLandEOL, embedded_data_size_words);
133
134         switch (format)
135         {
136         case ATOMISP_INPUT_FORMAT_RAW_6:                /* 4p, 3B, 24bits */
137                 bits_per_pixel = 6;
138                 break;
139         case ATOMISP_INPUT_FORMAT_RAW_7:                /* 8p, 7B, 56bits */
140                 bits_per_pixel = 7;
141                 break;
142         case ATOMISP_INPUT_FORMAT_RAW_8:                /* 1p, 1B, 8bits */
143         case ATOMISP_INPUT_FORMAT_BINARY_8:             /*  8bits, TODO: check. */
144         case ATOMISP_INPUT_FORMAT_YUV420_8:             /* odd 2p, 2B, 16bits, even 2p, 4B, 32bits */
145                 bits_per_pixel = 8;
146                 break;
147         case ATOMISP_INPUT_FORMAT_YUV420_10:            /* odd 4p, 5B, 40bits, even 4p, 10B, 80bits */
148         case ATOMISP_INPUT_FORMAT_RAW_10:               /* 4p, 5B, 40bits */
149 #if !defined(HAS_NO_PACKED_RAW_PIXELS)
150                 /* The changes will be reverted as soon as RAW
151                  * Buffers are deployed by the 2401 Input System
152                  * in the non-continuous use scenario.
153                  */
154                 bits_per_pixel = 10;
155 #else
156                 bits_per_pixel = 16;
157 #endif
158                 break;
159         case ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY:      /* 2p, 3B, 24bits */
160         case ATOMISP_INPUT_FORMAT_RAW_12:               /* 2p, 3B, 24bits */
161                 bits_per_pixel = 12;
162                 break;
163         case ATOMISP_INPUT_FORMAT_RAW_14:               /* 4p, 7B, 56bits */
164                 bits_per_pixel = 14;
165                 break;
166         case ATOMISP_INPUT_FORMAT_RGB_444:              /* 1p, 2B, 16bits */
167         case ATOMISP_INPUT_FORMAT_RGB_555:              /* 1p, 2B, 16bits */
168         case ATOMISP_INPUT_FORMAT_RGB_565:              /* 1p, 2B, 16bits */
169         case ATOMISP_INPUT_FORMAT_YUV422_8:             /* 2p, 4B, 32bits */
170                 bits_per_pixel = 16;
171                 break;
172         case ATOMISP_INPUT_FORMAT_RGB_666:              /* 4p, 9B, 72bits */
173                 bits_per_pixel = 18;
174                 break;
175         case ATOMISP_INPUT_FORMAT_YUV422_10:            /* 2p, 5B, 40bits */
176                 bits_per_pixel = 20;
177                 break;
178         case ATOMISP_INPUT_FORMAT_RGB_888:              /* 1p, 3B, 24bits */
179                 bits_per_pixel = 24;
180                 break;
181
182         case ATOMISP_INPUT_FORMAT_YUV420_16:            /* Not supported */
183         case ATOMISP_INPUT_FORMAT_YUV422_16:            /* Not supported */
184         case ATOMISP_INPUT_FORMAT_RAW_16:               /* TODO: not specified in MIPI SPEC, check */
185         default:
186                 return -EINVAL;
187         }
188
189         odd_line_bytes = (width_padded * bits_per_pixel + 7) >> 3; /* ceil ( bits per line / 8) */
190
191         /* Even lines for YUV420 formats are double in bits_per_pixel. */
192         if (format == ATOMISP_INPUT_FORMAT_YUV420_8
193             || format == ATOMISP_INPUT_FORMAT_YUV420_10
194             || format == ATOMISP_INPUT_FORMAT_YUV420_16)
195         {
196                 even_line_bytes = (width_padded * 2 * bits_per_pixel + 7) >>
197                         3; /* ceil ( bits per line / 8) */
198         } else
199         {
200                 even_line_bytes = odd_line_bytes;
201         }
202
203         /*  a frame represented in memory:  ()- optional; data - payload words.
204         *  addr         0       1       2       3       4       5       6       7:
205         *  first        SOF     (SOL)   PACK_H  data    data    data    data    data
206         *               data    data    data    data    data    data    data    data
207         *               ...
208         *               data    data    0       0       0       0       0       0
209         *  second       (EOL)   (SOL)   PACK_H  data    data    data    data    data
210         *               data    data    data    data    data    data    data    data
211         *               ...
212         *               data    data    0       0       0       0       0       0
213         *  ...
214         *  last         (EOL)   EOF     0       0       0       0       0       0
215         *
216         *  Embedded lines are regular lines stored before the first and after
217         *  payload lines.
218         */
219
220         words_per_odd_line = (odd_line_bytes + 3) >> 2;
221         /* ceil(odd_line_bytes/4); word = 4 bytes */
222         words_per_even_line  = (even_line_bytes  + 3) >> 2;
223         words_for_first_line = words_per_odd_line + 2 + (hasSOLandEOL ? 1 : 0);
224         /* + SOF +packet header + optionally (SOL), but (EOL) is not in the first line */
225         words_per_odd_line      += (1 + (hasSOLandEOL ? 2 : 0));
226         /* each non-first line has format header, and optionally (SOL) and (EOL). */
227         words_per_even_line += (1 + (hasSOLandEOL ? 2 : 0));
228
229         mem_words_per_odd_line   = (words_per_odd_line + 7) >> 3;
230         /* ceil(words_per_odd_line/8); mem_word = 32 bytes, 8 words */
231         mem_words_for_first_line = (words_for_first_line + 7) >> 3;
232         mem_words_per_even_line  = (words_per_even_line + 7) >> 3;
233         mem_words_for_EOF        = 1; /* last line consisit of the optional (EOL) and EOF */
234
235         mem_words = ((embedded_data_size_words + 7) >> 3) +
236         mem_words_for_first_line +
237         (((height + 1) >> 1) - 1) * mem_words_per_odd_line +
238         /* ceil (height/2) - 1 (first line is calculated separatelly) */
239         (height      >> 1) * mem_words_per_even_line + /* floor(height/2) */
240         mem_words_for_EOF;
241
242         *size_mem_words = mem_words; /* ceil(words/8); mem word is 32B = 8words. */
243         /* Check if the above is still needed. */
244
245         IA_CSS_LEAVE_ERR(err);
246         return err;
247 }
248
249 #if !defined(HAS_NO_INPUT_SYSTEM) && defined(USE_INPUT_SYSTEM_VERSION_2)
250 int
251 ia_css_mipi_frame_enable_check_on_size(const enum mipi_port_id port,
252                                        const unsigned int       size_mem_words) {
253         u32 idx;
254
255         int err = -EBUSY;
256
257         OP___assert(port < N_CSI_PORTS);
258         OP___assert(size_mem_words != 0);
259
260         for (idx = 0; idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT &&
261              my_css.mipi_sizes_for_check[port][idx] != 0;
262              idx++)   /* do nothing */
263         {
264         }
265         if (idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT)
266         {
267                 my_css.mipi_sizes_for_check[port][idx] = size_mem_words;
268                 err = 0;
269         }
270
271         return err;
272 }
273 #endif
274
275 void
276 mipi_init(void)
277 {
278 #if defined(USE_INPUT_SYSTEM_VERSION_2) || defined(USE_INPUT_SYSTEM_VERSION_2401)
279         unsigned int i;
280
281         for (i = 0; i < N_CSI_PORTS; i++)
282                 ref_count_mipi_allocation[i] = 0;
283 #endif
284 }
285
286 int
287 calculate_mipi_buff_size(
288     struct ia_css_stream_config *stream_cfg,
289     unsigned int *size_mem_words) {
290 #if !defined(USE_INPUT_SYSTEM_VERSION_2401)
291         int err = -EINVAL;
292         (void)stream_cfg;
293         (void)size_mem_words;
294 #else
295         unsigned int width;
296         unsigned int height;
297         enum atomisp_input_format format;
298         bool pack_raw_pixels;
299
300         unsigned int width_padded;
301         unsigned int bits_per_pixel = 0;
302
303         unsigned int even_line_bytes = 0;
304         unsigned int odd_line_bytes = 0;
305
306         unsigned int words_per_odd_line = 0;
307         unsigned int words_per_even_line = 0;
308
309         unsigned int mem_words_per_even_line = 0;
310         unsigned int mem_words_per_odd_line = 0;
311
312         unsigned int mem_words_per_buff_line = 0;
313         unsigned int mem_words_per_buff = 0;
314         int err = 0;
315
316         /**
317          * zhengjie.lu@intel.com
318          *
319          * NOTE
320          * - In the struct "ia_css_stream_config", there
321          *   are two members: "input_config" and "isys_config".
322          *   Both of them provide the same information, e.g.
323          *   input_res and format.
324          *
325          *   Question here is that: which one shall be used?
326          */
327         width = stream_cfg->input_config.input_res.width;
328         height = stream_cfg->input_config.input_res.height;
329         format = stream_cfg->input_config.format;
330         pack_raw_pixels = stream_cfg->pack_raw_pixels;
331         /* end of NOTE */
332
333         /**
334          * zhengjie.lu@intel.com
335          *
336          * NOTE
337          * - The following code is derived from the
338          *   existing code "ia_css_mipi_frame_calculate_size()".
339          *
340          *   Question here is: why adding "2 * ISP_VEC_NELEMS"
341          *   to "width_padded", but not making "width_padded"
342          *   aligned with "2 * ISP_VEC_NELEMS"?
343          */
344         /* The changes will be reverted as soon as RAW
345          * Buffers are deployed by the 2401 Input System
346          * in the non-continuous use scenario.
347          */
348         width_padded = width + (2 * ISP_VEC_NELEMS);
349         /* end of NOTE */
350
351         IA_CSS_ENTER("padded_width=%d, height=%d, format=%d\n",
352                      width_padded, height, format);
353
354         bits_per_pixel = sh_css_stream_format_2_bits_per_subpixel(format);
355         bits_per_pixel =
356         (format == ATOMISP_INPUT_FORMAT_RAW_10 && pack_raw_pixels) ? bits_per_pixel : 16;
357         if (bits_per_pixel == 0)
358                 return -EINVAL;
359
360         odd_line_bytes = (width_padded * bits_per_pixel + 7) >> 3; /* ceil ( bits per line / 8) */
361
362         /* Even lines for YUV420 formats are double in bits_per_pixel. */
363         if (format == ATOMISP_INPUT_FORMAT_YUV420_8
364             || format == ATOMISP_INPUT_FORMAT_YUV420_10)
365         {
366                 even_line_bytes = (width_padded * 2 * bits_per_pixel + 7) >>
367                         3; /* ceil ( bits per line / 8) */
368         } else
369         {
370                 even_line_bytes = odd_line_bytes;
371         }
372
373         words_per_odd_line       = (odd_line_bytes   + 3) >> 2;
374         /* ceil(odd_line_bytes/4); word = 4 bytes */
375         words_per_even_line  = (even_line_bytes  + 3) >> 2;
376
377         mem_words_per_odd_line   = (words_per_odd_line + 7) >> 3;
378         /* ceil(words_per_odd_line/8); mem_word = 32 bytes, 8 words */
379         mem_words_per_even_line  = (words_per_even_line + 7) >> 3;
380
381         mem_words_per_buff_line =
382         (mem_words_per_odd_line > mem_words_per_even_line) ? mem_words_per_odd_line : mem_words_per_even_line;
383         mem_words_per_buff = mem_words_per_buff_line * height;
384
385         *size_mem_words = mem_words_per_buff;
386
387         IA_CSS_LEAVE_ERR(err);
388 #endif
389         return err;
390 }
391
392 static bool buffers_needed(struct ia_css_pipe *pipe)
393 {
394         if (!IS_ISP2401) {
395                 if (pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR)
396                         return false;
397                 else
398                         return true;
399         }
400
401         if (pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR ||
402             pipe->stream->config.mode == IA_CSS_INPUT_MODE_TPG ||
403             pipe->stream->config.mode == IA_CSS_INPUT_MODE_PRBS)
404                 return false;
405
406         return true;
407 }
408
409 int
410 allocate_mipi_frames(struct ia_css_pipe *pipe,
411                      struct ia_css_stream_info *info) {
412 #if defined(USE_INPUT_SYSTEM_VERSION_2) || defined(USE_INPUT_SYSTEM_VERSION_2401)
413         int err = -EINVAL;
414         unsigned int port;
415         struct ia_css_frame_info mipi_intermediate_info;
416
417         ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
418                             "allocate_mipi_frames(%p) enter:\n", pipe);
419
420         assert(pipe);
421         assert(pipe->stream);
422         if ((!pipe) || (!pipe->stream))
423         {
424                 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
425                                     "allocate_mipi_frames(%p) exit: pipe or stream is null.\n",
426                                     pipe);
427                 return -EINVAL;
428         }
429
430 #ifdef USE_INPUT_SYSTEM_VERSION_2401
431         if (pipe->stream->config.online)
432         {
433                 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
434                                     "allocate_mipi_frames(%p) exit: no buffers needed for 2401 pipe mode.\n",
435                                     pipe);
436                 return 0;
437         }
438
439 #endif
440
441         if (!buffers_needed(pipe)) {
442                 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
443                                     "allocate_mipi_frames(%p) exit: no buffers needed for pipe mode.\n",
444                                     pipe);
445                 return 0; /* AM TODO: Check  */
446         }
447
448         if (!IS_ISP2401)
449                 port = (unsigned int)pipe->stream->config.source.port.port;
450         else
451                 err = ia_css_mipi_is_source_port_valid(pipe, &port);
452
453         assert(port < N_CSI_PORTS);
454
455         if (port >= N_CSI_PORTS || err) {
456                 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
457                                     "allocate_mipi_frames(%p) exit: error: port is not correct (port=%d).\n",
458                                     pipe, port);
459                 return -EINVAL;
460         }
461
462 #ifdef USE_INPUT_SYSTEM_VERSION_2401
463         err = calculate_mipi_buff_size(
464             &pipe->stream->config,
465             &my_css.mipi_frame_size[port]);
466 #endif
467
468 #if defined(USE_INPUT_SYSTEM_VERSION_2)
469         if (ref_count_mipi_allocation[port] != 0)
470         {
471                 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
472                                     "allocate_mipi_frames(%p) exit: already allocated for this port (port=%d).\n",
473                                     pipe, port);
474                 return 0;
475         }
476 #else
477         /* 2401 system allows multiple streams to use same physical port. This is not
478          * true for 2400 system. Currently 2401 uses MIPI buffers as a temporary solution.
479          * TODO AM: Once that is changed (removed) this code should be removed as well.
480          * In that case only 2400 related code should remain.
481          */
482         if (ref_count_mipi_allocation[port] != 0)
483         {
484                 ref_count_mipi_allocation[port]++;
485                 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
486                                     "allocate_mipi_frames(%p) leave: nothing to do, already allocated for this port (port=%d).\n",
487                                     pipe, port);
488                 return 0;
489         }
490 #endif
491
492         ref_count_mipi_allocation[port]++;
493
494         /* TODO: Cleaning needed. */
495         /* This code needs to modified to allocate the MIPI frames in the correct normal way
496           with an allocate from info, by justin */
497         mipi_intermediate_info = pipe->pipe_settings.video.video_binary.internal_frame_info;
498         mipi_intermediate_info.res.width = 0;
499         mipi_intermediate_info.res.height = 0;
500         /* To indicate it is not (yet) valid format. */
501         mipi_intermediate_info.format = IA_CSS_FRAME_FORMAT_NUM;
502         mipi_intermediate_info.padded_width = 0;
503         mipi_intermediate_info.raw_bit_depth = 0;
504
505         /* AM TODO: mipi frames number should come from stream struct. */
506         my_css.num_mipi_frames[port] = NUM_MIPI_FRAMES_PER_STREAM;
507
508         /* Incremental allocation (per stream), not for all streams at once. */
509         { /* limit the scope of i,j */
510                 unsigned int i, j;
511
512                 for (i = 0; i < my_css.num_mipi_frames[port]; i++)
513                 {
514                         /* free previous frame */
515                         if (my_css.mipi_frames[port][i]) {
516                                 ia_css_frame_free(my_css.mipi_frames[port][i]);
517                                 my_css.mipi_frames[port][i] = NULL;
518                         }
519                         /* check if new frame is needed */
520                         if (i < my_css.num_mipi_frames[port]) {
521                                 /* allocate new frame */
522                                 err = ia_css_frame_allocate_with_buffer_size(
523                                           &my_css.mipi_frames[port][i],
524                                           my_css.mipi_frame_size[port] * HIVE_ISP_DDR_WORD_BYTES,
525                                           false);
526                                 if (err) {
527                                         for (j = 0; j < i; j++) {
528                                                 if (my_css.mipi_frames[port][j]) {
529                                                         ia_css_frame_free(my_css.mipi_frames[port][j]);
530                                                         my_css.mipi_frames[port][j] = NULL;
531                                                 }
532                                         }
533                                         ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
534                                                             "allocate_mipi_frames(%p, %d) exit: error: allocation failed.\n",
535                                                             pipe, port);
536                                         return err;
537                                 }
538                         }
539                         if (info->metadata_info.size > 0) {
540                                 /* free previous metadata buffer */
541                                 if (my_css.mipi_metadata[port][i]) {
542                                         ia_css_metadata_free(my_css.mipi_metadata[port][i]);
543                                         my_css.mipi_metadata[port][i] = NULL;
544                                 }
545                                 /* check if need to allocate a new metadata buffer */
546                                 if (i < my_css.num_mipi_frames[port]) {
547                                         /* allocate new metadata buffer */
548                                         my_css.mipi_metadata[port][i] = ia_css_metadata_allocate(&info->metadata_info);
549                                         if (!my_css.mipi_metadata[port][i]) {
550                                                 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
551                                                                     "allocate_mipi_metadata(%p, %d) failed.\n",
552                                                                     pipe, port);
553                                                 return err;
554                                         }
555                                 }
556                         }
557                 }
558         }
559         ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
560                             "allocate_mipi_frames(%p) exit:\n", pipe);
561
562         return err;
563 #else
564         (void)pipe;
565         (void)info;
566         return 0;
567 #endif
568 }
569
570 int
571 free_mipi_frames(struct ia_css_pipe *pipe) {
572 #if defined(USE_INPUT_SYSTEM_VERSION_2) || defined(USE_INPUT_SYSTEM_VERSION_2401)
573         int err = -EINVAL;
574         unsigned int port;
575
576         ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
577                             "free_mipi_frames(%p) enter:\n", pipe);
578
579         /* assert(pipe != NULL); TEMP: TODO: Should be assert only. */
580         if (pipe)
581         {
582                 assert(pipe->stream);
583                 if ((!pipe) || (!pipe->stream)) {
584                         ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
585                                             "free_mipi_frames(%p) exit: error: pipe or stream is null.\n",
586                                             pipe);
587                         return -EINVAL;
588                 }
589
590                 if (!buffers_needed(pipe)) {
591                         ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
592                                             "free_mipi_frames(%p) exit: error: wrong mode.\n",
593                                             pipe);
594                         return err;
595                 }
596
597                 if (!IS_ISP2401)
598                         port = (unsigned int)pipe->stream->config.source.port.port;
599                 else
600                         err = ia_css_mipi_is_source_port_valid(pipe, &port);
601
602                 assert(port < N_CSI_PORTS);
603
604                 if (port >= N_CSI_PORTS || err) {
605                         ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
606                                             "free_mipi_frames(%p, %d) exit: error: pipe port is not correct.\n",
607                                             pipe, port);
608                         return err;
609                 }
610
611                 if (ref_count_mipi_allocation[port] > 0) {
612 #if defined(USE_INPUT_SYSTEM_VERSION_2)
613                         assert(ref_count_mipi_allocation[port] == 1);
614                         if (ref_count_mipi_allocation[port] != 1) {
615                                 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
616                                                     "free_mipi_frames(%p) exit: error: wrong ref_count (ref_count=%d).\n",
617                                                     pipe, ref_count_mipi_allocation[port]);
618                                 return err;
619                         }
620 #endif
621
622                         ref_count_mipi_allocation[port]--;
623
624                         if (ref_count_mipi_allocation[port] == 0) {
625                                 /* no streams are using this buffer, so free it */
626                                 unsigned int i;
627
628                                 for (i = 0; i < my_css.num_mipi_frames[port]; i++) {
629                                         if (my_css.mipi_frames[port][i]) {
630                                                 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
631                                                                     "free_mipi_frames(port=%d, num=%d).\n", port, i);
632                                                 ia_css_frame_free(my_css.mipi_frames[port][i]);
633                                                 my_css.mipi_frames[port][i] = NULL;
634                                         }
635                                         if (my_css.mipi_metadata[port][i]) {
636                                                 ia_css_metadata_free(my_css.mipi_metadata[port][i]);
637                                                 my_css.mipi_metadata[port][i] = NULL;
638                                         }
639                                 }
640
641                                 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
642                                                     "free_mipi_frames(%p) exit (deallocated).\n", pipe);
643                         }
644 #if defined(USE_INPUT_SYSTEM_VERSION_2401)
645                         else {
646                                 /* 2401 system allows multiple streams to use same physical port. This is not
647                                  * true for 2400 system. Currently 2401 uses MIPI buffers as a temporary solution.
648                                  * TODO AM: Once that is changed (removed) this code should be removed as well.
649                                  * In that case only 2400 related code should remain.
650                                  */
651                                 ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
652                                                     "free_mipi_frames(%p) leave: nothing to do, other streams still use this port (port=%d).\n",
653                                                     pipe, port);
654                         }
655 #endif
656                 }
657         } else   /* pipe ==NULL */
658         {
659                 /* AM TEMP: free-ing all mipi buffers just like a legacy code. */
660                 for (port = CSI_PORT0_ID; port < N_CSI_PORTS; port++) {
661                         unsigned int i;
662
663                         for (i = 0; i < my_css.num_mipi_frames[port]; i++) {
664                                 if (my_css.mipi_frames[port][i]) {
665                                         ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
666                                                             "free_mipi_frames(port=%d, num=%d).\n", port, i);
667                                         ia_css_frame_free(my_css.mipi_frames[port][i]);
668                                         my_css.mipi_frames[port][i] = NULL;
669                                 }
670                                 if (my_css.mipi_metadata[port][i]) {
671                                         ia_css_metadata_free(my_css.mipi_metadata[port][i]);
672                                         my_css.mipi_metadata[port][i] = NULL;
673                                 }
674                         }
675                         ref_count_mipi_allocation[port] = 0;
676                 }
677         }
678 #else
679         (void)pipe;
680 #endif
681         return 0;
682 }
683
684 int
685 send_mipi_frames(struct ia_css_pipe *pipe) {
686 #if defined(USE_INPUT_SYSTEM_VERSION_2) || defined(USE_INPUT_SYSTEM_VERSION_2401)
687         int err = -EINVAL;
688         unsigned int i;
689 #ifndef ISP2401
690         unsigned int port;
691 #else
692         unsigned int port = 0;
693 #endif
694
695         IA_CSS_ENTER_PRIVATE("pipe=%p", pipe);
696
697         assert(pipe);
698         assert(pipe->stream);
699         if (!pipe || !pipe->stream)
700         {
701                 IA_CSS_ERROR("pipe or stream is null");
702                 return -EINVAL;
703         }
704
705         /* multi stream video needs mipi buffers */
706         /* nothing to be done in other cases. */
707         if (!buffers_needed(pipe)) {
708                 IA_CSS_LOG("nothing to be done for this mode");
709                 return 0;
710                 /* TODO: AM: maybe this should be returning an error. */
711         }
712
713         if (!IS_ISP2401)
714                 port = (unsigned int)pipe->stream->config.source.port.port;
715         else
716                 err = ia_css_mipi_is_source_port_valid(pipe, &port);
717
718         assert(port < N_CSI_PORTS);
719
720         if (port >= N_CSI_PORTS || err) {
721                 IA_CSS_ERROR("send_mipi_frames(%p) exit: invalid port specified (port=%d).\n",
722                              pipe, port);
723                 return err;
724         }
725
726         /* Hand-over the SP-internal mipi buffers */
727         for (i = 0; i < my_css.num_mipi_frames[port]; i++)
728         {
729                 /* Need to include the ofset for port. */
730                 sh_css_update_host2sp_mipi_frame(port * NUM_MIPI_FRAMES_PER_STREAM + i,
731                                                  my_css.mipi_frames[port][i]);
732                 sh_css_update_host2sp_mipi_metadata(port * NUM_MIPI_FRAMES_PER_STREAM + i,
733                                                     my_css.mipi_metadata[port][i]);
734         }
735         sh_css_update_host2sp_num_mipi_frames(my_css.num_mipi_frames[port]);
736
737         /**********************************
738          * Send an event to inform the SP
739          * that all MIPI frames are passed.
740          **********************************/
741         if (!sh_css_sp_is_running())
742         {
743                 /* SP is not running. The queues are not valid */
744                 IA_CSS_ERROR("sp is not running");
745                 return err;
746         }
747
748         ia_css_bufq_enqueue_psys_event(
749             IA_CSS_PSYS_SW_EVENT_MIPI_BUFFERS_READY,
750             (uint8_t)port,
751             (uint8_t)my_css.num_mipi_frames[port],
752             0 /* not used */);
753         IA_CSS_LEAVE_ERR_PRIVATE(0);
754 #else
755         (void)pipe;
756 #endif
757         return 0;
758 }