diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:27:49 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:27:49 +0000 |
commit | ace9429bb58fd418f0c81d4c2835699bddf6bde6 (patch) | |
tree | b2d64bc10158fdd5497876388cd68142ca374ed3 /drivers/staging/media/atomisp/pci/runtime/ifmtr/src | |
parent | Initial commit. (diff) | |
download | linux-ace9429bb58fd418f0c81d4c2835699bddf6bde6.tar.xz linux-ace9429bb58fd418f0c81d4c2835699bddf6bde6.zip |
Adding upstream version 6.6.15.upstream/6.6.15
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/staging/media/atomisp/pci/runtime/ifmtr/src')
-rw-r--r-- | drivers/staging/media/atomisp/pci/runtime/ifmtr/src/ifmtr.c | 553 |
1 files changed, 553 insertions, 0 deletions
diff --git a/drivers/staging/media/atomisp/pci/runtime/ifmtr/src/ifmtr.c b/drivers/staging/media/atomisp/pci/runtime/ifmtr/src/ifmtr.c new file mode 100644 index 0000000000..6d9f47629f --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/ifmtr/src/ifmtr.c @@ -0,0 +1,553 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Support for Intel Camera Imaging ISP subsystem. + * Copyright (c) 2010 - 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 "system_global.h" +#include <linux/kernel.h> + +#ifndef ISP2401 + +#include "ia_css_ifmtr.h" +#include <math_support.h> +#include "sh_css_internal.h" +#include "input_formatter.h" +#include "assert_support.h" +#include "sh_css_sp.h" +#include "isp/modes/interface/input_buf.isp.h" + +/************************************************************ + * Static functions declarations + ************************************************************/ +static int ifmtr_start_column( + const struct ia_css_stream_config *config, + unsigned int bin_in, + unsigned int *start_column); + +static int ifmtr_input_start_line( + const struct ia_css_stream_config *config, + unsigned int bin_in, + unsigned int *start_line); + +static void ifmtr_set_if_blocking_mode( + const input_formatter_cfg_t *const config_a, + const input_formatter_cfg_t *const config_b); + +/************************************************************ + * Public functions + ************************************************************/ + +/* ISP expects GRBG bayer order, we skip one line and/or one row + * to correct in case the input bayer order is different. + */ +unsigned int ia_css_ifmtr_lines_needed_for_bayer_order( + const struct ia_css_stream_config *config) +{ + assert(config); + if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_BGGR) + || (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG)) + return 1; + + return 0; +} + +unsigned int ia_css_ifmtr_columns_needed_for_bayer_order( + const struct ia_css_stream_config *config) +{ + assert(config); + if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_RGGB) + || (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG)) + return 1; + + return 0; +} + +int ia_css_ifmtr_configure(struct ia_css_stream_config *config, + struct ia_css_binary *binary) +{ + unsigned int start_line, start_column = 0, + cropped_height, + cropped_width, + num_vectors, + buffer_height = 2, + buffer_width, + two_ppc, + vmem_increment = 0, + deinterleaving = 0, + deinterleaving_b = 0, + width_a = 0, + width_b = 0, + bits_per_pixel, + vectors_per_buffer, + vectors_per_line = 0, + buffers_per_line = 0, + buf_offset_a = 0, + buf_offset_b = 0, + line_width = 0, + width_b_factor = 1, start_column_b, + left_padding = 0; + input_formatter_cfg_t if_a_config, if_b_config; + enum atomisp_input_format input_format; + int err = 0; + u8 if_config_index; + + /* Determine which input formatter config set is targeted. */ + /* Index is equal to the CSI-2 port used. */ + enum mipi_port_id port; + + if (binary) { + cropped_height = binary->in_frame_info.res.height; + cropped_width = binary->in_frame_info.res.width; + /* This should correspond to the input buffer definition for + ISP binaries in input_buf.isp.h */ + if (binary->info->sp.enable.continuous && + binary->info->sp.pipeline.mode != IA_CSS_BINARY_MODE_COPY) + buffer_width = MAX_VECTORS_PER_INPUT_LINE_CONT * ISP_VEC_NELEMS; + else + buffer_width = binary->info->sp.input.max_width; + input_format = binary->input_format; + } else { + /* sp raw copy pipe (IA_CSS_PIPE_MODE_COPY): binary is NULL */ + cropped_height = config->input_config.input_res.height; + cropped_width = config->input_config.input_res.width; + buffer_width = MAX_VECTORS_PER_INPUT_LINE_CONT * ISP_VEC_NELEMS; + input_format = config->input_config.format; + } + two_ppc = config->pixels_per_clock == 2; + if (config->mode == IA_CSS_INPUT_MODE_SENSOR + || config->mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) { + port = config->source.port.port; + if_config_index = (uint8_t)(port - MIPI_PORT0_ID); + } else if (config->mode == IA_CSS_INPUT_MODE_MEMORY) { + if_config_index = SH_CSS_IF_CONFIG_NOT_NEEDED; + } else { + if_config_index = 0; + } + + assert(if_config_index <= SH_CSS_MAX_IF_CONFIGS + || if_config_index == SH_CSS_IF_CONFIG_NOT_NEEDED); + + /* TODO: check to see if input is RAW and if current mode interprets + * RAW data in any particular bayer order. copy binary with output + * format other than raw should not result in dropping lines and/or + * columns. + */ + err = ifmtr_input_start_line(config, cropped_height, &start_line); + if (err) + return err; + err = ifmtr_start_column(config, cropped_width, &start_column); + if (err) + return err; + + if (config->left_padding == -1) + if (!binary) + /* sp raw copy pipe: set left_padding value */ + left_padding = 0; + else + left_padding = binary->left_padding; + else + left_padding = 2 * ISP_VEC_NELEMS - config->left_padding; + + if (left_padding) { + num_vectors = CEIL_DIV(cropped_width + left_padding, + ISP_VEC_NELEMS); + } else { + num_vectors = CEIL_DIV(cropped_width, ISP_VEC_NELEMS); + num_vectors *= buffer_height; + /* todo: in case of left padding, + num_vectors is vectors per line, + otherwise vectors per line * buffer_height. */ + } + + start_column_b = start_column; + + bits_per_pixel = input_formatter_get_alignment(INPUT_FORMATTER0_ID) + * 8 / ISP_VEC_NELEMS; + switch (input_format) { + case ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY: + if (two_ppc) { + vmem_increment = 1; + deinterleaving = 1; + deinterleaving_b = 1; + /* half lines */ + width_a = cropped_width * deinterleaving / 2; + width_b_factor = 2; + /* full lines */ + width_b = width_a * width_b_factor; + buffer_width *= deinterleaving * 2; + /* Patch from bayer to yuv */ + num_vectors *= deinterleaving; + buf_offset_b = buffer_width / 2 / ISP_VEC_NELEMS; + vectors_per_line = num_vectors / buffer_height; + /* Even lines are half size */ + line_width = vectors_per_line * + input_formatter_get_alignment(INPUT_FORMATTER0_ID) / + 2; + start_column /= 2; + } else { + vmem_increment = 1; + deinterleaving = 3; + width_a = cropped_width * deinterleaving / 2; + buffer_width = buffer_width * deinterleaving / 2; + /* Patch from bayer to yuv */ + num_vectors = num_vectors / 2 * deinterleaving; + start_column = start_column * deinterleaving / 2; + } + break; + case ATOMISP_INPUT_FORMAT_YUV420_8: + case ATOMISP_INPUT_FORMAT_YUV420_10: + case ATOMISP_INPUT_FORMAT_YUV420_16: + if (two_ppc) { + vmem_increment = 1; + deinterleaving = 1; + width_a = width_b = cropped_width * deinterleaving / 2; + buffer_width *= deinterleaving * 2; + num_vectors *= deinterleaving; + buf_offset_b = buffer_width / 2 / ISP_VEC_NELEMS; + vectors_per_line = num_vectors / buffer_height; + /* Even lines are half size */ + line_width = vectors_per_line * + input_formatter_get_alignment(INPUT_FORMATTER0_ID) / + 2; + start_column *= deinterleaving; + start_column /= 2; + start_column_b = start_column; + } else { + vmem_increment = 1; + deinterleaving = 1; + width_a = cropped_width * deinterleaving; + buffer_width *= deinterleaving * 2; + num_vectors *= deinterleaving; + start_column *= deinterleaving; + } + break; + case ATOMISP_INPUT_FORMAT_YUV422_8: + case ATOMISP_INPUT_FORMAT_YUV422_10: + case ATOMISP_INPUT_FORMAT_YUV422_16: + if (two_ppc) { + vmem_increment = 1; + deinterleaving = 1; + width_a = width_b = cropped_width * deinterleaving; + buffer_width *= deinterleaving * 2; + num_vectors *= deinterleaving; + start_column *= deinterleaving; + buf_offset_b = buffer_width / 2 / ISP_VEC_NELEMS; + start_column_b = start_column; + } else { + vmem_increment = 1; + deinterleaving = 2; + width_a = cropped_width * deinterleaving; + buffer_width *= deinterleaving; + num_vectors *= deinterleaving; + start_column *= deinterleaving; + } + break; + case ATOMISP_INPUT_FORMAT_RGB_444: + case ATOMISP_INPUT_FORMAT_RGB_555: + case ATOMISP_INPUT_FORMAT_RGB_565: + case ATOMISP_INPUT_FORMAT_RGB_666: + case ATOMISP_INPUT_FORMAT_RGB_888: + num_vectors *= 2; + if (two_ppc) { + deinterleaving = 2; /* BR in if_a, G in if_b */ + deinterleaving_b = 1; /* BR in if_a, G in if_b */ + buffers_per_line = 4; + start_column_b = start_column; + start_column *= deinterleaving; + start_column_b *= deinterleaving_b; + } else { + deinterleaving = 3; /* BGR */ + buffers_per_line = 3; + start_column *= deinterleaving; + } + vmem_increment = 1; + width_a = cropped_width * deinterleaving; + width_b = cropped_width * deinterleaving_b; + buffer_width *= buffers_per_line; + /* Patch from bayer to rgb */ + num_vectors = num_vectors / 2 * deinterleaving; + buf_offset_b = buffer_width / 2 / ISP_VEC_NELEMS; + break; + case ATOMISP_INPUT_FORMAT_RAW_6: + case ATOMISP_INPUT_FORMAT_RAW_7: + case ATOMISP_INPUT_FORMAT_RAW_8: + case ATOMISP_INPUT_FORMAT_RAW_10: + case ATOMISP_INPUT_FORMAT_RAW_12: + if (two_ppc) { + int crop_col = (start_column % 2) == 1; + + vmem_increment = 2; + deinterleaving = 1; + width_a = width_b = cropped_width / 2; + + /* When two_ppc is enabled AND we need to crop one extra + * column, if_a crops by one extra and we swap the + * output offsets to interleave the bayer pattern in + * the correct order. + */ + buf_offset_a = crop_col ? 1 : 0; + buf_offset_b = crop_col ? 0 : 1; + start_column_b = start_column / 2; + start_column = start_column / 2 + crop_col; + } else { + vmem_increment = 1; + deinterleaving = 2; + if ((!binary) || (config->continuous && binary + && binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_COPY)) { + /* !binary -> sp raw copy pipe, no deinterleaving */ + deinterleaving = 1; + } + width_a = cropped_width; + /* Must be multiple of deinterleaving */ + num_vectors = CEIL_MUL(num_vectors, deinterleaving); + } + buffer_height *= 2; + if ((!binary) || config->continuous) + /* !binary -> sp raw copy pipe */ + buffer_height *= 2; + vectors_per_line = CEIL_DIV(cropped_width, ISP_VEC_NELEMS); + vectors_per_line = CEIL_MUL(vectors_per_line, deinterleaving); + break; + case ATOMISP_INPUT_FORMAT_RAW_14: + case ATOMISP_INPUT_FORMAT_RAW_16: + if (two_ppc) { + num_vectors *= 2; + vmem_increment = 1; + deinterleaving = 2; + width_a = width_b = cropped_width; + /* B buffer is one line further */ + buf_offset_b = buffer_width / ISP_VEC_NELEMS; + bits_per_pixel *= 2; + } else { + vmem_increment = 1; + deinterleaving = 2; + width_a = cropped_width; + start_column /= deinterleaving; + } + buffer_height *= 2; + break; + case ATOMISP_INPUT_FORMAT_BINARY_8: + case ATOMISP_INPUT_FORMAT_GENERIC_SHORT1: + case ATOMISP_INPUT_FORMAT_GENERIC_SHORT2: + case ATOMISP_INPUT_FORMAT_GENERIC_SHORT3: + case ATOMISP_INPUT_FORMAT_GENERIC_SHORT4: + case ATOMISP_INPUT_FORMAT_GENERIC_SHORT5: + case ATOMISP_INPUT_FORMAT_GENERIC_SHORT6: + case ATOMISP_INPUT_FORMAT_GENERIC_SHORT7: + case ATOMISP_INPUT_FORMAT_GENERIC_SHORT8: + case ATOMISP_INPUT_FORMAT_YUV420_8_SHIFT: + case ATOMISP_INPUT_FORMAT_YUV420_10_SHIFT: + case ATOMISP_INPUT_FORMAT_EMBEDDED: + case ATOMISP_INPUT_FORMAT_USER_DEF1: + case ATOMISP_INPUT_FORMAT_USER_DEF2: + case ATOMISP_INPUT_FORMAT_USER_DEF3: + case ATOMISP_INPUT_FORMAT_USER_DEF4: + case ATOMISP_INPUT_FORMAT_USER_DEF5: + case ATOMISP_INPUT_FORMAT_USER_DEF6: + case ATOMISP_INPUT_FORMAT_USER_DEF7: + case ATOMISP_INPUT_FORMAT_USER_DEF8: + break; + } + if (width_a == 0) + return -EINVAL; + + if (two_ppc) + left_padding /= 2; + + /* Default values */ + if (left_padding) + vectors_per_line = num_vectors; + if (!vectors_per_line) { + vectors_per_line = CEIL_MUL(num_vectors / buffer_height, + deinterleaving); + line_width = 0; + } + if (!line_width) + line_width = vectors_per_line * + input_formatter_get_alignment(INPUT_FORMATTER0_ID); + if (!buffers_per_line) + buffers_per_line = deinterleaving; + line_width = CEIL_MUL(line_width, + input_formatter_get_alignment(INPUT_FORMATTER0_ID) + * vmem_increment); + + vectors_per_buffer = buffer_height * buffer_width / ISP_VEC_NELEMS; + + if (config->mode == IA_CSS_INPUT_MODE_TPG && + ((binary && binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_VIDEO) || + (!binary))) { + /* !binary -> sp raw copy pipe */ + /* workaround for TPG in video mode */ + start_line = 0; + start_column = 0; + cropped_height -= start_line; + width_a -= start_column; + } + + if_a_config.start_line = start_line; + if_a_config.start_column = start_column; + if_a_config.left_padding = left_padding / deinterleaving; + if_a_config.cropped_height = cropped_height; + if_a_config.cropped_width = width_a; + if_a_config.deinterleaving = deinterleaving; + if_a_config.buf_vecs = vectors_per_buffer; + if_a_config.buf_start_index = buf_offset_a; + if_a_config.buf_increment = vmem_increment; + if_a_config.buf_eol_offset = + buffer_width * bits_per_pixel / 8 - line_width; + if_a_config.is_yuv420_format = + (input_format == ATOMISP_INPUT_FORMAT_YUV420_8) + || (input_format == ATOMISP_INPUT_FORMAT_YUV420_10) + || (input_format == ATOMISP_INPUT_FORMAT_YUV420_16); + if_a_config.block_no_reqs = (config->mode != IA_CSS_INPUT_MODE_SENSOR); + + if (two_ppc) { + if (deinterleaving_b) { + deinterleaving = deinterleaving_b; + width_b = cropped_width * deinterleaving; + buffer_width *= deinterleaving; + /* Patch from bayer to rgb */ + num_vectors = num_vectors / 2 * + deinterleaving * width_b_factor; + vectors_per_line = num_vectors / buffer_height; + line_width = vectors_per_line * + input_formatter_get_alignment(INPUT_FORMATTER0_ID); + } + if_b_config.start_line = start_line; + if_b_config.start_column = start_column_b; + if_b_config.left_padding = left_padding / deinterleaving; + if_b_config.cropped_height = cropped_height; + if_b_config.cropped_width = width_b; + if_b_config.deinterleaving = deinterleaving; + if_b_config.buf_vecs = vectors_per_buffer; + if_b_config.buf_start_index = buf_offset_b; + if_b_config.buf_increment = vmem_increment; + if_b_config.buf_eol_offset = + buffer_width * bits_per_pixel / 8 - line_width; + if_b_config.is_yuv420_format = + input_format == ATOMISP_INPUT_FORMAT_YUV420_8 + || input_format == ATOMISP_INPUT_FORMAT_YUV420_10 + || input_format == ATOMISP_INPUT_FORMAT_YUV420_16; + if_b_config.block_no_reqs = + (config->mode != IA_CSS_INPUT_MODE_SENSOR); + + if (if_config_index != SH_CSS_IF_CONFIG_NOT_NEEDED) { + assert(if_config_index <= SH_CSS_MAX_IF_CONFIGS); + + ifmtr_set_if_blocking_mode(&if_a_config, &if_b_config); + /* Set the ifconfigs to SP group */ + sh_css_sp_set_if_configs(&if_a_config, &if_b_config, + if_config_index); + } + } else { + if (if_config_index != SH_CSS_IF_CONFIG_NOT_NEEDED) { + assert(if_config_index <= SH_CSS_MAX_IF_CONFIGS); + + ifmtr_set_if_blocking_mode(&if_a_config, NULL); + /* Set the ifconfigs to SP group */ + sh_css_sp_set_if_configs(&if_a_config, NULL, + if_config_index); + } + } + + return 0; +} + +bool ifmtr_set_if_blocking_mode_reset = true; + +/************************************************************ + * Static functions + ************************************************************/ +static void ifmtr_set_if_blocking_mode( + const input_formatter_cfg_t *const config_a, + const input_formatter_cfg_t *const config_b) +{ + int i; + bool block[] = { false, false, false, false }; + + assert(N_INPUT_FORMATTER_ID <= (ARRAY_SIZE(block))); + + block[INPUT_FORMATTER0_ID] = (bool)config_a->block_no_reqs; + if (config_b) + block[INPUT_FORMATTER1_ID] = (bool)config_b->block_no_reqs; + + /* TODO: next could cause issues when streams are started after + * eachother. */ + /*IF should not be reconfigured/reset from host */ + if (ifmtr_set_if_blocking_mode_reset) { + ifmtr_set_if_blocking_mode_reset = false; + for (i = 0; i < N_INPUT_FORMATTER_ID; i++) { + input_formatter_ID_t id = (input_formatter_ID_t)i; + + input_formatter_rst(id); + input_formatter_set_fifo_blocking_mode(id, block[id]); + } + } + + return; +} + +static int ifmtr_start_column( + const struct ia_css_stream_config *config, + unsigned int bin_in, + unsigned int *start_column) +{ + unsigned int in = config->input_config.input_res.width, start, + for_bayer = ia_css_ifmtr_columns_needed_for_bayer_order(config); + + if (bin_in + 2 * for_bayer > in) + return -EINVAL; + + /* On the hardware, we want to use the middle of the input, so we + * divide the start column by 2. */ + start = (in - bin_in) / 2; + /* in case the number of extra columns is 2 or odd, we round the start + * column down */ + start &= ~0x1; + + /* now we add the one column (if needed) to correct for the bayer + * order). + */ + start += for_bayer; + *start_column = start; + return 0; +} + +static int ifmtr_input_start_line( + const struct ia_css_stream_config *config, + unsigned int bin_in, + unsigned int *start_line) +{ + unsigned int in = config->input_config.input_res.height, start, + for_bayer = ia_css_ifmtr_lines_needed_for_bayer_order(config); + + if (bin_in + 2 * for_bayer > in) + return -EINVAL; + + /* On the hardware, we want to use the middle of the input, so we + * divide the start line by 2. On the simulator, we cannot handle extra + * lines at the end of the frame. + */ + start = (in - bin_in) / 2; + /* in case the number of extra lines is 2 or odd, we round the start + * line down. + */ + start &= ~0x1; + + /* now we add the one line (if needed) to correct for the bayer order */ + start += for_bayer; + *start_line = start; + return 0; +} + +#endif |