| // 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 */ |
| |
| /* 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 */ |
| /* 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; |
| 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; |
| } |
| |
| /* |
| * Check if a source port or TPG/PRBS ID is valid |
| */ |
| |
| #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; |
| } |
| |
| bool mipi_is_free(void) |
| { |
| unsigned int i; |
| |
| for (i = 0; i < N_CSI_PORTS; i++) |
| if (ref_count_mipi_allocation[i]) |
| return false; |
| |
| return true; |
| } |
| |
| #if defined(ISP2401) |
| /* |
| * @brief Calculate the required MIPI buffer sizes. |
| * Based on the stream configuration, calculate the |
| * required MIPI buffer sizes (in DDR words). |
| * |
| * @param[in] stream_cfg Point to the target stream configuration |
| * @param[out] size_mem_words MIPI buffer size in DDR words. |
| * |
| * @return |
| */ |
| static int calculate_mipi_buff_size(struct ia_css_stream_config *stream_cfg, |
| unsigned int *size_mem_words) |
| { |
| 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); |
| return err; |
| } |
| #endif |
| |
| 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 (pipe->stream->config.mode != IA_CSS_INPUT_MODE_BUFFERED_SENSOR) { |
| 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 */ |
| } |
| |
| port = (unsigned int)pipe->stream->config.source.port.port; |
| if (port >= N_CSI_PORTS) { |
| IA_CSS_ERROR("allocate_mipi_frames(%p) exit: port is not correct (port=%d).", |
| pipe, port); |
| return -EINVAL; |
| } |
| |
| #ifdef ISP2401 |
| err = calculate_mipi_buff_size(&pipe->stream->config, |
| &my_css.mipi_frame_size[port]); |
| /* |
| * 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; |
| } |
| #else |
| 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; |
| } |
| #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); |
| 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_ERROR("allocate_mipi_frames(%p, %d) exit: allocation failed.", |
| 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_ERROR("free_mipi_frames(%p) exit: pipe or stream is null.", |
| pipe); |
| return -EINVAL; |
| } |
| |
| if (pipe->stream->config.mode != IA_CSS_INPUT_MODE_BUFFERED_SENSOR) { |
| IA_CSS_ERROR("free_mipi_frames(%p) exit: wrong mode.", |
| pipe); |
| return err; |
| } |
| |
| port = (unsigned int)pipe->stream->config.source.port.port; |
| |
| if (port >= N_CSI_PORTS) { |
| IA_CSS_ERROR("free_mipi_frames(%p, %d) exit: pipe port is not correct.", |
| 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_ERROR("free_mipi_frames(%p) exit: wrong ref_count (ref_count=%d).", |
| 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; |
| unsigned int port; |
| |
| 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 (pipe->stream->config.mode != IA_CSS_INPUT_MODE_BUFFERED_SENSOR) { |
| IA_CSS_LOG("nothing to be done for this mode"); |
| return 0; |
| /* TODO: AM: maybe this should be returning an error. */ |
| } |
| |
| port = (unsigned int)pipe->stream->config.source.port.port; |
| |
| if (port >= N_CSI_PORTS) { |
| IA_CSS_ERROR("send_mipi_frames(%p) exit: invalid port specified (port=%d).", |
| 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; |
| } |