// SPDX-License-Identifier: GPL-2.0
|
/*
|
* Support for Intel Camera Imaging ISP subsystem.
|
* Copyright (c) 2015, Intel Corporation.
|
*
|
* This program is free software; you can redistribute it and/or modify it
|
* under the terms and conditions of the GNU General Public License,
|
* version 2, as published by the Free Software Foundation.
|
*
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
* more details.
|
*/
|
|
#include "ia_css_mipi.h"
|
#include "sh_css_mipi.h"
|
#include <type_support.h>
|
#include "system_global.h"
|
#include "ia_css_err.h"
|
#include "ia_css_pipe.h"
|
#include "ia_css_stream_format.h"
|
#include "sh_css_stream_format.h"
|
#include "ia_css_stream_public.h"
|
#include "ia_css_frame_public.h"
|
#include "ia_css_input_port.h"
|
#include "ia_css_debug.h"
|
#include "sh_css_struct.h"
|
#include "sh_css_defs.h"
|
#include "sh_css_sp.h" /* sh_css_update_host2sp_mipi_frame sh_css_update_host2sp_num_mipi_frames ... */
|
#include "sw_event_global.h" /* IA_CSS_PSYS_SW_EVENT_MIPI_BUFFERS_READY */
|
|
static u32
|
ref_count_mipi_allocation[N_CSI_PORTS]; /* Initialized in mipi_init */
|
|
int
|
ia_css_mipi_frame_specify(const unsigned int size_mem_words,
|
const bool contiguous) {
|
int err = 0;
|
|
my_css.size_mem_words = size_mem_words;
|
(void)contiguous;
|
|
return err;
|
}
|
|
/*
|
* Check if a source port or TPG/PRBS ID is valid
|
*/
|
static bool ia_css_mipi_is_source_port_valid(struct ia_css_pipe *pipe,
|
unsigned int *pport)
|
{
|
bool ret = true;
|
unsigned int port = 0;
|
unsigned int max_ports = 0;
|
|
switch (pipe->stream->config.mode) {
|
case IA_CSS_INPUT_MODE_BUFFERED_SENSOR:
|
port = (unsigned int)pipe->stream->config.source.port.port;
|
max_ports = N_CSI_PORTS;
|
break;
|
case IA_CSS_INPUT_MODE_TPG:
|
port = (unsigned int)pipe->stream->config.source.tpg.id;
|
max_ports = N_CSS_TPG_IDS;
|
break;
|
case IA_CSS_INPUT_MODE_PRBS:
|
port = (unsigned int)pipe->stream->config.source.prbs.id;
|
max_ports = N_CSS_PRBS_IDS;
|
break;
|
default:
|
assert(false);
|
ret = false;
|
break;
|
}
|
|
if (ret) {
|
assert(port < max_ports);
|
|
if (port >= max_ports)
|
ret = false;
|
}
|
|
*pport = port;
|
|
return ret;
|
}
|
|
/* Assumptions:
|
* - A line is multiple of 4 bytes = 1 word.
|
* - Each frame has SOF and EOF (each 1 word).
|
* - Each line has format header and optionally SOL and EOL (each 1 word).
|
* - Odd and even lines of YUV420 format are different in bites per pixel size.
|
* - Custom size of embedded data.
|
* -- Interleaved frames are not taken into account.
|
* -- Lines are multiples of 8B, and not necessary of (custom 3B, or 7B
|
* etc.).
|
* Result is given in DDR mem words, 32B or 256 bits
|
*/
|
int
|
ia_css_mipi_frame_calculate_size(const unsigned int width,
|
const unsigned int height,
|
const enum atomisp_input_format format,
|
const bool hasSOLandEOL,
|
const unsigned int embedded_data_size_words,
|
unsigned int *size_mem_words) {
|
int err = 0;
|
|
unsigned int bits_per_pixel = 0;
|
unsigned int even_line_bytes = 0;
|
unsigned int odd_line_bytes = 0;
|
unsigned int words_per_odd_line = 0;
|
unsigned int words_for_first_line = 0;
|
unsigned int words_per_even_line = 0;
|
unsigned int mem_words_per_even_line = 0;
|
unsigned int mem_words_per_odd_line = 0;
|
unsigned int mem_words_for_first_line = 0;
|
unsigned int mem_words_for_EOF = 0;
|
unsigned int mem_words = 0;
|
unsigned int width_padded = width;
|
|
#if defined(ISP2401)
|
/* The changes will be reverted as soon as RAW
|
* Buffers are deployed by the 2401 Input System
|
* in the non-continuous use scenario.
|
*/
|
width_padded += (2 * ISP_VEC_NELEMS);
|
#endif
|
|
IA_CSS_ENTER("padded_width=%d, height=%d, format=%d, hasSOLandEOL=%d, embedded_data_size_words=%d\n",
|
width_padded, height, format, hasSOLandEOL, embedded_data_size_words);
|
|
switch (format)
|
{
|
case ATOMISP_INPUT_FORMAT_RAW_6: /* 4p, 3B, 24bits */
|
bits_per_pixel = 6;
|
break;
|
case ATOMISP_INPUT_FORMAT_RAW_7: /* 8p, 7B, 56bits */
|
bits_per_pixel = 7;
|
break;
|
case ATOMISP_INPUT_FORMAT_RAW_8: /* 1p, 1B, 8bits */
|
case ATOMISP_INPUT_FORMAT_BINARY_8: /* 8bits, TODO: check. */
|
case ATOMISP_INPUT_FORMAT_YUV420_8: /* odd 2p, 2B, 16bits, even 2p, 4B, 32bits */
|
bits_per_pixel = 8;
|
break;
|
case ATOMISP_INPUT_FORMAT_YUV420_10: /* odd 4p, 5B, 40bits, even 4p, 10B, 80bits */
|
case ATOMISP_INPUT_FORMAT_RAW_10: /* 4p, 5B, 40bits */
|
#if !defined(HAS_NO_PACKED_RAW_PIXELS)
|
/* The changes will be reverted as soon as RAW
|
* Buffers are deployed by the 2401 Input System
|
* in the non-continuous use scenario.
|
*/
|
bits_per_pixel = 10;
|
#else
|
bits_per_pixel = 16;
|
#endif
|
break;
|
case ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY: /* 2p, 3B, 24bits */
|
case ATOMISP_INPUT_FORMAT_RAW_12: /* 2p, 3B, 24bits */
|
bits_per_pixel = 12;
|
break;
|
case ATOMISP_INPUT_FORMAT_RAW_14: /* 4p, 7B, 56bits */
|
bits_per_pixel = 14;
|
break;
|
case ATOMISP_INPUT_FORMAT_RGB_444: /* 1p, 2B, 16bits */
|
case ATOMISP_INPUT_FORMAT_RGB_555: /* 1p, 2B, 16bits */
|
case ATOMISP_INPUT_FORMAT_RGB_565: /* 1p, 2B, 16bits */
|
case ATOMISP_INPUT_FORMAT_YUV422_8: /* 2p, 4B, 32bits */
|
bits_per_pixel = 16;
|
break;
|
case ATOMISP_INPUT_FORMAT_RGB_666: /* 4p, 9B, 72bits */
|
bits_per_pixel = 18;
|
break;
|
case ATOMISP_INPUT_FORMAT_YUV422_10: /* 2p, 5B, 40bits */
|
bits_per_pixel = 20;
|
break;
|
case ATOMISP_INPUT_FORMAT_RGB_888: /* 1p, 3B, 24bits */
|
bits_per_pixel = 24;
|
break;
|
|
case ATOMISP_INPUT_FORMAT_YUV420_16: /* Not supported */
|
case ATOMISP_INPUT_FORMAT_YUV422_16: /* Not supported */
|
case ATOMISP_INPUT_FORMAT_RAW_16: /* TODO: not specified in MIPI SPEC, check */
|
default:
|
return -EINVAL;
|
}
|
|
odd_line_bytes = (width_padded * bits_per_pixel + 7) >> 3; /* ceil ( bits per line / 8) */
|
|
/* Even lines for YUV420 formats are double in bits_per_pixel. */
|
if (format == ATOMISP_INPUT_FORMAT_YUV420_8
|
|| format == ATOMISP_INPUT_FORMAT_YUV420_10
|
|| format == ATOMISP_INPUT_FORMAT_YUV420_16)
|
{
|
even_line_bytes = (width_padded * 2 * bits_per_pixel + 7) >>
|
3; /* ceil ( bits per line / 8) */
|
} else
|
{
|
even_line_bytes = odd_line_bytes;
|
}
|
|
/* a frame represented in memory: ()- optional; data - payload words.
|
* addr 0 1 2 3 4 5 6 7:
|
* first SOF (SOL) PACK_H data data data data data
|
* data data data data data data data data
|
* ...
|
* data data 0 0 0 0 0 0
|
* second (EOL) (SOL) PACK_H data data data data data
|
* data data data data data data data data
|
* ...
|
* data data 0 0 0 0 0 0
|
* ...
|
* last (EOL) EOF 0 0 0 0 0 0
|
*
|
* Embedded lines are regular lines stored before the first and after
|
* payload lines.
|
*/
|
|
words_per_odd_line = (odd_line_bytes + 3) >> 2;
|
/* ceil(odd_line_bytes/4); word = 4 bytes */
|
words_per_even_line = (even_line_bytes + 3) >> 2;
|
words_for_first_line = words_per_odd_line + 2 + (hasSOLandEOL ? 1 : 0);
|
/* + SOF +packet header + optionally (SOL), but (EOL) is not in the first line */
|
words_per_odd_line += (1 + (hasSOLandEOL ? 2 : 0));
|
/* each non-first line has format header, and optionally (SOL) and (EOL). */
|
words_per_even_line += (1 + (hasSOLandEOL ? 2 : 0));
|
|
mem_words_per_odd_line = (words_per_odd_line + 7) >> 3;
|
/* ceil(words_per_odd_line/8); mem_word = 32 bytes, 8 words */
|
mem_words_for_first_line = (words_for_first_line + 7) >> 3;
|
mem_words_per_even_line = (words_per_even_line + 7) >> 3;
|
mem_words_for_EOF = 1; /* last line consisit of the optional (EOL) and EOF */
|
|
mem_words = ((embedded_data_size_words + 7) >> 3) +
|
mem_words_for_first_line +
|
(((height + 1) >> 1) - 1) * mem_words_per_odd_line +
|
/* ceil (height/2) - 1 (first line is calculated separatelly) */
|
(height >> 1) * mem_words_per_even_line + /* floor(height/2) */
|
mem_words_for_EOF;
|
|
*size_mem_words = mem_words; /* ceil(words/8); mem word is 32B = 8words. */
|
/* Check if the above is still needed. */
|
|
IA_CSS_LEAVE_ERR(err);
|
return err;
|
}
|
|
#if !defined(ISP2401)
|
int
|
ia_css_mipi_frame_enable_check_on_size(const enum mipi_port_id port,
|
const unsigned int size_mem_words) {
|
u32 idx;
|
|
int err = -EBUSY;
|
|
OP___assert(port < N_CSI_PORTS);
|
OP___assert(size_mem_words != 0);
|
|
for (idx = 0; idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT &&
|
my_css.mipi_sizes_for_check[port][idx] != 0;
|
idx++) /* do nothing */
|
{
|
}
|
if (idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT)
|
{
|
my_css.mipi_sizes_for_check[port][idx] = size_mem_words;
|
err = 0;
|
}
|
|
return err;
|
}
|
#endif
|
|
void
|
mipi_init(void)
|
{
|
unsigned int i;
|
|
for (i = 0; i < N_CSI_PORTS; i++)
|
ref_count_mipi_allocation[i] = 0;
|
}
|
|
int
|
calculate_mipi_buff_size(
|
struct ia_css_stream_config *stream_cfg,
|
unsigned int *size_mem_words) {
|
#if !defined(ISP2401)
|
int err = -EINVAL;
|
(void)stream_cfg;
|
(void)size_mem_words;
|
#else
|
unsigned int width;
|
unsigned int height;
|
enum atomisp_input_format format;
|
bool pack_raw_pixels;
|
|
unsigned int width_padded;
|
unsigned int bits_per_pixel = 0;
|
|
unsigned int even_line_bytes = 0;
|
unsigned int odd_line_bytes = 0;
|
|
unsigned int words_per_odd_line = 0;
|
unsigned int words_per_even_line = 0;
|
|
unsigned int mem_words_per_even_line = 0;
|
unsigned int mem_words_per_odd_line = 0;
|
|
unsigned int mem_words_per_buff_line = 0;
|
unsigned int mem_words_per_buff = 0;
|
int err = 0;
|
|
/**
|
* zhengjie.lu@intel.com
|
*
|
* NOTE
|
* - In the struct "ia_css_stream_config", there
|
* are two members: "input_config" and "isys_config".
|
* Both of them provide the same information, e.g.
|
* input_res and format.
|
*
|
* Question here is that: which one shall be used?
|
*/
|
width = stream_cfg->input_config.input_res.width;
|
height = stream_cfg->input_config.input_res.height;
|
format = stream_cfg->input_config.format;
|
pack_raw_pixels = stream_cfg->pack_raw_pixels;
|
/* end of NOTE */
|
|
/**
|
* zhengjie.lu@intel.com
|
*
|
* NOTE
|
* - The following code is derived from the
|
* existing code "ia_css_mipi_frame_calculate_size()".
|
*
|
* Question here is: why adding "2 * ISP_VEC_NELEMS"
|
* to "width_padded", but not making "width_padded"
|
* aligned with "2 * ISP_VEC_NELEMS"?
|
*/
|
/* The changes will be reverted as soon as RAW
|
* Buffers are deployed by the 2401 Input System
|
* in the non-continuous use scenario.
|
*/
|
width_padded = width + (2 * ISP_VEC_NELEMS);
|
/* end of NOTE */
|
|
IA_CSS_ENTER("padded_width=%d, height=%d, format=%d\n",
|
width_padded, height, format);
|
|
bits_per_pixel = sh_css_stream_format_2_bits_per_subpixel(format);
|
bits_per_pixel =
|
(format == ATOMISP_INPUT_FORMAT_RAW_10 && pack_raw_pixels) ? bits_per_pixel : 16;
|
if (bits_per_pixel == 0)
|
return -EINVAL;
|
|
odd_line_bytes = (width_padded * bits_per_pixel + 7) >> 3; /* ceil ( bits per line / 8) */
|
|
/* Even lines for YUV420 formats are double in bits_per_pixel. */
|
if (format == ATOMISP_INPUT_FORMAT_YUV420_8
|
|| format == ATOMISP_INPUT_FORMAT_YUV420_10)
|
{
|
even_line_bytes = (width_padded * 2 * bits_per_pixel + 7) >>
|
3; /* ceil ( bits per line / 8) */
|
} else
|
{
|
even_line_bytes = odd_line_bytes;
|
}
|
|
words_per_odd_line = (odd_line_bytes + 3) >> 2;
|
/* ceil(odd_line_bytes/4); word = 4 bytes */
|
words_per_even_line = (even_line_bytes + 3) >> 2;
|
|
mem_words_per_odd_line = (words_per_odd_line + 7) >> 3;
|
/* ceil(words_per_odd_line/8); mem_word = 32 bytes, 8 words */
|
mem_words_per_even_line = (words_per_even_line + 7) >> 3;
|
|
mem_words_per_buff_line =
|
(mem_words_per_odd_line > mem_words_per_even_line) ? mem_words_per_odd_line : mem_words_per_even_line;
|
mem_words_per_buff = mem_words_per_buff_line * height;
|
|
*size_mem_words = mem_words_per_buff;
|
|
IA_CSS_LEAVE_ERR(err);
|
#endif
|
return err;
|
}
|
|
static bool buffers_needed(struct ia_css_pipe *pipe)
|
{
|
if (!IS_ISP2401) {
|
if (pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR)
|
return true;
|
else
|
return false;
|
}
|
|
if (pipe->stream->config.mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR ||
|
pipe->stream->config.mode == IA_CSS_INPUT_MODE_TPG ||
|
pipe->stream->config.mode == IA_CSS_INPUT_MODE_PRBS)
|
return true;
|
|
return false;
|
}
|
|
int
|
allocate_mipi_frames(struct ia_css_pipe *pipe,
|
struct ia_css_stream_info *info) {
|
int err = -EINVAL;
|
unsigned int port;
|
|
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
|
"allocate_mipi_frames(%p) enter:\n", pipe);
|
|
assert(pipe);
|
assert(pipe->stream);
|
if ((!pipe) || (!pipe->stream))
|
{
|
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
|
"allocate_mipi_frames(%p) exit: pipe or stream is null.\n",
|
pipe);
|
return -EINVAL;
|
}
|
|
#ifdef ISP2401
|
if (pipe->stream->config.online)
|
{
|
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
|
"allocate_mipi_frames(%p) exit: no buffers needed for 2401 pipe mode.\n",
|
pipe);
|
return 0;
|
}
|
|
#endif
|
|
if (!buffers_needed(pipe)) {
|
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
|
"allocate_mipi_frames(%p) exit: no buffers needed for pipe mode.\n",
|
pipe);
|
return 0; /* AM TODO: Check */
|
}
|
|
if (!IS_ISP2401) {
|
port = (unsigned int)pipe->stream->config.source.port.port;
|
} else {
|
/* Returns true if port is valid. So, invert it */
|
err = !ia_css_mipi_is_source_port_valid(pipe, &port);
|
}
|
|
assert(port < N_CSI_PORTS);
|
|
if ((!IS_ISP2401 && port >= N_CSI_PORTS) ||
|
(IS_ISP2401 && err)) {
|
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
|
"allocate_mipi_frames(%p) exit: error: port is not correct (port=%d).\n",
|
pipe, port);
|
return -EINVAL;
|
}
|
|
#ifdef ISP2401
|
err = calculate_mipi_buff_size(
|
&pipe->stream->config,
|
&my_css.mipi_frame_size[port]);
|
#endif
|
|
#if !defined(ISP2401)
|
if (ref_count_mipi_allocation[port] != 0)
|
{
|
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
|
"allocate_mipi_frames(%p) exit: already allocated for this port (port=%d).\n",
|
pipe, port);
|
return 0;
|
}
|
#else
|
/* 2401 system allows multiple streams to use same physical port. This is not
|
* true for 2400 system. Currently 2401 uses MIPI buffers as a temporary solution.
|
* TODO AM: Once that is changed (removed) this code should be removed as well.
|
* In that case only 2400 related code should remain.
|
*/
|
if (ref_count_mipi_allocation[port] != 0)
|
{
|
ref_count_mipi_allocation[port]++;
|
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
|
"allocate_mipi_frames(%p) leave: nothing to do, already allocated for this port (port=%d).\n",
|
pipe, port);
|
return 0;
|
}
|
#endif
|
|
ref_count_mipi_allocation[port]++;
|
|
/* AM TODO: mipi frames number should come from stream struct. */
|
my_css.num_mipi_frames[port] = NUM_MIPI_FRAMES_PER_STREAM;
|
|
/* Incremental allocation (per stream), not for all streams at once. */
|
{ /* limit the scope of i,j */
|
unsigned int i, j;
|
|
for (i = 0; i < my_css.num_mipi_frames[port]; i++)
|
{
|
/* free previous frame */
|
if (my_css.mipi_frames[port][i]) {
|
ia_css_frame_free(my_css.mipi_frames[port][i]);
|
my_css.mipi_frames[port][i] = NULL;
|
}
|
/* check if new frame is needed */
|
if (i < my_css.num_mipi_frames[port]) {
|
/* allocate new frame */
|
err = ia_css_frame_allocate_with_buffer_size(
|
&my_css.mipi_frames[port][i],
|
my_css.mipi_frame_size[port] * HIVE_ISP_DDR_WORD_BYTES,
|
false);
|
if (err) {
|
for (j = 0; j < i; j++) {
|
if (my_css.mipi_frames[port][j]) {
|
ia_css_frame_free(my_css.mipi_frames[port][j]);
|
my_css.mipi_frames[port][j] = NULL;
|
}
|
}
|
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
|
"allocate_mipi_frames(%p, %d) exit: error: allocation failed.\n",
|
pipe, port);
|
return err;
|
}
|
}
|
if (info->metadata_info.size > 0) {
|
/* free previous metadata buffer */
|
if (my_css.mipi_metadata[port][i]) {
|
ia_css_metadata_free(my_css.mipi_metadata[port][i]);
|
my_css.mipi_metadata[port][i] = NULL;
|
}
|
/* check if need to allocate a new metadata buffer */
|
if (i < my_css.num_mipi_frames[port]) {
|
/* allocate new metadata buffer */
|
my_css.mipi_metadata[port][i] = ia_css_metadata_allocate(&info->metadata_info);
|
if (!my_css.mipi_metadata[port][i]) {
|
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
|
"allocate_mipi_metadata(%p, %d) failed.\n",
|
pipe, port);
|
return err;
|
}
|
}
|
}
|
}
|
}
|
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
|
"allocate_mipi_frames(%p) exit:\n", pipe);
|
|
return err;
|
}
|
|
int
|
free_mipi_frames(struct ia_css_pipe *pipe) {
|
int err = -EINVAL;
|
unsigned int port;
|
|
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
|
"free_mipi_frames(%p) enter:\n", pipe);
|
|
/* assert(pipe != NULL); TEMP: TODO: Should be assert only. */
|
if (pipe)
|
{
|
assert(pipe->stream);
|
if ((!pipe) || (!pipe->stream)) {
|
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
|
"free_mipi_frames(%p) exit: error: pipe or stream is null.\n",
|
pipe);
|
return -EINVAL;
|
}
|
|
if (!buffers_needed(pipe)) {
|
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
|
"free_mipi_frames(%p) exit: error: wrong mode.\n",
|
pipe);
|
return err;
|
}
|
|
if (!IS_ISP2401) {
|
port = (unsigned int)pipe->stream->config.source.port.port;
|
} else {
|
/* Returns true if port is valid. So, invert it */
|
err = !ia_css_mipi_is_source_port_valid(pipe, &port);
|
}
|
|
assert(port < N_CSI_PORTS);
|
|
if ((!IS_ISP2401 && port >= N_CSI_PORTS) ||
|
(IS_ISP2401 && err)) {
|
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
|
"free_mipi_frames(%p, %d) exit: error: pipe port is not correct.\n",
|
pipe, port);
|
return err;
|
}
|
|
if (ref_count_mipi_allocation[port] > 0) {
|
#if !defined(ISP2401)
|
assert(ref_count_mipi_allocation[port] == 1);
|
if (ref_count_mipi_allocation[port] != 1) {
|
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
|
"free_mipi_frames(%p) exit: error: wrong ref_count (ref_count=%d).\n",
|
pipe, ref_count_mipi_allocation[port]);
|
return err;
|
}
|
#endif
|
|
ref_count_mipi_allocation[port]--;
|
|
if (ref_count_mipi_allocation[port] == 0) {
|
/* no streams are using this buffer, so free it */
|
unsigned int i;
|
|
for (i = 0; i < my_css.num_mipi_frames[port]; i++) {
|
if (my_css.mipi_frames[port][i]) {
|
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
|
"free_mipi_frames(port=%d, num=%d).\n", port, i);
|
ia_css_frame_free(my_css.mipi_frames[port][i]);
|
my_css.mipi_frames[port][i] = NULL;
|
}
|
if (my_css.mipi_metadata[port][i]) {
|
ia_css_metadata_free(my_css.mipi_metadata[port][i]);
|
my_css.mipi_metadata[port][i] = NULL;
|
}
|
}
|
|
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
|
"free_mipi_frames(%p) exit (deallocated).\n", pipe);
|
}
|
#if defined(ISP2401)
|
else {
|
/* 2401 system allows multiple streams to use same physical port. This is not
|
* true for 2400 system. Currently 2401 uses MIPI buffers as a temporary solution.
|
* TODO AM: Once that is changed (removed) this code should be removed as well.
|
* In that case only 2400 related code should remain.
|
*/
|
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
|
"free_mipi_frames(%p) leave: nothing to do, other streams still use this port (port=%d).\n",
|
pipe, port);
|
}
|
#endif
|
}
|
} else /* pipe ==NULL */
|
{
|
/* AM TEMP: free-ing all mipi buffers just like a legacy code. */
|
for (port = CSI_PORT0_ID; port < N_CSI_PORTS; port++) {
|
unsigned int i;
|
|
for (i = 0; i < my_css.num_mipi_frames[port]; i++) {
|
if (my_css.mipi_frames[port][i]) {
|
ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE,
|
"free_mipi_frames(port=%d, num=%d).\n", port, i);
|
ia_css_frame_free(my_css.mipi_frames[port][i]);
|
my_css.mipi_frames[port][i] = NULL;
|
}
|
if (my_css.mipi_metadata[port][i]) {
|
ia_css_metadata_free(my_css.mipi_metadata[port][i]);
|
my_css.mipi_metadata[port][i] = NULL;
|
}
|
}
|
ref_count_mipi_allocation[port] = 0;
|
}
|
}
|
return 0;
|
}
|
|
int
|
send_mipi_frames(struct ia_css_pipe *pipe) {
|
int err = -EINVAL;
|
unsigned int i;
|
#ifndef ISP2401
|
unsigned int port;
|
#else
|
unsigned int port = 0;
|
#endif
|
|
IA_CSS_ENTER_PRIVATE("pipe=%p", pipe);
|
|
assert(pipe);
|
assert(pipe->stream);
|
if (!pipe || !pipe->stream)
|
{
|
IA_CSS_ERROR("pipe or stream is null");
|
return -EINVAL;
|
}
|
|
/* multi stream video needs mipi buffers */
|
/* nothing to be done in other cases. */
|
if (!buffers_needed(pipe)) {
|
IA_CSS_LOG("nothing to be done for this mode");
|
return 0;
|
/* TODO: AM: maybe this should be returning an error. */
|
}
|
|
if (!IS_ISP2401) {
|
port = (unsigned int)pipe->stream->config.source.port.port;
|
} else {
|
/* Returns true if port is valid. So, invert it */
|
err = !ia_css_mipi_is_source_port_valid(pipe, &port);
|
}
|
|
assert(port < N_CSI_PORTS);
|
|
if ((!IS_ISP2401 && port >= N_CSI_PORTS) ||
|
(IS_ISP2401 && err)) {
|
IA_CSS_ERROR("send_mipi_frames(%p) exit: invalid port specified (port=%d).\n",
|
pipe, port);
|
return err;
|
}
|
|
/* Hand-over the SP-internal mipi buffers */
|
for (i = 0; i < my_css.num_mipi_frames[port]; i++)
|
{
|
/* Need to include the ofset for port. */
|
sh_css_update_host2sp_mipi_frame(port * NUM_MIPI_FRAMES_PER_STREAM + i,
|
my_css.mipi_frames[port][i]);
|
sh_css_update_host2sp_mipi_metadata(port * NUM_MIPI_FRAMES_PER_STREAM + i,
|
my_css.mipi_metadata[port][i]);
|
}
|
sh_css_update_host2sp_num_mipi_frames(my_css.num_mipi_frames[port]);
|
|
/**********************************
|
* Send an event to inform the SP
|
* that all MIPI frames are passed.
|
**********************************/
|
if (!sh_css_sp_is_running())
|
{
|
/* SP is not running. The queues are not valid */
|
IA_CSS_ERROR("sp is not running");
|
return err;
|
}
|
|
ia_css_bufq_enqueue_psys_event(
|
IA_CSS_PSYS_SW_EVENT_MIPI_BUFFERS_READY,
|
(uint8_t)port,
|
(uint8_t)my_css.num_mipi_frames[port],
|
0 /* not used */);
|
IA_CSS_LEAVE_ERR_PRIVATE(0);
|
return 0;
|
}
|