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