diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:49:45 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:49:45 +0000 |
commit | 2c3c1048746a4622d8c89a29670120dc8fab93c4 (patch) | |
tree | 848558de17fb3008cdf4d861b01ac7781903ce39 /drivers/staging/media/atomisp/pci/runtime | |
parent | Initial commit. (diff) | |
download | linux-upstream.tar.xz linux-upstream.zip |
Adding upstream version 6.1.76.upstream/6.1.76upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/staging/media/atomisp/pci/runtime')
54 files changed, 14646 insertions, 0 deletions
diff --git a/drivers/staging/media/atomisp/pci/runtime/binary/interface/ia_css_binary.h b/drivers/staging/media/atomisp/pci/runtime/binary/interface/ia_css_binary.h new file mode 100644 index 000000000..9935ac860 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/binary/interface/ia_css_binary.h @@ -0,0 +1,225 @@ +/* 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. +*/ + +#ifndef _IA_CSS_BINARY_H_ +#define _IA_CSS_BINARY_H_ + +#include <type_support.h> +#include "ia_css_types.h" +#include "ia_css_err.h" +#include "ia_css_stream_format.h" +#include "ia_css_stream_public.h" +#include "ia_css_frame_public.h" +#include "sh_css_metrics.h" +#include "isp/kernels/fixedbds/fixedbds_1.0/ia_css_fixedbds_types.h" + +/* The binary mode is used in pre-processor expressions so we cannot + * use an enum here. */ +#define IA_CSS_BINARY_MODE_COPY 0 +#define IA_CSS_BINARY_MODE_PREVIEW 1 +#define IA_CSS_BINARY_MODE_PRIMARY 2 +#define IA_CSS_BINARY_MODE_VIDEO 3 +#define IA_CSS_BINARY_MODE_PRE_ISP 4 +#define IA_CSS_BINARY_MODE_GDC 5 +#define IA_CSS_BINARY_MODE_POST_ISP 6 +#define IA_CSS_BINARY_MODE_ANR 7 +#define IA_CSS_BINARY_MODE_CAPTURE_PP 8 +#define IA_CSS_BINARY_MODE_VF_PP 9 +#define IA_CSS_BINARY_MODE_PRE_DE 10 +#define IA_CSS_BINARY_MODE_PRIMARY_HQ_STAGE0 11 +#define IA_CSS_BINARY_MODE_PRIMARY_HQ_STAGE1 12 +#define IA_CSS_BINARY_MODE_PRIMARY_HQ_STAGE2 13 +#define IA_CSS_BINARY_MODE_PRIMARY_HQ_STAGE3 14 +#define IA_CSS_BINARY_MODE_PRIMARY_HQ_STAGE4 15 +#define IA_CSS_BINARY_MODE_PRIMARY_HQ_STAGE5 16 +#define IA_CSS_BINARY_NUM_MODES 17 + +#define MAX_NUM_PRIMARY_STAGES 6 +#define NUM_PRIMARY_HQ_STAGES 6 /* number of primary stages for ISP2.6.1 high quality pipe */ +#define NUM_PRIMARY_STAGES 1 /* number of primary satges for ISP1/ISP2.2 pipe */ + +/* Indicate where binaries can read input from */ +#define IA_CSS_BINARY_INPUT_SENSOR 0 +#define IA_CSS_BINARY_INPUT_MEMORY 1 +#define IA_CSS_BINARY_INPUT_VARIABLE 2 + +/* Should be included without the path. + However, that requires adding the path to numerous makefiles + that have nothing to do with isp parameters. + */ +#include "runtime/isp_param/interface/ia_css_isp_param_types.h" + +/* now these ports only include output ports but not vf output ports */ +enum { + IA_CSS_BINARY_OUTPUT_PORT_0 = 0, + IA_CSS_BINARY_OUTPUT_PORT_1 = 1, + IA_CSS_BINARY_MAX_OUTPUT_PORTS = 2 +}; + +struct ia_css_cas_binary_descr { + unsigned int num_stage; + unsigned int num_output_stage; + struct ia_css_frame_info *in_info; + struct ia_css_frame_info *internal_out_info; + struct ia_css_frame_info *out_info; + struct ia_css_frame_info *vf_info; + bool *is_output_stage; +}; + +struct ia_css_binary_descr { + int mode; + bool online; + bool continuous; + bool striped; + bool two_ppc; + bool enable_yuv_ds; + bool enable_high_speed; + bool enable_dvs_6axis; + bool enable_reduced_pipe; + bool enable_dz; + bool enable_xnr; + bool enable_fractional_ds; + bool enable_dpc; + + /* ISP2401 */ + bool enable_tnr; + + bool enable_capture_pp_bli; + struct ia_css_resolution dvs_env; + enum atomisp_input_format stream_format; + struct ia_css_frame_info *in_info; /* the info of the input-frame with the + ISP required resolution. */ + struct ia_css_frame_info *bds_out_info; + struct ia_css_frame_info *out_info[IA_CSS_BINARY_MAX_OUTPUT_PORTS]; + struct ia_css_frame_info *vf_info; + unsigned int isp_pipe_version; + unsigned int required_bds_factor; + int stream_config_left_padding; +}; + +struct ia_css_binary { + const struct ia_css_binary_xinfo *info; + enum atomisp_input_format input_format; + struct ia_css_frame_info in_frame_info; + struct ia_css_frame_info internal_frame_info; + struct ia_css_frame_info out_frame_info[IA_CSS_BINARY_MAX_OUTPUT_PORTS]; + struct ia_css_resolution effective_in_frame_res; + struct ia_css_frame_info vf_frame_info; + int input_buf_vectors; + int deci_factor_log2; + int vf_downscale_log2; + int s3atbl_width; + int s3atbl_height; + int s3atbl_isp_width; + int s3atbl_isp_height; + unsigned int morph_tbl_width; + unsigned int morph_tbl_aligned_width; + unsigned int morph_tbl_height; + int sctbl_width_per_color; + int sctbl_aligned_width_per_color; + int sctbl_height; + struct ia_css_sdis_info dis; + struct ia_css_resolution dvs_envelope; + bool online; + unsigned int uds_xc; + unsigned int uds_yc; + unsigned int left_padding; + struct sh_css_binary_metrics metrics; + struct ia_css_isp_param_host_segments mem_params; + struct ia_css_isp_param_css_segments css_params; +}; + +#define IA_CSS_BINARY_DEFAULT_SETTINGS { \ + .input_format = ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY, \ + .in_frame_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO, \ + .internal_frame_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO, \ + .out_frame_info = {IA_CSS_BINARY_DEFAULT_FRAME_INFO}, \ + .vf_frame_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO, \ +} + +int +ia_css_binary_init_infos(void); + +int +ia_css_binary_uninit(void); + +int +ia_css_binary_fill_info(const struct ia_css_binary_xinfo *xinfo, + bool online, + bool two_ppc, + enum atomisp_input_format stream_format, + const struct ia_css_frame_info *in_info, + const struct ia_css_frame_info *bds_out_info, + const struct ia_css_frame_info *out_info[], + const struct ia_css_frame_info *vf_info, + struct ia_css_binary *binary, + struct ia_css_resolution *dvs_env, + int stream_config_left_padding, + bool accelerator); + +int +ia_css_binary_find(struct ia_css_binary_descr *descr, + struct ia_css_binary *binary); + +/* @brief Get the shading information of the specified shading correction type. + * + * @param[in] binary: The isp binary which has the shading correction. + * @param[in] type: The shading correction type. + * @param[in] required_bds_factor: The bayer downscaling factor required in the pipe. + * @param[in] stream_config: The stream configuration. + * @param[out] shading_info: The shading information. + * The shading information necessary as API is stored in the shading_info. + * The driver needs to get this information to generate + * the shading table directly required from ISP. + * @param[out] pipe_config: The pipe configuration. + * The shading information related to ISP (but, not necessary as API) is stored in the pipe_config. + * @return 0 or error code upon error. + * + */ +int +ia_css_binary_get_shading_info(const struct ia_css_binary *binary, + enum ia_css_shading_correction_type type, + unsigned int required_bds_factor, + const struct ia_css_stream_config *stream_config, + struct ia_css_shading_info *shading_info, + struct ia_css_pipe_config *pipe_config); + +int +ia_css_binary_3a_grid_info(const struct ia_css_binary *binary, + struct ia_css_grid_info *info, + struct ia_css_pipe *pipe); + +void +ia_css_binary_dvs_grid_info(const struct ia_css_binary *binary, + struct ia_css_grid_info *info, + struct ia_css_pipe *pipe); + +void +ia_css_binary_dvs_stat_grid_info( + const struct ia_css_binary *binary, + struct ia_css_grid_info *info, + struct ia_css_pipe *pipe); + +unsigned +ia_css_binary_max_vf_width(void); + +void +ia_css_binary_destroy_isp_parameters(struct ia_css_binary *binary); + +void +ia_css_binary_get_isp_binaries(struct ia_css_binary_xinfo **binaries, + uint32_t *num_isp_binaries); + +#endif /* _IA_CSS_BINARY_H_ */ diff --git a/drivers/staging/media/atomisp/pci/runtime/binary/src/binary.c b/drivers/staging/media/atomisp/pci/runtime/binary/src/binary.c new file mode 100644 index 000000000..406ed5fb4 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/binary/src/binary.c @@ -0,0 +1,1375 @@ +// 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 <math_support.h> +#include <gdc_device.h> /* HR_GDC_N */ + +#include "hmm.h" + +#include "isp.h" /* ISP_VEC_NELEMS */ + +#include "ia_css_binary.h" +#include "ia_css_debug.h" +#include "ia_css_util.h" +#include "ia_css_isp_param.h" +#include "sh_css_internal.h" +#include "sh_css_sp.h" +#include "sh_css_firmware.h" +#include "sh_css_defs.h" +#include "sh_css_legacy.h" + +#include "atomisp_internal.h" + +#include "vf/vf_1.0/ia_css_vf.host.h" +#include "sc/sc_1.0/ia_css_sc.host.h" +#include "sdis/sdis_1.0/ia_css_sdis.host.h" +#include "fixedbds/fixedbds_1.0/ia_css_fixedbds_param.h" /* FRAC_ACC */ + +#include "camera/pipe/interface/ia_css_pipe_binarydesc.h" + +#include "assert_support.h" + +#define IMPLIES(a, b) (!(a) || (b)) /* A => B */ + +static struct ia_css_binary_xinfo *all_binaries; /* ISP binaries only (no SP) */ +static struct ia_css_binary_xinfo + *binary_infos[IA_CSS_BINARY_NUM_MODES] = { NULL, }; + +static void +ia_css_binary_dvs_env(const struct ia_css_binary_info *info, + const struct ia_css_resolution *dvs_env, + struct ia_css_resolution *binary_dvs_env) +{ + if (info->enable.dvs_envelope) { + assert(dvs_env); + binary_dvs_env->width = max(dvs_env->width, SH_CSS_MIN_DVS_ENVELOPE); + binary_dvs_env->height = max(dvs_env->height, SH_CSS_MIN_DVS_ENVELOPE); + } +} + +static void +ia_css_binary_internal_res(const struct ia_css_frame_info *in_info, + const struct ia_css_frame_info *bds_out_info, + const struct ia_css_frame_info *out_info, + const struct ia_css_resolution *dvs_env, + const struct ia_css_binary_info *info, + struct ia_css_resolution *internal_res) +{ + unsigned int isp_tmp_internal_width = 0, + isp_tmp_internal_height = 0; + bool binary_supports_yuv_ds = info->enable.ds & 2; + struct ia_css_resolution binary_dvs_env; + + binary_dvs_env.width = 0; + binary_dvs_env.height = 0; + ia_css_binary_dvs_env(info, dvs_env, &binary_dvs_env); + + if (binary_supports_yuv_ds) { + if (in_info) { + isp_tmp_internal_width = in_info->res.width + + info->pipeline.left_cropping + binary_dvs_env.width; + isp_tmp_internal_height = in_info->res.height + + info->pipeline.top_cropping + binary_dvs_env.height; + } + } else if ((bds_out_info) && (out_info) && + /* TODO: hack to make video_us case work. this should be reverted after + a nice solution in ISP */ + (bds_out_info->res.width >= out_info->res.width)) { + isp_tmp_internal_width = bds_out_info->padded_width; + isp_tmp_internal_height = bds_out_info->res.height; + } else { + if (out_info) { + isp_tmp_internal_width = out_info->padded_width; + isp_tmp_internal_height = out_info->res.height; + } + } + + /* We first calculate the resolutions used by the ISP. After that, + * we use those resolutions to compute sizes for tables etc. */ + internal_res->width = __ISP_INTERNAL_WIDTH(isp_tmp_internal_width, + (int)binary_dvs_env.width, + info->pipeline.left_cropping, info->pipeline.mode, + info->pipeline.c_subsampling, + info->output.num_chunks, info->pipeline.pipelining); + internal_res->height = __ISP_INTERNAL_HEIGHT(isp_tmp_internal_height, + info->pipeline.top_cropping, + binary_dvs_env.height); +} + +/* Computation results of the origin coordinate of bayer on the shading table. */ +struct sh_css_shading_table_bayer_origin_compute_results { + u32 bayer_scale_hor_ratio_in; /* Horizontal ratio (in) of bayer scaling. */ + u32 bayer_scale_hor_ratio_out; /* Horizontal ratio (out) of bayer scaling. */ + u32 bayer_scale_ver_ratio_in; /* Vertical ratio (in) of bayer scaling. */ + u32 bayer_scale_ver_ratio_out; /* Vertical ratio (out) of bayer scaling. */ + u32 sc_bayer_origin_x_bqs_on_shading_table; /* X coordinate (in bqs) of bayer origin on shading table. */ + u32 sc_bayer_origin_y_bqs_on_shading_table; /* Y coordinate (in bqs) of bayer origin on shading table. */ +}; + +/* Get the requirements for the shading correction. */ +static int +ia_css_binary_compute_shading_table_bayer_origin( + const struct ia_css_binary *binary, /* [in] */ + unsigned int required_bds_factor, /* [in] */ + const struct ia_css_stream_config *stream_config, /* [in] */ + struct sh_css_shading_table_bayer_origin_compute_results *res) /* [out] */ +{ + int err; + + /* Numerator and denominator of the fixed bayer downscaling factor. + (numerator >= denominator) */ + unsigned int bds_num, bds_den; + + /* Horizontal/Vertical ratio of bayer scaling + between input area and output area. */ + unsigned int bs_hor_ratio_in; + unsigned int bs_hor_ratio_out; + unsigned int bs_ver_ratio_in; + unsigned int bs_ver_ratio_out; + + /* Left padding set by InputFormatter. */ + unsigned int left_padding_bqs; /* in bqs */ + + /* Flag for the NEED_BDS_FACTOR_2_00 macro defined in isp kernels. */ + unsigned int need_bds_factor_2_00; + + /* Left padding adjusted inside the isp. */ + unsigned int left_padding_adjusted_bqs; /* in bqs */ + + /* Bad pixels caused by filters. + NxN-filter (before/after bayer scaling) moves the image position + to right/bottom directions by a few pixels. + It causes bad pixels at left/top sides, + and effective bayer size decreases. */ + unsigned int bad_bqs_on_left_before_bs; /* in bqs */ + unsigned int bad_bqs_on_left_after_bs; /* in bqs */ + unsigned int bad_bqs_on_top_before_bs; /* in bqs */ + unsigned int bad_bqs_on_top_after_bs; /* in bqs */ + + /* Get the numerator and denominator of bayer downscaling factor. */ + err = sh_css_bds_factor_get_numerator_denominator + (required_bds_factor, &bds_num, &bds_den); + if (err) + return err; + + /* Set the horizontal/vertical ratio of bayer scaling + between input area and output area. */ + bs_hor_ratio_in = bds_num; + bs_hor_ratio_out = bds_den; + bs_ver_ratio_in = bds_num; + bs_ver_ratio_out = bds_den; + + /* Set the left padding set by InputFormatter. (ifmtr.c) */ + if (stream_config->left_padding == -1) + left_padding_bqs = _ISP_BQS(binary->left_padding); + else + left_padding_bqs = (unsigned int)((int)ISP_VEC_NELEMS + - _ISP_BQS(stream_config->left_padding)); + + /* Set the left padding adjusted inside the isp. + When bds_factor 2.00 is needed, some padding is added to left_padding + inside the isp, before bayer downscaling. (raw.isp.c) + (Hopefully, left_crop/left_padding/top_crop should be defined in css + appropriately, depending on bds_factor.) + */ + need_bds_factor_2_00 = ((binary->info->sp.bds.supported_bds_factors & + (PACK_BDS_FACTOR(SH_CSS_BDS_FACTOR_2_00) | + PACK_BDS_FACTOR(SH_CSS_BDS_FACTOR_2_50) | + PACK_BDS_FACTOR(SH_CSS_BDS_FACTOR_3_00) | + PACK_BDS_FACTOR(SH_CSS_BDS_FACTOR_4_00) | + PACK_BDS_FACTOR(SH_CSS_BDS_FACTOR_4_50) | + PACK_BDS_FACTOR(SH_CSS_BDS_FACTOR_5_00) | + PACK_BDS_FACTOR(SH_CSS_BDS_FACTOR_6_00) | + PACK_BDS_FACTOR(SH_CSS_BDS_FACTOR_8_00))) != 0); + + if (need_bds_factor_2_00 && binary->info->sp.pipeline.left_cropping > 0) + left_padding_adjusted_bqs = left_padding_bqs + ISP_VEC_NELEMS; + else + left_padding_adjusted_bqs = left_padding_bqs; + + /* Currently, the bad pixel caused by filters before bayer scaling + is NOT considered, because the bad pixel is subtle. + When some large filter is used in the future, + we need to consider the bad pixel. + + Currently, when bds_factor isn't 1.00, 3x3 anti-alias filter is applied + to each color plane(Gr/R/B/Gb) before bayer downscaling. + This filter moves each color plane to right/bottom directions + by 1 pixel at the most, depending on downscaling factor. + */ + bad_bqs_on_left_before_bs = 0; + bad_bqs_on_top_before_bs = 0; + + /* Currently, the bad pixel caused by filters after bayer scaling + is NOT considered, because the bad pixel is subtle. + When some large filter is used in the future, + we need to consider the bad pixel. + + Currently, when DPC&BNR is processed between bayer scaling and + shading correction, DPC&BNR moves each color plane to + right/bottom directions by 1 pixel. + */ + bad_bqs_on_left_after_bs = 0; + bad_bqs_on_top_after_bs = 0; + + /* Calculate the origin of bayer (real sensor data area) + located on the shading table during the shading correction. */ + res->sc_bayer_origin_x_bqs_on_shading_table = + ((left_padding_adjusted_bqs + bad_bqs_on_left_before_bs) + * bs_hor_ratio_out + bs_hor_ratio_in / 2) / bs_hor_ratio_in + + bad_bqs_on_left_after_bs; + /* "+ bs_hor_ratio_in/2": rounding for division by bs_hor_ratio_in */ + res->sc_bayer_origin_y_bqs_on_shading_table = + (bad_bqs_on_top_before_bs * bs_ver_ratio_out + bs_ver_ratio_in / 2) / bs_ver_ratio_in + + bad_bqs_on_top_after_bs; + /* "+ bs_ver_ratio_in/2": rounding for division by bs_ver_ratio_in */ + + res->bayer_scale_hor_ratio_in = (uint32_t)bs_hor_ratio_in; + res->bayer_scale_hor_ratio_out = (uint32_t)bs_hor_ratio_out; + res->bayer_scale_ver_ratio_in = (uint32_t)bs_ver_ratio_in; + res->bayer_scale_ver_ratio_out = (uint32_t)bs_ver_ratio_out; + + return err; +} + +/* Get the shading information of Shading Correction Type 1. */ +static int +binary_get_shading_info_type_1(const struct ia_css_binary *binary, /* [in] */ + unsigned int required_bds_factor, /* [in] */ + const struct ia_css_stream_config *stream_config, /* [in] */ + struct ia_css_shading_info *info) /* [out] */ +{ + int err; + struct sh_css_shading_table_bayer_origin_compute_results res; + + assert(binary); + assert(info); + + info->type = IA_CSS_SHADING_CORRECTION_TYPE_1; + + info->info.type_1.enable = binary->info->sp.enable.sc; + info->info.type_1.num_hor_grids = binary->sctbl_width_per_color; + info->info.type_1.num_ver_grids = binary->sctbl_height; + info->info.type_1.bqs_per_grid_cell = (1 << binary->deci_factor_log2); + + /* Initialize by default values. */ + info->info.type_1.bayer_scale_hor_ratio_in = 1; + info->info.type_1.bayer_scale_hor_ratio_out = 1; + info->info.type_1.bayer_scale_ver_ratio_in = 1; + info->info.type_1.bayer_scale_ver_ratio_out = 1; + info->info.type_1.sc_bayer_origin_x_bqs_on_shading_table = 0; + info->info.type_1.sc_bayer_origin_y_bqs_on_shading_table = 0; + + err = ia_css_binary_compute_shading_table_bayer_origin( + binary, + required_bds_factor, + stream_config, + &res); + if (err) + return err; + + info->info.type_1.bayer_scale_hor_ratio_in = res.bayer_scale_hor_ratio_in; + info->info.type_1.bayer_scale_hor_ratio_out = res.bayer_scale_hor_ratio_out; + info->info.type_1.bayer_scale_ver_ratio_in = res.bayer_scale_ver_ratio_in; + info->info.type_1.bayer_scale_ver_ratio_out = res.bayer_scale_ver_ratio_out; + info->info.type_1.sc_bayer_origin_x_bqs_on_shading_table = res.sc_bayer_origin_x_bqs_on_shading_table; + info->info.type_1.sc_bayer_origin_y_bqs_on_shading_table = res.sc_bayer_origin_y_bqs_on_shading_table; + + return err; +} + + +int +ia_css_binary_get_shading_info(const struct ia_css_binary *binary, /* [in] */ + enum ia_css_shading_correction_type type, /* [in] */ + unsigned int required_bds_factor, /* [in] */ + const struct ia_css_stream_config *stream_config, /* [in] */ + struct ia_css_shading_info *shading_info, /* [out] */ + struct ia_css_pipe_config *pipe_config) /* [out] */ +{ + int err; + + assert(binary); + assert(shading_info); + + IA_CSS_ENTER_PRIVATE("binary=%p, type=%d, required_bds_factor=%d, stream_config=%p", + binary, type, required_bds_factor, stream_config); + + if (type == IA_CSS_SHADING_CORRECTION_TYPE_1) + err = binary_get_shading_info_type_1(binary, + required_bds_factor, + stream_config, + shading_info); + else + err = -ENOTSUPP; + + IA_CSS_LEAVE_ERR_PRIVATE(err); + return err; +} + +static void sh_css_binary_common_grid_info(const struct ia_css_binary *binary, + struct ia_css_grid_info *info) +{ + assert(binary); + assert(info); + + info->isp_in_width = binary->internal_frame_info.res.width; + info->isp_in_height = binary->internal_frame_info.res.height; + + info->vamem_type = IA_CSS_VAMEM_TYPE_2; +} + +void +ia_css_binary_dvs_grid_info(const struct ia_css_binary *binary, + struct ia_css_grid_info *info, + struct ia_css_pipe *pipe) +{ + struct ia_css_dvs_grid_info *dvs_info; + + (void)pipe; + assert(binary); + assert(info); + + dvs_info = &info->dvs_grid.dvs_grid_info; + + /* for DIS, we use a division instead of a ceil_div. If this is smaller + * than the 3a grid size, it indicates that the outer values are not + * valid for DIS. + */ + dvs_info->enable = binary->info->sp.enable.dis; + dvs_info->width = binary->dis.grid.dim.width; + dvs_info->height = binary->dis.grid.dim.height; + dvs_info->aligned_width = binary->dis.grid.pad.width; + dvs_info->aligned_height = binary->dis.grid.pad.height; + dvs_info->bqs_per_grid_cell = 1 << binary->dis.deci_factor_log2; + dvs_info->num_hor_coefs = binary->dis.coef.dim.width; + dvs_info->num_ver_coefs = binary->dis.coef.dim.height; + + sh_css_binary_common_grid_info(binary, info); +} + +void +ia_css_binary_dvs_stat_grid_info( + const struct ia_css_binary *binary, + struct ia_css_grid_info *info, + struct ia_css_pipe *pipe) +{ + (void)pipe; + sh_css_binary_common_grid_info(binary, info); + return; +} + +int +ia_css_binary_3a_grid_info(const struct ia_css_binary *binary, + struct ia_css_grid_info *info, + struct ia_css_pipe *pipe) { + struct ia_css_3a_grid_info *s3a_info; + int err = 0; + + IA_CSS_ENTER_PRIVATE("binary=%p, info=%p, pipe=%p", + binary, info, pipe); + + assert(binary); + assert(info); + s3a_info = &info->s3a_grid; + + /* 3A statistics grid */ + s3a_info->enable = binary->info->sp.enable.s3a; + s3a_info->width = binary->s3atbl_width; + s3a_info->height = binary->s3atbl_height; + s3a_info->aligned_width = binary->s3atbl_isp_width; + s3a_info->aligned_height = binary->s3atbl_isp_height; + s3a_info->bqs_per_grid_cell = (1 << binary->deci_factor_log2); + s3a_info->deci_factor_log2 = binary->deci_factor_log2; + s3a_info->elem_bit_depth = SH_CSS_BAYER_BITS; + s3a_info->use_dmem = binary->info->sp.s3a.s3atbl_use_dmem; + s3a_info->has_histogram = 0; + IA_CSS_LEAVE_ERR_PRIVATE(err); + return err; +} + +static void +binary_init_pc_histogram(struct sh_css_pc_histogram *histo) +{ + assert(histo); + + histo->length = 0; + histo->run = NULL; + histo->stall = NULL; +} + +static void +binary_init_metrics(struct sh_css_binary_metrics *metrics, + const struct ia_css_binary_info *info) +{ + assert(metrics); + assert(info); + + metrics->mode = info->pipeline.mode; + metrics->id = info->id; + metrics->next = NULL; + binary_init_pc_histogram(&metrics->isp_histogram); + binary_init_pc_histogram(&metrics->sp_histogram); +} + +/* move to host part of output module */ +static bool +binary_supports_output_format(const struct ia_css_binary_xinfo *info, + enum ia_css_frame_format format) +{ + int i; + + assert(info); + + for (i = 0; i < info->num_output_formats; i++) { + if (info->output_formats[i] == format) + return true; + } + return false; +} + +static bool +binary_supports_vf_format(const struct ia_css_binary_xinfo *info, + enum ia_css_frame_format format) +{ + int i; + + assert(info); + + for (i = 0; i < info->num_vf_formats; i++) { + if (info->vf_formats[i] == format) + return true; + } + return false; +} + +/* move to host part of bds module */ +static bool +supports_bds_factor(u32 supported_factors, + uint32_t bds_factor) +{ + return ((supported_factors & PACK_BDS_FACTOR(bds_factor)) != 0); +} + +static int +binary_init_info(struct ia_css_binary_xinfo *info, unsigned int i, + bool *binary_found) { + const unsigned char *blob = sh_css_blob_info[i].blob; + unsigned int size = sh_css_blob_info[i].header.blob.size; + + if ((!info) || (!binary_found)) + return -EINVAL; + + *info = sh_css_blob_info[i].header.info.isp; + *binary_found = blob; + info->blob_index = i; + /* we don't have this binary, skip it */ + if (!size) + return 0; + + info->xmem_addr = sh_css_load_blob(blob, size); + if (!info->xmem_addr) + return -ENOMEM; + return 0; +} + +/* When binaries are put at the beginning, they will only + * be selected if no other primary matches. + */ +int +ia_css_binary_init_infos(void) { + unsigned int i; + unsigned int num_of_isp_binaries = sh_css_num_binaries - NUM_OF_SPS - NUM_OF_BLS; + + if (num_of_isp_binaries == 0) + return 0; + + all_binaries = kvmalloc(num_of_isp_binaries * sizeof(*all_binaries), + GFP_KERNEL); + if (!all_binaries) + return -ENOMEM; + + for (i = 0; i < num_of_isp_binaries; i++) + { + int ret; + struct ia_css_binary_xinfo *binary = &all_binaries[i]; + bool binary_found; + + ret = binary_init_info(binary, i, &binary_found); + if (ret) + return ret; + if (!binary_found) + continue; + /* Prepend new binary information */ + binary->next = binary_infos[binary->sp.pipeline.mode]; + binary_infos[binary->sp.pipeline.mode] = binary; + binary->blob = &sh_css_blob_info[i]; + binary->mem_offsets = sh_css_blob_info[i].mem_offsets; + } + return 0; +} + +int +ia_css_binary_uninit(void) { + unsigned int i; + struct ia_css_binary_xinfo *b; + + for (i = 0; i < IA_CSS_BINARY_NUM_MODES; i++) + { + for (b = binary_infos[i]; b; b = b->next) { + if (b->xmem_addr) + hmm_free(b->xmem_addr); + b->xmem_addr = mmgr_NULL; + } + binary_infos[i] = NULL; + } + kvfree(all_binaries); + return 0; +} + +/* @brief Compute decimation factor for 3A statistics and shading correction. + * + * @param[in] width Frame width in pixels. + * @param[in] height Frame height in pixels. + * @return Log2 of decimation factor (= grid cell size) in bayer quads. + */ +static int +binary_grid_deci_factor_log2(int width, int height) +{ + /* 3A/Shading decimation factor spcification (at August 2008) + * ------------------------------------------------------------------ + * [Image Width (BQ)] [Decimation Factor (BQ)] [Resulting grid cells] + * 1280 ?c 32 40 ?c + * 640 ?c 1279 16 40 ?c 80 + * ?c 639 8 ?c 80 + * ------------------------------------------------------------------ + */ + /* Maximum and minimum decimation factor by the specification */ +#define MAX_SPEC_DECI_FACT_LOG2 5 +#define MIN_SPEC_DECI_FACT_LOG2 3 + /* the smallest frame width in bayer quads when decimation factor (log2) is 5 or 4, by the specification */ +#define DECI_FACT_LOG2_5_SMALLEST_FRAME_WIDTH_BQ 1280 +#define DECI_FACT_LOG2_4_SMALLEST_FRAME_WIDTH_BQ 640 + + int smallest_factor; /* the smallest factor (log2) where the number of cells does not exceed the limitation */ + int spec_factor; /* the factor (log2) which satisfies the specification */ + + /* Currently supported maximum width and height are 5120(=80*64) and 3840(=60*64). */ + assert(ISP_BQ_GRID_WIDTH(width, + MAX_SPEC_DECI_FACT_LOG2) <= SH_CSS_MAX_BQ_GRID_WIDTH); + assert(ISP_BQ_GRID_HEIGHT(height, + MAX_SPEC_DECI_FACT_LOG2) <= SH_CSS_MAX_BQ_GRID_HEIGHT); + + /* Compute the smallest factor. */ + smallest_factor = MAX_SPEC_DECI_FACT_LOG2; + while (ISP_BQ_GRID_WIDTH(width, + smallest_factor - 1) <= SH_CSS_MAX_BQ_GRID_WIDTH && + ISP_BQ_GRID_HEIGHT(height, smallest_factor - 1) <= SH_CSS_MAX_BQ_GRID_HEIGHT + && smallest_factor > MIN_SPEC_DECI_FACT_LOG2) + smallest_factor--; + + /* Get the factor by the specification. */ + if (_ISP_BQS(width) >= DECI_FACT_LOG2_5_SMALLEST_FRAME_WIDTH_BQ) + spec_factor = 5; + else if (_ISP_BQS(width) >= DECI_FACT_LOG2_4_SMALLEST_FRAME_WIDTH_BQ) + spec_factor = 4; + else + spec_factor = 3; + + /* If smallest_factor is smaller than or equal to spec_factor, choose spec_factor to follow the specification. + If smallest_factor is larger than spec_factor, choose smallest_factor. + + ex. width=2560, height=1920 + smallest_factor=4, spec_factor=5 + smallest_factor < spec_factor -> return spec_factor + + ex. width=300, height=3000 + smallest_factor=5, spec_factor=3 + smallest_factor > spec_factor -> return smallest_factor + */ + return max(smallest_factor, spec_factor); + +#undef MAX_SPEC_DECI_FACT_LOG2 +#undef MIN_SPEC_DECI_FACT_LOG2 +#undef DECI_FACT_LOG2_5_SMALLEST_FRAME_WIDTH_BQ +#undef DECI_FACT_LOG2_4_SMALLEST_FRAME_WIDTH_BQ +} + +static int +binary_in_frame_padded_width(int in_frame_width, + int isp_internal_width, + int dvs_env_width, + int stream_config_left_padding, + int left_cropping, + bool need_scaling) +{ + int rval; + int nr_of_left_paddings; /* number of paddings pixels on the left of an image line */ + +#if defined(ISP2401) + /* the output image line of Input System 2401 does not have the left paddings */ + nr_of_left_paddings = 0; +#else + /* in other cases, the left padding pixels are always 128 */ + nr_of_left_paddings = 2 * ISP_VEC_NELEMS; +#endif + if (need_scaling) { + /* In SDV use-case, we need to match left-padding of + * primary and the video binary. */ + if (stream_config_left_padding != -1) { + /* Different than before, we do left&right padding. */ + rval = + CEIL_MUL(in_frame_width + nr_of_left_paddings, + 2 * ISP_VEC_NELEMS); + } else { + /* Different than before, we do left&right padding. */ + in_frame_width += dvs_env_width; + rval = + CEIL_MUL(in_frame_width + + (left_cropping ? nr_of_left_paddings : 0), + 2 * ISP_VEC_NELEMS); + } + } else { + rval = isp_internal_width; + } + + return rval; +} + +int +ia_css_binary_fill_info(const struct ia_css_binary_xinfo *xinfo, + bool online, + bool two_ppc, + enum atomisp_input_format stream_format, + const struct ia_css_frame_info *in_info, /* can be NULL */ + const struct ia_css_frame_info *bds_out_info, /* can be NULL */ + const struct ia_css_frame_info *out_info[], /* can be NULL */ + const struct ia_css_frame_info *vf_info, /* can be NULL */ + struct ia_css_binary *binary, + struct ia_css_resolution *dvs_env, + int stream_config_left_padding, + bool accelerator) { + const struct ia_css_binary_info *info = &xinfo->sp; + unsigned int dvs_env_width = 0, + dvs_env_height = 0, + vf_log_ds = 0, + s3a_log_deci = 0, + bits_per_pixel = 0, + /* Resolution at SC/3A/DIS kernel. */ + sc_3a_dis_width = 0, + /* Resolution at SC/3A/DIS kernel. */ + sc_3a_dis_padded_width = 0, + /* Resolution at SC/3A/DIS kernel. */ + sc_3a_dis_height = 0, + isp_internal_width = 0, + isp_internal_height = 0, + s3a_isp_width = 0; + + bool need_scaling = false; + struct ia_css_resolution binary_dvs_env, internal_res; + int err; + unsigned int i; + const struct ia_css_frame_info *bin_out_info = NULL; + + assert(info); + assert(binary); + + binary->info = xinfo; + if (!accelerator) + { + /* binary->css_params has been filled by accelerator itself. */ + err = ia_css_isp_param_allocate_isp_parameters( + &binary->mem_params, &binary->css_params, + &info->mem_initializers); + if (err) { + return err; + } + } + for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) + { + if (out_info[i] && (out_info[i]->res.width != 0)) { + bin_out_info = out_info[i]; + break; + } + } + if (in_info && bin_out_info) + { + need_scaling = (in_info->res.width != bin_out_info->res.width) || + (in_info->res.height != bin_out_info->res.height); + } + + /* binary_dvs_env has to be equal or larger than SH_CSS_MIN_DVS_ENVELOPE */ + binary_dvs_env.width = 0; + binary_dvs_env.height = 0; + ia_css_binary_dvs_env(info, dvs_env, &binary_dvs_env); + dvs_env_width = binary_dvs_env.width; + dvs_env_height = binary_dvs_env.height; + binary->dvs_envelope.width = dvs_env_width; + binary->dvs_envelope.height = dvs_env_height; + + /* internal resolution calculation */ + internal_res.width = 0; + internal_res.height = 0; + ia_css_binary_internal_res(in_info, bds_out_info, bin_out_info, dvs_env, + info, &internal_res); + isp_internal_width = internal_res.width; + isp_internal_height = internal_res.height; + + /* internal frame info */ + if (bin_out_info) /* { */ + binary->internal_frame_info.format = bin_out_info->format; + /* } */ + binary->internal_frame_info.res.width = isp_internal_width; + binary->internal_frame_info.padded_width = CEIL_MUL(isp_internal_width, 2 * ISP_VEC_NELEMS); + binary->internal_frame_info.res.height = isp_internal_height; + binary->internal_frame_info.raw_bit_depth = bits_per_pixel; + + if (in_info) + { + binary->effective_in_frame_res.width = in_info->res.width; + binary->effective_in_frame_res.height = in_info->res.height; + + bits_per_pixel = in_info->raw_bit_depth; + + /* input info */ + binary->in_frame_info.res.width = in_info->res.width + + info->pipeline.left_cropping; + binary->in_frame_info.res.height = in_info->res.height + + info->pipeline.top_cropping; + + binary->in_frame_info.res.width += dvs_env_width; + binary->in_frame_info.res.height += dvs_env_height; + + binary->in_frame_info.padded_width = + binary_in_frame_padded_width(in_info->res.width, + isp_internal_width, + dvs_env_width, + stream_config_left_padding, + info->pipeline.left_cropping, + need_scaling); + + binary->in_frame_info.format = in_info->format; + binary->in_frame_info.raw_bayer_order = in_info->raw_bayer_order; + binary->in_frame_info.crop_info = in_info->crop_info; + } + + if (online) + { + bits_per_pixel = ia_css_util_input_format_bpp( + stream_format, two_ppc); + } + binary->in_frame_info.raw_bit_depth = bits_per_pixel; + + for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) + { + if (out_info[i]) { + binary->out_frame_info[i].res.width = out_info[i]->res.width; + binary->out_frame_info[i].res.height = out_info[i]->res.height; + binary->out_frame_info[i].padded_width = out_info[i]->padded_width; + if (info->pipeline.mode == IA_CSS_BINARY_MODE_COPY) { + binary->out_frame_info[i].raw_bit_depth = bits_per_pixel; + } else { + /* Only relevant for RAW format. + * At the moment, all outputs are raw, 16 bit per pixel, except for copy. + * To do this cleanly, the binary should specify in its info + * the bit depth per output channel. + */ + binary->out_frame_info[i].raw_bit_depth = 16; + } + binary->out_frame_info[i].format = out_info[i]->format; + } + } + + if (vf_info && (vf_info->res.width != 0)) + { + err = ia_css_vf_configure(binary, bin_out_info, + (struct ia_css_frame_info *)vf_info, &vf_log_ds); + if (err) { + if (!accelerator) { + ia_css_isp_param_destroy_isp_parameters( + &binary->mem_params, + &binary->css_params); + } + return err; + } + } + binary->vf_downscale_log2 = vf_log_ds; + + binary->online = online; + binary->input_format = stream_format; + + /* viewfinder output info */ + if ((vf_info) && (vf_info->res.width != 0)) + { + unsigned int vf_out_vecs, vf_out_width, vf_out_height; + + binary->vf_frame_info.format = vf_info->format; + if (!bin_out_info) + return -EINVAL; + vf_out_vecs = __ISP_VF_OUTPUT_WIDTH_VECS(bin_out_info->padded_width, + vf_log_ds); + vf_out_width = _ISP_VF_OUTPUT_WIDTH(vf_out_vecs); + vf_out_height = _ISP_VF_OUTPUT_HEIGHT(bin_out_info->res.height, + vf_log_ds); + + /* For preview mode, output pin is used instead of vf. */ + if (info->pipeline.mode == IA_CSS_BINARY_MODE_PREVIEW) { + binary->out_frame_info[0].res.width = + (bin_out_info->res.width >> vf_log_ds); + binary->out_frame_info[0].padded_width = vf_out_width; + binary->out_frame_info[0].res.height = vf_out_height; + + binary->vf_frame_info.res.width = 0; + binary->vf_frame_info.padded_width = 0; + binary->vf_frame_info.res.height = 0; + } else { + /* we also store the raw downscaled width. This is + * used for digital zoom in preview to zoom only on + * the width that we actually want to keep, not on + * the aligned width. */ + binary->vf_frame_info.res.width = + (bin_out_info->res.width >> vf_log_ds); + binary->vf_frame_info.padded_width = vf_out_width; + binary->vf_frame_info.res.height = vf_out_height; + } + } else + { + binary->vf_frame_info.res.width = 0; + binary->vf_frame_info.padded_width = 0; + binary->vf_frame_info.res.height = 0; + } + + if (info->enable.ca_gdc) + { + binary->morph_tbl_width = + _ISP_MORPH_TABLE_WIDTH(isp_internal_width); + binary->morph_tbl_aligned_width = + _ISP_MORPH_TABLE_ALIGNED_WIDTH(isp_internal_width); + binary->morph_tbl_height = + _ISP_MORPH_TABLE_HEIGHT(isp_internal_height); + } else + { + binary->morph_tbl_width = 0; + binary->morph_tbl_aligned_width = 0; + binary->morph_tbl_height = 0; + } + + sc_3a_dis_width = binary->in_frame_info.res.width; + sc_3a_dis_padded_width = binary->in_frame_info.padded_width; + sc_3a_dis_height = binary->in_frame_info.res.height; + if (bds_out_info && in_info && + bds_out_info->res.width != in_info->res.width) + { + /* TODO: Next, "internal_frame_info" should be derived from + * bds_out. So this part will change once it is in place! */ + sc_3a_dis_width = bds_out_info->res.width + info->pipeline.left_cropping; + sc_3a_dis_padded_width = isp_internal_width; + sc_3a_dis_height = isp_internal_height; + } + + s3a_isp_width = _ISP_S3A_ELEMS_ISP_WIDTH(sc_3a_dis_padded_width, + info->pipeline.left_cropping); + if (info->s3a.fixed_s3a_deci_log) + { + s3a_log_deci = info->s3a.fixed_s3a_deci_log; + } else + { + s3a_log_deci = binary_grid_deci_factor_log2(s3a_isp_width, + sc_3a_dis_height); + } + binary->deci_factor_log2 = s3a_log_deci; + + if (info->enable.s3a) + { + binary->s3atbl_width = + _ISP_S3ATBL_WIDTH(sc_3a_dis_width, + s3a_log_deci); + binary->s3atbl_height = + _ISP_S3ATBL_HEIGHT(sc_3a_dis_height, + s3a_log_deci); + binary->s3atbl_isp_width = + _ISP_S3ATBL_ISP_WIDTH(s3a_isp_width, + s3a_log_deci); + binary->s3atbl_isp_height = + _ISP_S3ATBL_ISP_HEIGHT(sc_3a_dis_height, + s3a_log_deci); + } else + { + binary->s3atbl_width = 0; + binary->s3atbl_height = 0; + binary->s3atbl_isp_width = 0; + binary->s3atbl_isp_height = 0; + } + + if (info->enable.sc) + { + binary->sctbl_width_per_color = _ISP_SCTBL_WIDTH_PER_COLOR(sc_3a_dis_padded_width, s3a_log_deci); + binary->sctbl_aligned_width_per_color = SH_CSS_MAX_SCTBL_ALIGNED_WIDTH_PER_COLOR; + binary->sctbl_height = _ISP_SCTBL_HEIGHT(sc_3a_dis_height, s3a_log_deci); + } else + { + binary->sctbl_width_per_color = 0; + binary->sctbl_aligned_width_per_color = 0; + binary->sctbl_height = 0; + } + ia_css_sdis_init_info(&binary->dis, + sc_3a_dis_width, + sc_3a_dis_padded_width, + sc_3a_dis_height, + info->pipeline.isp_pipe_version, + info->enable.dis); + if (info->pipeline.left_cropping) + binary->left_padding = 2 * ISP_VEC_NELEMS - info->pipeline.left_cropping; + else + binary->left_padding = 0; + + return 0; +} + +static int __ia_css_binary_find(struct ia_css_binary_descr *descr, + struct ia_css_binary *binary) { + int mode; + bool online; + bool two_ppc; + enum atomisp_input_format stream_format; + const struct ia_css_frame_info *req_in_info, + *req_bds_out_info, + *req_out_info[IA_CSS_BINARY_MAX_OUTPUT_PORTS], + *req_bin_out_info = NULL, + *req_vf_info; + + struct ia_css_binary_xinfo *xcandidate; + bool need_ds, need_dz, need_dvs, need_xnr, need_dpc; + bool striped; + bool enable_yuv_ds; + bool enable_high_speed; + bool enable_dvs_6axis; + bool enable_reduced_pipe; + bool enable_capture_pp_bli; + int err = -EINVAL; + bool continuous; + unsigned int isp_pipe_version; + struct ia_css_resolution dvs_env, internal_res; + unsigned int i; + + assert(descr); + /* MW: used after an error check, may accept NULL, but doubtfull */ + assert(binary); + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() enter: descr=%p, (mode=%d), binary=%p\n", + descr, descr->mode, + binary); + + mode = descr->mode; + online = descr->online; + two_ppc = descr->two_ppc; + stream_format = descr->stream_format; + req_in_info = descr->in_info; + req_bds_out_info = descr->bds_out_info; + for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) { + req_out_info[i] = descr->out_info[i]; + if (req_out_info[i] && (req_out_info[i]->res.width != 0)) + req_bin_out_info = req_out_info[i]; + } + if (!req_bin_out_info) + return -EINVAL; + req_vf_info = descr->vf_info; + + need_xnr = descr->enable_xnr; + need_ds = descr->enable_fractional_ds; + need_dz = false; + need_dvs = false; + need_dpc = descr->enable_dpc; + + enable_yuv_ds = descr->enable_yuv_ds; + enable_high_speed = descr->enable_high_speed; + enable_dvs_6axis = descr->enable_dvs_6axis; + enable_reduced_pipe = descr->enable_reduced_pipe; + enable_capture_pp_bli = descr->enable_capture_pp_bli; + continuous = descr->continuous; + striped = descr->striped; + isp_pipe_version = descr->isp_pipe_version; + + dvs_env.width = 0; + dvs_env.height = 0; + internal_res.width = 0; + internal_res.height = 0; + + if (mode == IA_CSS_BINARY_MODE_VIDEO) { + dvs_env = descr->dvs_env; + need_dz = descr->enable_dz; + /* Video is the only mode that has a nodz variant. */ + need_dvs = dvs_env.width || dvs_env.height; + } + + /* print a map of the binary file */ + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "BINARY INFO:\n"); + for (i = 0; i < IA_CSS_BINARY_NUM_MODES; i++) { + xcandidate = binary_infos[i]; + if (xcandidate) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "%d:\n", i); + while (xcandidate) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, " Name:%s Type:%d Cont:%d\n", + xcandidate->blob->name, xcandidate->type, + xcandidate->sp.enable.continuous); + xcandidate = xcandidate->next; + } + } + } + + /* printf("sh_css_binary_find: pipe version %d\n", isp_pipe_version); */ + for (xcandidate = binary_infos[mode]; xcandidate; + xcandidate = xcandidate->next) { + struct ia_css_binary_info *candidate = &xcandidate->sp; + /* printf("sh_css_binary_find: evaluating candidate: + * %d\n",candidate->id); */ + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() candidate = %p, mode = %d ID = %d\n", + candidate, candidate->pipeline.mode, candidate->id); + + /* + * MW: Only a limited set of jointly configured binaries can + * be used in a continuous preview/video mode unless it is + * the copy mode and runs on SP. + */ + if (!candidate->enable.continuous && + continuous && (mode != IA_CSS_BINARY_MODE_COPY)) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() [%d] continue: !%d && %d && (%d != %d)\n", + __LINE__, candidate->enable.continuous, + continuous, mode, + IA_CSS_BINARY_MODE_COPY); + continue; + } + if (striped && candidate->iterator.num_stripes == 1) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() [%d] continue: binary is not striped\n", + __LINE__); + continue; + } + + if (candidate->pipeline.isp_pipe_version != isp_pipe_version && + (mode != IA_CSS_BINARY_MODE_COPY) && + (mode != IA_CSS_BINARY_MODE_CAPTURE_PP) && + (mode != IA_CSS_BINARY_MODE_VF_PP)) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() [%d] continue: (%d != %d)\n", + __LINE__, + candidate->pipeline.isp_pipe_version, isp_pipe_version); + continue; + } + if (!candidate->enable.reduced_pipe && enable_reduced_pipe) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() [%d] continue: !%d && %d\n", + __LINE__, + candidate->enable.reduced_pipe, + enable_reduced_pipe); + continue; + } + if (!candidate->enable.dvs_6axis && enable_dvs_6axis) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() [%d] continue: !%d && %d\n", + __LINE__, + candidate->enable.dvs_6axis, + enable_dvs_6axis); + continue; + } + if (candidate->enable.high_speed && !enable_high_speed) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() [%d] continue: %d && !%d\n", + __LINE__, + candidate->enable.high_speed, + enable_high_speed); + continue; + } + if (!candidate->enable.xnr && need_xnr) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() [%d] continue: %d && !%d\n", + __LINE__, + candidate->enable.xnr, + need_xnr); + continue; + } + if (!(candidate->enable.ds & 2) && enable_yuv_ds) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() [%d] continue: !%d && %d\n", + __LINE__, + ((candidate->enable.ds & 2) != 0), + enable_yuv_ds); + continue; + } + if ((candidate->enable.ds & 2) && !enable_yuv_ds) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() [%d] continue: %d && !%d\n", + __LINE__, + ((candidate->enable.ds & 2) != 0), + enable_yuv_ds); + continue; + } + + if (mode == IA_CSS_BINARY_MODE_VIDEO && + candidate->enable.ds && need_ds) + need_dz = false; + + /* when we require vf output, we need to have vf_veceven */ + if ((req_vf_info) && !(candidate->enable.vf_veceven || + /* or variable vf vec even */ + candidate->vf_dec.is_variable || + /* or more than one output pin. */ + xcandidate->num_output_pins > 1)) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() [%d] continue: (%p != NULL) && !(%d || %d || (%d >%d))\n", + __LINE__, req_vf_info, + candidate->enable.vf_veceven, + candidate->vf_dec.is_variable, + xcandidate->num_output_pins, 1); + continue; + } + if (!candidate->enable.dvs_envelope && need_dvs) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() [%d] continue: !%d && %d\n", + __LINE__, + candidate->enable.dvs_envelope, (int)need_dvs); + continue; + } + /* internal_res check considers input, output, and dvs envelope sizes */ + ia_css_binary_internal_res(req_in_info, req_bds_out_info, + req_bin_out_info, &dvs_env, candidate, &internal_res); + if (internal_res.width > candidate->internal.max_width) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() [%d] continue: (%d > %d)\n", + __LINE__, internal_res.width, + candidate->internal.max_width); + continue; + } + if (internal_res.height > candidate->internal.max_height) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() [%d] continue: (%d > %d)\n", + __LINE__, internal_res.height, + candidate->internal.max_height); + continue; + } + if (!candidate->enable.ds && need_ds && !(xcandidate->num_output_pins > 1)) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() [%d] continue: !%d && %d\n", + __LINE__, candidate->enable.ds, (int)need_ds); + continue; + } + if (!candidate->enable.uds && !candidate->enable.dvs_6axis && need_dz) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() [%d] continue: !%d && !%d && %d\n", + __LINE__, candidate->enable.uds, + candidate->enable.dvs_6axis, (int)need_dz); + continue; + } + if (online && candidate->input.source == IA_CSS_BINARY_INPUT_MEMORY) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() [%d] continue: %d && (%d == %d)\n", + __LINE__, online, candidate->input.source, + IA_CSS_BINARY_INPUT_MEMORY); + continue; + } + if (!online && candidate->input.source == IA_CSS_BINARY_INPUT_SENSOR) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() [%d] continue: !%d && (%d == %d)\n", + __LINE__, online, candidate->input.source, + IA_CSS_BINARY_INPUT_SENSOR); + continue; + } + if (req_bin_out_info->res.width < candidate->output.min_width || + req_bin_out_info->res.width > candidate->output.max_width) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() [%d] continue: (%d > %d) || (%d < %d)\n", + __LINE__, + req_bin_out_info->padded_width, + candidate->output.min_width, + req_bin_out_info->padded_width, + candidate->output.max_width); + continue; + } + if (xcandidate->num_output_pins > 1 && + /* in case we have a second output pin, */ + req_vf_info) { /* and we need vf output. */ + if (req_vf_info->res.width > candidate->output.max_width) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() [%d] continue: (%d < %d)\n", + __LINE__, + req_vf_info->res.width, + candidate->output.max_width); + continue; + } + } + if (req_in_info->padded_width > candidate->input.max_width) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() [%d] continue: (%d > %d)\n", + __LINE__, req_in_info->padded_width, + candidate->input.max_width); + continue; + } + if (!binary_supports_output_format(xcandidate, req_bin_out_info->format)) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() [%d] continue: !%d\n", + __LINE__, + binary_supports_output_format(xcandidate, req_bin_out_info->format)); + continue; + } + if (xcandidate->num_output_pins > 1 && + /* in case we have a second output pin, */ + req_vf_info && /* and we need vf output. */ + /* check if the required vf format + is supported. */ + !binary_supports_output_format(xcandidate, req_vf_info->format)) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() [%d] continue: (%d > %d) && (%p != NULL) && !%d\n", + __LINE__, xcandidate->num_output_pins, 1, + req_vf_info, + binary_supports_output_format(xcandidate, req_vf_info->format)); + continue; + } + + /* Check if vf_veceven supports the requested vf format */ + if (xcandidate->num_output_pins == 1 && + req_vf_info && candidate->enable.vf_veceven && + !binary_supports_vf_format(xcandidate, req_vf_info->format)) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() [%d] continue: (%d == %d) && (%p != NULL) && %d && !%d\n", + __LINE__, xcandidate->num_output_pins, 1, + req_vf_info, candidate->enable.vf_veceven, + binary_supports_vf_format(xcandidate, req_vf_info->format)); + continue; + } + + /* Check if vf_veceven supports the requested vf width */ + if (xcandidate->num_output_pins == 1 && + req_vf_info && candidate->enable.vf_veceven) { /* and we need vf output. */ + if (req_vf_info->res.width > candidate->output.max_width) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() [%d] continue: (%d < %d)\n", + __LINE__, + req_vf_info->res.width, + candidate->output.max_width); + continue; + } + } + + if (!supports_bds_factor(candidate->bds.supported_bds_factors, + descr->required_bds_factor)) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() [%d] continue: 0x%x & 0x%x)\n", + __LINE__, candidate->bds.supported_bds_factors, + descr->required_bds_factor); + continue; + } + + if (!candidate->enable.dpc && need_dpc) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() [%d] continue: 0x%x & 0x%x)\n", + __LINE__, candidate->enable.dpc, + descr->enable_dpc); + continue; + } + + if (candidate->uds.use_bci && enable_capture_pp_bli) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() [%d] continue: 0x%x & 0x%x)\n", + __LINE__, candidate->uds.use_bci, + descr->enable_capture_pp_bli); + continue; + } + + /* reconfigure any variable properties of the binary */ + err = ia_css_binary_fill_info(xcandidate, online, two_ppc, + stream_format, req_in_info, + req_bds_out_info, + req_out_info, req_vf_info, + binary, &dvs_env, + descr->stream_config_left_padding, + false); + + if (err) + break; + binary_init_metrics(&binary->metrics, &binary->info->sp); + break; + } + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() selected = %p, mode = %d ID = %d\n", + xcandidate, xcandidate ? xcandidate->sp.pipeline.mode : 0, xcandidate ? xcandidate->sp.id : 0); + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_binary_find() leave: return_err=%d\n", err); + + if (!err && xcandidate) + dev_dbg(atomisp_dev, + "Using binary %s (id %d), type %d, mode %d, continuous %s\n", + xcandidate->blob->name, + xcandidate->sp.id, + xcandidate->type, + xcandidate->sp.pipeline.mode, + xcandidate->sp.enable.continuous ? "true" : "false"); + + + return err; +} + +int ia_css_binary_find(struct ia_css_binary_descr *descr, + struct ia_css_binary *binary) +{ + int ret = __ia_css_binary_find(descr, binary); + + if (unlikely(ret)) { + dev_dbg(atomisp_dev, "Seeking for binary failed at:"); + dump_stack(); + } + + return ret; +} + +unsigned +ia_css_binary_max_vf_width(void) +{ + /* This is (should be) true for IPU1 and IPU2 */ + /* For IPU3 (SkyCam) this pointer is guaranteed to be NULL simply because such a binary does not exist */ + if (binary_infos[IA_CSS_BINARY_MODE_VF_PP]) + return binary_infos[IA_CSS_BINARY_MODE_VF_PP]->sp.output.max_width; + return 0; +} + +void +ia_css_binary_destroy_isp_parameters(struct ia_css_binary *binary) +{ + if (binary) { + ia_css_isp_param_destroy_isp_parameters(&binary->mem_params, + &binary->css_params); + } +} + +void +ia_css_binary_get_isp_binaries(struct ia_css_binary_xinfo **binaries, + uint32_t *num_isp_binaries) +{ + assert(binaries); + + if (num_isp_binaries) + *num_isp_binaries = 0; + + *binaries = all_binaries; + if (all_binaries && num_isp_binaries) { + /* -1 to account for sp binary which is not stored in all_binaries */ + if (sh_css_num_binaries > 0) + *num_isp_binaries = sh_css_num_binaries - 1; + } +} diff --git a/drivers/staging/media/atomisp/pci/runtime/bufq/interface/ia_css_bufq.h b/drivers/staging/media/atomisp/pci/runtime/bufq/interface/ia_css_bufq.h new file mode 100644 index 000000000..a461b0ed0 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/bufq/interface/ia_css_bufq.h @@ -0,0 +1,178 @@ +/* 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. + */ + +#ifndef _IA_CSS_BUFQ_H +#define _IA_CSS_BUFQ_H + +#include <type_support.h> +#include "ia_css_bufq_comm.h" +#include "ia_css_buffer.h" +#include "ia_css_err.h" +#define BUFQ_EVENT_SIZE 4 + +/** + * @brief Query the internal frame ID. + * + * @param[in] key The query key. + * @param[out] val The query value. + * + * @return + * true, if the query succeeds; + * false, if the query fails. + */ +bool ia_css_query_internal_queue_id( + enum ia_css_buffer_type buf_type, + unsigned int thread_id, + enum sh_css_queue_id *val +); + +/** + * @brief Map buffer type to a internal queue id. + * + * @param[in] thread id Thread in which the buffer type has to be mapped or unmapped + * @param[in] buf_type buffer type. + * @param[in] map boolean flag to specify map or unmap + * @return none + */ +void ia_css_queue_map( + unsigned int thread_id, + enum ia_css_buffer_type buf_type, + bool map +); + +/** + * @brief Initialize buffer type to a queue id mapping + * @return none + */ +void ia_css_queue_map_init(void); + +/** + * @brief initializes bufq module + * It create instances of + * -host to SP buffer queue which is a list with predefined size, + * MxN queues where M is the number threads and N is the number queues per thread + *-SP to host buffer queue , is a list with N queues + *-host to SP event communication queue + * -SP to host event communication queue + * -queue for tagger commands + * @return none + */ +void ia_css_bufq_init(void); + +/** +* @brief Enqueues an item into host to SP buffer queue + * + * @param thread_index[in] Thread in which the item to be enqueued + * + * @param queue_id[in] Index of the queue in the specified thread + * @param item[in] Object to enqueue. + * @return 0 or error code upon error. + * +*/ +int ia_css_bufq_enqueue_buffer( + int thread_index, + int queue_id, + uint32_t item); + +/** +* @brief Dequeues an item from SP to host buffer queue. + * + * @param queue_id[in] Specifies the index of the queue in the list where + * the item has to be read. + * @paramitem [out] Object to be dequeued into this item. + * @return 0 or error code upon error. + * +*/ +int ia_css_bufq_dequeue_buffer( + int queue_id, + uint32_t *item); + +/** +* @brief Enqueue an event item into host to SP communication event queue. + * + * @param[in] evt_id The event ID. + * @param[in] evt_payload_0 The event payload. + * @param[in] evt_payload_1 The event payload. + * @param[in] evt_payload_2 The event payload. + * @return 0 or error code upon error. + * +*/ +int ia_css_bufq_enqueue_psys_event( + u8 evt_id, + u8 evt_payload_0, + u8 evt_payload_1, + uint8_t evt_payload_2 +); + +/** + * @brief Dequeue an item from SP to host communication event queue. + * + * @param item Object to be dequeued into this item. + * @return 0 or error code upon error. + * +*/ +int ia_css_bufq_dequeue_psys_event( + u8 item[BUFQ_EVENT_SIZE] + +); + +/** + * @brief Enqueue an event item into host to SP EOF event queue. + * + * @param[in] evt_id The event ID. + * @return 0 or error code upon error. + * + */ +int ia_css_bufq_enqueue_isys_event( + uint8_t evt_id); + +/** +* @brief Dequeue an item from SP to host communication EOF event queue. + + * + * @param item Object to be dequeued into this item. + * @return 0 or error code upon error. + * + */ +int ia_css_bufq_dequeue_isys_event( + u8 item[BUFQ_EVENT_SIZE]); + +/** +* @brief Enqueue a tagger command item into tagger command queue.. + * + * @param item Object to be enqueue. + * @return 0 or error code upon error. + * +*/ +int ia_css_bufq_enqueue_tag_cmd( + uint32_t item); + +/** +* @brief Uninitializes bufq module. + * + * @return 0 or error code upon error. + * +*/ +int ia_css_bufq_deinit(void); + +/** +* @brief Dump queue states + * + * @return None + * +*/ +void ia_css_bufq_dump_queue_info(void); + +#endif /* _IA_CSS_BUFQ_H */ diff --git a/drivers/staging/media/atomisp/pci/runtime/bufq/interface/ia_css_bufq_comm.h b/drivers/staging/media/atomisp/pci/runtime/bufq/interface/ia_css_bufq_comm.h new file mode 100644 index 000000000..567d94d91 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/bufq/interface/ia_css_bufq_comm.h @@ -0,0 +1,41 @@ +/* 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. + */ + +#ifndef _IA_CSS_BUFQ_COMM_H +#define _IA_CSS_BUFQ_COMM_H + +#include "system_global.h" + +enum sh_css_queue_id { + SH_CSS_INVALID_QUEUE_ID = -1, + SH_CSS_QUEUE_A_ID = 0, + SH_CSS_QUEUE_B_ID, + SH_CSS_QUEUE_C_ID, + SH_CSS_QUEUE_D_ID, + SH_CSS_QUEUE_E_ID, + SH_CSS_QUEUE_F_ID, + SH_CSS_QUEUE_G_ID, + SH_CSS_QUEUE_H_ID, /* for metadata */ + +#define SH_CSS_MAX_NUM_QUEUES (SH_CSS_QUEUE_H_ID + 1) + +}; + +#define SH_CSS_MAX_DYNAMIC_BUFFERS_PER_THREAD SH_CSS_MAX_NUM_QUEUES +/* for now we staticaly assign queue 0 & 1 to parameter sets */ +#define IA_CSS_PARAMETER_SET_QUEUE_ID SH_CSS_QUEUE_A_ID +#define IA_CSS_PER_FRAME_PARAMETER_SET_QUEUE_ID SH_CSS_QUEUE_B_ID + +#endif diff --git a/drivers/staging/media/atomisp/pci/runtime/bufq/src/bufq.c b/drivers/staging/media/atomisp/pci/runtime/bufq/src/bufq.c new file mode 100644 index 000000000..6a75cba48 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/bufq/src/bufq.c @@ -0,0 +1,532 @@ +// 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 "assert_support.h" /* assert */ +#include "ia_css_buffer.h" +#include "sp.h" +#include "ia_css_bufq.h" /* Bufq API's */ +#include "ia_css_queue.h" /* ia_css_queue_t */ +#include "sw_event_global.h" /* Event IDs.*/ +#include "ia_css_eventq.h" /* ia_css_eventq_recv()*/ +#include "ia_css_debug.h" /* ia_css_debug_dtrace*/ +#include "sh_css_internal.h" /* sh_css_queue_type */ +#include "sp_local.h" /* sp_address_of */ +#include "sh_css_firmware.h" /* sh_css_sp_fw*/ + +#define BUFQ_DUMP_FILE_NAME_PREFIX_SIZE 256 + +static char prefix[BUFQ_DUMP_FILE_NAME_PREFIX_SIZE] = {0}; + +/*********************************************************/ +/* Global Queue objects used by CSS */ +/*********************************************************/ + +struct sh_css_queues { + /* Host2SP buffer queue */ + ia_css_queue_t host2sp_buffer_queue_handles + [SH_CSS_MAX_SP_THREADS][SH_CSS_MAX_NUM_QUEUES]; + /* SP2Host buffer queue */ + ia_css_queue_t sp2host_buffer_queue_handles + [SH_CSS_MAX_NUM_QUEUES]; + + /* Host2SP event queue */ + ia_css_queue_t host2sp_psys_event_queue_handle; + + /* SP2Host event queue */ + ia_css_queue_t sp2host_psys_event_queue_handle; + + /* Host2SP ISYS event queue */ + ia_css_queue_t host2sp_isys_event_queue_handle; + + /* SP2Host ISYS event queue */ + ia_css_queue_t sp2host_isys_event_queue_handle; + /* Tagger command queue */ + ia_css_queue_t host2sp_tag_cmd_queue_handle; +}; + +/******************************************************* +*** Static variables +********************************************************/ +static struct sh_css_queues css_queues; + +static int +buffer_type_to_queue_id_map[SH_CSS_MAX_SP_THREADS][IA_CSS_NUM_DYNAMIC_BUFFER_TYPE]; +static bool queue_availability[SH_CSS_MAX_SP_THREADS][SH_CSS_MAX_NUM_QUEUES]; + +/******************************************************* +*** Static functions +********************************************************/ +static void map_buffer_type_to_queue_id( + unsigned int thread_id, + enum ia_css_buffer_type buf_type +); +static void unmap_buffer_type_to_queue_id( + unsigned int thread_id, + enum ia_css_buffer_type buf_type +); + +static ia_css_queue_t *bufq_get_qhandle( + enum sh_css_queue_type type, + enum sh_css_queue_id id, + int thread +); + +/******************************************************* +*** Public functions +********************************************************/ +void ia_css_queue_map_init(void) +{ + unsigned int i, j; + + for (i = 0; i < SH_CSS_MAX_SP_THREADS; i++) { + for (j = 0; j < SH_CSS_MAX_NUM_QUEUES; j++) + queue_availability[i][j] = true; + } + + for (i = 0; i < SH_CSS_MAX_SP_THREADS; i++) { + for (j = 0; j < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE; j++) + buffer_type_to_queue_id_map[i][j] = SH_CSS_INVALID_QUEUE_ID; + } +} + +void ia_css_queue_map( + unsigned int thread_id, + enum ia_css_buffer_type buf_type, + bool map) +{ + assert(buf_type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE); + assert(thread_id < SH_CSS_MAX_SP_THREADS); + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_queue_map() enter: buf_type=%d, thread_id=%d\n", buf_type, thread_id); + + if (map) + map_buffer_type_to_queue_id(thread_id, buf_type); + else + unmap_buffer_type_to_queue_id(thread_id, buf_type); +} + +/* + * @brief Query the internal queue ID. + */ +bool ia_css_query_internal_queue_id( + enum ia_css_buffer_type buf_type, + unsigned int thread_id, + enum sh_css_queue_id *val) +{ + IA_CSS_ENTER("buf_type=%d, thread_id=%d, val = %p", buf_type, thread_id, val); + + if ((!val) || (thread_id >= SH_CSS_MAX_SP_THREADS) || + (buf_type >= IA_CSS_NUM_DYNAMIC_BUFFER_TYPE)) { + IA_CSS_LEAVE("return_val = false"); + return false; + } + + *val = buffer_type_to_queue_id_map[thread_id][buf_type]; + if ((*val == SH_CSS_INVALID_QUEUE_ID) || (*val >= SH_CSS_MAX_NUM_QUEUES)) { + IA_CSS_LOG("INVALID queue ID MAP = %d\n", *val); + IA_CSS_LEAVE("return_val = false"); + return false; + } + IA_CSS_LEAVE("return_val = true"); + return true; +} + +/******************************************************* +*** Static functions +********************************************************/ +static void map_buffer_type_to_queue_id( + unsigned int thread_id, + enum ia_css_buffer_type buf_type) +{ + unsigned int i; + + assert(thread_id < SH_CSS_MAX_SP_THREADS); + assert(buf_type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE); + assert(buffer_type_to_queue_id_map[thread_id][buf_type] == + SH_CSS_INVALID_QUEUE_ID); + + /* queue 0 is reserved for parameters because it doesn't depend on events */ + if (buf_type == IA_CSS_BUFFER_TYPE_PARAMETER_SET) { + assert(queue_availability[thread_id][IA_CSS_PARAMETER_SET_QUEUE_ID]); + queue_availability[thread_id][IA_CSS_PARAMETER_SET_QUEUE_ID] = false; + buffer_type_to_queue_id_map[thread_id][buf_type] = + IA_CSS_PARAMETER_SET_QUEUE_ID; + return; + } + + /* queue 1 is reserved for per frame parameters because it doesn't depend on events */ + if (buf_type == IA_CSS_BUFFER_TYPE_PER_FRAME_PARAMETER_SET) { + assert(queue_availability[thread_id][IA_CSS_PER_FRAME_PARAMETER_SET_QUEUE_ID]); + queue_availability[thread_id][IA_CSS_PER_FRAME_PARAMETER_SET_QUEUE_ID] = false; + buffer_type_to_queue_id_map[thread_id][buf_type] = + IA_CSS_PER_FRAME_PARAMETER_SET_QUEUE_ID; + return; + } + + for (i = SH_CSS_QUEUE_C_ID; i < SH_CSS_MAX_NUM_QUEUES; i++) { + if (queue_availability[thread_id][i]) { + queue_availability[thread_id][i] = false; + buffer_type_to_queue_id_map[thread_id][buf_type] = i; + break; + } + } + + assert(i != SH_CSS_MAX_NUM_QUEUES); + return; +} + +static void unmap_buffer_type_to_queue_id( + unsigned int thread_id, + enum ia_css_buffer_type buf_type) +{ + int queue_id; + + assert(thread_id < SH_CSS_MAX_SP_THREADS); + assert(buf_type < IA_CSS_NUM_DYNAMIC_BUFFER_TYPE); + assert(buffer_type_to_queue_id_map[thread_id][buf_type] != + SH_CSS_INVALID_QUEUE_ID); + + queue_id = buffer_type_to_queue_id_map[thread_id][buf_type]; + buffer_type_to_queue_id_map[thread_id][buf_type] = SH_CSS_INVALID_QUEUE_ID; + queue_availability[thread_id][queue_id] = true; +} + +static ia_css_queue_t *bufq_get_qhandle( + enum sh_css_queue_type type, + enum sh_css_queue_id id, + int thread) +{ + ia_css_queue_t *q = NULL; + + switch (type) { + case sh_css_host2sp_buffer_queue: + if ((thread >= SH_CSS_MAX_SP_THREADS) || (thread < 0) || + (id == SH_CSS_INVALID_QUEUE_ID)) + break; + q = &css_queues.host2sp_buffer_queue_handles[thread][id]; + break; + case sh_css_sp2host_buffer_queue: + if (id == SH_CSS_INVALID_QUEUE_ID) + break; + q = &css_queues.sp2host_buffer_queue_handles[id]; + break; + case sh_css_host2sp_psys_event_queue: + q = &css_queues.host2sp_psys_event_queue_handle; + break; + case sh_css_sp2host_psys_event_queue: + q = &css_queues.sp2host_psys_event_queue_handle; + break; + case sh_css_host2sp_isys_event_queue: + q = &css_queues.host2sp_isys_event_queue_handle; + break; + case sh_css_sp2host_isys_event_queue: + q = &css_queues.sp2host_isys_event_queue_handle; + break; + case sh_css_host2sp_tag_cmd_queue: + q = &css_queues.host2sp_tag_cmd_queue_handle; + break; + default: + break; + } + + return q; +} + +/* Local function to initialize a buffer queue. This reduces + * the chances of copy-paste errors or typos. + */ +static inline void +init_bufq(unsigned int desc_offset, + unsigned int elems_offset, + ia_css_queue_t *handle) +{ + const struct ia_css_fw_info *fw; + unsigned int q_base_addr; + ia_css_queue_remote_t remoteq; + + fw = &sh_css_sp_fw; + q_base_addr = fw->info.sp.host_sp_queue; + + /* Setup queue location as SP and proc id as SP0_ID */ + remoteq.location = IA_CSS_QUEUE_LOC_SP; + remoteq.proc_id = SP0_ID; + remoteq.cb_desc_addr = q_base_addr + desc_offset; + remoteq.cb_elems_addr = q_base_addr + elems_offset; + /* Initialize the queue instance and obtain handle */ + ia_css_queue_remote_init(handle, &remoteq); +} + +void ia_css_bufq_init(void) +{ + int i, j; + + IA_CSS_ENTER_PRIVATE(""); + + /* Setup all the local queue descriptors for Host2SP Buffer Queues */ + for (i = 0; i < SH_CSS_MAX_SP_THREADS; i++) + for (j = 0; j < SH_CSS_MAX_NUM_QUEUES; j++) { + init_bufq((uint32_t)offsetof(struct host_sp_queues, + host2sp_buffer_queues_desc[i][j]), + (uint32_t)offsetof(struct host_sp_queues, host2sp_buffer_queues_elems[i][j]), + &css_queues.host2sp_buffer_queue_handles[i][j]); + } + + /* Setup all the local queue descriptors for SP2Host Buffer Queues */ + for (i = 0; i < SH_CSS_MAX_NUM_QUEUES; i++) { + init_bufq(offsetof(struct host_sp_queues, sp2host_buffer_queues_desc[i]), + offsetof(struct host_sp_queues, sp2host_buffer_queues_elems[i]), + &css_queues.sp2host_buffer_queue_handles[i]); + } + + /* Host2SP event queue*/ + init_bufq((uint32_t)offsetof(struct host_sp_queues, + host2sp_psys_event_queue_desc), + (uint32_t)offsetof(struct host_sp_queues, host2sp_psys_event_queue_elems), + &css_queues.host2sp_psys_event_queue_handle); + + /* SP2Host event queue */ + init_bufq((uint32_t)offsetof(struct host_sp_queues, + sp2host_psys_event_queue_desc), + (uint32_t)offsetof(struct host_sp_queues, sp2host_psys_event_queue_elems), + &css_queues.sp2host_psys_event_queue_handle); + + /* Host2SP ISYS event queue */ + init_bufq((uint32_t)offsetof(struct host_sp_queues, + host2sp_isys_event_queue_desc), + (uint32_t)offsetof(struct host_sp_queues, host2sp_isys_event_queue_elems), + &css_queues.host2sp_isys_event_queue_handle); + + /* SP2Host ISYS event queue*/ + init_bufq((uint32_t)offsetof(struct host_sp_queues, + sp2host_isys_event_queue_desc), + (uint32_t)offsetof(struct host_sp_queues, sp2host_isys_event_queue_elems), + &css_queues.sp2host_isys_event_queue_handle); + + /* Host2SP tagger command queue */ + init_bufq((uint32_t)offsetof(struct host_sp_queues, host2sp_tag_cmd_queue_desc), + (uint32_t)offsetof(struct host_sp_queues, host2sp_tag_cmd_queue_elems), + &css_queues.host2sp_tag_cmd_queue_handle); + + IA_CSS_LEAVE_PRIVATE(""); +} + +int ia_css_bufq_enqueue_buffer( + int thread_index, + int queue_id, + uint32_t item) +{ + ia_css_queue_t *q; + int error; + + IA_CSS_ENTER_PRIVATE("queue_id=%d", queue_id); + if ((thread_index >= SH_CSS_MAX_SP_THREADS) || (thread_index < 0) || + (queue_id == SH_CSS_INVALID_QUEUE_ID)) + return -EINVAL; + + /* Get the queue for communication */ + q = bufq_get_qhandle(sh_css_host2sp_buffer_queue, + queue_id, + thread_index); + if (q) { + error = ia_css_queue_enqueue(q, item); + } else { + IA_CSS_ERROR("queue is not initialized"); + error = -EBUSY; + } + + IA_CSS_LEAVE_ERR_PRIVATE(error); + return error; +} + +int ia_css_bufq_dequeue_buffer( + int queue_id, + uint32_t *item) +{ + int error; + ia_css_queue_t *q; + + IA_CSS_ENTER_PRIVATE("queue_id=%d", queue_id); + if ((!item) || + (queue_id <= SH_CSS_INVALID_QUEUE_ID) || + (queue_id >= SH_CSS_MAX_NUM_QUEUES) + ) + return -EINVAL; + + q = bufq_get_qhandle(sh_css_sp2host_buffer_queue, + queue_id, + -1); + if (q) { + error = ia_css_queue_dequeue(q, item); + } else { + IA_CSS_ERROR("queue is not initialized"); + error = -EBUSY; + } + + IA_CSS_LEAVE_ERR_PRIVATE(error); + return error; +} + +int ia_css_bufq_enqueue_psys_event( + u8 evt_id, + u8 evt_payload_0, + u8 evt_payload_1, + uint8_t evt_payload_2) +{ + int error = 0; + ia_css_queue_t *q; + + IA_CSS_ENTER_PRIVATE("evt_id=%d", evt_id); + q = bufq_get_qhandle(sh_css_host2sp_psys_event_queue, -1, -1); + if (!q) { + IA_CSS_ERROR("queue is not initialized"); + return -EBUSY; + } + + error = ia_css_eventq_send(q, + evt_id, evt_payload_0, evt_payload_1, evt_payload_2); + + IA_CSS_LEAVE_ERR_PRIVATE(error); + return error; +} + +int ia_css_bufq_dequeue_psys_event( + u8 item[BUFQ_EVENT_SIZE]) +{ + int error = 0; + ia_css_queue_t *q; + + /* No ENTER/LEAVE in this function since this is polled + * by some test apps. Enablign logging here floods the log + * files which may cause timeouts. */ + if (!item) + return -EINVAL; + + q = bufq_get_qhandle(sh_css_sp2host_psys_event_queue, -1, -1); + if (!q) { + IA_CSS_ERROR("queue is not initialized"); + return -EBUSY; + } + error = ia_css_eventq_recv(q, item); + + return error; +} + +int ia_css_bufq_dequeue_isys_event( + u8 item[BUFQ_EVENT_SIZE]) +{ + int error = 0; + ia_css_queue_t *q; + + /* No ENTER/LEAVE in this function since this is polled + * by some test apps. Enablign logging here floods the log + * files which may cause timeouts. */ + if (!item) + return -EINVAL; + + q = bufq_get_qhandle(sh_css_sp2host_isys_event_queue, -1, -1); + if (!q) { + IA_CSS_ERROR("queue is not initialized"); + return -EBUSY; + } + error = ia_css_eventq_recv(q, item); + return error; +} + +int ia_css_bufq_enqueue_isys_event(uint8_t evt_id) +{ + int error = 0; + ia_css_queue_t *q; + + IA_CSS_ENTER_PRIVATE("event_id=%d", evt_id); + q = bufq_get_qhandle(sh_css_host2sp_isys_event_queue, -1, -1); + if (!q) { + IA_CSS_ERROR("queue is not initialized"); + return -EBUSY; + } + + error = ia_css_eventq_send(q, evt_id, 0, 0, 0); + + IA_CSS_LEAVE_ERR_PRIVATE(error); + return error; +} + +int ia_css_bufq_enqueue_tag_cmd( + uint32_t item) +{ + int error; + ia_css_queue_t *q; + + IA_CSS_ENTER_PRIVATE("item=%d", item); + q = bufq_get_qhandle(sh_css_host2sp_tag_cmd_queue, -1, -1); + if (!q) { + IA_CSS_ERROR("queue is not initialized"); + return -EBUSY; + } + error = ia_css_queue_enqueue(q, item); + + IA_CSS_LEAVE_ERR_PRIVATE(error); + return error; +} + +int ia_css_bufq_deinit(void) +{ + return 0; +} + +static void bufq_dump_queue_info(const char *prefix, ia_css_queue_t *qhandle) +{ + u32 free = 0, used = 0; + + assert(prefix && qhandle); + ia_css_queue_get_used_space(qhandle, &used); + ia_css_queue_get_free_space(qhandle, &free); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "%s: used=%u free=%u\n", + prefix, used, free); +} + +void ia_css_bufq_dump_queue_info(void) +{ + int i, j; + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "Queue Information:\n"); + + for (i = 0; i < SH_CSS_MAX_SP_THREADS; i++) { + for (j = 0; j < SH_CSS_MAX_NUM_QUEUES; j++) { + snprintf(prefix, BUFQ_DUMP_FILE_NAME_PREFIX_SIZE, + "host2sp_buffer_queue[%u][%u]", i, j); + bufq_dump_queue_info(prefix, + &css_queues.host2sp_buffer_queue_handles[i][j]); + } + } + + for (i = 0; i < SH_CSS_MAX_NUM_QUEUES; i++) { + snprintf(prefix, BUFQ_DUMP_FILE_NAME_PREFIX_SIZE, + "sp2host_buffer_queue[%u]", i); + bufq_dump_queue_info(prefix, + &css_queues.sp2host_buffer_queue_handles[i]); + } + bufq_dump_queue_info("host2sp_psys_event", + &css_queues.host2sp_psys_event_queue_handle); + bufq_dump_queue_info("sp2host_psys_event", + &css_queues.sp2host_psys_event_queue_handle); + + bufq_dump_queue_info("host2sp_isys_event", + &css_queues.host2sp_isys_event_queue_handle); + bufq_dump_queue_info("sp2host_isys_event", + &css_queues.sp2host_isys_event_queue_handle); + bufq_dump_queue_info("host2sp_tag_cmd", + &css_queues.host2sp_tag_cmd_queue_handle); +} diff --git a/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h new file mode 100644 index 000000000..fff89e9b4 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h @@ -0,0 +1,500 @@ +/* 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. + */ + +#ifndef _IA_CSS_DEBUG_H_ +#define _IA_CSS_DEBUG_H_ + +/*! \file */ + +#include <type_support.h> +#include <linux/stdarg.h> +#include <linux/bits.h> +#include "ia_css_types.h" +#include "ia_css_binary.h" +#include "ia_css_frame_public.h" +#include "ia_css_pipe_public.h" +#include "ia_css_stream_public.h" +#include "ia_css_metadata.h" +#include "sh_css_internal.h" +/* ISP2500 */ +#include "ia_css_pipe.h" + +/* available levels */ +/*! Level for tracing errors */ +#define IA_CSS_DEBUG_ERROR 1 +/*! Level for tracing warnings */ +#define IA_CSS_DEBUG_WARNING 3 +/*! Level for tracing debug messages */ +#define IA_CSS_DEBUG_VERBOSE 5 +/*! Level for tracing trace messages a.o. ia_css public function calls */ +#define IA_CSS_DEBUG_TRACE 6 +/*! Level for tracing trace messages a.o. ia_css private function calls */ +#define IA_CSS_DEBUG_TRACE_PRIVATE 7 +/*! Level for tracing parameter messages e.g. in and out params of functions */ +#define IA_CSS_DEBUG_PARAM 8 +/*! Level for tracing info messages */ +#define IA_CSS_DEBUG_INFO 9 + +/* Global variable which controls the verbosity levels of the debug tracing */ +extern int dbg_level; + +/*! @brief Enum defining the different isp parameters to dump. + * Values can be combined to dump a combination of sets. + */ +enum ia_css_debug_enable_param_dump { + IA_CSS_DEBUG_DUMP_FPN = BIT(0), /** FPN table */ + IA_CSS_DEBUG_DUMP_OB = BIT(1), /** OB table */ + IA_CSS_DEBUG_DUMP_SC = BIT(2), /** Shading table */ + IA_CSS_DEBUG_DUMP_WB = BIT(3), /** White balance */ + IA_CSS_DEBUG_DUMP_DP = BIT(4), /** Defect Pixel */ + IA_CSS_DEBUG_DUMP_BNR = BIT(5), /** Bayer Noise Reductions */ + IA_CSS_DEBUG_DUMP_S3A = BIT(6), /** 3A Statistics */ + IA_CSS_DEBUG_DUMP_DE = BIT(7), /** De Mosaicing */ + IA_CSS_DEBUG_DUMP_YNR = BIT(8), /** Luma Noise Reduction */ + IA_CSS_DEBUG_DUMP_CSC = BIT(9), /** Color Space Conversion */ + IA_CSS_DEBUG_DUMP_GC = BIT(10), /** Gamma Correction */ + IA_CSS_DEBUG_DUMP_TNR = BIT(11), /** Temporal Noise Reduction */ + IA_CSS_DEBUG_DUMP_ANR = BIT(12), /** Advanced Noise Reduction */ + IA_CSS_DEBUG_DUMP_CE = BIT(13), /** Chroma Enhancement */ + IA_CSS_DEBUG_DUMP_ALL = BIT(14), /** Dump all device parameters */ +}; + +#define IA_CSS_ERROR(fmt, ...) \ + ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR, \ + "%s() %d: error: " fmt "\n", __func__, __LINE__, ##__VA_ARGS__) + +#define IA_CSS_WARNING(fmt, ...) \ + ia_css_debug_dtrace(IA_CSS_DEBUG_WARNING, \ + "%s() %d: warning: " fmt "\n", __func__, __LINE__, ##__VA_ARGS__) + +/* Logging macros for public functions (API functions) */ +#define IA_CSS_ENTER(fmt, ...) \ + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, \ + "%s(): enter: " fmt "\n", __func__, ##__VA_ARGS__) + +/* Use this macro for small functions that do not call other functions. */ +#define IA_CSS_ENTER_LEAVE(fmt, ...) \ + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, \ + "%s(): enter: leave: " fmt "\n", __func__, ##__VA_ARGS__) + +#define IA_CSS_LEAVE(fmt, ...) \ + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, \ + "%s(): leave: " fmt "\n", __func__, ##__VA_ARGS__) + +/* Shorthand for returning an int return value */ +#define IA_CSS_LEAVE_ERR(__err) \ + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, \ + "%s() %d: leave: return_err=%d\n", __func__, __LINE__, __err) + +/* Use this macro for logging other than enter/leave. + * Note that this macro always uses the PRIVATE logging level. + */ +#define IA_CSS_LOG(fmt, ...) \ + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, \ + "%s(): " fmt "\n", __func__, ##__VA_ARGS__) + +/* Logging macros for non-API functions. These have a lower trace level */ +#define IA_CSS_ENTER_PRIVATE(fmt, ...) \ + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, \ + "%s(): enter: " fmt "\n", __func__, ##__VA_ARGS__) + +#define IA_CSS_LEAVE_PRIVATE(fmt, ...) \ + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, \ + "%s(): leave: " fmt "\n", __func__, ##__VA_ARGS__) + +/* Shorthand for returning an int return value */ +#define IA_CSS_LEAVE_ERR_PRIVATE(__err) \ + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, \ + "%s() %d: leave: return_err=%d\n", __func__, __LINE__, __err) + +/* Use this macro for small functions that do not call other functions. */ +#define IA_CSS_ENTER_LEAVE_PRIVATE(fmt, ...) \ + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, \ + "%s(): enter: leave: " fmt "\n", __func__, ##__VA_ARGS__) + +/*! @brief Function for tracing to the provided printf function in the + * environment. + * @param[in] level Level of the message. + * @param[in] fmt printf like format string + * @param[in] args arguments for the format string + */ +static inline void __printf(2, 0) ia_css_debug_vdtrace(unsigned int level, + const char *fmt, + va_list args) +{ + if (dbg_level >= level) + sh_css_vprint(fmt, args); +} + +__printf(2, 3) void ia_css_debug_dtrace(unsigned int level, + const char *fmt, ...); + +/*! @brief Dump sp thread's stack contents + * SP thread's stack contents are set to 0xcafecafe. This function dumps the + * stack to inspect if the stack's boundaries are compromised. + * @return None + */ +void ia_css_debug_dump_sp_stack_info(void); + +/*! @brief Function to set the global dtrace verbosity level. + * @param[in] trace_level Maximum level of the messages to be traced. + * @return None + */ +void ia_css_debug_set_dtrace_level( + const unsigned int trace_level); + +/*! @brief Function to get the global dtrace verbosity level. + * @return global dtrace verbosity level + */ +unsigned int ia_css_debug_get_dtrace_level(void); + +/*! @brief Dump isp hardware state. + * Dumps the isp hardware state to tracing output. + * @return None + */ +void ia_css_debug_dump_isp_state(void); + +/*! @brief Dump sp hardware state. + * Dumps the sp hardware state to tracing output. + * @return None + */ +void ia_css_debug_dump_sp_state(void); + +/* ISP2401 */ +/*! @brief Dump GAC hardware state. + * Dumps the GAC ACB hardware registers. may be useful for + * detecting a GAC which got hang. + * @return None + */ +void ia_css_debug_dump_gac_state(void); + +/*! @brief Dump dma controller state. + * Dumps the dma controller state to tracing output. + * @return None + */ +void ia_css_debug_dump_dma_state(void); + +/*! @brief Dump internal sp software state. + * Dumps the sp software state to tracing output. + * @return None + */ +void ia_css_debug_dump_sp_sw_debug_info(void); + +/*! @brief Dump all related hardware state to the trace output + * @param[in] context String to identify context in output. + * @return None + */ +void ia_css_debug_dump_debug_info( + const char *context); + +#if SP_DEBUG != SP_DEBUG_NONE +void ia_css_debug_print_sp_debug_state( + const struct sh_css_sp_debug_state *state); +#endif + +/*! @brief Dump all related binary info data + * @param[in] bi Binary info struct. + * @return None + */ +void ia_css_debug_binary_print( + const struct ia_css_binary *bi); + +void ia_css_debug_sp_dump_mipi_fifo_high_water(void); + +/*! @brief Dump isp gdc fifo state to the trace output + * Dumps the isp gdc fifo state to tracing output. + * @return None + */ +void ia_css_debug_dump_isp_gdc_fifo_state(void); + +/*! @brief Dump dma isp fifo state + * Dumps the dma isp fifo state to tracing output. + * @return None + */ +void ia_css_debug_dump_dma_isp_fifo_state(void); + +/*! @brief Dump dma sp fifo state + * Dumps the dma sp fifo state to tracing output. + * @return None + */ +void ia_css_debug_dump_dma_sp_fifo_state(void); + +/*! \brief Dump pif A isp fifo state + * Dumps the primary input formatter state to tracing output. + * @return None + */ +void ia_css_debug_dump_pif_a_isp_fifo_state(void); + +/*! \brief Dump pif B isp fifo state + * Dumps the primary input formatter state to tracing output. + * \return None + */ +void ia_css_debug_dump_pif_b_isp_fifo_state(void); + +/*! @brief Dump stream-to-memory sp fifo state + * Dumps the stream-to-memory block state to tracing output. + * @return None + */ +void ia_css_debug_dump_str2mem_sp_fifo_state(void); + +/*! @brief Dump isp sp fifo state + * Dumps the isp sp fifo state to tracing output. + * @return None + */ +void ia_css_debug_dump_isp_sp_fifo_state(void); + +/*! @brief Dump all fifo state info to the output + * Dumps all fifo state to tracing output. + * @return None + */ +void ia_css_debug_dump_all_fifo_state(void); + +/*! @brief Dump the rx state to the output + * Dumps the rx state to tracing output. + * @return None + */ +void ia_css_debug_dump_rx_state(void); + +/*! @brief Dump the input system state to the output + * Dumps the input system state to tracing output. + * @return None + */ +void ia_css_debug_dump_isys_state(void); + +/*! @brief Dump the frame info to the trace output + * Dumps the frame info to tracing output. + * @param[in] frame pointer to struct ia_css_frame + * @param[in] descr description output along with the frame info + * @return None + */ +void ia_css_debug_frame_print( + const struct ia_css_frame *frame, + const char *descr); + +/*! @brief Function to enable sp sleep mode. + * Function that enables sp sleep mode + * @param[in] mode indicates when to put sp to sleep + * @return None + */ +void ia_css_debug_enable_sp_sleep_mode(enum ia_css_sp_sleep_mode mode); + +/*! @brief Function to wake up sp when in sleep mode. + * After sp has been put to sleep, use this function to let it continue + * to run again. + * @return None + */ +void ia_css_debug_wake_up_sp(void); + +/*! @brief Function to dump isp parameters. + * Dump isp parameters to tracing output + * @param[in] stream pointer to ia_css_stream struct + * @param[in] enable flag indicating which parameters to dump. + * @return None + */ +void ia_css_debug_dump_isp_params(struct ia_css_stream *stream, + unsigned int enable); + +/*! @brief Function to dump some sp performance counters. + * Dump sp performance counters, currently input system errors. + * @return None + */ +void ia_css_debug_dump_perf_counters(void); + +#ifdef HAS_WATCHDOG_SP_THREAD_DEBUG +void sh_css_dump_thread_wait_info(void); +void sh_css_dump_pipe_stage_info(void); +void sh_css_dump_pipe_stripe_info(void); +#endif + +void ia_css_debug_dump_isp_binary(void); + +void sh_css_dump_sp_raw_copy_linecount(bool reduced); + +/*! @brief Dump the resolution info to the trace output + * Dumps the resolution info to the trace output. + * @param[in] res pointer to struct ia_css_resolution + * @param[in] label description of resolution output + * @return None + */ +void ia_css_debug_dump_resolution( + const struct ia_css_resolution *res, + const char *label); + +/*! @brief Dump the frame info to the trace output + * Dumps the frame info to the trace output. + * @param[in] info pointer to struct ia_css_frame_info + * @param[in] label description of frame_info output + * @return None + */ +void ia_css_debug_dump_frame_info( + const struct ia_css_frame_info *info, + const char *label); + +/*! @brief Dump the capture config info to the trace output + * Dumps the capture config info to the trace output. + * @param[in] config pointer to struct ia_css_capture_config + * @return None + */ +void ia_css_debug_dump_capture_config( + const struct ia_css_capture_config *config); + +/*! @brief Dump the pipe extra config info to the trace output + * Dumps the pipe extra config info to the trace output. + * @param[in] extra_config pointer to struct ia_css_pipe_extra_config + * @return None + */ +void ia_css_debug_dump_pipe_extra_config( + const struct ia_css_pipe_extra_config *extra_config); + +/*! @brief Dump the pipe config info to the trace output + * Dumps the pipe config info to the trace output. + * @param[in] config pointer to struct ia_css_pipe_config + * @return None + */ +void ia_css_debug_dump_pipe_config( + const struct ia_css_pipe_config *config); + +/*! @brief Dump the stream config source info to the trace output + * Dumps the stream config source info to the trace output. + * @param[in] config pointer to struct ia_css_stream_config + * @return None + */ +void ia_css_debug_dump_stream_config_source( + const struct ia_css_stream_config *config); + +/*! @brief Dump the mipi buffer config info to the trace output + * Dumps the mipi buffer config info to the trace output. + * @param[in] config pointer to struct ia_css_mipi_buffer_config + * @return None + */ +void ia_css_debug_dump_mipi_buffer_config( + const struct ia_css_mipi_buffer_config *config); + +/*! @brief Dump the metadata config info to the trace output + * Dumps the metadata config info to the trace output. + * @param[in] config pointer to struct ia_css_metadata_config + * @return None + */ +void ia_css_debug_dump_metadata_config( + const struct ia_css_metadata_config *config); + +/*! @brief Dump the stream config info to the trace output + * Dumps the stream config info to the trace output. + * @param[in] config pointer to struct ia_css_stream_config + * @param[in] num_pipes number of pipes for the stream + * @return None + */ +void ia_css_debug_dump_stream_config( + const struct ia_css_stream_config *config, + int num_pipes); + +/*! @brief Dump the state of the SP tagger + * Dumps the internal state of the SP tagger + * @return None + */ +void ia_css_debug_tagger_state(void); + +/** + * @brief Initialize the debug mode. + * + * WARNING: + * This API should be called ONLY once in the debug mode. + * + * @return + * - true, if it is successful. + * - false, otherwise. + */ +bool ia_css_debug_mode_init(void); + +/** + * @brief Disable the DMA channel. + * + * @param[in] dma_ID The ID of the target DMA. + * @param[in] channel_id The ID of the target DMA channel. + * @param[in] request_type The type of the DMA request. + * For example: + * - "0" indicates the writing request. + * - "1" indicates the reading request. + * + * This is part of the DMA API -> dma.h + * + * @return + * - true, if it is successful. + * - false, otherwise. + */ +bool ia_css_debug_mode_disable_dma_channel( + int dma_ID, + int channel_id, + int request_type); +/** + * @brief Enable the DMA channel. + * + * @param[in] dma_ID The ID of the target DMA. + * @param[in] channel_id The ID of the target DMA channel. + * @param[in] request_type The type of the DMA request. + * For example: + * - "0" indicates the writing request. + * - "1" indicates the reading request. + * + * @return + * - true, if it is successful. + * - false, otherwise. + */ +bool ia_css_debug_mode_enable_dma_channel( + int dma_ID, + int channel_id, + int request_type); + +/** + * @brief Dump tracer data. + * [Currently support is only for SKC] + * + * @return + * - none. + */ +void ia_css_debug_dump_trace(void); + +/* ISP2401 */ +/** + * @brief Program counter dumping (in loop) + * + * @param[in] id The ID of the SP + * @param[in] num_of_dumps The number of dumps + * + * @return + * - none + */ +void ia_css_debug_pc_dump(sp_ID_t id, unsigned int num_of_dumps); + +/* ISP2500 */ +/*! @brief Dump all states for ISP hang case. + * Dumps the ISP previous and current configurations + * GACs status, SP0/1 statuses. + * + * @param[in] pipe The current pipe + * + * @return None + */ +void ia_css_debug_dump_hang_status( + struct ia_css_pipe *pipe); + +/*! @brief External command handler + * External command handler + * + * @return None + */ +void ia_css_debug_ext_command_handler(void); + +#endif /* _IA_CSS_DEBUG_H_ */ diff --git a/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug_internal.h b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug_internal.h new file mode 100644 index 000000000..8ec487ad4 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug_internal.h @@ -0,0 +1,16 @@ +/* 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. + */ + +/* TO DO: Move debug related code from ia_css_internal.h in */ diff --git a/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug_pipe.h b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug_pipe.h new file mode 100644 index 000000000..538918cfb --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug_pipe.h @@ -0,0 +1,68 @@ +/* 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. + */ + +#ifndef _IA_CSS_DEBUG_PIPE_H_ +#define _IA_CSS_DEBUG_PIPE_H_ + +/*! \file */ + +#include <ia_css_frame_public.h> +#include <ia_css_stream_public.h> +#include "ia_css_pipeline.h" + +/** + * @brief Internal debug support for constructing a pipe graph. + * + * @return None + */ +void ia_css_debug_pipe_graph_dump_prologue(void); + +/** + * @brief Internal debug support for constructing a pipe graph. + * + * @return None + */ +void ia_css_debug_pipe_graph_dump_epilogue(void); + +/** + * @brief Internal debug support for constructing a pipe graph. + * @param[in] stage Pipeline stage. + * @param[in] id Pipe id. + * + * @return None + */ +void ia_css_debug_pipe_graph_dump_stage( + struct ia_css_pipeline_stage *stage, + enum ia_css_pipe_id id); + +/** + * @brief Internal debug support for constructing a pipe graph. + * @param[in] out_frame Output frame of SP raw copy. + * + * @return None + */ +void ia_css_debug_pipe_graph_dump_sp_raw_copy( + struct ia_css_frame *out_frame); + +/** + * @brief Internal debug support for constructing a pipe graph. + * @param[in] stream_config info about sensor and input formatter. + * + * @return None + */ +void ia_css_debug_pipe_graph_dump_stream_config( + const struct ia_css_stream_config *stream_config); + +#endif /* _IA_CSS_DEBUG_PIPE_H_ */ diff --git a/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c b/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c new file mode 100644 index 000000000..3d269bd23 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c @@ -0,0 +1,3410 @@ +// 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 "debug.h" + +#ifndef __INLINE_INPUT_SYSTEM__ +#define __INLINE_INPUT_SYSTEM__ +#endif +#ifndef __INLINE_IBUF_CTRL__ +#define __INLINE_IBUF_CTRL__ +#endif +#ifndef __INLINE_CSI_RX__ +#define __INLINE_CSI_RX__ +#endif +#ifndef __INLINE_PIXELGEN__ +#define __INLINE_PIXELGEN__ +#endif +#ifndef __INLINE_STREAM2MMIO__ +#define __INLINE_STREAM2MMIO__ +#endif + +#include <linux/string.h> /* for strscpy() */ + +#include "ia_css_debug.h" +#include "ia_css_debug_pipe.h" +#include "ia_css_irq.h" +#include "ia_css_stream.h" +#include "ia_css_pipeline.h" +#include "ia_css_isp_param.h" +#include "sh_css_params.h" +#include "ia_css_bufq.h" +/* ISP2401 */ +#include "ia_css_queue.h" + +#include "ia_css_isp_params.h" + +#include "system_local.h" +#include "assert_support.h" +#include "print_support.h" + +#include "fifo_monitor.h" + +#include "input_formatter.h" +#include "dma.h" +#include "irq.h" +#include "gp_device.h" +#include "sp.h" +#include "isp.h" +#include "type_support.h" +#include "math_support.h" /* CEIL_DIV */ +#include "input_system.h" /* input_formatter_reg_load */ +#include "ia_css_tagger_common.h" + +#include "sh_css_internal.h" +#include "ia_css_isys.h" +#include "sh_css_sp.h" /* sh_css_sp_get_debug_state() */ + +#include "css_trace.h" /* tracer */ + +#include "device_access.h" /* for ia_css_device_load_uint32 */ + +/* Include all kernel host interfaces for ISP1 */ +#include "anr/anr_1.0/ia_css_anr.host.h" +#include "cnr/cnr_1.0/ia_css_cnr.host.h" +#include "csc/csc_1.0/ia_css_csc.host.h" +#include "de/de_1.0/ia_css_de.host.h" +#include "dp/dp_1.0/ia_css_dp.host.h" +#include "bnr/bnr_1.0/ia_css_bnr.host.h" +#include "fpn/fpn_1.0/ia_css_fpn.host.h" +#include "gc/gc_1.0/ia_css_gc.host.h" +#include "ob/ob_1.0/ia_css_ob.host.h" +#include "s3a/s3a_1.0/ia_css_s3a.host.h" +#include "sc/sc_1.0/ia_css_sc.host.h" +#include "tnr/tnr_1.0/ia_css_tnr.host.h" +#include "uds/uds_1.0/ia_css_uds_param.h" +#include "wb/wb_1.0/ia_css_wb.host.h" +#include "ynr/ynr_1.0/ia_css_ynr.host.h" + +/* Include additional kernel host interfaces for ISP2 */ +#include "aa/aa_2/ia_css_aa2.host.h" +#include "anr/anr_2/ia_css_anr2.host.h" +#include "cnr/cnr_2/ia_css_cnr2.host.h" +#include "de/de_2/ia_css_de2.host.h" +#include "gc/gc_2/ia_css_gc2.host.h" +#include "ynr/ynr_2/ia_css_ynr2.host.h" + +#define DPG_START "ia_css_debug_pipe_graph_dump_start " +#define DPG_END " ia_css_debug_pipe_graph_dump_end\n" + +#define ENABLE_LINE_MAX_LENGTH (25) + +/* + * TODO:SH_CSS_MAX_SP_THREADS is not the max number of sp threads + * future rework should fix this and remove the define MAX_THREAD_NUM + */ +#define MAX_THREAD_NUM (SH_CSS_MAX_SP_THREADS + SH_CSS_MAX_SP_INTERNAL_THREADS) + +static struct pipe_graph_class { + bool do_init; + int height; + int width; + int eff_height; + int eff_width; + enum atomisp_input_format stream_format; +} pg_inst = {true, 0, 0, 0, 0, N_ATOMISP_INPUT_FORMAT}; + +static const char *const queue_id_to_str[] = { + /* [SH_CSS_QUEUE_A_ID] =*/ "queue_A", + /* [SH_CSS_QUEUE_B_ID] =*/ "queue_B", + /* [SH_CSS_QUEUE_C_ID] =*/ "queue_C", + /* [SH_CSS_QUEUE_D_ID] =*/ "queue_D", + /* [SH_CSS_QUEUE_E_ID] =*/ "queue_E", + /* [SH_CSS_QUEUE_F_ID] =*/ "queue_F", + /* [SH_CSS_QUEUE_G_ID] =*/ "queue_G", + /* [SH_CSS_QUEUE_H_ID] =*/ "queue_H" +}; + +static const char *const pipe_id_to_str[] = { + /* [IA_CSS_PIPE_ID_PREVIEW] =*/ "preview", + /* [IA_CSS_PIPE_ID_COPY] =*/ "copy", + /* [IA_CSS_PIPE_ID_VIDEO] =*/ "video", + /* [IA_CSS_PIPE_ID_CAPTURE] =*/ "capture", + /* [IA_CSS_PIPE_ID_YUVPP] =*/ "yuvpp", + /* [IA_CSS_PIPE_ID_ACC] =*/ "accelerator" +}; + +static char dot_id_input_bin[SH_CSS_MAX_BINARY_NAME + 10]; +static char ring_buffer[200]; + +void ia_css_debug_dtrace(unsigned int level, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + ia_css_debug_vdtrace(level, fmt, ap); + va_end(ap); +} + +static void debug_dump_long_array_formatted( + const sp_ID_t sp_id, + hrt_address stack_sp_addr, + unsigned int stack_size) +{ + unsigned int i; + u32 val; + u32 addr = (uint32_t)stack_sp_addr; + u32 stack_size_words = CEIL_DIV(stack_size, sizeof(uint32_t)); + + /* When size is not multiple of four, last word is only relevant for + * remaining bytes */ + for (i = 0; i < stack_size_words; i++) { + val = sp_dmem_load_uint32(sp_id, (hrt_address)addr); + if ((i % 8) == 0) + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, "\n"); + + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, "0x%08x ", val); + addr += sizeof(uint32_t); + } + + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, "\n"); +} + +static void debug_dump_sp_stack_info( + const sp_ID_t sp_id) +{ + const struct ia_css_fw_info *fw; + unsigned int HIVE_ADDR_sp_threads_stack; + unsigned int HIVE_ADDR_sp_threads_stack_size; + u32 stack_sizes[MAX_THREAD_NUM]; + u32 stack_sp_addr[MAX_THREAD_NUM]; + unsigned int i; + + fw = &sh_css_sp_fw; + + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, "sp_id(%u) stack info\n", sp_id); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "from objects stack_addr_offset:0x%x stack_size_offset:0x%x\n", + fw->info.sp.threads_stack, + fw->info.sp.threads_stack_size); + + HIVE_ADDR_sp_threads_stack = fw->info.sp.threads_stack; + HIVE_ADDR_sp_threads_stack_size = fw->info.sp.threads_stack_size; + + if (fw->info.sp.threads_stack == 0 || + fw->info.sp.threads_stack_size == 0) + return; + + (void)HIVE_ADDR_sp_threads_stack; + (void)HIVE_ADDR_sp_threads_stack_size; + + sp_dmem_load(sp_id, + (unsigned int)sp_address_of(sp_threads_stack), + &stack_sp_addr, sizeof(stack_sp_addr)); + sp_dmem_load(sp_id, + (unsigned int)sp_address_of(sp_threads_stack_size), + &stack_sizes, sizeof(stack_sizes)); + + for (i = 0 ; i < MAX_THREAD_NUM; i++) { + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "thread: %u stack_addr: 0x%08x stack_size: %u\n", + i, stack_sp_addr[i], stack_sizes[i]); + debug_dump_long_array_formatted(sp_id, (hrt_address)stack_sp_addr[i], + stack_sizes[i]); + } +} + +void ia_css_debug_dump_sp_stack_info(void) +{ + debug_dump_sp_stack_info(SP0_ID); +} + +void ia_css_debug_set_dtrace_level(const unsigned int trace_level) +{ + dbg_level = trace_level; + return; +} + +unsigned int ia_css_debug_get_dtrace_level(void) +{ + return dbg_level; +} + +static const char *debug_stream_format2str(const enum atomisp_input_format + stream_format) +{ + switch (stream_format) { + case ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY: + return "yuv420-8-legacy"; + case ATOMISP_INPUT_FORMAT_YUV420_8: + return "yuv420-8"; + case ATOMISP_INPUT_FORMAT_YUV420_10: + return "yuv420-10"; + case ATOMISP_INPUT_FORMAT_YUV420_16: + return "yuv420-16"; + case ATOMISP_INPUT_FORMAT_YUV422_8: + return "yuv422-8"; + case ATOMISP_INPUT_FORMAT_YUV422_10: + return "yuv422-10"; + case ATOMISP_INPUT_FORMAT_YUV422_16: + return "yuv422-16"; + case ATOMISP_INPUT_FORMAT_RGB_444: + return "rgb444"; + case ATOMISP_INPUT_FORMAT_RGB_555: + return "rgb555"; + case ATOMISP_INPUT_FORMAT_RGB_565: + return "rgb565"; + case ATOMISP_INPUT_FORMAT_RGB_666: + return "rgb666"; + case ATOMISP_INPUT_FORMAT_RGB_888: + return "rgb888"; + case ATOMISP_INPUT_FORMAT_RAW_6: + return "raw6"; + case ATOMISP_INPUT_FORMAT_RAW_7: + return "raw7"; + case ATOMISP_INPUT_FORMAT_RAW_8: + return "raw8"; + case ATOMISP_INPUT_FORMAT_RAW_10: + return "raw10"; + case ATOMISP_INPUT_FORMAT_RAW_12: + return "raw12"; + case ATOMISP_INPUT_FORMAT_RAW_14: + return "raw14"; + case ATOMISP_INPUT_FORMAT_RAW_16: + return "raw16"; + case ATOMISP_INPUT_FORMAT_BINARY_8: + return "binary8"; + case ATOMISP_INPUT_FORMAT_GENERIC_SHORT1: + return "generic-short1"; + case ATOMISP_INPUT_FORMAT_GENERIC_SHORT2: + return "generic-short2"; + case ATOMISP_INPUT_FORMAT_GENERIC_SHORT3: + return "generic-short3"; + case ATOMISP_INPUT_FORMAT_GENERIC_SHORT4: + return "generic-short4"; + case ATOMISP_INPUT_FORMAT_GENERIC_SHORT5: + return "generic-short5"; + case ATOMISP_INPUT_FORMAT_GENERIC_SHORT6: + return "generic-short6"; + case ATOMISP_INPUT_FORMAT_GENERIC_SHORT7: + return "generic-short7"; + case ATOMISP_INPUT_FORMAT_GENERIC_SHORT8: + return "generic-short8"; + case ATOMISP_INPUT_FORMAT_YUV420_8_SHIFT: + return "yuv420-8-shift"; + case ATOMISP_INPUT_FORMAT_YUV420_10_SHIFT: + return "yuv420-10-shift"; + case ATOMISP_INPUT_FORMAT_EMBEDDED: + return "embedded-8"; + case ATOMISP_INPUT_FORMAT_USER_DEF1: + return "user-def-8-type-1"; + case ATOMISP_INPUT_FORMAT_USER_DEF2: + return "user-def-8-type-2"; + case ATOMISP_INPUT_FORMAT_USER_DEF3: + return "user-def-8-type-3"; + case ATOMISP_INPUT_FORMAT_USER_DEF4: + return "user-def-8-type-4"; + case ATOMISP_INPUT_FORMAT_USER_DEF5: + return "user-def-8-type-5"; + case ATOMISP_INPUT_FORMAT_USER_DEF6: + return "user-def-8-type-6"; + case ATOMISP_INPUT_FORMAT_USER_DEF7: + return "user-def-8-type-7"; + case ATOMISP_INPUT_FORMAT_USER_DEF8: + return "user-def-8-type-8"; + + default: + assert(!"Unknown stream format"); + return "unknown-stream-format"; + } +}; + +static const char *debug_frame_format2str(const enum ia_css_frame_format + frame_format) +{ + switch (frame_format) { + case IA_CSS_FRAME_FORMAT_NV11: + return "NV11"; + case IA_CSS_FRAME_FORMAT_NV12: + return "NV12"; + case IA_CSS_FRAME_FORMAT_NV12_16: + return "NV12_16"; + case IA_CSS_FRAME_FORMAT_NV12_TILEY: + return "NV12_TILEY"; + case IA_CSS_FRAME_FORMAT_NV16: + return "NV16"; + case IA_CSS_FRAME_FORMAT_NV21: + return "NV21"; + case IA_CSS_FRAME_FORMAT_NV61: + return "NV61"; + case IA_CSS_FRAME_FORMAT_YV12: + return "YV12"; + case IA_CSS_FRAME_FORMAT_YV16: + return "YV16"; + case IA_CSS_FRAME_FORMAT_YUV420: + return "YUV420"; + case IA_CSS_FRAME_FORMAT_YUV420_16: + return "YUV420_16"; + case IA_CSS_FRAME_FORMAT_YUV422: + return "YUV422"; + case IA_CSS_FRAME_FORMAT_YUV422_16: + return "YUV422_16"; + case IA_CSS_FRAME_FORMAT_UYVY: + return "UYVY"; + case IA_CSS_FRAME_FORMAT_YUYV: + return "YUYV"; + case IA_CSS_FRAME_FORMAT_YUV444: + return "YUV444"; + case IA_CSS_FRAME_FORMAT_YUV_LINE: + return "YUV_LINE"; + case IA_CSS_FRAME_FORMAT_RAW: + return "RAW"; + case IA_CSS_FRAME_FORMAT_RGB565: + return "RGB565"; + case IA_CSS_FRAME_FORMAT_PLANAR_RGB888: + return "PLANAR_RGB888"; + case IA_CSS_FRAME_FORMAT_RGBA888: + return "RGBA888"; + case IA_CSS_FRAME_FORMAT_QPLANE6: + return "QPLANE6"; + case IA_CSS_FRAME_FORMAT_BINARY_8: + return "BINARY_8"; + case IA_CSS_FRAME_FORMAT_MIPI: + return "MIPI"; + case IA_CSS_FRAME_FORMAT_RAW_PACKED: + return "RAW_PACKED"; + case IA_CSS_FRAME_FORMAT_CSI_MIPI_YUV420_8: + return "CSI_MIPI_YUV420_8"; + case IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8: + return "CSI_MIPI_LEGACY_YUV420_8"; + case IA_CSS_FRAME_FORMAT_CSI_MIPI_YUV420_10: + return "CSI_MIPI_YUV420_10"; + + default: + assert(!"Unknown frame format"); + return "unknown-frame-format"; + } +} + +static void debug_print_sp_state(const sp_state_t *state, const char *cell) +{ + assert(cell); + assert(state); + + ia_css_debug_dtrace(2, "%s state:\n", cell); + ia_css_debug_dtrace(2, "\t%-32s: 0x%X\n", "PC", state->pc); + ia_css_debug_dtrace(2, "\t%-32s: 0x%X\n", "Status register", + state->status_register); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "Is broken", state->is_broken); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "Is idle", state->is_idle); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "Is sleeping", + state->is_sleeping); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "Is stalling", + state->is_stalling); + return; +} + +static void debug_print_isp_state(const isp_state_t *state, const char *cell) +{ + assert(state); + assert(cell); + + ia_css_debug_dtrace(2, "%s state:\n", cell); + ia_css_debug_dtrace(2, "\t%-32s: 0x%X\n", "PC", state->pc); + ia_css_debug_dtrace(2, "\t%-32s: 0x%X\n", "Status register", + state->status_register); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "Is broken", state->is_broken); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "Is idle", state->is_idle); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "Is sleeping", + state->is_sleeping); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "Is stalling", + state->is_stalling); + return; +} + +void ia_css_debug_dump_isp_state(void) +{ + isp_state_t state; + isp_stall_t stall; + + isp_get_state(ISP0_ID, &state, &stall); + + debug_print_isp_state(&state, "ISP"); + + if (state.is_stalling) { + if (!IS_ISP2401) { + ia_css_debug_dtrace(2, "\t%-32s: %d\n", + "[0] if_prim_a_FIFO stalled", stall.fifo0); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", + "[1] if_prim_b_FIFO stalled", stall.fifo1); + } + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "[2] dma_FIFO stalled", + stall.fifo2); + + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "[3] gdc0_FIFO stalled", + stall.fifo3); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "[4] gdc1_FIFO stalled", + stall.fifo4); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "[5] gpio_FIFO stalled", + stall.fifo5); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "[6] sp_FIFO stalled", + stall.fifo6); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", + "status & control stalled", + stall.stat_ctrl); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "dmem stalled", + stall.dmem); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "vmem stalled", + stall.vmem); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "vamem1 stalled", + stall.vamem1); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "vamem2 stalled", + stall.vamem2); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "vamem3 stalled", + stall.vamem3); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "hmem stalled", + stall.hmem); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "pmem stalled", + stall.pmem); + } + return; +} + +void ia_css_debug_dump_sp_state(void) +{ + sp_state_t state; + sp_stall_t stall; + + sp_get_state(SP0_ID, &state, &stall); + debug_print_sp_state(&state, "SP"); + if (state.is_stalling) { + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "isys_FIFO stalled", + stall.fifo0); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "if_sec_FIFO stalled", + stall.fifo1); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", + "str_to_mem_FIFO stalled", stall.fifo2); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "dma_FIFO stalled", + stall.fifo3); + if (!IS_ISP2401) + ia_css_debug_dtrace(2, "\t%-32s: %d\n", + "if_prim_a_FIFO stalled", stall.fifo4); + + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "isp_FIFO stalled", + stall.fifo5); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "gp_FIFO stalled", + stall.fifo6); + if (!IS_ISP2401) + ia_css_debug_dtrace(2, "\t%-32s: %d\n", + "if_prim_b_FIFO stalled", stall.fifo7); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "gdc0_FIFO stalled", + stall.fifo8); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "gdc1_FIFO stalled", + stall.fifo9); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "irq FIFO stalled", + stall.fifoa); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "dmem stalled", + stall.dmem); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", + "control master stalled", + stall.control_master); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", + "i-cache master stalled", + stall.icache_master); + } + ia_css_debug_dump_trace(); + return; +} + +static void debug_print_fifo_channel_state(const fifo_channel_state_t *state, + const char *descr) +{ + assert(state); + assert(descr); + + ia_css_debug_dtrace(2, "FIFO channel: %s\n", descr); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "source valid", + state->src_valid); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "fifo accept", + state->fifo_accept); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "fifo valid", + state->fifo_valid); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "sink accept", + state->sink_accept); + return; +} + +void ia_css_debug_dump_pif_a_isp_fifo_state(void) +{ + fifo_channel_state_t pif_to_isp, isp_to_pif; + + fifo_channel_get_state(FIFO_MONITOR0_ID, + FIFO_CHANNEL_IF0_TO_ISP0, &pif_to_isp); + fifo_channel_get_state(FIFO_MONITOR0_ID, + FIFO_CHANNEL_ISP0_TO_IF0, &isp_to_pif); + debug_print_fifo_channel_state(&pif_to_isp, "Primary IF A to ISP"); + debug_print_fifo_channel_state(&isp_to_pif, "ISP to Primary IF A"); +} + +void ia_css_debug_dump_pif_b_isp_fifo_state(void) +{ + fifo_channel_state_t pif_to_isp, isp_to_pif; + + fifo_channel_get_state(FIFO_MONITOR0_ID, + FIFO_CHANNEL_IF1_TO_ISP0, &pif_to_isp); + fifo_channel_get_state(FIFO_MONITOR0_ID, + FIFO_CHANNEL_ISP0_TO_IF1, &isp_to_pif); + debug_print_fifo_channel_state(&pif_to_isp, "Primary IF B to ISP"); + debug_print_fifo_channel_state(&isp_to_pif, "ISP to Primary IF B"); +} + +void ia_css_debug_dump_str2mem_sp_fifo_state(void) +{ + fifo_channel_state_t s2m_to_sp, sp_to_s2m; + + fifo_channel_get_state(FIFO_MONITOR0_ID, + FIFO_CHANNEL_STREAM2MEM0_TO_SP0, &s2m_to_sp); + fifo_channel_get_state(FIFO_MONITOR0_ID, + FIFO_CHANNEL_SP0_TO_STREAM2MEM0, &sp_to_s2m); + debug_print_fifo_channel_state(&s2m_to_sp, "Stream-to-memory to SP"); + debug_print_fifo_channel_state(&sp_to_s2m, "SP to stream-to-memory"); +} + +#ifndef ISP2401 +static void debug_print_if_state(input_formatter_state_t *state, const char *id) +{ + unsigned int val; + + const char *st_vsync_active_low = + (state->vsync_active_low ? "low" : "high"); + const char *st_hsync_active_low = + (state->hsync_active_low ? "low" : "high"); + + const char *fsm_sync_status_str = "unknown"; + const char *fsm_crop_status_str = "unknown"; + const char *fsm_padding_status_str = "unknown"; + + int st_stline = state->start_line; + int st_stcol = state->start_column; + int st_crpht = state->cropped_height; + int st_crpwd = state->cropped_width; + int st_verdcm = state->ver_decimation; + int st_hordcm = state->hor_decimation; + int st_ver_deinterleaving = state->ver_deinterleaving; + int st_hor_deinterleaving = state->hor_deinterleaving; + int st_leftpd = state->left_padding; + int st_eoloff = state->eol_offset; + int st_vmstartaddr = state->vmem_start_address; + int st_vmendaddr = state->vmem_end_address; + int st_vmincr = state->vmem_increment; + int st_yuv420 = state->is_yuv420; + int st_allow_fifo_overflow = state->allow_fifo_overflow; + int st_block_fifo_when_no_req = state->block_fifo_when_no_req; + + assert(state); + ia_css_debug_dtrace(2, "InputFormatter State (%s):\n", id); + + ia_css_debug_dtrace(2, "\tConfiguration:\n"); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Start line", st_stline); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Start column", st_stcol); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Cropped height", st_crpht); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Cropped width", st_crpwd); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Ver decimation", st_verdcm); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Hor decimation", st_hordcm); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "Ver deinterleaving", st_ver_deinterleaving); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "Hor deinterleaving", st_hor_deinterleaving); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Left padding", st_leftpd); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "EOL offset (bytes)", st_eoloff); + ia_css_debug_dtrace(2, "\t\t%-32s: 0x%06X\n", + "VMEM start address", st_vmstartaddr); + ia_css_debug_dtrace(2, "\t\t%-32s: 0x%06X\n", + "VMEM end address", st_vmendaddr); + ia_css_debug_dtrace(2, "\t\t%-32s: 0x%06X\n", + "VMEM increment", st_vmincr); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "YUV 420 format", st_yuv420); + ia_css_debug_dtrace(2, "\t\t%-32s: Active %s\n", + "Vsync", st_vsync_active_low); + ia_css_debug_dtrace(2, "\t\t%-32s: Active %s\n", + "Hsync", st_hsync_active_low); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "Allow FIFO overflow", st_allow_fifo_overflow); + /* Flag that tells whether the IF gives backpressure on frames */ + /* + * FYI, this is only on the frame request (indicate), when the IF has + * synch'd on a frame it will always give back pressure + */ + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "Block when no request", st_block_fifo_when_no_req); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "IF_BLOCKED_FIFO_NO_REQ_ADDRESS", + input_formatter_reg_load(INPUT_FORMATTER0_ID, + HIVE_IF_BLOCK_FIFO_NO_REQ_ADDRESS) + ); + + ia_css_debug_dtrace(2, "\t%-32s:\n", "InputSwitch State"); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "_REG_GP_IFMT_input_switch_lut_reg0", + gp_device_reg_load(GP_DEVICE0_ID, + _REG_GP_IFMT_input_switch_lut_reg0)); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "_REG_GP_IFMT_input_switch_lut_reg1", + gp_device_reg_load(GP_DEVICE0_ID, + _REG_GP_IFMT_input_switch_lut_reg1)); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "_REG_GP_IFMT_input_switch_lut_reg2", + gp_device_reg_load(GP_DEVICE0_ID, + _REG_GP_IFMT_input_switch_lut_reg2)); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "_REG_GP_IFMT_input_switch_lut_reg3", + gp_device_reg_load(GP_DEVICE0_ID, + _REG_GP_IFMT_input_switch_lut_reg3)); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "_REG_GP_IFMT_input_switch_lut_reg4", + gp_device_reg_load(GP_DEVICE0_ID, + _REG_GP_IFMT_input_switch_lut_reg4)); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "_REG_GP_IFMT_input_switch_lut_reg5", + gp_device_reg_load(GP_DEVICE0_ID, + _REG_GP_IFMT_input_switch_lut_reg5)); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "_REG_GP_IFMT_input_switch_lut_reg6", + gp_device_reg_load(GP_DEVICE0_ID, + _REG_GP_IFMT_input_switch_lut_reg6)); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "_REG_GP_IFMT_input_switch_lut_reg7", + gp_device_reg_load(GP_DEVICE0_ID, + _REG_GP_IFMT_input_switch_lut_reg7)); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "_REG_GP_IFMT_input_switch_fsync_lut", + gp_device_reg_load(GP_DEVICE0_ID, + _REG_GP_IFMT_input_switch_fsync_lut)); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "_REG_GP_IFMT_srst", + gp_device_reg_load(GP_DEVICE0_ID, + _REG_GP_IFMT_srst)); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "_REG_GP_IFMT_slv_reg_srst", + gp_device_reg_load(GP_DEVICE0_ID, + _REG_GP_IFMT_slv_reg_srst)); + + ia_css_debug_dtrace(2, "\tFSM Status:\n"); + + val = state->fsm_sync_status; + + if (val > 7) + fsm_sync_status_str = "ERROR"; + + switch (val & 0x7) { + case 0: + fsm_sync_status_str = "idle"; + break; + case 1: + fsm_sync_status_str = "request frame"; + break; + case 2: + fsm_sync_status_str = "request lines"; + break; + case 3: + fsm_sync_status_str = "request vectors"; + break; + case 4: + fsm_sync_status_str = "send acknowledge"; + break; + default: + fsm_sync_status_str = "unknown"; + break; + } + + ia_css_debug_dtrace(2, "\t\t%-32s: (0x%X: %s)\n", + "FSM Synchronization Status", val, + fsm_sync_status_str); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "FSM Synchronization Counter", + state->fsm_sync_counter); + + val = state->fsm_crop_status; + + if (val > 7) + fsm_crop_status_str = "ERROR"; + + switch (val & 0x7) { + case 0: + fsm_crop_status_str = "idle"; + break; + case 1: + fsm_crop_status_str = "wait line"; + break; + case 2: + fsm_crop_status_str = "crop line"; + break; + case 3: + fsm_crop_status_str = "crop pixel"; + break; + case 4: + fsm_crop_status_str = "pass pixel"; + break; + case 5: + fsm_crop_status_str = "pass line"; + break; + case 6: + fsm_crop_status_str = "lost line"; + break; + default: + fsm_crop_status_str = "unknown"; + break; + } + ia_css_debug_dtrace(2, "\t\t%-32s: (0x%X: %s)\n", + "FSM Crop Status", val, fsm_crop_status_str); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "FSM Crop Line Counter", + state->fsm_crop_line_counter); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "FSM Crop Pixel Counter", + state->fsm_crop_pixel_counter); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "FSM Deinterleaving idx buffer", + state->fsm_deinterleaving_index); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "FSM H decimation counter", + state->fsm_dec_h_counter); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "FSM V decimation counter", + state->fsm_dec_v_counter); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "FSM block V decimation counter", + state->fsm_dec_block_v_counter); + + val = state->fsm_padding_status; + + if (val > 7) + fsm_padding_status_str = "ERROR"; + + switch (val & 0x7) { + case 0: + fsm_padding_status_str = "idle"; + break; + case 1: + fsm_padding_status_str = "left pad"; + break; + case 2: + fsm_padding_status_str = "write"; + break; + case 3: + fsm_padding_status_str = "right pad"; + break; + case 4: + fsm_padding_status_str = "send end of line"; + break; + default: + fsm_padding_status_str = "unknown"; + break; + } + + ia_css_debug_dtrace(2, "\t\t%-32s: (0x%X: %s)\n", "FSM Padding Status", + val, fsm_padding_status_str); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "FSM Padding element idx counter", + state->fsm_padding_elem_counter); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Vector support error", + state->fsm_vector_support_error); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Vector support buf full", + state->fsm_vector_buffer_full); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Vector support", + state->vector_support); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Fifo sensor data lost", + state->sensor_data_lost); +} + +static void debug_print_if_bin_state(input_formatter_bin_state_t *state) +{ + ia_css_debug_dtrace(2, "Stream-to-memory state:\n"); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "reset", state->reset); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "input endianness", + state->input_endianness); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "output endianness", + state->output_endianness); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "bitswap", state->bitswap); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "block_synch", + state->block_synch); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "packet_synch", + state->packet_synch); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "readpostwrite_sync", + state->readpostwrite_synch); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "is_2ppc", state->is_2ppc); + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "en_status_update", + state->en_status_update); +} + +static void ia_css_debug_dump_if_state(void) +{ + input_formatter_state_t if_state; + input_formatter_bin_state_t if_bin_state; + + input_formatter_get_state(INPUT_FORMATTER0_ID, &if_state); + debug_print_if_state(&if_state, "Primary IF A"); + ia_css_debug_dump_pif_a_isp_fifo_state(); + + input_formatter_get_state(INPUT_FORMATTER1_ID, &if_state); + debug_print_if_state(&if_state, "Primary IF B"); + ia_css_debug_dump_pif_b_isp_fifo_state(); + + input_formatter_bin_get_state(INPUT_FORMATTER3_ID, &if_bin_state); + debug_print_if_bin_state(&if_bin_state); + ia_css_debug_dump_str2mem_sp_fifo_state(); +} +#endif + +void ia_css_debug_dump_dma_state(void) +{ + /* note: the var below is made static as it is quite large; + if it is not static it ends up on the stack which could + cause issues for drivers + */ + static dma_state_t state; + int i, ch_id; + + const char *fsm_cmd_st_lbl = "FSM Command flag state"; + const char *fsm_ctl_st_lbl = "FSM Control flag state"; + const char *fsm_ctl_state = NULL; + const char *fsm_ctl_flag = NULL; + const char *fsm_pack_st = NULL; + const char *fsm_read_st = NULL; + const char *fsm_write_st = NULL; + char last_cmd_str[64]; + + dma_get_state(DMA0_ID, &state); + /* Print header for DMA dump status */ + ia_css_debug_dtrace(2, "DMA dump status:\n"); + + /* Print FSM command flag state */ + if (state.fsm_command_idle) + ia_css_debug_dtrace(2, "\t%-32s: %s\n", fsm_cmd_st_lbl, "IDLE"); + if (state.fsm_command_run) + ia_css_debug_dtrace(2, "\t%-32s: %s\n", fsm_cmd_st_lbl, "RUN"); + if (state.fsm_command_stalling) + ia_css_debug_dtrace(2, "\t%-32s: %s\n", fsm_cmd_st_lbl, + "STALL"); + if (state.fsm_command_error) + ia_css_debug_dtrace(2, "\t%-32s: %s\n", fsm_cmd_st_lbl, + "ERROR"); + + /* Print last command along with the channel */ + ch_id = state.last_command_channel; + + switch (state.last_command) { + case DMA_COMMAND_READ: + snprintf(last_cmd_str, 64, + "Read 2D Block [Channel: %d]", ch_id); + break; + case DMA_COMMAND_WRITE: + snprintf(last_cmd_str, 64, + "Write 2D Block [Channel: %d]", ch_id); + break; + case DMA_COMMAND_SET_CHANNEL: + snprintf(last_cmd_str, 64, "Set Channel [Channel: %d]", ch_id); + break; + case DMA_COMMAND_SET_PARAM: + snprintf(last_cmd_str, 64, + "Set Param: %d [Channel: %d]", + state.last_command_param, ch_id); + break; + case DMA_COMMAND_READ_SPECIFIC: + snprintf(last_cmd_str, 64, + "Read Specific 2D Block [Channel: %d]", ch_id); + break; + case DMA_COMMAND_WRITE_SPECIFIC: + snprintf(last_cmd_str, 64, + "Write Specific 2D Block [Channel: %d]", ch_id); + break; + case DMA_COMMAND_INIT: + snprintf(last_cmd_str, 64, + "Init 2D Block on Device A [Channel: %d]", ch_id); + break; + case DMA_COMMAND_INIT_SPECIFIC: + snprintf(last_cmd_str, 64, + "Init Specific 2D Block [Channel: %d]", ch_id); + break; + case DMA_COMMAND_RST: + snprintf(last_cmd_str, 64, "DMA SW Reset"); + break; + case N_DMA_COMMANDS: + snprintf(last_cmd_str, 64, "UNKNOWN"); + break; + default: + snprintf(last_cmd_str, 64, + "unknown [Channel: %d]", ch_id); + break; + } + ia_css_debug_dtrace(2, "\t%-32s: (0x%X : %s)\n", + "last command received", state.last_command, + last_cmd_str); + + /* Print DMA registers */ + ia_css_debug_dtrace(2, "\t%-32s\n", + "DMA registers, connection group 0"); + ia_css_debug_dtrace(2, "\t\t%-32s: 0x%X\n", "Cmd Fifo Command", + state.current_command); + ia_css_debug_dtrace(2, "\t\t%-32s: 0x%X\n", "Cmd Fifo Address A", + state.current_addr_a); + ia_css_debug_dtrace(2, "\t\t%-32s: 0x%X\n", "Cmd Fifo Address B", + state.current_addr_b); + + if (state.fsm_ctrl_idle) + fsm_ctl_flag = "IDLE"; + else if (state.fsm_ctrl_run) + fsm_ctl_flag = "RUN"; + else if (state.fsm_ctrl_stalling) + fsm_ctl_flag = "STAL"; + else if (state.fsm_ctrl_error) + fsm_ctl_flag = "ERROR"; + else + fsm_ctl_flag = "UNKNOWN"; + + switch (state.fsm_ctrl_state) { + case DMA_CTRL_STATE_IDLE: + fsm_ctl_state = "Idle state"; + break; + case DMA_CTRL_STATE_REQ_RCV: + fsm_ctl_state = "Req Rcv state"; + break; + case DMA_CTRL_STATE_RCV: + fsm_ctl_state = "Rcv state"; + break; + case DMA_CTRL_STATE_RCV_REQ: + fsm_ctl_state = "Rcv Req state"; + break; + case DMA_CTRL_STATE_INIT: + fsm_ctl_state = "Init state"; + break; + case N_DMA_CTRL_STATES: + fsm_ctl_state = "Unknown"; + break; + } + + ia_css_debug_dtrace(2, "\t\t%-32s: %s -> %s\n", fsm_ctl_st_lbl, + fsm_ctl_flag, fsm_ctl_state); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Ctrl source dev", + state.fsm_ctrl_source_dev); + ia_css_debug_dtrace(2, "\t\t%-32s: 0x%X\n", "FSM Ctrl source addr", + state.fsm_ctrl_source_addr); + ia_css_debug_dtrace(2, "\t\t%-32s: 0x%X\n", "FSM Ctrl source stride", + state.fsm_ctrl_source_stride); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Ctrl source width", + state.fsm_ctrl_source_width); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Ctrl source height", + state.fsm_ctrl_source_height); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Ctrl pack source dev", + state.fsm_ctrl_pack_source_dev); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Ctrl pack dest dev", + state.fsm_ctrl_pack_dest_dev); + ia_css_debug_dtrace(2, "\t\t%-32s: 0x%X\n", "FSM Ctrl dest addr", + state.fsm_ctrl_dest_addr); + ia_css_debug_dtrace(2, "\t\t%-32s: 0x%X\n", "FSM Ctrl dest stride", + state.fsm_ctrl_dest_stride); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Ctrl pack source width", + state.fsm_ctrl_pack_source_width); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Ctrl pack dest height", + state.fsm_ctrl_pack_dest_height); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Ctrl pack dest width", + state.fsm_ctrl_pack_dest_width); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Ctrl pack source elems", + state.fsm_ctrl_pack_source_elems); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Ctrl pack dest elems", + state.fsm_ctrl_pack_dest_elems); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Ctrl pack extension", + state.fsm_ctrl_pack_extension); + + if (state.pack_idle) + fsm_pack_st = "IDLE"; + if (state.pack_run) + fsm_pack_st = "RUN"; + if (state.pack_stalling) + fsm_pack_st = "STALL"; + if (state.pack_error) + fsm_pack_st = "ERROR"; + + ia_css_debug_dtrace(2, "\t\t%-32s: %s\n", "FSM Pack flag state", + fsm_pack_st); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Pack cnt height", + state.pack_cnt_height); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Pack src cnt width", + state.pack_src_cnt_width); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Pack dest cnt width", + state.pack_dest_cnt_width); + + if (state.read_state == DMA_RW_STATE_IDLE) + fsm_read_st = "Idle state"; + if (state.read_state == DMA_RW_STATE_REQ) + fsm_read_st = "Req state"; + if (state.read_state == DMA_RW_STATE_NEXT_LINE) + fsm_read_st = "Next line"; + if (state.read_state == DMA_RW_STATE_UNLOCK_CHANNEL) + fsm_read_st = "Unlock channel"; + + ia_css_debug_dtrace(2, "\t\t%-32s: %s\n", "FSM Read state", + fsm_read_st); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Read cnt height", + state.read_cnt_height); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Read cnt width", + state.read_cnt_width); + + if (state.write_state == DMA_RW_STATE_IDLE) + fsm_write_st = "Idle state"; + if (state.write_state == DMA_RW_STATE_REQ) + fsm_write_st = "Req state"; + if (state.write_state == DMA_RW_STATE_NEXT_LINE) + fsm_write_st = "Next line"; + if (state.write_state == DMA_RW_STATE_UNLOCK_CHANNEL) + fsm_write_st = "Unlock channel"; + + ia_css_debug_dtrace(2, "\t\t%-32s: %s\n", "FSM Write state", + fsm_write_st); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Write height", + state.write_height); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "FSM Write width", + state.write_width); + + for (i = 0; i < HIVE_ISP_NUM_DMA_CONNS; i++) { + dma_port_state_t *port = &state.port_states[i]; + + ia_css_debug_dtrace(2, "\tDMA device interface %d\n", i); + ia_css_debug_dtrace(2, "\t\tDMA internal side state\n"); + ia_css_debug_dtrace(2, + "\t\t\tCS:%d - We_n:%d - Run:%d - Ack:%d\n", + port->req_cs, port->req_we_n, port->req_run, + port->req_ack); + ia_css_debug_dtrace(2, "\t\tMaster Output side state\n"); + ia_css_debug_dtrace(2, + "\t\t\tCS:%d - We_n:%d - Run:%d - Ack:%d\n", + port->send_cs, port->send_we_n, + port->send_run, port->send_ack); + ia_css_debug_dtrace(2, "\t\tFifo state\n"); + if (port->fifo_state == DMA_FIFO_STATE_WILL_BE_FULL) + ia_css_debug_dtrace(2, "\t\t\tFiFo will be full\n"); + else if (port->fifo_state == DMA_FIFO_STATE_FULL) + ia_css_debug_dtrace(2, "\t\t\tFifo Full\n"); + else if (port->fifo_state == DMA_FIFO_STATE_EMPTY) + ia_css_debug_dtrace(2, "\t\t\tFifo Empty\n"); + else + ia_css_debug_dtrace(2, "\t\t\tFifo state unknown\n"); + + ia_css_debug_dtrace(2, "\t\tFifo counter %d\n\n", + port->fifo_counter); + } + + for (i = 0; i < HIVE_DMA_NUM_CHANNELS; i++) { + dma_channel_state_t *ch = &state.channel_states[i]; + + ia_css_debug_dtrace(2, "\t%-32s: %d\n", "DMA channel register", + i); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Connection", + ch->connection); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Sign extend", + ch->sign_extend); + ia_css_debug_dtrace(2, "\t\t%-32s: 0x%X\n", "Stride Dev A", + ch->stride_a); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Elems Dev A", + ch->elems_a); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Cropping Dev A", + ch->cropping_a); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Width Dev A", + ch->width_a); + ia_css_debug_dtrace(2, "\t\t%-32s: 0x%X\n", "Stride Dev B", + ch->stride_b); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Elems Dev B", + ch->elems_b); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Cropping Dev B", + ch->cropping_b); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Width Dev B", + ch->width_b); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "Height", ch->height); + } + ia_css_debug_dtrace(2, "\n"); + return; +} + +void ia_css_debug_dump_dma_sp_fifo_state(void) +{ + fifo_channel_state_t dma_to_sp, sp_to_dma; + + fifo_channel_get_state(FIFO_MONITOR0_ID, + FIFO_CHANNEL_DMA0_TO_SP0, &dma_to_sp); + fifo_channel_get_state(FIFO_MONITOR0_ID, + FIFO_CHANNEL_SP0_TO_DMA0, &sp_to_dma); + debug_print_fifo_channel_state(&dma_to_sp, "DMA to SP"); + debug_print_fifo_channel_state(&sp_to_dma, "SP to DMA"); + return; +} + +void ia_css_debug_dump_dma_isp_fifo_state(void) +{ + fifo_channel_state_t dma_to_isp, isp_to_dma; + + fifo_channel_get_state(FIFO_MONITOR0_ID, + FIFO_CHANNEL_DMA0_TO_ISP0, &dma_to_isp); + fifo_channel_get_state(FIFO_MONITOR0_ID, + FIFO_CHANNEL_ISP0_TO_DMA0, &isp_to_dma); + debug_print_fifo_channel_state(&dma_to_isp, "DMA to ISP"); + debug_print_fifo_channel_state(&isp_to_dma, "ISP to DMA"); + return; +} + +void ia_css_debug_dump_isp_sp_fifo_state(void) +{ + fifo_channel_state_t sp_to_isp, isp_to_sp; + + fifo_channel_get_state(FIFO_MONITOR0_ID, + FIFO_CHANNEL_SP0_TO_ISP0, &sp_to_isp); + fifo_channel_get_state(FIFO_MONITOR0_ID, + FIFO_CHANNEL_ISP0_TO_SP0, &isp_to_sp); + debug_print_fifo_channel_state(&sp_to_isp, "SP to ISP"); + debug_print_fifo_channel_state(&isp_to_sp, "ISP to SP"); + return; +} + +void ia_css_debug_dump_isp_gdc_fifo_state(void) +{ + fifo_channel_state_t gdc_to_isp, isp_to_gdc; + + fifo_channel_get_state(FIFO_MONITOR0_ID, + FIFO_CHANNEL_GDC0_TO_ISP0, &gdc_to_isp); + fifo_channel_get_state(FIFO_MONITOR0_ID, + FIFO_CHANNEL_ISP0_TO_GDC0, &isp_to_gdc); + debug_print_fifo_channel_state(&gdc_to_isp, "GDC to ISP"); + debug_print_fifo_channel_state(&isp_to_gdc, "ISP to GDC"); + return; +} + +void ia_css_debug_dump_all_fifo_state(void) +{ + int i; + fifo_monitor_state_t state; + + fifo_monitor_get_state(FIFO_MONITOR0_ID, &state); + + for (i = 0; i < N_FIFO_CHANNEL; i++) + debug_print_fifo_channel_state(&state.fifo_channels[i], + "squepfstqkt"); + return; +} + +static void debug_binary_info_print(const struct ia_css_binary_xinfo *info) +{ + assert(info); + ia_css_debug_dtrace(2, "id = %d\n", info->sp.id); + ia_css_debug_dtrace(2, "mode = %d\n", info->sp.pipeline.mode); + ia_css_debug_dtrace(2, "max_input_width = %d\n", info->sp.input.max_width); + ia_css_debug_dtrace(2, "min_output_width = %d\n", + info->sp.output.min_width); + ia_css_debug_dtrace(2, "max_output_width = %d\n", + info->sp.output.max_width); + ia_css_debug_dtrace(2, "top_cropping = %d\n", info->sp.pipeline.top_cropping); + ia_css_debug_dtrace(2, "left_cropping = %d\n", info->sp.pipeline.left_cropping); + ia_css_debug_dtrace(2, "xmem_addr = %d\n", info->xmem_addr); + ia_css_debug_dtrace(2, "enable_vf_veceven = %d\n", + info->sp.enable.vf_veceven); + ia_css_debug_dtrace(2, "enable_dis = %d\n", info->sp.enable.dis); + ia_css_debug_dtrace(2, "enable_uds = %d\n", info->sp.enable.uds); + ia_css_debug_dtrace(2, "enable ds = %d\n", info->sp.enable.ds); + ia_css_debug_dtrace(2, "s3atbl_use_dmem = %d\n", info->sp.s3a.s3atbl_use_dmem); + return; +} + +void ia_css_debug_binary_print(const struct ia_css_binary *bi) +{ + unsigned int i; + + debug_binary_info_print(bi->info); + ia_css_debug_dtrace(2, + "input: %dx%d, format = %d, padded width = %d\n", + bi->in_frame_info.res.width, + bi->in_frame_info.res.height, + bi->in_frame_info.format, + bi->in_frame_info.padded_width); + ia_css_debug_dtrace(2, + "internal :%dx%d, format = %d, padded width = %d\n", + bi->internal_frame_info.res.width, + bi->internal_frame_info.res.height, + bi->internal_frame_info.format, + bi->internal_frame_info.padded_width); + for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) { + if (bi->out_frame_info[i].res.width != 0) { + ia_css_debug_dtrace(2, + "out%d: %dx%d, format = %d, padded width = %d\n", + i, + bi->out_frame_info[i].res.width, + bi->out_frame_info[i].res.height, + bi->out_frame_info[i].format, + bi->out_frame_info[i].padded_width); + } + } + ia_css_debug_dtrace(2, + "vf out: %dx%d, format = %d, padded width = %d\n", + bi->vf_frame_info.res.width, + bi->vf_frame_info.res.height, + bi->vf_frame_info.format, + bi->vf_frame_info.padded_width); + ia_css_debug_dtrace(2, "online = %d\n", bi->online); + ia_css_debug_dtrace(2, "input_buf_vectors = %d\n", + bi->input_buf_vectors); + ia_css_debug_dtrace(2, "deci_factor_log2 = %d\n", bi->deci_factor_log2); + ia_css_debug_dtrace(2, "vf_downscale_log2 = %d\n", + bi->vf_downscale_log2); + ia_css_debug_dtrace(2, "dis_deci_factor_log2 = %d\n", + bi->dis.deci_factor_log2); + ia_css_debug_dtrace(2, "dis hor coef num = %d\n", + bi->dis.coef.pad.width); + ia_css_debug_dtrace(2, "dis ver coef num = %d\n", + bi->dis.coef.pad.height); + ia_css_debug_dtrace(2, "dis hor proj num = %d\n", + bi->dis.proj.pad.height); + ia_css_debug_dtrace(2, "sctbl_width_per_color = %d\n", + bi->sctbl_width_per_color); + ia_css_debug_dtrace(2, "s3atbl_width = %d\n", bi->s3atbl_width); + ia_css_debug_dtrace(2, "s3atbl_height = %d\n", bi->s3atbl_height); + return; +} + +void ia_css_debug_frame_print(const struct ia_css_frame *frame, + const char *descr) +{ + char *data = NULL; + + assert(frame); + assert(descr); + + data = (char *)HOST_ADDRESS(frame->data); + ia_css_debug_dtrace(2, "frame %s (%p):\n", descr, frame); + ia_css_debug_dtrace(2, " resolution = %dx%d\n", + frame->info.res.width, frame->info.res.height); + ia_css_debug_dtrace(2, " padded width = %d\n", + frame->info.padded_width); + ia_css_debug_dtrace(2, " format = %d\n", frame->info.format); + switch (frame->info.format) { + case IA_CSS_FRAME_FORMAT_NV12: + case IA_CSS_FRAME_FORMAT_NV16: + case IA_CSS_FRAME_FORMAT_NV21: + case IA_CSS_FRAME_FORMAT_NV61: + ia_css_debug_dtrace(2, " Y = %p\n", + data + frame->planes.nv.y.offset); + ia_css_debug_dtrace(2, " UV = %p\n", + data + frame->planes.nv.uv.offset); + break; + case IA_CSS_FRAME_FORMAT_YUYV: + case IA_CSS_FRAME_FORMAT_UYVY: + case IA_CSS_FRAME_FORMAT_CSI_MIPI_YUV420_8: + case IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8: + case IA_CSS_FRAME_FORMAT_YUV_LINE: + ia_css_debug_dtrace(2, " YUYV = %p\n", + data + frame->planes.yuyv.offset); + break; + case IA_CSS_FRAME_FORMAT_YUV420: + case IA_CSS_FRAME_FORMAT_YUV422: + case IA_CSS_FRAME_FORMAT_YUV444: + case IA_CSS_FRAME_FORMAT_YV12: + case IA_CSS_FRAME_FORMAT_YV16: + case IA_CSS_FRAME_FORMAT_YUV420_16: + case IA_CSS_FRAME_FORMAT_YUV422_16: + ia_css_debug_dtrace(2, " Y = %p\n", + data + frame->planes.yuv.y.offset); + ia_css_debug_dtrace(2, " U = %p\n", + data + frame->planes.yuv.u.offset); + ia_css_debug_dtrace(2, " V = %p\n", + data + frame->planes.yuv.v.offset); + break; + case IA_CSS_FRAME_FORMAT_RAW_PACKED: + ia_css_debug_dtrace(2, " RAW PACKED = %p\n", + data + frame->planes.raw.offset); + break; + case IA_CSS_FRAME_FORMAT_RAW: + ia_css_debug_dtrace(2, " RAW = %p\n", + data + frame->planes.raw.offset); + break; + case IA_CSS_FRAME_FORMAT_RGBA888: + case IA_CSS_FRAME_FORMAT_RGB565: + ia_css_debug_dtrace(2, " RGB = %p\n", + data + frame->planes.rgb.offset); + break; + case IA_CSS_FRAME_FORMAT_QPLANE6: + ia_css_debug_dtrace(2, " R = %p\n", + data + frame->planes.plane6.r.offset); + ia_css_debug_dtrace(2, " RatB = %p\n", + data + frame->planes.plane6.r_at_b.offset); + ia_css_debug_dtrace(2, " Gr = %p\n", + data + frame->planes.plane6.gr.offset); + ia_css_debug_dtrace(2, " Gb = %p\n", + data + frame->planes.plane6.gb.offset); + ia_css_debug_dtrace(2, " B = %p\n", + data + frame->planes.plane6.b.offset); + ia_css_debug_dtrace(2, " BatR = %p\n", + data + frame->planes.plane6.b_at_r.offset); + break; + case IA_CSS_FRAME_FORMAT_BINARY_8: + ia_css_debug_dtrace(2, " Binary data = %p\n", + data + frame->planes.binary.data.offset); + break; + default: + ia_css_debug_dtrace(2, " unknown frame type\n"); + break; + } + return; +} + +#if SP_DEBUG != SP_DEBUG_NONE + +void ia_css_debug_print_sp_debug_state(const struct sh_css_sp_debug_state + *state) +{ +#endif + +#if SP_DEBUG == SP_DEBUG_DUMP + + assert(state); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "current SP software counter: %d\n", + state->debug[0]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "empty output buffer queue head: 0x%x\n", + state->debug[1]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "empty output buffer queue tail: 0x%x\n", + state->debug[2]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "empty s3a buffer queue head: 0x%x\n", + state->debug[3]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "empty s3a buffer queue tail: 0x%x\n", + state->debug[4]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "full output buffer queue head: 0x%x\n", + state->debug[5]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "full output buffer queue tail: 0x%x\n", + state->debug[6]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "full s3a buffer queue head: 0x%x\n", + state->debug[7]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "full s3a buffer queue tail: 0x%x\n", + state->debug[8]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, "event queue head: 0x%x\n", + state->debug[9]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, "event queue tail: 0x%x\n", + state->debug[10]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "num of stages of current pipeline: 0x%x\n", + state->debug[11]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, "DDR address of stage 1: 0x%x\n", + state->debug[12]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, "DDR address of stage 2: 0x%x\n", + state->debug[13]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "current stage out_vf buffer idx: 0x%x\n", + state->debug[14]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "current stage output buffer idx: 0x%x\n", + state->debug[15]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "current stage s3a buffer idx: 0x%x\n", + state->debug[16]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "first char of current stage name: 0x%x\n", + state->debug[17]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, "current SP thread id: 0x%x\n", + state->debug[18]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "empty output buffer address 1: 0x%x\n", + state->debug[19]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "empty output buffer address 2: 0x%x\n", + state->debug[20]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "empty out_vf buffer address 1: 0x%x\n", + state->debug[21]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "empty out_vf buffer address 2: 0x%x\n", + state->debug[22]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "empty s3a_hi buffer address 1: 0x%x\n", + state->debug[23]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "empty s3a_hi buffer address 2: 0x%x\n", + state->debug[24]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "empty s3a_lo buffer address 1: 0x%x\n", + state->debug[25]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "empty s3a_lo buffer address 2: 0x%x\n", + state->debug[26]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "empty dis_hor buffer address 1: 0x%x\n", + state->debug[27]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "empty dis_hor buffer address 2: 0x%x\n", + state->debug[28]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "empty dis_ver buffer address 1: 0x%x\n", + state->debug[29]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "empty dis_ver buffer address 2: 0x%x\n", + state->debug[30]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "empty param buffer address: 0x%x\n", + state->debug[31]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "first incorrect frame address: 0x%x\n", + state->debug[32]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "first incorrect frame container address: 0x%x\n", + state->debug[33]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "first incorrect frame container payload: 0x%x\n", + state->debug[34]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "first incorrect s3a_hi address: 0x%x\n", + state->debug[35]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "first incorrect s3a_hi container address: 0x%x\n", + state->debug[36]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "first incorrect s3a_hi container payload: 0x%x\n", + state->debug[37]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "first incorrect s3a_lo address: 0x%x\n", + state->debug[38]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "first incorrect s3a_lo container address: 0x%x\n", + state->debug[39]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "first incorrect s3a_lo container payload: 0x%x\n", + state->debug[40]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "number of calling flash start function: 0x%x\n", + state->debug[41]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "number of calling flash close function: 0x%x\n", + state->debug[42]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, "number of flashed frame: 0x%x\n", + state->debug[43]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, "flash in use flag: 0x%x\n", + state->debug[44]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "number of update frame flashed flag: 0x%x\n", + state->debug[46]); + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "number of active threads: 0x%x\n", + state->debug[45]); + +#elif SP_DEBUG == SP_DEBUG_COPY + + /* Remember last_index because we only want to print new entries */ + static int last_index; + int sp_index = state->index; + int n; + + assert(state); + if (sp_index < last_index) { + /* SP has been reset */ + last_index = 0; + } + + if (last_index == 0) { + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "copy-trace init: sp_dbg_if_start_line=%d, sp_dbg_if_start_column=%d, sp_dbg_if_cropped_height=%d, sp_debg_if_cropped_width=%d\n", + state->if_start_line, + state->if_start_column, + state->if_cropped_height, + state->if_cropped_width); + } + + if ((last_index + SH_CSS_SP_DBG_TRACE_DEPTH) < sp_index) { + /* last index can be multiple rounds behind */ + /* while trace size is only SH_CSS_SP_DBG_TRACE_DEPTH */ + last_index = sp_index - SH_CSS_SP_DBG_TRACE_DEPTH; + } + + for (n = last_index; n < sp_index; n++) { + int i = n % SH_CSS_SP_DBG_TRACE_DEPTH; + + if (state->trace[i].frame != 0) { + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "copy-trace: frame=%d, line=%d, pixel_distance=%d, mipi_used_dword=%d, sp_index=%d\n", + state->trace[i].frame, + state->trace[i].line, + state->trace[i].pixel_distance, + state->trace[i].mipi_used_dword, + state->trace[i].sp_index); + } + } + + last_index = sp_index; + +#elif SP_DEBUG == SP_DEBUG_TRACE + + /* + * This is just an example how TRACE_FILE_ID (see ia_css_debug.sp.h) will + * me mapped on the file name string. + * + * Adjust this to your trace case! + */ + static char const *const id2filename[8] = { + "param_buffer.sp.c | tagger.sp.c | pipe_data.sp.c", + "isp_init.sp.c", + "sp_raw_copy.hive.c", + "dma_configure.sp.c", + "sp.hive.c", + "event_proxy_sp.hive.c", + "circular_buffer.sp.c", + "frame_buffer.sp.c" + }; + + /* Example SH_CSS_SP_DBG_NR_OF_TRACES==1 */ + /* Adjust this to your trace case */ + static char const *trace_name[SH_CSS_SP_DBG_NR_OF_TRACES] = { + "default" + }; + + /* Remember host_index_last because we only want to print new entries */ + static int host_index_last[SH_CSS_SP_DBG_NR_OF_TRACES] = { 0 }; + int t, n; + + assert(state); + + for (t = 0; t < SH_CSS_SP_DBG_NR_OF_TRACES; t++) { + int sp_index_last = state->index_last[t]; + + if (sp_index_last < host_index_last[t]) { + /* SP has been reset */ + host_index_last[t] = 0; + } + + if ((host_index_last[t] + SH_CSS_SP_DBG_TRACE_DEPTH) < + sp_index_last) { + /* last index can be multiple rounds behind */ + /* while trace size is only SH_CSS_SP_DBG_TRACE_DEPTH */ + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "Warning: trace %s has gap of %d traces\n", + trace_name[t], + (sp_index_last - + (host_index_last[t] + + SH_CSS_SP_DBG_TRACE_DEPTH))); + + host_index_last[t] = + sp_index_last - SH_CSS_SP_DBG_TRACE_DEPTH; + } + + for (n = host_index_last[t]; n < sp_index_last; n++) { + int i = n % SH_CSS_SP_DBG_TRACE_DEPTH; + int l = state->trace[t][i].location & + ((1 << SH_CSS_SP_DBG_TRACE_FILE_ID_BIT_POS) - 1); + int fid = state->trace[t][i].location >> + SH_CSS_SP_DBG_TRACE_FILE_ID_BIT_POS; + int ts = state->trace[t][i].time_stamp; + + if (ts) { + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "%05d trace=%s, file=%s:%d, data=0x%08x\n", + ts, + trace_name[t], + id2filename[fid], l, + state->trace[t][i].data); + } + } + host_index_last[t] = sp_index_last; + } + +#elif SP_DEBUG == SP_DEBUG_MINIMAL + int i; + int base = 0; + int limit = SH_CSS_NUM_SP_DEBUG; + int step = 1; + + assert(state); + + for (i = base; i < limit; i += step) { + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "sp_dbg_trace[%d] = %d\n", + i, state->debug[i]); + } +#endif + +#if SP_DEBUG != SP_DEBUG_NONE + + return; +} +#endif + +#if !defined(ISP2401) +static void debug_print_rx_mipi_port_state(mipi_port_state_t *state) +{ + int i; + unsigned int bits, infos; + + assert(state); + + bits = state->irq_status; + infos = ia_css_isys_rx_translate_irq_infos(bits); + + ia_css_debug_dtrace(2, "\t\t%-32s: (irq reg = 0x%X)\n", + "receiver errors", bits); + + if (infos & IA_CSS_RX_IRQ_INFO_BUFFER_OVERRUN) + ia_css_debug_dtrace(2, "\t\t\tbuffer overrun\n"); + if (infos & IA_CSS_RX_IRQ_INFO_ERR_SOT) + ia_css_debug_dtrace(2, "\t\t\tstart-of-transmission error\n"); + if (infos & IA_CSS_RX_IRQ_INFO_ERR_SOT_SYNC) + ia_css_debug_dtrace(2, "\t\t\tstart-of-transmission sync error\n"); + if (infos & IA_CSS_RX_IRQ_INFO_ERR_CONTROL) + ia_css_debug_dtrace(2, "\t\t\tcontrol error\n"); + if (infos & IA_CSS_RX_IRQ_INFO_ERR_ECC_DOUBLE) + ia_css_debug_dtrace(2, "\t\t\t2 or more ECC errors\n"); + if (infos & IA_CSS_RX_IRQ_INFO_ERR_CRC) + ia_css_debug_dtrace(2, "\t\t\tCRC mismatch\n"); + if (infos & IA_CSS_RX_IRQ_INFO_ERR_UNKNOWN_ID) + ia_css_debug_dtrace(2, "\t\t\tunknown error\n"); + if (infos & IA_CSS_RX_IRQ_INFO_ERR_FRAME_SYNC) + ia_css_debug_dtrace(2, "\t\t\tframe sync error\n"); + if (infos & IA_CSS_RX_IRQ_INFO_ERR_FRAME_DATA) + ia_css_debug_dtrace(2, "\t\t\tframe data error\n"); + if (infos & IA_CSS_RX_IRQ_INFO_ERR_DATA_TIMEOUT) + ia_css_debug_dtrace(2, "\t\t\tdata timeout\n"); + if (infos & IA_CSS_RX_IRQ_INFO_ERR_UNKNOWN_ESC) + ia_css_debug_dtrace(2, "\t\t\tunknown escape command entry\n"); + if (infos & IA_CSS_RX_IRQ_INFO_ERR_LINE_SYNC) + ia_css_debug_dtrace(2, "\t\t\tline sync error\n"); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "device_ready", state->device_ready); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "irq_status", state->irq_status); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "irq_enable", state->irq_enable); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "timeout_count", state->timeout_count); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "init_count", state->init_count); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "raw16_18", state->raw16_18); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "sync_count", state->sync_count); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "rx_count", state->rx_count); + + for (i = 0; i < MIPI_4LANE_CFG; i++) { + ia_css_debug_dtrace(2, "\t\t%-32s%d%-32s: %d\n", + "lane_sync_count[", i, "]", + state->lane_sync_count[i]); + } + + for (i = 0; i < MIPI_4LANE_CFG; i++) { + ia_css_debug_dtrace(2, "\t\t%-32s%d%-32s: %d\n", + "lane_rx_count[", i, "]", + state->lane_rx_count[i]); + } + + return; +} + +static void debug_print_rx_channel_state(rx_channel_state_t *state) +{ + int i; + + assert(state); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "compression_scheme0", state->comp_scheme0); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "compression_scheme1", state->comp_scheme1); + + for (i = 0; i < N_MIPI_FORMAT_CUSTOM; i++) { + ia_css_debug_dtrace(2, "\t\t%-32s%d: %d\n", + "MIPI Predictor ", i, state->pred[i]); + } + + for (i = 0; i < N_MIPI_FORMAT_CUSTOM; i++) { + ia_css_debug_dtrace(2, "\t\t%-32s%d: %d\n", + "MIPI Compressor ", i, state->comp[i]); + } + + return; +} + +static void debug_print_rx_state(receiver_state_t *state) +{ + int i; + + assert(state); + ia_css_debug_dtrace(2, "CSI Receiver State:\n"); + + ia_css_debug_dtrace(2, "\tConfiguration:\n"); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "fs_to_ls_delay", state->fs_to_ls_delay); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "ls_to_data_delay", state->ls_to_data_delay); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "data_to_le_delay", state->data_to_le_delay); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "le_to_fe_delay", state->le_to_fe_delay); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "fe_to_fs_delay", state->fe_to_fs_delay); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "le_to_fs_delay", state->le_to_fs_delay); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "is_two_ppc", state->is_two_ppc); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "backend_rst", state->backend_rst); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "raw18", state->raw18); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "force_raw8", state->force_raw8); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "raw16", state->raw16); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "be_gsp_acc_ovl", state->be_gsp_acc_ovl); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "be_srst", state->be_srst); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "be_is_two_ppc", state->be_is_two_ppc); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "be_comp_format0", state->be_comp_format0); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "be_comp_format1", state->be_comp_format1); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "be_comp_format2", state->be_comp_format2); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "be_comp_format3", state->be_comp_format3); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "be_sel", state->be_sel); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "be_raw16_config", state->be_raw16_config); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "be_raw18_config", state->be_raw18_config); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "be_force_raw8", state->be_force_raw8); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "be_irq_status", state->be_irq_status); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "be_irq_clear", state->be_irq_clear); + + /* mipi port state */ + for (i = 0; i < N_MIPI_PORT_ID; i++) { + ia_css_debug_dtrace(2, "\tMIPI Port %d State:\n", i); + + debug_print_rx_mipi_port_state(&state->mipi_port_state[i]); + } + /* end of mipi port state */ + + /* rx channel state */ + for (i = 0; i < N_RX_CHANNEL_ID; i++) { + ia_css_debug_dtrace(2, "\tRX Channel %d State:\n", i); + + debug_print_rx_channel_state(&state->rx_channel_state[i]); + } + /* end of rx channel state */ + + return; +} +#endif + +void ia_css_debug_dump_rx_state(void) +{ +#if !defined(ISP2401) + receiver_state_t state; + + receiver_get_state(RX0_ID, &state); + debug_print_rx_state(&state); +#endif +} + +void ia_css_debug_dump_sp_sw_debug_info(void) +{ +#if SP_DEBUG != SP_DEBUG_NONE + struct sh_css_sp_debug_state state; + + sh_css_sp_get_debug_state(&state); + ia_css_debug_print_sp_debug_state(&state); +#endif + ia_css_bufq_dump_queue_info(); + ia_css_pipeline_dump_thread_map_info(); + return; +} + +#if !defined(ISP2401) +static void debug_print_isys_capture_unit_state(capture_unit_state_t *state) +{ + assert(state); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "Packet_Length", state->Packet_Length); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "Received_Length", state->Received_Length); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "Received_Short_Packets", + state->Received_Short_Packets); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "Received_Long_Packets", + state->Received_Long_Packets); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "Last_Command", state->Last_Command); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "Next_Command", state->Next_Command); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "Last_Acknowledge", state->Last_Acknowledge); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "Next_Acknowledge", state->Next_Acknowledge); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "FSM_State_Info", state->FSM_State_Info); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "StartMode", state->StartMode); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "Start_Addr", state->Start_Addr); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "Mem_Region_Size", state->Mem_Region_Size); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "Num_Mem_Regions", state->Num_Mem_Regions); + return; +} + +static void debug_print_isys_acquisition_unit_state( + acquisition_unit_state_t *state) +{ + assert(state); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "Received_Short_Packets", + state->Received_Short_Packets); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "Received_Long_Packets", + state->Received_Long_Packets); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "Last_Command", state->Last_Command); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "Next_Command", state->Next_Command); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "Last_Acknowledge", state->Last_Acknowledge); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "Next_Acknowledge", state->Next_Acknowledge); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "FSM_State_Info", state->FSM_State_Info); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "Int_Cntr_Info", state->Int_Cntr_Info); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "Start_Addr", state->Start_Addr); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "Mem_Region_Size", state->Mem_Region_Size); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "Num_Mem_Regions", state->Num_Mem_Regions); +} + +static void debug_print_isys_ctrl_unit_state(ctrl_unit_state_t *state) +{ + assert(state); + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "last_cmd", state->last_cmd); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "next_cmd", state->next_cmd); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "last_ack", state->last_ack); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", "next_ack", state->next_ack); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "top_fsm_state", state->top_fsm_state); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "captA_fsm_state", state->captA_fsm_state); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "captB_fsm_state", state->captB_fsm_state); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "captC_fsm_state", state->captC_fsm_state); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "acq_fsm_state", state->acq_fsm_state); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "captA_start_addr", state->captA_start_addr); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "captB_start_addr", state->captB_start_addr); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "captC_start_addr", state->captC_start_addr); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "captA_mem_region_size", + state->captA_mem_region_size); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "captB_mem_region_size", + state->captB_mem_region_size); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "captC_mem_region_size", + state->captC_mem_region_size); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "captA_num_mem_regions", + state->captA_num_mem_regions); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "captB_num_mem_regions", + state->captB_num_mem_regions); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "captC_num_mem_regions", + state->captC_num_mem_regions); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "acq_start_addr", state->acq_start_addr); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "acq_mem_region_size", state->acq_mem_region_size); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "acq_num_mem_regions", state->acq_num_mem_regions); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "capt_reserve_one_mem_region", + state->capt_reserve_one_mem_region); + + return; +} + +static void debug_print_isys_state(input_system_state_t *state) +{ + int i; + + assert(state); + ia_css_debug_dtrace(2, "InputSystem State:\n"); + + /* configuration */ + ia_css_debug_dtrace(2, "\tConfiguration:\n"); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "str_multiCastA_sel", state->str_multicastA_sel); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "str_multicastB_sel", state->str_multicastB_sel); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "str_multicastC_sel", state->str_multicastC_sel); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "str_mux_sel", state->str_mux_sel); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "str_mon_status", state->str_mon_status); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "str_mon_irq_cond", state->str_mon_irq_cond); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "str_mon_irq_en", state->str_mon_irq_en); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "isys_srst", state->isys_srst); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "isys_slv_reg_srst", state->isys_slv_reg_srst); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "str_deint_portA_cnt", state->str_deint_portA_cnt); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "str_deint_portB_cnd", state->str_deint_portB_cnt); + /* end of configuration */ + + /* capture unit state */ + for (i = 0; i < N_CAPTURE_UNIT_ID; i++) { + capture_unit_state_t *capture_unit_state; + + ia_css_debug_dtrace(2, "\tCaptureUnit %d State:\n", i); + + capture_unit_state = &state->capture_unit[i]; + debug_print_isys_capture_unit_state(capture_unit_state); + } + /* end of capture unit state */ + + /* acquisition unit state */ + for (i = 0; i < N_ACQUISITION_UNIT_ID; i++) { + acquisition_unit_state_t *acquisition_unit_state; + + ia_css_debug_dtrace(2, "\tAcquisitionUnit %d State:\n", i); + + acquisition_unit_state = &state->acquisition_unit[i]; + debug_print_isys_acquisition_unit_state(acquisition_unit_state); + } + /* end of acquisition unit state */ + + /* control unit state */ + for (i = 0; i < N_CTRL_UNIT_ID; i++) { + ia_css_debug_dtrace(2, "\tControlUnit %d State:\n", i); + + debug_print_isys_ctrl_unit_state(&state->ctrl_unit_state[i]); + } + /* end of control unit state */ +} +#endif + +void ia_css_debug_dump_isys_state(void) +{ + static input_system_state_t state; + + input_system_get_state(INPUT_SYSTEM0_ID, &state); + +#ifndef ISP2401 + debug_print_isys_state(&state); +#else + input_system_dump_state(INPUT_SYSTEM0_ID, &state); +#endif +} + +void ia_css_debug_dump_debug_info(const char *context) +{ + if (!context) + context = "No Context provided"; + + ia_css_debug_dtrace(2, "CSS Debug Info dump [Context = %s]\n", context); + if (!IS_ISP2401) + ia_css_debug_dump_rx_state(); + +#ifndef ISP2401 + ia_css_debug_dump_if_state(); +#endif + ia_css_debug_dump_isp_state(); + ia_css_debug_dump_isp_sp_fifo_state(); + ia_css_debug_dump_isp_gdc_fifo_state(); + ia_css_debug_dump_sp_state(); + ia_css_debug_dump_perf_counters(); + +#ifdef HAS_WATCHDOG_SP_THREAD_DEBUG + sh_css_dump_thread_wait_info(); + sh_css_dump_pipe_stage_info(); + sh_css_dump_pipe_stripe_info(); +#endif + ia_css_debug_dump_dma_isp_fifo_state(); + ia_css_debug_dump_dma_sp_fifo_state(); + ia_css_debug_dump_dma_state(); + + if (!IS_ISP2401) { + struct irq_controller_state state; + + ia_css_debug_dump_isys_state(); + + irq_controller_get_state(IRQ2_ID, &state); + + ia_css_debug_dtrace(2, "\t%-32s:\n", + "Input System IRQ Controller State"); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "irq_edge", state.irq_edge); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "irq_mask", state.irq_mask); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "irq_status", state.irq_status); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "irq_enable", state.irq_enable); + + ia_css_debug_dtrace(2, "\t\t%-32s: %d\n", + "irq_level_not_pulse", + state.irq_level_not_pulse); + } else { + ia_css_debug_dump_isys_state(); + } + + ia_css_debug_tagger_state(); + + return; +} + +/* this function is for debug use, it can make SP go to sleep + state after each frame, then user can dump the stable SP dmem. + this function can be called after ia_css_start_sp() + and before sh_css_init_buffer_queues() +*/ +void ia_css_debug_enable_sp_sleep_mode(enum ia_css_sp_sleep_mode mode) +{ + const struct ia_css_fw_info *fw; + unsigned int HIVE_ADDR_sp_sleep_mode; + + fw = &sh_css_sp_fw; + HIVE_ADDR_sp_sleep_mode = fw->info.sp.sleep_mode; + + (void)HIVE_ADDR_sp_sleep_mode; /* Suppres warnings in CRUN */ + + sp_dmem_store_uint32(SP0_ID, + (unsigned int)sp_address_of(sp_sleep_mode), + (uint32_t)mode); +} + +void ia_css_debug_wake_up_sp(void) +{ + /*hrt_ctl_start(SP); */ + sp_ctrl_setbit(SP0_ID, SP_SC_REG, SP_START_BIT); +} + +#define FIND_DMEM_PARAMS_TYPE(stream, kernel, type) \ + (struct HRTCAT(HRTCAT(sh_css_isp_, type), _params) *) \ + findf_dmem_params(stream, offsetof(struct ia_css_memory_offsets, dmem.kernel)) + +#define FIND_DMEM_PARAMS(stream, kernel) FIND_DMEM_PARAMS_TYPE(stream, kernel, kernel) + +/* Find a stage that support the kernel and return the parameters for that kernel */ +static char * +findf_dmem_params(struct ia_css_stream *stream, short idx) +{ + int i; + + for (i = 0; i < stream->num_pipes; i++) { + struct ia_css_pipe *pipe = stream->pipes[i]; + struct ia_css_pipeline *pipeline = ia_css_pipe_get_pipeline(pipe); + struct ia_css_pipeline_stage *stage; + + for (stage = pipeline->stages; stage; stage = stage->next) { + struct ia_css_binary *binary = stage->binary; + short *offsets = (short *)&binary->info->mem_offsets.offsets.param->dmem; + short dmem_offset = offsets[idx]; + const struct ia_css_host_data *isp_data = + ia_css_isp_param_get_mem_init(&binary->mem_params, + IA_CSS_PARAM_CLASS_PARAM, IA_CSS_ISP_DMEM0); + if (dmem_offset < 0) + continue; + return &isp_data->address[dmem_offset]; + } + } + return NULL; +} + +void ia_css_debug_dump_isp_params(struct ia_css_stream *stream, + unsigned int enable) +{ + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, "ISP PARAMETERS:\n"); + + assert(stream); + if ((enable & IA_CSS_DEBUG_DUMP_FPN) + || (enable & IA_CSS_DEBUG_DUMP_ALL)) { + ia_css_fpn_dump(FIND_DMEM_PARAMS(stream, fpn), IA_CSS_DEBUG_VERBOSE); + } + if ((enable & IA_CSS_DEBUG_DUMP_OB) + || (enable & IA_CSS_DEBUG_DUMP_ALL)) { + ia_css_ob_dump(FIND_DMEM_PARAMS(stream, ob), IA_CSS_DEBUG_VERBOSE); + } + if ((enable & IA_CSS_DEBUG_DUMP_SC) + || (enable & IA_CSS_DEBUG_DUMP_ALL)) { + ia_css_sc_dump(FIND_DMEM_PARAMS(stream, sc), IA_CSS_DEBUG_VERBOSE); + } + if ((enable & IA_CSS_DEBUG_DUMP_WB) + || (enable & IA_CSS_DEBUG_DUMP_ALL)) { + ia_css_wb_dump(FIND_DMEM_PARAMS(stream, wb), IA_CSS_DEBUG_VERBOSE); + } + if ((enable & IA_CSS_DEBUG_DUMP_DP) + || (enable & IA_CSS_DEBUG_DUMP_ALL)) { + ia_css_dp_dump(FIND_DMEM_PARAMS(stream, dp), IA_CSS_DEBUG_VERBOSE); + } + if ((enable & IA_CSS_DEBUG_DUMP_BNR) + || (enable & IA_CSS_DEBUG_DUMP_ALL)) { + ia_css_bnr_dump(FIND_DMEM_PARAMS(stream, bnr), IA_CSS_DEBUG_VERBOSE); + } + if ((enable & IA_CSS_DEBUG_DUMP_S3A) + || (enable & IA_CSS_DEBUG_DUMP_ALL)) { + ia_css_s3a_dump(FIND_DMEM_PARAMS(stream, s3a), IA_CSS_DEBUG_VERBOSE); + } + if ((enable & IA_CSS_DEBUG_DUMP_DE) + || (enable & IA_CSS_DEBUG_DUMP_ALL)) { + ia_css_de_dump(FIND_DMEM_PARAMS(stream, de), IA_CSS_DEBUG_VERBOSE); + } + if ((enable & IA_CSS_DEBUG_DUMP_YNR) + || (enable & IA_CSS_DEBUG_DUMP_ALL)) { + ia_css_nr_dump(FIND_DMEM_PARAMS_TYPE(stream, nr, ynr), IA_CSS_DEBUG_VERBOSE); + ia_css_yee_dump(FIND_DMEM_PARAMS(stream, yee), IA_CSS_DEBUG_VERBOSE); + } + if ((enable & IA_CSS_DEBUG_DUMP_CSC) + || (enable & IA_CSS_DEBUG_DUMP_ALL)) { + ia_css_csc_dump(FIND_DMEM_PARAMS(stream, csc), IA_CSS_DEBUG_VERBOSE); + ia_css_yuv2rgb_dump(FIND_DMEM_PARAMS_TYPE(stream, yuv2rgb, csc), + IA_CSS_DEBUG_VERBOSE); + ia_css_rgb2yuv_dump(FIND_DMEM_PARAMS_TYPE(stream, rgb2yuv, csc), + IA_CSS_DEBUG_VERBOSE); + } + if ((enable & IA_CSS_DEBUG_DUMP_GC) + || (enable & IA_CSS_DEBUG_DUMP_ALL)) { + ia_css_gc_dump(FIND_DMEM_PARAMS(stream, gc), IA_CSS_DEBUG_VERBOSE); + } + if ((enable & IA_CSS_DEBUG_DUMP_TNR) + || (enable & IA_CSS_DEBUG_DUMP_ALL)) { + ia_css_tnr_dump(FIND_DMEM_PARAMS(stream, tnr), IA_CSS_DEBUG_VERBOSE); + } + if ((enable & IA_CSS_DEBUG_DUMP_ANR) + || (enable & IA_CSS_DEBUG_DUMP_ALL)) { + ia_css_anr_dump(FIND_DMEM_PARAMS(stream, anr), IA_CSS_DEBUG_VERBOSE); + } + if ((enable & IA_CSS_DEBUG_DUMP_CE) + || (enable & IA_CSS_DEBUG_DUMP_ALL)) { + ia_css_ce_dump(FIND_DMEM_PARAMS(stream, ce), IA_CSS_DEBUG_VERBOSE); + } +} + +void sh_css_dump_sp_raw_copy_linecount(bool reduced) +{ + const struct ia_css_fw_info *fw; + unsigned int HIVE_ADDR_raw_copy_line_count; + s32 raw_copy_line_count; + static s32 prev_raw_copy_line_count = -1; + + fw = &sh_css_sp_fw; + HIVE_ADDR_raw_copy_line_count = + fw->info.sp.raw_copy_line_count; + + (void)HIVE_ADDR_raw_copy_line_count; + + sp_dmem_load(SP0_ID, + (unsigned int)sp_address_of(raw_copy_line_count), + &raw_copy_line_count, + sizeof(raw_copy_line_count)); + + /* only indicate if copy loop is active */ + if (reduced) + raw_copy_line_count = (raw_copy_line_count < 0) ? raw_copy_line_count : 1; + /* do the handling */ + if (prev_raw_copy_line_count != raw_copy_line_count) { + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "sh_css_dump_sp_raw_copy_linecount() line_count=%d\n", + raw_copy_line_count); + prev_raw_copy_line_count = raw_copy_line_count; + } +} + +void ia_css_debug_dump_isp_binary(void) +{ + const struct ia_css_fw_info *fw; + unsigned int HIVE_ADDR_pipeline_sp_curr_binary_id; + u32 curr_binary_id; + static u32 prev_binary_id = 0xFFFFFFFF; + static u32 sample_count; + + fw = &sh_css_sp_fw; + HIVE_ADDR_pipeline_sp_curr_binary_id = fw->info.sp.curr_binary_id; + + (void)HIVE_ADDR_pipeline_sp_curr_binary_id; + + sp_dmem_load(SP0_ID, + (unsigned int)sp_address_of(pipeline_sp_curr_binary_id), + &curr_binary_id, + sizeof(curr_binary_id)); + + /* do the handling */ + sample_count++; + if (prev_binary_id != curr_binary_id) { + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "sh_css_dump_isp_binary() pipe_id=%d, binary_id=%d, sample_count=%d\n", + (curr_binary_id >> 16), + (curr_binary_id & 0x0ffff), + sample_count); + sample_count = 0; + prev_binary_id = curr_binary_id; + } +} + +void ia_css_debug_dump_perf_counters(void) +{ + const struct ia_css_fw_info *fw; + int i; + unsigned int HIVE_ADDR_ia_css_isys_sp_error_cnt; + /* N_MIPI_PORT_ID + 1: 3 Capture Units and 1 Acquire Unit. */ + s32 ia_css_sp_input_system_error_cnt[N_MIPI_PORT_ID + 1]; + + if (IS_ISP2401) + return; + + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, "Input System Error Counters:\n"); + + fw = &sh_css_sp_fw; + HIVE_ADDR_ia_css_isys_sp_error_cnt = + fw->info.sp.perf_counter_input_system_error; + + (void)HIVE_ADDR_ia_css_isys_sp_error_cnt; + + sp_dmem_load(SP0_ID, + (unsigned int)sp_address_of(ia_css_isys_sp_error_cnt), + &ia_css_sp_input_system_error_cnt, + sizeof(ia_css_sp_input_system_error_cnt)); + + for (i = 0; i < N_MIPI_PORT_ID + 1; i++) { + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, "\tport[%d] = %d\n", + i, ia_css_sp_input_system_error_cnt[i]); + } +} + +/* + * @brief Initialize the debug mode. + * Refer to "ia_css_debug.h" for more details. + */ +bool ia_css_debug_mode_init(void) +{ + bool rc; + + rc = sh_css_sp_init_dma_sw_reg(0); + return rc; +} + +/* + * @brief Disable the DMA channel. + * Refer to "ia_css_debug.h" for more details. + */ +bool +ia_css_debug_mode_disable_dma_channel(int dma_id, + int channel_id, int request_type) +{ + bool rc; + + rc = sh_css_sp_set_dma_sw_reg(dma_id, channel_id, request_type, false); + + return rc; +} + +/* + * @brief Enable the DMA channel. + * Refer to "ia_css_debug.h" for more details. + */ +bool +ia_css_debug_mode_enable_dma_channel(int dma_id, + int channel_id, int request_type) +{ + bool rc; + + rc = sh_css_sp_set_dma_sw_reg(dma_id, channel_id, request_type, true); + + return rc; +} + +static void __printf(1, 2) dtrace_dot(const char *fmt, ...) +{ + va_list ap; + + assert(fmt); + va_start(ap, fmt); + + ia_css_debug_dtrace(IA_CSS_DEBUG_INFO, "%s", DPG_START); + ia_css_debug_vdtrace(IA_CSS_DEBUG_INFO, fmt, ap); + ia_css_debug_dtrace(IA_CSS_DEBUG_INFO, "%s", DPG_END); + va_end(ap); +} + +#ifdef HAS_WATCHDOG_SP_THREAD_DEBUG +void sh_css_dump_thread_wait_info(void) +{ + const struct ia_css_fw_info *fw; + int i; + unsigned int HIVE_ADDR_sp_thread_wait; + s32 sp_thread_wait[MAX_THREAD_NUM]; + + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, "SEM WAITS:\n"); + + fw = &sh_css_sp_fw; + HIVE_ADDR_sp_thread_wait = + fw->info.sp.debug_wait; + + (void)HIVE_ADDR_sp_thread_wait; + + sp_dmem_load(SP0_ID, + (unsigned int)sp_address_of(sp_thread_wait), + &sp_thread_wait, + sizeof(sp_thread_wait)); + for (i = 0; i < MAX_THREAD_NUM; i++) { + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "\twait[%d] = 0x%X\n", + i, sp_thread_wait[i]); + } +} + +void sh_css_dump_pipe_stage_info(void) +{ + const struct ia_css_fw_info *fw; + int i; + unsigned int HIVE_ADDR_sp_pipe_stage; + s32 sp_pipe_stage[MAX_THREAD_NUM]; + + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, "PIPE STAGE:\n"); + + fw = &sh_css_sp_fw; + HIVE_ADDR_sp_pipe_stage = + fw->info.sp.debug_stage; + + (void)HIVE_ADDR_sp_pipe_stage; + + sp_dmem_load(SP0_ID, + (unsigned int)sp_address_of(sp_pipe_stage), + &sp_pipe_stage, + sizeof(sp_pipe_stage)); + for (i = 0; i < MAX_THREAD_NUM; i++) { + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "\tstage[%d] = %d\n", + i, sp_pipe_stage[i]); + } +} + +void sh_css_dump_pipe_stripe_info(void) +{ + const struct ia_css_fw_info *fw; + int i; + unsigned int HIVE_ADDR_sp_pipe_stripe; + s32 sp_pipe_stripe[MAX_THREAD_NUM]; + + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, "PIPE STRIPE:\n"); + + fw = &sh_css_sp_fw; + HIVE_ADDR_sp_pipe_stripe = + fw->info.sp.debug_stripe; + + (void)HIVE_ADDR_sp_pipe_stripe; + + sp_dmem_load(SP0_ID, + (unsigned int)sp_address_of(sp_pipe_stripe), + &sp_pipe_stripe, + sizeof(sp_pipe_stripe)); + for (i = 0; i < MAX_THREAD_NUM; i++) { + ia_css_debug_dtrace(IA_CSS_DEBUG_VERBOSE, + "\tstripe[%d] = %d\n", + i, sp_pipe_stripe[i]); + } +} +#endif + +static void +ia_css_debug_pipe_graph_dump_frame( + const struct ia_css_frame *frame, + enum ia_css_pipe_id id, + char const *blob_name, + char const *frame_name, + bool in_frame) +{ + char bufinfo[100]; + + if (frame->dynamic_queue_id == SH_CSS_INVALID_QUEUE_ID) { + snprintf(bufinfo, sizeof(bufinfo), "Internal"); + } else { + snprintf(bufinfo, sizeof(bufinfo), "Queue: %s %s", + pipe_id_to_str[id], + queue_id_to_str[frame->dynamic_queue_id]); + } + dtrace_dot( + "node [shape = box, fixedsize=true, width=2, height=0.7]; \"%p\" [label = \"%s\\n%d(%d) x %d, %dbpp\\n%s\"];", + frame, + debug_frame_format2str(frame->info.format), + frame->info.res.width, + frame->info.padded_width, + frame->info.res.height, + frame->info.raw_bit_depth, + bufinfo); + + if (in_frame) { + dtrace_dot( + "\"%p\"->\"%s(pipe%d)\" [label = %s_frame];", + frame, + blob_name, id, frame_name); + } else { + dtrace_dot( + "\"%s(pipe%d)\"->\"%p\" [label = %s_frame];", + blob_name, id, + frame, + frame_name); + } +} + +void +ia_css_debug_pipe_graph_dump_prologue(void) +{ + dtrace_dot("digraph sh_css_pipe_graph {"); + dtrace_dot("rankdir=LR;"); + + dtrace_dot("fontsize=9;"); + dtrace_dot("label = \"\\nEnable options: rp=reduced pipe, vfve=vf_veceven, dvse=dvs_envelope, dvs6=dvs_6axis, bo=block_out, fbds=fixed_bayer_ds, bf6=bayer_fir_6db, rawb=raw_binning, cont=continuous, disc=dis_crop\\n" + "dp2a=dp_2adjacent, outp=output, outt=out_table, reff=ref_frame, par=params, gam=gamma, cagdc=ca_gdc, ispa=isp_addresses, inf=in_frame, outf=out_frame, hs=high_speed, inpc=input_chunking\""); +} + +void ia_css_debug_pipe_graph_dump_epilogue(void) +{ + if (strlen(ring_buffer) > 0) { + dtrace_dot(ring_buffer); + } + + if (pg_inst.stream_format != N_ATOMISP_INPUT_FORMAT) { + /* An input stream format has been set so assume we have + * an input system and sensor + */ + + dtrace_dot( + "node [shape = doublecircle, fixedsize=true, width=2.5]; \"input_system\" [label = \"Input system\"];"); + + dtrace_dot( + "\"input_system\"->\"%s\" [label = \"%s\"];", + dot_id_input_bin, debug_stream_format2str(pg_inst.stream_format)); + + dtrace_dot( + "node [shape = doublecircle, fixedsize=true, width=2.5]; \"sensor\" [label = \"Sensor\"];"); + + dtrace_dot( + "\"sensor\"->\"input_system\" [label = \"%s\\n%d x %d\\n(%d x %d)\"];", + debug_stream_format2str(pg_inst.stream_format), + pg_inst.width, pg_inst.height, + pg_inst.eff_width, pg_inst.eff_height); + } + + dtrace_dot("}"); + + /* Reset temp strings */ + memset(dot_id_input_bin, 0, sizeof(dot_id_input_bin)); + memset(ring_buffer, 0, sizeof(ring_buffer)); + + pg_inst.do_init = true; + pg_inst.width = 0; + pg_inst.height = 0; + pg_inst.eff_width = 0; + pg_inst.eff_height = 0; + pg_inst.stream_format = N_ATOMISP_INPUT_FORMAT; +} + +void +ia_css_debug_pipe_graph_dump_stage( + struct ia_css_pipeline_stage *stage, + enum ia_css_pipe_id id) +{ + char blob_name[SH_CSS_MAX_BINARY_NAME + 10] = "<unknown type>"; + char const *bin_type = "<unknown type>"; + int i; + + assert(stage); + if (stage->sp_func != IA_CSS_PIPELINE_NO_FUNC) + return; + + if (pg_inst.do_init) { + ia_css_debug_pipe_graph_dump_prologue(); + pg_inst.do_init = false; + } + + if (stage->binary) { + bin_type = "binary"; + if (stage->binary->info->blob) + snprintf(blob_name, sizeof(blob_name), "%s_stage%d", + stage->binary->info->blob->name, stage->stage_num); + } else if (stage->firmware) { + bin_type = "firmware"; + + strscpy(blob_name, IA_CSS_EXT_ISP_PROG_NAME(stage->firmware), + sizeof(blob_name)); + } + + /* Guard in case of binaries that don't have any binary_info */ + if (stage->binary_info) { + char enable_info1[100]; + char enable_info2[100]; + char enable_info3[100]; + char enable_info[200]; + struct ia_css_binary_info *bi = stage->binary_info; + + /* Split it in 2 function-calls to keep the amount of + * parameters per call "reasonable" + */ + snprintf(enable_info1, sizeof(enable_info1), + "%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + bi->enable.reduced_pipe ? "rp," : "", + bi->enable.vf_veceven ? "vfve," : "", + bi->enable.dis ? "dis," : "", + bi->enable.dvs_envelope ? "dvse," : "", + bi->enable.uds ? "uds," : "", + bi->enable.dvs_6axis ? "dvs6," : "", + bi->enable.block_output ? "bo," : "", + bi->enable.ds ? "ds," : "", + bi->enable.bayer_fir_6db ? "bf6," : "", + bi->enable.raw_binning ? "rawb," : "", + bi->enable.continuous ? "cont," : "", + bi->enable.s3a ? "s3a," : "", + bi->enable.fpnr ? "fpnr," : "", + bi->enable.sc ? "sc," : "" + ); + + snprintf(enable_info2, sizeof(enable_info2), + "%s%s%s%s%s%s%s%s%s%s%s", + bi->enable.macc ? "macc," : "", + bi->enable.output ? "outp," : "", + bi->enable.ref_frame ? "reff," : "", + bi->enable.tnr ? "tnr," : "", + bi->enable.xnr ? "xnr," : "", + bi->enable.params ? "par," : "", + bi->enable.ca_gdc ? "cagdc," : "", + bi->enable.isp_addresses ? "ispa," : "", + bi->enable.in_frame ? "inf," : "", + bi->enable.out_frame ? "outf," : "", + bi->enable.high_speed ? "hs," : "" + ); + + /* And merge them into one string */ + snprintf(enable_info, sizeof(enable_info), "%s%s", + enable_info1, enable_info2); + { + int l, p; + char *ei = enable_info; + + l = strlen(ei); + + /* Replace last ',' with \0 if present */ + if (l && enable_info[l - 1] == ',') + enable_info[--l] = '\0'; + + if (l > ENABLE_LINE_MAX_LENGTH) { + /* Too big for one line, find last comma */ + p = ENABLE_LINE_MAX_LENGTH; + while (ei[p] != ',') + p--; + /* Last comma found, copy till that comma */ + strscpy(enable_info1, ei, + p > sizeof(enable_info1) ? sizeof(enable_info1) : p); + + ei += p + 1; + l = strlen(ei); + + if (l <= ENABLE_LINE_MAX_LENGTH) { + /* The 2nd line fits */ + /* we cannot use ei as argument because + * it is not guaranteed dword aligned + */ + + strscpy(enable_info2, ei, + l > sizeof(enable_info2) ? sizeof(enable_info2) : l); + + snprintf(enable_info, sizeof(enable_info), "%s\\n%s", + enable_info1, enable_info2); + + } else { + /* 2nd line is still too long */ + p = ENABLE_LINE_MAX_LENGTH; + while (ei[p] != ',') + p--; + + strscpy(enable_info2, ei, + p > sizeof(enable_info2) ? sizeof(enable_info2) : p); + + ei += p + 1; + l = strlen(ei); + + if (l <= ENABLE_LINE_MAX_LENGTH) { + /* The 3rd line fits */ + /* we cannot use ei as argument because + * it is not guaranteed dword aligned + */ + strscpy(enable_info3, ei, + sizeof(enable_info3)); + snprintf(enable_info, sizeof(enable_info), + "%s\\n%s\\n%s", + enable_info1, enable_info2, + enable_info3); + } else { + /* 3rd line is still too long */ + p = ENABLE_LINE_MAX_LENGTH; + while (ei[p] != ',') + p--; + strscpy(enable_info3, ei, + p > sizeof(enable_info3) ? sizeof(enable_info3) : p); + ei += p + 1; + strscpy(enable_info3, ei, + sizeof(enable_info3)); + snprintf(enable_info, sizeof(enable_info), + "%s\\n%s\\n%s", + enable_info1, enable_info2, + enable_info3); + } + } + } + } + + dtrace_dot("node [shape = circle, fixedsize=true, width=2.5, label=\"%s\\n%s\\n\\n%s\"]; \"%s(pipe%d)\"", + bin_type, blob_name, enable_info, blob_name, id); + } else { + dtrace_dot("node [shape = circle, fixedsize=true, width=2.5, label=\"%s\\n%s\\n\"]; \"%s(pipe%d)\"", + bin_type, blob_name, blob_name, id); + } + + if (stage->stage_num == 0) { + /* + * There are some implicite assumptions about which bin is the + * input binary e.g. which one is connected to the input system + * Priority: + * 1) sp_raw_copy bin has highest priority + * 2) First stage==0 binary of preview, video or capture + */ + if (strlen(dot_id_input_bin) == 0) { + snprintf(dot_id_input_bin, sizeof(dot_id_input_bin), + "%s(pipe%d)", blob_name, id); + } + } + + if (stage->args.in_frame) { + ia_css_debug_pipe_graph_dump_frame( + stage->args.in_frame, id, blob_name, + "in", true); + } + + for (i = 0; i < NUM_VIDEO_TNR_FRAMES; i++) { + if (stage->args.tnr_frames[i]) { + ia_css_debug_pipe_graph_dump_frame( + stage->args.tnr_frames[i], id, + blob_name, "tnr_frame", true); + } + } + + for (i = 0; i < MAX_NUM_VIDEO_DELAY_FRAMES; i++) { + if (stage->args.delay_frames[i]) { + ia_css_debug_pipe_graph_dump_frame( + stage->args.delay_frames[i], id, + blob_name, "delay_frame", true); + } + } + + for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) { + if (stage->args.out_frame[i]) { + ia_css_debug_pipe_graph_dump_frame( + stage->args.out_frame[i], id, blob_name, + "out", false); + } + } + + if (stage->args.out_vf_frame) { + ia_css_debug_pipe_graph_dump_frame( + stage->args.out_vf_frame, id, blob_name, + "out_vf", false); + } +} + +void +ia_css_debug_pipe_graph_dump_sp_raw_copy( + struct ia_css_frame *out_frame) +{ + assert(out_frame); + if (pg_inst.do_init) { + ia_css_debug_pipe_graph_dump_prologue(); + pg_inst.do_init = false; + } + + dtrace_dot("node [shape = circle, fixedsize=true, width=2.5, label=\"%s\\n%s\"]; \"%s(pipe%d)\"", + "sp-binary", "sp_raw_copy", "sp_raw_copy", 1); + + snprintf(ring_buffer, sizeof(ring_buffer), + "node [shape = box, fixedsize=true, width=2, height=0.7]; \"%p\" [label = \"%s\\n%d(%d) x %d\\nRingbuffer\"];", + out_frame, + debug_frame_format2str(out_frame->info.format), + out_frame->info.res.width, + out_frame->info.padded_width, + out_frame->info.res.height); + + dtrace_dot(ring_buffer); + + dtrace_dot( + "\"%s(pipe%d)\"->\"%p\" [label = out_frame];", + "sp_raw_copy", 1, out_frame); + + snprintf(dot_id_input_bin, sizeof(dot_id_input_bin), "%s(pipe%d)", + "sp_raw_copy", 1); +} + +void +ia_css_debug_pipe_graph_dump_stream_config( + const struct ia_css_stream_config *stream_config) +{ + pg_inst.width = stream_config->input_config.input_res.width; + pg_inst.height = stream_config->input_config.input_res.height; + pg_inst.eff_width = stream_config->input_config.effective_res.width; + pg_inst.eff_height = stream_config->input_config.effective_res.height; + pg_inst.stream_format = stream_config->input_config.format; +} + +void +ia_css_debug_dump_resolution( + const struct ia_css_resolution *res, + const char *label) +{ + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "%s: =%d x =%d\n", + label, res->width, res->height); +} + +void +ia_css_debug_dump_frame_info( + const struct ia_css_frame_info *info, + const char *label) +{ + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "%s\n", label); + ia_css_debug_dump_resolution(&info->res, "res"); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "padded_width: %d\n", + info->padded_width); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "format: %d\n", info->format); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "raw_bit_depth: %d\n", + info->raw_bit_depth); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "raw_bayer_order: %d\n", + info->raw_bayer_order); +} + +void +ia_css_debug_dump_capture_config( + const struct ia_css_capture_config *config) +{ + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "%s\n", __func__); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "mode: %d\n", config->mode); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "enable_xnr: %d\n", + config->enable_xnr); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "enable_raw_output: %d\n", + config->enable_raw_output); +} + +void +ia_css_debug_dump_pipe_extra_config( + const struct ia_css_pipe_extra_config *extra_config) +{ + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "%s\n", __func__); + if (extra_config) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "enable_raw_binning: %d\n", + extra_config->enable_raw_binning); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "enable_yuv_ds: %d\n", + extra_config->enable_yuv_ds); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "enable_high_speed: %d\n", + extra_config->enable_high_speed); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "enable_dvs_6axis: %d\n", + extra_config->enable_dvs_6axis); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "enable_reduced_pipe: %d\n", + extra_config->enable_reduced_pipe); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "enable_fractional_ds: %d\n", + extra_config->enable_fractional_ds); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "disable_vf_pp: %d\n", + extra_config->disable_vf_pp); + } +} + +void +ia_css_debug_dump_pipe_config( + const struct ia_css_pipe_config *config) +{ + unsigned int i; + + IA_CSS_ENTER_PRIVATE("config = %p", config); + if (!config) { + IA_CSS_ERROR("NULL input parameter"); + IA_CSS_LEAVE_PRIVATE(""); + return; + } + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "mode: %d\n", config->mode); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "isp_pipe_version: %d\n", + config->isp_pipe_version); + ia_css_debug_dump_resolution(&config->bayer_ds_out_res, + "bayer_ds_out_res"); + ia_css_debug_dump_resolution(&config->capt_pp_in_res, + "capt_pp_in_res"); + ia_css_debug_dump_resolution(&config->vf_pp_in_res, "vf_pp_in_res"); + + if (IS_ISP2401) { + ia_css_debug_dump_resolution(&config->output_system_in_res, + "output_system_in_res"); + } + ia_css_debug_dump_resolution(&config->dvs_crop_out_res, + "dvs_crop_out_res"); + for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) { + ia_css_debug_dump_frame_info(&config->output_info[i], "output_info"); + ia_css_debug_dump_frame_info(&config->vf_output_info[i], + "vf_output_info"); + } + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "acc_extension: %p\n", + config->acc_extension); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "num_acc_stages: %d\n", + config->num_acc_stages); + ia_css_debug_dump_capture_config(&config->default_capture_config); + ia_css_debug_dump_resolution(&config->dvs_envelope, "dvs_envelope"); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "dvs_frame_delay: %d\n", + config->dvs_frame_delay); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "acc_num_execs: %d\n", + config->acc_num_execs); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "enable_dz: %d\n", + config->enable_dz); + IA_CSS_LEAVE_PRIVATE(""); +} + +void +ia_css_debug_dump_stream_config_source( + const struct ia_css_stream_config *config) +{ + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "%s()\n", __func__); + switch (config->mode) { + case IA_CSS_INPUT_MODE_SENSOR: + case IA_CSS_INPUT_MODE_BUFFERED_SENSOR: + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "source.port\n"); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "port: %d\n", + config->source.port.port); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "num_lanes: %d\n", + config->source.port.num_lanes); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "timeout: %d\n", + config->source.port.timeout); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "compression: %d\n", + config->source.port.compression.type); + break; + case IA_CSS_INPUT_MODE_TPG: + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "source.tpg\n"); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "id: %d\n", + config->source.tpg.id); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "mode: %d\n", + config->source.tpg.mode); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "x_mask: 0x%x\n", + config->source.tpg.x_mask); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "x_delta: %d\n", + config->source.tpg.x_delta); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "y_mask: 0x%x\n", + config->source.tpg.y_mask); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "y_delta: %d\n", + config->source.tpg.y_delta); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "xy_mask: 0x%x\n", + config->source.tpg.xy_mask); + break; + case IA_CSS_INPUT_MODE_PRBS: + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "source.prbs\n"); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "id: %d\n", + config->source.prbs.id); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "h_blank: %d\n", + config->source.prbs.h_blank); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "v_blank: %d\n", + config->source.prbs.v_blank); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "seed: 0x%x\n", + config->source.prbs.seed); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "seed1: 0x%x\n", + config->source.prbs.seed1); + break; + default: + case IA_CSS_INPUT_MODE_FIFO: + case IA_CSS_INPUT_MODE_MEMORY: + break; + } +} + +void +ia_css_debug_dump_mipi_buffer_config( + const struct ia_css_mipi_buffer_config *config) +{ + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "%s()\n", __func__); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "size_mem_words: %d\n", + config->size_mem_words); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "nof_mipi_buffers: %d\n", + config->nof_mipi_buffers); +} + +void +ia_css_debug_dump_metadata_config( + const struct ia_css_metadata_config *config) +{ + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "%s()\n", __func__); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "data_type: %d\n", + config->data_type); + ia_css_debug_dump_resolution(&config->resolution, "resolution"); +} + +void +ia_css_debug_dump_stream_config( + const struct ia_css_stream_config *config, + int num_pipes) +{ + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "%s()\n", __func__); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "num_pipes: %d\n", num_pipes); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "mode: %d\n", config->mode); + ia_css_debug_dump_stream_config_source(config); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "channel_id: %d\n", + config->channel_id); + ia_css_debug_dump_resolution(&config->input_config.input_res, "input_res"); + ia_css_debug_dump_resolution(&config->input_config.effective_res, + "effective_res"); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "format: %d\n", + config->input_config.format); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "bayer_order: %d\n", + config->input_config.bayer_order); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "sensor_binning_factor: %d\n", + config->sensor_binning_factor); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "pixels_per_clock: %d\n", + config->pixels_per_clock); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "online: %d\n", + config->online); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "init_num_cont_raw_buf: %d\n", + config->init_num_cont_raw_buf); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "target_num_cont_raw_buf: %d\n", + config->target_num_cont_raw_buf); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "pack_raw_pixels: %d\n", + config->pack_raw_pixels); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "continuous: %d\n", + config->continuous); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "flash_gpio_pin: %d\n", + config->flash_gpio_pin); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "left_padding: %d\n", + config->left_padding); + ia_css_debug_dump_mipi_buffer_config(&config->mipi_buffer_config); + ia_css_debug_dump_metadata_config(&config->metadata_config); +} + +/* + Trace support. + + This tracer is using a buffer to trace the flow of the FW and dump misc values (see below for details). + Currently, support is only for SKC. + To enable support for other platforms: + - Allocate a buffer for tracing in DMEM. The longer the better. + - Use the DBG_init routine in sp.hive.c to initiatilize the tracer with the address and size selected. + - Add trace points in the SP code wherever needed. + - Enable the dump below with the required address and required adjustments. + Dump is called at the end of ia_css_debug_dump_sp_state(). +*/ + +/* + dump_trace() : dump the trace points from DMEM2. + for every trace point, the following are printed: index, major:minor and the 16-bit attached value. + The routine looks for the first 0, and then prints from it cyclically. + Data forma in DMEM2: + first 4 DWORDS: header + DWORD 0: data description + byte 0: version + byte 1: number of threads (for future use) + byte 2+3: number ot TPs + DWORD 1: command byte + data (for future use) + byte 0: command + byte 1-3: command signature + DWORD 2-3: additional data (for future use) + Following data is 4-byte oriented: + byte 0: major + byte 1: minor + byte 2-3: data +*/ +#if TRACE_ENABLE_SP0 || TRACE_ENABLE_SP1 || TRACE_ENABLE_ISP +static void debug_dump_one_trace(enum TRACE_CORE_ID proc_id) +{ +#if defined(HAS_TRACER_V2) + u32 start_addr; + u32 start_addr_data; + u32 item_size; + u32 tmp; + u8 tid_val; + enum TRACE_DUMP_FORMAT dump_format; + + int i, j, max_trace_points, point_num, limit = -1; + /* using a static buffer here as the driver has issues allocating memory */ + static u32 trace_read_buf[TRACE_BUFF_SIZE] = {0}; + static struct trace_header_t header; + u8 *header_arr; + + /* read the header and parse it */ + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "~~~ Tracer "); + switch (proc_id) { + case TRACE_SP0_ID: + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "SP0"); + start_addr = TRACE_SP0_ADDR; + start_addr_data = TRACE_SP0_DATA_ADDR; + item_size = TRACE_SP0_ITEM_SIZE; + max_trace_points = TRACE_SP0_MAX_POINTS; + break; + case TRACE_SP1_ID: + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "SP1"); + start_addr = TRACE_SP1_ADDR; + start_addr_data = TRACE_SP1_DATA_ADDR; + item_size = TRACE_SP1_ITEM_SIZE; + max_trace_points = TRACE_SP1_MAX_POINTS; + break; + case TRACE_ISP_ID: + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ISP"); + start_addr = TRACE_ISP_ADDR; + start_addr_data = TRACE_ISP_DATA_ADDR; + item_size = TRACE_ISP_ITEM_SIZE; + max_trace_points = TRACE_ISP_MAX_POINTS; + break; + default: + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "\t\ttraces are not supported for this processor ID - exiting\n"); + return; + } + + if (!IS_ISP2401) { + tmp = ia_css_device_load_uint32(start_addr); + point_num = (tmp >> 16) & 0xFFFF; + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, " ver %d %d points\n", tmp & 0xFF, + point_num); + } else { + /* Loading byte-by-byte as using the master routine had issues */ + header_arr = (uint8_t *)&header; + for (i = 0; i < (int)sizeof(struct trace_header_t); i++) + header_arr[i] = ia_css_device_load_uint8(start_addr + (i)); + + point_num = header.max_tracer_points; + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, " ver %d %d points\n", header.version, + point_num); + + tmp = header.version; + } + if ((tmp & 0xFF) != TRACER_VER) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "\t\tUnknown version - exiting\n"); + return; + } + if (point_num > max_trace_points) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "\t\tToo many points - exiting\n"); + return; + } + /* copy the TPs and find the first 0 */ + for (i = 0; i < point_num; i++) { + trace_read_buf[i] = ia_css_device_load_uint32(start_addr_data + + (i * item_size)); + if ((limit == (-1)) && (trace_read_buf[i] == 0)) + limit = i; + } + if (IS_ISP2401) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "Status:\n"); + for (i = 0; i < SH_CSS_MAX_SP_THREADS; i++) + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "\tT%d: %3d (%02x) %6d (%04x) %10d (%08x)\n", i, + header.thr_status_byte[i], header.thr_status_byte[i], + header.thr_status_word[i], header.thr_status_word[i], + header.thr_status_dword[i], header.thr_status_dword[i]); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "Scratch:\n"); + for (i = 0; i < MAX_SCRATCH_DATA; i++) + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "%10d (%08x) ", + header.scratch_debug[i], header.scratch_debug[i]); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "\n"); + } + /* two 0s in the beginning: empty buffer */ + if ((trace_read_buf[0] == 0) && (trace_read_buf[1] == 0)) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "\t\tEmpty tracer - exiting\n"); + return; + } + /* no overrun: start from 0 */ + if ((limit == point_num - 1) || + /* first 0 is at the end - border case */ + (trace_read_buf[limit + 1] == + 0)) /* did not make a full cycle after the memset */ + limit = 0; + /* overrun: limit is the first non-zero after the first zero */ + else + limit++; + + /* print the TPs */ + for (i = 0; i < point_num; i++) { + j = (limit + i) % point_num; + if (trace_read_buf[j]) { + if (!IS_ISP2401) { + TRACE_DUMP_FORMAT dump_format = FIELD_FORMAT_UNPACK(trace_read_buf[j]); + } else { + tid_val = FIELD_TID_UNPACK(trace_read_buf[j]); + dump_format = TRACE_DUMP_FORMAT_POINT; + + /* + * When tid value is 111b, the data will be interpreted differently: + * tid val is ignored, major field contains 2 bits (msb) for format type + */ + if (tid_val == FIELD_TID_SEL_FORMAT_PAT) { + dump_format = FIELD_FORMAT_UNPACK(trace_read_buf[j]); + } + } + switch (dump_format) { + case TRACE_DUMP_FORMAT_POINT: + ia_css_debug_dtrace( + IA_CSS_DEBUG_TRACE, "\t\t%d %d:%d value - %d\n", + j, FIELD_MAJOR_UNPACK(trace_read_buf[j]), + FIELD_MINOR_UNPACK(trace_read_buf[j]), + FIELD_VALUE_UNPACK(trace_read_buf[j])); + break; + /* ISP2400 */ + case TRACE_DUMP_FORMAT_VALUE24_HEX: + ia_css_debug_dtrace( + IA_CSS_DEBUG_TRACE, "\t\t%d, %d, 24bit value %x H\n", + j, + FIELD_MAJOR_UNPACK(trace_read_buf[j]), + FIELD_VALUE_24_UNPACK(trace_read_buf[j])); + break; + /* ISP2400 */ + case TRACE_DUMP_FORMAT_VALUE24_DEC: + ia_css_debug_dtrace( + IA_CSS_DEBUG_TRACE, "\t\t%d, %d, 24bit value %d D\n", + j, + FIELD_MAJOR_UNPACK(trace_read_buf[j]), + FIELD_VALUE_24_UNPACK(trace_read_buf[j])); + break; + /* ISP2401 */ + case TRACE_DUMP_FORMAT_POINT_NO_TID: + ia_css_debug_dtrace( + IA_CSS_DEBUG_TRACE, "\t\t%d %d:%d value - %x (%d)\n", + j, + FIELD_MAJOR_W_FMT_UNPACK(trace_read_buf[j]), + FIELD_MINOR_UNPACK(trace_read_buf[j]), + FIELD_VALUE_UNPACK(trace_read_buf[j]), + FIELD_VALUE_UNPACK(trace_read_buf[j])); + break; + /* ISP2401 */ + case TRACE_DUMP_FORMAT_VALUE24: + ia_css_debug_dtrace( + IA_CSS_DEBUG_TRACE, "\t\t%d, %d, 24bit value %x (%d)\n", + j, + FIELD_MAJOR_UNPACK(trace_read_buf[j]), + FIELD_MAJOR_W_FMT_UNPACK(trace_read_buf[j]), + FIELD_VALUE_24_UNPACK(trace_read_buf[j]), + FIELD_VALUE_24_UNPACK(trace_read_buf[j])); + break; + case TRACE_DUMP_FORMAT_VALUE24_TIMING: + ia_css_debug_dtrace( + IA_CSS_DEBUG_TRACE, "\t\t%d, %d, timing %x\n", + j, + FIELD_MAJOR_UNPACK(trace_read_buf[j]), + FIELD_VALUE_24_UNPACK(trace_read_buf[j])); + break; + case TRACE_DUMP_FORMAT_VALUE24_TIMING_DELTA: + ia_css_debug_dtrace( + IA_CSS_DEBUG_TRACE, "\t\t%d, %d, timing delta %x\n", + j, + FIELD_MAJOR_UNPACK(trace_read_buf[j]), + FIELD_VALUE_24_UNPACK(trace_read_buf[j])); + break; + default: + ia_css_debug_dtrace( + IA_CSS_DEBUG_TRACE, + "no such trace dump format %d", + dump_format); + break; + } + } + } +#else + (void)proc_id; +#endif /* HAS_TRACER_V2 */ +} +#endif /* TRACE_ENABLE_SP0 || TRACE_ENABLE_SP1 || TRACE_ENABLE_ISP */ + +void ia_css_debug_dump_trace(void) +{ +#if TRACE_ENABLE_SP0 + debug_dump_one_trace(TRACE_SP0_ID); +#endif +#if TRACE_ENABLE_SP1 + debug_dump_one_trace(TRACE_SP1_ID); +#endif +#if TRACE_ENABLE_ISP + debug_dump_one_trace(TRACE_ISP_ID); +#endif +} + +/* Tagger state dump function. The tagger is only available when the CSS + * contains an input system (2400 or 2401). */ +void ia_css_debug_tagger_state(void) +{ + unsigned int i; + unsigned int HIVE_ADDR_tagger_frames; + ia_css_tagger_buf_sp_elem_t tbuf_frames[MAX_CB_ELEMS_FOR_TAGGER]; + + HIVE_ADDR_tagger_frames = sh_css_sp_fw.info.sp.tagger_frames_addr; + + /* This variable is not used in crun */ + (void)HIVE_ADDR_tagger_frames; + + /* 2400 and 2401 only have 1 SP, so the tagger lives on SP0 */ + sp_dmem_load(SP0_ID, + (unsigned int)sp_address_of(tagger_frames), + tbuf_frames, + sizeof(tbuf_frames)); + + ia_css_debug_dtrace(2, "Tagger Info:\n"); + for (i = 0; i < MAX_CB_ELEMS_FOR_TAGGER; i++) { + ia_css_debug_dtrace(2, "\t tagger frame[%d]: exp_id=%d, marked=%d, locked=%d\n", + i, tbuf_frames[i].exp_id, tbuf_frames[i].mark, tbuf_frames[i].lock); + } +} + +/* ISP2401 */ +void ia_css_debug_pc_dump(sp_ID_t id, unsigned int num_of_dumps) +{ + unsigned int pc; + unsigned int i; + hrt_data sc = sp_ctrl_load(id, SP_SC_REG); + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "SP%-1d Status reg: 0x%X\n", id, sc); + sc = sp_ctrl_load(id, SP_CTRL_SINK_REG); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "SP%-1d Stall reg: 0x%X\n", id, sc); + for (i = 0; i < num_of_dumps; i++) { + pc = sp_ctrl_load(id, SP_PC_REG); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "SP%-1d PC: 0x%X\n", id, pc); + } +} diff --git a/drivers/staging/media/atomisp/pci/runtime/event/interface/ia_css_event.h b/drivers/staging/media/atomisp/pci/runtime/event/interface/ia_css_event.h new file mode 100644 index 000000000..ebbd90b14 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/event/interface/ia_css_event.h @@ -0,0 +1,31 @@ +/* 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. + */ + +#ifndef _IA_CSS_EVENT_H +#define _IA_CSS_EVENT_H + +#include <type_support.h> +#include "sw_event_global.h" /*event macros.TODO : Change File Name..???*/ + +bool ia_css_event_encode( + u8 *in, + u8 nr, + uint32_t *out); + +void ia_css_event_decode( + u32 event, + uint8_t *payload); + +#endif /*_IA_CSS_EVENT_H*/ diff --git a/drivers/staging/media/atomisp/pci/runtime/event/src/event.c b/drivers/staging/media/atomisp/pci/runtime/event/src/event.c new file mode 100644 index 000000000..e702297b0 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/event/src/event.c @@ -0,0 +1,110 @@ +// 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 "sh_css_sp.h" + +#include "dma.h" /* N_DMA_CHANNEL_ID */ + +#include <type_support.h> +#include "ia_css_binary.h" +#include "sh_css_hrt.h" +#include "sh_css_defs.h" +#include "sh_css_internal.h" +#include "ia_css_debug.h" +#include "ia_css_debug_internal.h" +#include "sh_css_legacy.h" + +#include "gdc_device.h" /* HRT_GDC_N */ + +/*#include "sp.h"*/ /* host2sp_enqueue_frame_data() */ + +#include "assert_support.h" + +#include "ia_css_queue.h" /* host_sp_enqueue_XXX */ +#include "ia_css_event.h" /* ia_css_event_encode */ +/* + * @brief Encode the information into the software-event. + * Refer to "sw_event_public.h" for details. + */ +bool ia_css_event_encode( + u8 *in, + u8 nr, + uint32_t *out) +{ + bool ret; + u32 nr_of_bits; + u32 i; + + assert(in); + assert(out); + OP___assert(nr > 0 && nr <= MAX_NR_OF_PAYLOADS_PER_SW_EVENT); + + /* initialize the output */ + *out = 0; + + /* get the number of bits per information */ + nr_of_bits = sizeof(uint32_t) * 8 / nr; + + /* compress the all inputs into a signle output */ + for (i = 0; i < nr; i++) { + *out <<= nr_of_bits; + *out |= in[i]; + } + + /* get the return value */ + ret = (nr > 0 && nr <= MAX_NR_OF_PAYLOADS_PER_SW_EVENT); + + return ret; +} + +void ia_css_event_decode( + u32 event, + uint8_t *payload) +{ + assert(payload[1] == 0); + assert(payload[2] == 0); + assert(payload[3] == 0); + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, + "ia_css_event_decode() enter:\n"); + + /* First decode according to the common case + * In case of a PORT_EOF event we overwrite with + * the specific values + * This is somewhat ugly but probably somewhat efficient + * (and it avoids some code duplication) + */ + payload[0] = event & 0xff; /*event_code */ + payload[1] = (event >> 8) & 0xff; + payload[2] = (event >> 16) & 0xff; + payload[3] = 0; + + switch (payload[0]) { + case SH_CSS_SP_EVENT_PORT_EOF: + payload[2] = 0; + payload[3] = (event >> 24) & 0xff; + break; + + case SH_CSS_SP_EVENT_ACC_STAGE_COMPLETE: + case SH_CSS_SP_EVENT_TIMER: + case SH_CSS_SP_EVENT_FRAME_TAGGED: + case SH_CSS_SP_EVENT_FW_WARNING: + case SH_CSS_SP_EVENT_FW_ASSERT: + payload[3] = (event >> 24) & 0xff; + break; + default: + break; + } +} diff --git a/drivers/staging/media/atomisp/pci/runtime/eventq/interface/ia_css_eventq.h b/drivers/staging/media/atomisp/pci/runtime/eventq/interface/ia_css_eventq.h new file mode 100644 index 000000000..fd001ae35 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/eventq/interface/ia_css_eventq.h @@ -0,0 +1,54 @@ +/* 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. + */ + +#ifndef _IA_CSS_EVENTQ_H +#define _IA_CSS_EVENTQ_H + +#include "ia_css_queue.h" /* queue APIs */ + +/** + * @brief HOST receives event from SP. + * + * @param[in] eventq_handle eventq_handle. + * @param[in] payload The event payload. + * @return 0 - Successfully dequeue. + * @return -EINVAL - Invalid argument. + * @return -ENODATA - Queue is empty. + */ +int ia_css_eventq_recv( + ia_css_queue_t *eventq_handle, + uint8_t *payload); + +/** + * @brief The Host sends the event to SP. + * The caller of this API will be blocked until the event + * is sent. + * + * @param[in] eventq_handle eventq_handle. + * @param[in] evt_id The event ID. + * @param[in] evt_payload_0 The event payload. + * @param[in] evt_payload_1 The event payload. + * @param[in] evt_payload_2 The event payload. + * @return 0 - Successfully enqueue. + * @return -EINVAL - Invalid argument. + * @return -ENOBUFS - Queue is full. + */ +int ia_css_eventq_send( + ia_css_queue_t *eventq_handle, + u8 evt_id, + u8 evt_payload_0, + u8 evt_payload_1, + uint8_t evt_payload_2); +#endif /* _IA_CSS_EVENTQ_H */ diff --git a/drivers/staging/media/atomisp/pci/runtime/eventq/src/eventq.c b/drivers/staging/media/atomisp/pci/runtime/eventq/src/eventq.c new file mode 100644 index 000000000..df75cef46 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/eventq/src/eventq.c @@ -0,0 +1,76 @@ +// 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_types.h" +#include "assert_support.h" +#include "ia_css_queue.h" /* sp2host_dequeue_irq_event() */ +#include "ia_css_eventq.h" +#include "ia_css_event.h" /* ia_css_event_encode() + ia_css_event_decode() + */ +int ia_css_eventq_recv( + ia_css_queue_t *eventq_handle, + uint8_t *payload) +{ + u32 sp_event; + int error; + + /* dequeue the IRQ event */ + error = ia_css_queue_dequeue(eventq_handle, &sp_event); + + /* check whether the IRQ event is available or not */ + if (!error) + ia_css_event_decode(sp_event, payload); + return error; +} + +/* + * @brief The Host sends the event to the SP. + * Refer to "sh_css_sp.h" for details. + */ +int ia_css_eventq_send( + ia_css_queue_t *eventq_handle, + u8 evt_id, + u8 evt_payload_0, + u8 evt_payload_1, + uint8_t evt_payload_2) +{ + u8 tmp[4]; + u32 sw_event; + int error = -ENOSYS; + + /* + * Encode the queue type, the thread ID and + * the queue ID into the event. + */ + tmp[0] = evt_id; + tmp[1] = evt_payload_0; + tmp[2] = evt_payload_1; + tmp[3] = evt_payload_2; + ia_css_event_encode(tmp, 4, &sw_event); + + /* queue the software event (busy-waiting) */ + for ( ; ; ) { + error = ia_css_queue_enqueue(eventq_handle, sw_event); + if (error != -ENOBUFS) { + /* We were able to successfully send the event + or had a real failure. return the status*/ + break; + } + /* Wait for the queue to be not full and try again*/ + udelay(1); + } + return error; +} diff --git a/drivers/staging/media/atomisp/pci/runtime/frame/interface/ia_css_frame.h b/drivers/staging/media/atomisp/pci/runtime/frame/interface/ia_css_frame.h new file mode 100644 index 000000000..700070c58 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/frame/interface/ia_css_frame.h @@ -0,0 +1,141 @@ +/* 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. + */ + +#ifndef __IA_CSS_FRAME_H__ +#define __IA_CSS_FRAME_H__ + +/* ISP2401 */ +#include <ia_css_types.h> + +#include <ia_css_frame_format.h> +#include <ia_css_frame_public.h> +#include "dma.h" + +/********************************************************************* +**** Frame INFO APIs +**********************************************************************/ +/* @brief Sets the given width and alignment to the frame info + * + * @param + * @param[in] info The info to which parameters would set + * @param[in] width The width to be set to info + * @param[in] aligned The aligned to be set to info + * @return + */ +void ia_css_frame_info_set_width(struct ia_css_frame_info *info, + unsigned int width, + unsigned int min_padded_width); + +/* @brief Sets the given format to the frame info + * + * @param + * @param[in] info The info to which parameters would set + * @param[in] format The format to be set to info + * @return + */ +void ia_css_frame_info_set_format(struct ia_css_frame_info *info, + enum ia_css_frame_format format); + +/* @brief Sets the frame info with the given parameters + * + * @param + * @param[in] info The info to which parameters would set + * @param[in] width The width to be set to info + * @param[in] height The height to be set to info + * @param[in] format The format to be set to info + * @param[in] aligned The aligned to be set to info + * @return + */ +void ia_css_frame_info_init(struct ia_css_frame_info *info, + unsigned int width, + unsigned int height, + enum ia_css_frame_format format, + unsigned int aligned); + +/* @brief Checks whether 2 frame infos has the same resolution + * + * @param + * @param[in] frame_a The first frame to be compared + * @param[in] frame_b The second frame to be compared + * @return Returns true if the frames are equal + */ +bool ia_css_frame_info_is_same_resolution( + const struct ia_css_frame_info *info_a, + const struct ia_css_frame_info *info_b); + +/* @brief Check the frame info is valid + * + * @param + * @param[in] info The frame attributes to be initialized + * @return The error code. + */ +int ia_css_frame_check_info(const struct ia_css_frame_info *info); + +/********************************************************************* +**** Frame APIs +**********************************************************************/ + +/* @brief Initialize the plane depending on the frame type + * + * @param + * @param[in] frame The frame attributes to be initialized + * @return The error code. + */ +int ia_css_frame_init_planes(struct ia_css_frame *frame); + +/* @brief Free an array of frames + * + * @param + * @param[in] num_frames The number of frames to be freed in the array + * @param[in] **frames_array The array of frames to be removed + * @return + */ +void ia_css_frame_free_multiple(unsigned int num_frames, + struct ia_css_frame **frames_array); + +/* @brief Allocate a CSS frame structure of given size in bytes.. + * + * @param frame The allocated frame. + * @param[in] size_bytes The frame size in bytes. + * @return The error code. + * + * Allocate a frame using the given size in bytes. + * The frame structure is partially null initialized. + */ +int ia_css_frame_allocate_with_buffer_size(struct ia_css_frame **frame, + const unsigned int size_bytes); + +/* @brief Check whether 2 frames are same type + * + * @param + * @param[in] frame_a The first frame to be compared + * @param[in] frame_b The second frame to be compared + * @return Returns true if the frames are equal + */ +bool ia_css_frame_is_same_type( + const struct ia_css_frame *frame_a, + const struct ia_css_frame *frame_b); + +/* @brief Configure a dma port from frame info + * + * @param + * @param[in] config The DAM port configuration + * @param[in] info The frame info + * @return + */ +int ia_css_dma_configure_from_info(struct dma_port_config *config, + const struct ia_css_frame_info *info); + +#endif /* __IA_CSS_FRAME_H__ */ diff --git a/drivers/staging/media/atomisp/pci/runtime/frame/interface/ia_css_frame_comm.h b/drivers/staging/media/atomisp/pci/runtime/frame/interface/ia_css_frame_comm.h new file mode 100644 index 000000000..ce6110efb --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/frame/interface/ia_css_frame_comm.h @@ -0,0 +1,116 @@ +/* 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. + */ + +#ifndef __IA_CSS_FRAME_COMM_H__ +#define __IA_CSS_FRAME_COMM_H__ + +#include "type_support.h" +#include "platform_support.h" +#include "runtime/bufq/interface/ia_css_bufq_comm.h" +#include <system_local.h> /* ia_css_ptr */ + +/* + * These structs are derived from structs defined in ia_css_types.h + * (just take out the "_sp" from the struct name to get the "original") + * All the fields that are not needed by the SP are removed. + */ +struct ia_css_frame_sp_plane { + unsigned int offset; /* offset in bytes to start of frame data */ + /* offset is wrt data in sh_css_sp_sp_frame */ +}; + +struct ia_css_frame_sp_binary_plane { + unsigned int size; + struct ia_css_frame_sp_plane data; +}; + +struct ia_css_frame_sp_yuv_planes { + struct ia_css_frame_sp_plane y; + struct ia_css_frame_sp_plane u; + struct ia_css_frame_sp_plane v; +}; + +struct ia_css_frame_sp_nv_planes { + struct ia_css_frame_sp_plane y; + struct ia_css_frame_sp_plane uv; +}; + +struct ia_css_frame_sp_rgb_planes { + struct ia_css_frame_sp_plane r; + struct ia_css_frame_sp_plane g; + struct ia_css_frame_sp_plane b; +}; + +struct ia_css_frame_sp_plane6 { + struct ia_css_frame_sp_plane r; + struct ia_css_frame_sp_plane r_at_b; + struct ia_css_frame_sp_plane gr; + struct ia_css_frame_sp_plane gb; + struct ia_css_frame_sp_plane b; + struct ia_css_frame_sp_plane b_at_r; +}; + +struct ia_css_sp_resolution { + u16 width; /* width of valid data in pixels */ + u16 height; /* Height of valid data in lines */ +}; + +/* + * Frame info struct. This describes the contents of an image frame buffer. + */ +struct ia_css_frame_sp_info { + struct ia_css_sp_resolution res; + u16 padded_width; /* stride of line in memory + (in pixels) */ + unsigned char format; /* format of the frame data */ + unsigned char raw_bit_depth; /* number of valid bits per pixel, + only valid for RAW bayer frames */ + unsigned char raw_bayer_order; /* bayer order, only valid + for RAW bayer frames */ + unsigned char padding[3]; /* Extend to 32 bit multiple */ +}; + +struct ia_css_buffer_sp { + union { + ia_css_ptr xmem_addr; + enum sh_css_queue_id queue_id; + } buf_src; + enum ia_css_buffer_type buf_type; +}; + +struct ia_css_frame_sp { + struct ia_css_frame_sp_info info; + struct ia_css_buffer_sp buf_attr; + union { + struct ia_css_frame_sp_plane raw; + struct ia_css_frame_sp_plane rgb; + struct ia_css_frame_sp_rgb_planes planar_rgb; + struct ia_css_frame_sp_plane yuyv; + struct ia_css_frame_sp_yuv_planes yuv; + struct ia_css_frame_sp_nv_planes nv; + struct ia_css_frame_sp_plane6 plane6; + struct ia_css_frame_sp_binary_plane binary; + } planes; +}; + +void ia_css_frame_info_to_frame_sp_info( + struct ia_css_frame_sp_info *sp_info, + const struct ia_css_frame_info *info); + +void ia_css_resolution_to_sp_resolution( + struct ia_css_sp_resolution *sp_info, + const struct ia_css_resolution *info); + +#endif /*__IA_CSS_FRAME_COMM_H__*/ diff --git a/drivers/staging/media/atomisp/pci/runtime/frame/src/frame.c b/drivers/staging/media/atomisp/pci/runtime/frame/src/frame.c new file mode 100644 index 000000000..5a7058320 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/frame/src/frame.c @@ -0,0 +1,849 @@ +// 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 "hmm.h" + +#include "ia_css_frame.h" +#include <math_support.h> +#include "assert_support.h" +#include "ia_css_debug.h" +#include "isp.h" +#include "sh_css_internal.h" +#include "atomisp_internal.h" + +#define NV12_TILEY_TILE_WIDTH 128 +#define NV12_TILEY_TILE_HEIGHT 32 + +/************************************************************************** +** Static functions declarations +**************************************************************************/ +static void frame_init_plane(struct ia_css_frame_plane *plane, + unsigned int width, + unsigned int stride, + unsigned int height, + unsigned int offset); + +static void frame_init_single_plane(struct ia_css_frame *frame, + struct ia_css_frame_plane *plane, + unsigned int height, + unsigned int subpixels_per_line, + unsigned int bytes_per_pixel); + +static void frame_init_raw_single_plane( + struct ia_css_frame *frame, + struct ia_css_frame_plane *plane, + unsigned int height, + unsigned int subpixels_per_line, + unsigned int bits_per_pixel); + +static void frame_init_nv_planes(struct ia_css_frame *frame, + unsigned int horizontal_decimation, + unsigned int vertical_decimation, + unsigned int bytes_per_element); + +static void frame_init_yuv_planes(struct ia_css_frame *frame, + unsigned int horizontal_decimation, + unsigned int vertical_decimation, + bool swap_uv, + unsigned int bytes_per_element); + +static void frame_init_rgb_planes(struct ia_css_frame *frame, + unsigned int bytes_per_element); + +static void frame_init_qplane6_planes(struct ia_css_frame *frame); + +static int frame_allocate_buffer_data(struct ia_css_frame *frame); + +static int frame_allocate_with_data(struct ia_css_frame **frame, + unsigned int width, + unsigned int height, + enum ia_css_frame_format format, + unsigned int padded_width, + unsigned int raw_bit_depth); + +static struct ia_css_frame *frame_create(unsigned int width, + unsigned int height, + enum ia_css_frame_format format, + unsigned int padded_width, + unsigned int raw_bit_depth, + bool valid); + +static unsigned +ia_css_elems_bytes_from_info( + const struct ia_css_frame_info *info); + +/************************************************************************** +** CSS API functions, exposed by ia_css.h +**************************************************************************/ + +void ia_css_frame_zero(struct ia_css_frame *frame) +{ + assert(frame); + hmm_set(frame->data, 0, frame->data_bytes); +} + +int ia_css_frame_allocate_from_info(struct ia_css_frame **frame, + const struct ia_css_frame_info *info) +{ + int err = 0; + + if (!frame || !info) + return -EINVAL; + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_frame_allocate_from_info() enter:\n"); + err = + ia_css_frame_allocate(frame, info->res.width, info->res.height, + info->format, info->padded_width, + info->raw_bit_depth); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_frame_allocate_from_info() leave:\n"); + return err; +} + +int ia_css_frame_allocate(struct ia_css_frame **frame, + unsigned int width, + unsigned int height, + enum ia_css_frame_format format, + unsigned int padded_width, + unsigned int raw_bit_depth) +{ + int err = 0; + + if (!frame || width == 0 || height == 0) + return -EINVAL; + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_frame_allocate() enter: width=%d, height=%d, format=%d, padded_width=%d, raw_bit_depth=%d\n", + width, height, format, padded_width, raw_bit_depth); + + err = frame_allocate_with_data(frame, width, height, format, + padded_width, raw_bit_depth); + + if ((*frame) && err == 0) + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_frame_allocate() leave: frame=%p, data(DDR address)=0x%x\n", *frame, + (*frame)->data); + else + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_frame_allocate() leave: frame=%p, data(DDR address)=0x%x\n", + (void *)-1, (unsigned int)-1); + + return err; +} + +int ia_css_frame_map(struct ia_css_frame **frame, + const struct ia_css_frame_info *info, + const void __user *data, + unsigned int pgnr) +{ + int err = 0; + struct ia_css_frame *me; + + assert(frame); + + /* Create the frame structure */ + err = ia_css_frame_create_from_info(&me, info); + + if (err) + return err; + + if (pgnr < ((PAGE_ALIGN(me->data_bytes)) >> PAGE_SHIFT)) { + dev_err(atomisp_dev, + "user space memory size is less than the expected size..\n"); + err = -ENOMEM; + goto error; + } else if (pgnr > ((PAGE_ALIGN(me->data_bytes)) >> PAGE_SHIFT)) { + dev_err(atomisp_dev, + "user space memory size is large than the expected size..\n"); + err = -ENOMEM; + goto error; + } + + me->data = hmm_create_from_userdata(me->data_bytes, data); + if (me->data == mmgr_NULL) + err = -EINVAL; + +error: + if (err) { + kvfree(me); + me = NULL; + } + + *frame = me; + + return err; +} + +int ia_css_frame_create_from_info(struct ia_css_frame **frame, + const struct ia_css_frame_info *info) +{ + int err = 0; + struct ia_css_frame *me; + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_frame_create_from_info() enter:\n"); + if (!frame || !info) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_frame_create_from_info() leave: invalid arguments\n"); + return -EINVAL; + } + + me = frame_create(info->res.width, + info->res.height, + info->format, + info->padded_width, + info->raw_bit_depth, + false); + if (!me) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_frame_create_from_info() leave: frame create failed\n"); + return -ENOMEM; + } + + err = ia_css_frame_init_planes(me); + + if (err) { + kvfree(me); + me = NULL; + } + + *frame = me; + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_frame_create_from_info() leave:\n"); + + return err; +} + +int ia_css_frame_set_data(struct ia_css_frame *frame, + const ia_css_ptr mapped_data, + size_t data_bytes) +{ + int err = 0; + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_frame_set_data() enter:\n"); + if (!frame) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_frame_set_data() leave: NULL frame\n"); + return -EINVAL; + } + + /* If we are setting a valid data. + * Make sure that there is enough + * room for the expected frame format + */ + if ((mapped_data != mmgr_NULL) && (frame->data_bytes > data_bytes)) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_frame_set_data() leave: invalid arguments\n"); + return -EINVAL; + } + + frame->data = mapped_data; + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_frame_set_data() leave:\n"); + + return err; +} + +void ia_css_frame_free(struct ia_css_frame *frame) +{ + IA_CSS_ENTER_PRIVATE("frame = %p", frame); + + if (frame) { + hmm_free(frame->data); + kvfree(frame); + } + + IA_CSS_LEAVE_PRIVATE("void"); +} + +/************************************************************************** +** Module public functions +**************************************************************************/ + +int ia_css_frame_check_info(const struct ia_css_frame_info *info) +{ + assert(info); + if (info->res.width == 0 || info->res.height == 0) + return -EINVAL; + return 0; +} + +int ia_css_frame_init_planes(struct ia_css_frame *frame) +{ + assert(frame); + + switch (frame->info.format) { + case IA_CSS_FRAME_FORMAT_MIPI: + dev_err(atomisp_dev, + "%s: unexpected use of IA_CSS_FRAME_FORMAT_MIPI\n", __func__); + return -EINVAL; + case IA_CSS_FRAME_FORMAT_RAW_PACKED: + frame_init_raw_single_plane(frame, &frame->planes.raw, + frame->info.res.height, + frame->info.padded_width, + frame->info.raw_bit_depth); + break; + case IA_CSS_FRAME_FORMAT_RAW: + frame_init_single_plane(frame, &frame->planes.raw, + frame->info.res.height, + frame->info.padded_width, + frame->info.raw_bit_depth <= 8 ? 1 : 2); + break; + case IA_CSS_FRAME_FORMAT_RGB565: + frame_init_single_plane(frame, &frame->planes.rgb, + frame->info.res.height, + frame->info.padded_width, 2); + break; + case IA_CSS_FRAME_FORMAT_RGBA888: + frame_init_single_plane(frame, &frame->planes.rgb, + frame->info.res.height, + frame->info.padded_width * 4, 1); + break; + case IA_CSS_FRAME_FORMAT_PLANAR_RGB888: + frame_init_rgb_planes(frame, 1); + break; + /* yuyv and uyvu have the same frame layout, only the data + * positioning differs. + */ + case IA_CSS_FRAME_FORMAT_YUYV: + case IA_CSS_FRAME_FORMAT_UYVY: + case IA_CSS_FRAME_FORMAT_CSI_MIPI_YUV420_8: + case IA_CSS_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8: + frame_init_single_plane(frame, &frame->planes.yuyv, + frame->info.res.height, + frame->info.padded_width * 2, 1); + break; + case IA_CSS_FRAME_FORMAT_YUV_LINE: + /* Needs 3 extra lines to allow vf_pp prefetching */ + frame_init_single_plane(frame, &frame->planes.yuyv, + frame->info.res.height * 3 / 2 + 3, + frame->info.padded_width, 1); + break; + case IA_CSS_FRAME_FORMAT_NV11: + frame_init_nv_planes(frame, 4, 1, 1); + break; + /* nv12 and nv21 have the same frame layout, only the data + * positioning differs. + */ + case IA_CSS_FRAME_FORMAT_NV12: + case IA_CSS_FRAME_FORMAT_NV21: + case IA_CSS_FRAME_FORMAT_NV12_TILEY: + frame_init_nv_planes(frame, 2, 2, 1); + break; + case IA_CSS_FRAME_FORMAT_NV12_16: + frame_init_nv_planes(frame, 2, 2, 2); + break; + /* nv16 and nv61 have the same frame layout, only the data + * positioning differs. + */ + case IA_CSS_FRAME_FORMAT_NV16: + case IA_CSS_FRAME_FORMAT_NV61: + frame_init_nv_planes(frame, 2, 1, 1); + break; + case IA_CSS_FRAME_FORMAT_YUV420: + frame_init_yuv_planes(frame, 2, 2, false, 1); + break; + case IA_CSS_FRAME_FORMAT_YUV422: + frame_init_yuv_planes(frame, 2, 1, false, 1); + break; + case IA_CSS_FRAME_FORMAT_YUV444: + frame_init_yuv_planes(frame, 1, 1, false, 1); + break; + case IA_CSS_FRAME_FORMAT_YUV420_16: + frame_init_yuv_planes(frame, 2, 2, false, 2); + break; + case IA_CSS_FRAME_FORMAT_YUV422_16: + frame_init_yuv_planes(frame, 2, 1, false, 2); + break; + case IA_CSS_FRAME_FORMAT_YV12: + frame_init_yuv_planes(frame, 2, 2, true, 1); + break; + case IA_CSS_FRAME_FORMAT_YV16: + frame_init_yuv_planes(frame, 2, 1, true, 1); + break; + case IA_CSS_FRAME_FORMAT_QPLANE6: + frame_init_qplane6_planes(frame); + break; + case IA_CSS_FRAME_FORMAT_BINARY_8: + frame_init_single_plane(frame, &frame->planes.binary.data, + frame->info.res.height, + frame->info.padded_width, 1); + frame->planes.binary.size = 0; + break; + default: + return -EINVAL; + } + return 0; +} + +void ia_css_frame_info_set_width(struct ia_css_frame_info *info, + unsigned int width, + unsigned int min_padded_width) +{ + unsigned int align; + + IA_CSS_ENTER_PRIVATE("info = %p,width = %d, minimum padded width = %d", + info, width, min_padded_width); + if (!info) { + IA_CSS_ERROR("NULL input parameter"); + IA_CSS_LEAVE_PRIVATE(""); + return; + } + align = max(min_padded_width, width); + + info->res.width = width; + /* frames with a U and V plane of 8 bits per pixel need to have + all planes aligned, this means double the alignment for the + Y plane if the horizontal decimation is 2. */ + if (info->format == IA_CSS_FRAME_FORMAT_YUV420 || + info->format == IA_CSS_FRAME_FORMAT_YV12 || + info->format == IA_CSS_FRAME_FORMAT_NV12 || + info->format == IA_CSS_FRAME_FORMAT_NV21 || + info->format == IA_CSS_FRAME_FORMAT_BINARY_8 || + info->format == IA_CSS_FRAME_FORMAT_YUV_LINE) + info->padded_width = + CEIL_MUL(align, 2 * HIVE_ISP_DDR_WORD_BYTES); + else if (info->format == IA_CSS_FRAME_FORMAT_NV12_TILEY) + info->padded_width = CEIL_MUL(align, NV12_TILEY_TILE_WIDTH); + else if (info->format == IA_CSS_FRAME_FORMAT_RAW || + info->format == IA_CSS_FRAME_FORMAT_RAW_PACKED) + info->padded_width = CEIL_MUL(align, 2 * ISP_VEC_NELEMS); + else { + info->padded_width = CEIL_MUL(align, HIVE_ISP_DDR_WORD_BYTES); + } + IA_CSS_LEAVE_PRIVATE(""); +} + +void ia_css_frame_info_set_format(struct ia_css_frame_info *info, + enum ia_css_frame_format format) +{ + assert(info); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_frame_info_set_format() enter:\n"); + info->format = format; +} + +void ia_css_frame_info_init(struct ia_css_frame_info *info, + unsigned int width, + unsigned int height, + enum ia_css_frame_format format, + unsigned int aligned) +{ + IA_CSS_ENTER_PRIVATE("info = %p, width = %d, height = %d, format = %d, aligned = %d", + info, width, height, format, aligned); + if (!info) { + IA_CSS_ERROR("NULL input parameter"); + IA_CSS_LEAVE_PRIVATE(""); + return; + } + info->res.height = height; + info->format = format; + ia_css_frame_info_set_width(info, width, aligned); + IA_CSS_LEAVE_PRIVATE(""); +} + +void ia_css_frame_free_multiple(unsigned int num_frames, + struct ia_css_frame **frames_array) +{ + unsigned int i; + + for (i = 0; i < num_frames; i++) { + if (frames_array[i]) { + ia_css_frame_free(frames_array[i]); + frames_array[i] = NULL; + } + } +} + +int ia_css_frame_allocate_with_buffer_size(struct ia_css_frame **frame, + const unsigned int buffer_size_bytes) +{ + /* AM: Body coppied from frame_allocate_with_data(). */ + int err; + struct ia_css_frame *me = frame_create(0, 0, + IA_CSS_FRAME_FORMAT_NUM,/* Not valid format yet */ + 0, 0, false); + + if (!me) + return -ENOMEM; + + /* Get the data size */ + me->data_bytes = buffer_size_bytes; + + err = frame_allocate_buffer_data(me); + + if (err) { + kvfree(me); + me = NULL; + } + + *frame = me; + + return err; +} + +bool ia_css_frame_info_is_same_resolution( + const struct ia_css_frame_info *info_a, + const struct ia_css_frame_info *info_b) +{ + if (!info_a || !info_b) + return false; + return (info_a->res.width == info_b->res.width) && + (info_a->res.height == info_b->res.height); +} + +bool ia_css_frame_is_same_type(const struct ia_css_frame *frame_a, + const struct ia_css_frame *frame_b) +{ + bool is_equal = false; + const struct ia_css_frame_info *info_a = &frame_a->info, + *info_b = &frame_b->info; + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_frame_is_same_type() enter:\n"); + + if (!info_a || !info_b) + return false; + if (info_a->format != info_b->format) + return false; + if (info_a->padded_width != info_b->padded_width) + return false; + is_equal = ia_css_frame_info_is_same_resolution(info_a, info_b); + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_frame_is_same_type() leave:\n"); + + return is_equal; +} + +int ia_css_dma_configure_from_info(struct dma_port_config *config, + const struct ia_css_frame_info *info) +{ + unsigned int is_raw_packed = info->format == IA_CSS_FRAME_FORMAT_RAW_PACKED; + unsigned int bits_per_pixel = is_raw_packed ? info->raw_bit_depth : + ia_css_elems_bytes_from_info(info) * 8; + unsigned int pix_per_ddrword = HIVE_ISP_DDR_WORD_BITS / bits_per_pixel; + unsigned int words_per_line = CEIL_DIV(info->padded_width, pix_per_ddrword); + unsigned int elems_b = pix_per_ddrword; + + config->stride = HIVE_ISP_DDR_WORD_BYTES * words_per_line; + config->elems = (uint8_t)elems_b; + config->width = (uint16_t)info->res.width; + config->crop = 0; + + if (config->width > info->padded_width) { + dev_err(atomisp_dev, "internal error: padded_width is too small!\n"); + return -EINVAL; + } + + return 0; +} + +/************************************************************************** +** Static functions +**************************************************************************/ + +static void frame_init_plane(struct ia_css_frame_plane *plane, + unsigned int width, + unsigned int stride, + unsigned int height, + unsigned int offset) +{ + plane->height = height; + plane->width = width; + plane->stride = stride; + plane->offset = offset; +} + +static void frame_init_single_plane(struct ia_css_frame *frame, + struct ia_css_frame_plane *plane, + unsigned int height, + unsigned int subpixels_per_line, + unsigned int bytes_per_pixel) +{ + unsigned int stride; + + stride = subpixels_per_line * bytes_per_pixel; + /* Frame height needs to be even number - needed by hw ISYS2401 + In case of odd number, round up to even. + Images won't be impacted by this round up, + only needed by jpeg/embedded data. + As long as buffer allocation and release are using data_bytes, + there won't be memory leak. */ + frame->data_bytes = stride * CEIL_MUL2(height, 2); + frame_init_plane(plane, subpixels_per_line, stride, height, 0); + return; +} + +static void frame_init_raw_single_plane( + struct ia_css_frame *frame, + struct ia_css_frame_plane *plane, + unsigned int height, + unsigned int subpixels_per_line, + unsigned int bits_per_pixel) +{ + unsigned int stride; + + assert(frame); + + stride = HIVE_ISP_DDR_WORD_BYTES * + CEIL_DIV(subpixels_per_line, + HIVE_ISP_DDR_WORD_BITS / bits_per_pixel); + frame->data_bytes = stride * height; + frame_init_plane(plane, subpixels_per_line, stride, height, 0); + return; +} + +static void frame_init_nv_planes(struct ia_css_frame *frame, + unsigned int horizontal_decimation, + unsigned int vertical_decimation, + unsigned int bytes_per_element) +{ + unsigned int y_width = frame->info.padded_width; + unsigned int y_height = frame->info.res.height; + unsigned int uv_width; + unsigned int uv_height; + unsigned int y_bytes; + unsigned int uv_bytes; + unsigned int y_stride; + unsigned int uv_stride; + + assert(horizontal_decimation != 0 && vertical_decimation != 0); + + uv_width = 2 * (y_width / horizontal_decimation); + uv_height = y_height / vertical_decimation; + + if (frame->info.format == IA_CSS_FRAME_FORMAT_NV12_TILEY) { + y_width = CEIL_MUL(y_width, NV12_TILEY_TILE_WIDTH); + uv_width = CEIL_MUL(uv_width, NV12_TILEY_TILE_WIDTH); + y_height = CEIL_MUL(y_height, NV12_TILEY_TILE_HEIGHT); + uv_height = CEIL_MUL(uv_height, NV12_TILEY_TILE_HEIGHT); + } + + y_stride = y_width * bytes_per_element; + uv_stride = uv_width * bytes_per_element; + y_bytes = y_stride * y_height; + uv_bytes = uv_stride * uv_height; + + frame->data_bytes = y_bytes + uv_bytes; + frame_init_plane(&frame->planes.nv.y, y_width, y_stride, y_height, 0); + frame_init_plane(&frame->planes.nv.uv, uv_width, + uv_stride, uv_height, y_bytes); + return; +} + +static void frame_init_yuv_planes(struct ia_css_frame *frame, + unsigned int horizontal_decimation, + unsigned int vertical_decimation, + bool swap_uv, + unsigned int bytes_per_element) +{ + unsigned int y_width = frame->info.padded_width, + y_height = frame->info.res.height, + uv_width = y_width / horizontal_decimation, + uv_height = y_height / vertical_decimation, + y_stride, y_bytes, uv_bytes, uv_stride; + + y_stride = y_width * bytes_per_element; + uv_stride = uv_width * bytes_per_element; + y_bytes = y_stride * y_height; + uv_bytes = uv_stride * uv_height; + + frame->data_bytes = y_bytes + 2 * uv_bytes; + frame_init_plane(&frame->planes.yuv.y, y_width, y_stride, y_height, 0); + if (swap_uv) { + frame_init_plane(&frame->planes.yuv.v, uv_width, uv_stride, + uv_height, y_bytes); + frame_init_plane(&frame->planes.yuv.u, uv_width, uv_stride, + uv_height, y_bytes + uv_bytes); + } else { + frame_init_plane(&frame->planes.yuv.u, uv_width, uv_stride, + uv_height, y_bytes); + frame_init_plane(&frame->planes.yuv.v, uv_width, uv_stride, + uv_height, y_bytes + uv_bytes); + } + return; +} + +static void frame_init_rgb_planes(struct ia_css_frame *frame, + unsigned int bytes_per_element) +{ + unsigned int width = frame->info.res.width, + height = frame->info.res.height, stride, bytes; + + stride = width * bytes_per_element; + bytes = stride * height; + frame->data_bytes = 3 * bytes; + frame_init_plane(&frame->planes.planar_rgb.r, width, stride, height, 0); + frame_init_plane(&frame->planes.planar_rgb.g, + width, stride, height, 1 * bytes); + frame_init_plane(&frame->planes.planar_rgb.b, + width, stride, height, 2 * bytes); + return; +} + +static void frame_init_qplane6_planes(struct ia_css_frame *frame) +{ + unsigned int width = frame->info.padded_width / 2, + height = frame->info.res.height / 2, bytes, stride; + + stride = width * 2; + bytes = stride * height; + + frame->data_bytes = 6 * bytes; + frame_init_plane(&frame->planes.plane6.r, + width, stride, height, 0 * bytes); + frame_init_plane(&frame->planes.plane6.r_at_b, + width, stride, height, 1 * bytes); + frame_init_plane(&frame->planes.plane6.gr, + width, stride, height, 2 * bytes); + frame_init_plane(&frame->planes.plane6.gb, + width, stride, height, 3 * bytes); + frame_init_plane(&frame->planes.plane6.b, + width, stride, height, 4 * bytes); + frame_init_plane(&frame->planes.plane6.b_at_r, + width, stride, height, 5 * bytes); + return; +} + +static int frame_allocate_buffer_data(struct ia_css_frame *frame) +{ +#ifdef ISP2401 + IA_CSS_ENTER_LEAVE_PRIVATE("frame->data_bytes=%d\n", frame->data_bytes); +#endif + frame->data = hmm_alloc(frame->data_bytes); + if (frame->data == mmgr_NULL) + return -ENOMEM; + return 0; +} + +static int frame_allocate_with_data(struct ia_css_frame **frame, + unsigned int width, + unsigned int height, + enum ia_css_frame_format format, + unsigned int padded_width, + unsigned int raw_bit_depth) +{ + int err; + struct ia_css_frame *me = frame_create(width, + height, + format, + padded_width, + raw_bit_depth, + true); + + if (!me) + return -ENOMEM; + + err = ia_css_frame_init_planes(me); + + if (!err) + err = frame_allocate_buffer_data(me); + + if (err) { + kvfree(me); +#ifndef ISP2401 + return err; +#else + me = NULL; +#endif + } + + *frame = me; + + return err; +} + +static struct ia_css_frame *frame_create(unsigned int width, + unsigned int height, + enum ia_css_frame_format format, + unsigned int padded_width, + unsigned int raw_bit_depth, + bool valid) +{ + struct ia_css_frame *me = kvmalloc(sizeof(*me), GFP_KERNEL); + + if (!me) + return NULL; + + memset(me, 0, sizeof(*me)); + me->info.res.width = width; + me->info.res.height = height; + me->info.format = format; + me->info.padded_width = padded_width; + me->info.raw_bit_depth = raw_bit_depth; + me->valid = valid; + me->data_bytes = 0; + me->data = mmgr_NULL; + /* To indicate it is not valid frame. */ + me->dynamic_queue_id = (int)SH_CSS_INVALID_QUEUE_ID; + me->buf_type = IA_CSS_BUFFER_TYPE_INVALID; + + return me; +} + +static unsigned +ia_css_elems_bytes_from_info(const struct ia_css_frame_info *info) +{ + if (info->format == IA_CSS_FRAME_FORMAT_RGB565) + return 2; /* bytes per pixel */ + if (info->format == IA_CSS_FRAME_FORMAT_YUV420_16) + return 2; /* bytes per pixel */ + if (info->format == IA_CSS_FRAME_FORMAT_YUV422_16) + return 2; /* bytes per pixel */ + /* Note: Essentially NV12_16 is a 2 bytes per pixel format, this return value is used + * to configure DMA for the output buffer, + * At least in SKC this data is overwritten by isp_output_init.sp.c except for elements(elems), + * which is configured from this return value, + * NV12_16 is implemented by a double buffer of 8 bit elements hence elems should be configured as 8 */ + if (info->format == IA_CSS_FRAME_FORMAT_NV12_16) + return 1; /* bytes per pixel */ + + if (info->format == IA_CSS_FRAME_FORMAT_RAW + || (info->format == IA_CSS_FRAME_FORMAT_RAW_PACKED)) { + if (info->raw_bit_depth) + return CEIL_DIV(info->raw_bit_depth, 8); + else + return 2; /* bytes per pixel */ + } + if (info->format == IA_CSS_FRAME_FORMAT_PLANAR_RGB888) + return 3; /* bytes per pixel */ + if (info->format == IA_CSS_FRAME_FORMAT_RGBA888) + return 4; /* bytes per pixel */ + if (info->format == IA_CSS_FRAME_FORMAT_QPLANE6) + return 2; /* bytes per pixel */ + return 1; /* Default is 1 byte per pixel */ +} + +void ia_css_frame_info_to_frame_sp_info( + struct ia_css_frame_sp_info *to, + const struct ia_css_frame_info *from) +{ + ia_css_resolution_to_sp_resolution(&to->res, &from->res); + to->padded_width = (uint16_t)from->padded_width; + to->format = (uint8_t)from->format; + to->raw_bit_depth = (uint8_t)from->raw_bit_depth; + to->raw_bayer_order = from->raw_bayer_order; +} + +void ia_css_resolution_to_sp_resolution( + struct ia_css_sp_resolution *to, + const struct ia_css_resolution *from) +{ + to->width = (uint16_t)from->width; + to->height = (uint16_t)from->height; +} diff --git a/drivers/staging/media/atomisp/pci/runtime/ifmtr/interface/ia_css_ifmtr.h b/drivers/staging/media/atomisp/pci/runtime/ifmtr/interface/ia_css_ifmtr.h new file mode 100644 index 000000000..2c440feec --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/ifmtr/interface/ia_css_ifmtr.h @@ -0,0 +1,34 @@ +/* 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. + */ + +#ifndef __IA_CSS_IFMTR_H__ +#define __IA_CSS_IFMTR_H__ + +#include <type_support.h> +#include <ia_css_stream_public.h> +#include <ia_css_binary.h> + +extern bool ifmtr_set_if_blocking_mode_reset; + +unsigned int ia_css_ifmtr_lines_needed_for_bayer_order( + const struct ia_css_stream_config *config); + +unsigned int ia_css_ifmtr_columns_needed_for_bayer_order( + const struct ia_css_stream_config *config); + +int ia_css_ifmtr_configure(struct ia_css_stream_config *config, + struct ia_css_binary *binary); + +#endif /* __IA_CSS_IFMTR_H__ */ 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 000000000..6d9f47629 --- /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 diff --git a/drivers/staging/media/atomisp/pci/runtime/inputfifo/interface/ia_css_inputfifo.h b/drivers/staging/media/atomisp/pci/runtime/inputfifo/interface/ia_css_inputfifo.h new file mode 100644 index 000000000..7950c5c36 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/inputfifo/interface/ia_css_inputfifo.h @@ -0,0 +1,54 @@ +/* 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. + */ + +#ifndef _IA_CSS_INPUTFIFO_H +#define _IA_CSS_INPUTFIFO_H + +#include <sp.h> +#include <isp.h> + +#include "ia_css_stream_format.h" + +/* SP access */ +void ia_css_inputfifo_send_input_frame( + const unsigned short *data, + unsigned int width, + unsigned int height, + unsigned int ch_id, + enum atomisp_input_format input_format, + bool two_ppc); + +void ia_css_inputfifo_start_frame( + unsigned int ch_id, + enum atomisp_input_format input_format, + bool two_ppc); + +void ia_css_inputfifo_send_line( + unsigned int ch_id, + const unsigned short *data, + unsigned int width, + const unsigned short *data2, + unsigned int width2); + +void ia_css_inputfifo_send_embedded_line( + unsigned int ch_id, + enum atomisp_input_format data_type, + const unsigned short *data, + unsigned int width); + +void ia_css_inputfifo_end_frame( + unsigned int ch_id); + +#endif /* _IA_CSS_INPUTFIFO_H */ diff --git a/drivers/staging/media/atomisp/pci/runtime/inputfifo/src/inputfifo.c b/drivers/staging/media/atomisp/pci/runtime/inputfifo/src/inputfifo.c new file mode 100644 index 000000000..2d06e1240 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/inputfifo/src/inputfifo.c @@ -0,0 +1,529 @@ +// 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 "platform_support.h" + +#include "ia_css_inputfifo.h" + +#include "device_access.h" + +#define __INLINE_SP__ +#include "sp.h" +#define __INLINE_ISP__ +#include "isp.h" +#define __INLINE_IRQ__ +#include "irq.h" +#define __INLINE_FIFO_MONITOR__ +#include "fifo_monitor.h" + +#define __INLINE_EVENT__ +#include "event_fifo.h" +#define __INLINE_SP__ + +#include "input_system.h" /* MIPI_PREDICTOR_NONE,... */ + +#include "assert_support.h" + +/* System independent */ +#include "sh_css_internal.h" +#include "ia_css_isys.h" + +#define HBLANK_CYCLES (187) +#define MARKER_CYCLES (6) + +#include <hive_isp_css_streaming_to_mipi_types_hrt.h> + +/* The data type is used to send special cases: + * yuv420: odd lines (1, 3 etc) are twice as wide as even + * lines (0, 2, 4 etc). + * rgb: for two pixels per clock, the R and B values are sent + * to output_0 while only G is sent to output_1. This means + * that output_1 only gets half the number of values of output_0. + * WARNING: This type should also be used for Legacy YUV420. + * regular: used for all other data types (RAW, YUV422, etc) + */ +enum inputfifo_mipi_data_type { + inputfifo_mipi_data_type_regular, + inputfifo_mipi_data_type_yuv420, + inputfifo_mipi_data_type_yuv420_legacy, + inputfifo_mipi_data_type_rgb, +}; + +static unsigned int inputfifo_curr_ch_id, inputfifo_curr_fmt_type; +struct inputfifo_instance { + unsigned int ch_id; + enum atomisp_input_format input_format; + bool two_ppc; + bool streaming; + unsigned int hblank_cycles; + unsigned int marker_cycles; + unsigned int fmt_type; + enum inputfifo_mipi_data_type type; +}; + +/* + * Maintain a basic streaming to Mipi administration with ch_id as index + * ch_id maps on the "Mipi virtual channel ID" and can have value 0..3 + */ +#define INPUTFIFO_NR_OF_S2M_CHANNELS (4) +static struct inputfifo_instance + inputfifo_inst_admin[INPUTFIFO_NR_OF_S2M_CHANNELS]; + +/* Streaming to MIPI */ +static unsigned int inputfifo_wrap_marker( + /* static inline unsigned inputfifo_wrap_marker( */ + unsigned int marker) +{ + return marker | + (inputfifo_curr_ch_id << HIVE_STR_TO_MIPI_CH_ID_LSB) | + (inputfifo_curr_fmt_type << _HIVE_STR_TO_MIPI_FMT_TYPE_LSB); +} + +static inline void +_sh_css_fifo_snd(unsigned int token) +{ + while (!can_event_send_token(STR2MIPI_EVENT_ID)) + udelay(1); + event_send_token(STR2MIPI_EVENT_ID, token); + return; +} + +static void inputfifo_send_data_a( + /* static inline void inputfifo_send_data_a( */ + unsigned int data) +{ + unsigned int token = (1 << HIVE_STR_TO_MIPI_VALID_A_BIT) | + (data << HIVE_STR_TO_MIPI_DATA_A_LSB); + _sh_css_fifo_snd(token); + return; +} + +static void inputfifo_send_data_b( + /* static inline void inputfifo_send_data_b( */ + unsigned int data) +{ + unsigned int token = (1 << HIVE_STR_TO_MIPI_VALID_B_BIT) | + (data << _HIVE_STR_TO_MIPI_DATA_B_LSB); + _sh_css_fifo_snd(token); + return; +} + +static void inputfifo_send_data( + /* static inline void inputfifo_send_data( */ + unsigned int a, + unsigned int b) +{ + unsigned int token = ((1 << HIVE_STR_TO_MIPI_VALID_A_BIT) | + (1 << HIVE_STR_TO_MIPI_VALID_B_BIT) | + (a << HIVE_STR_TO_MIPI_DATA_A_LSB) | + (b << _HIVE_STR_TO_MIPI_DATA_B_LSB)); + _sh_css_fifo_snd(token); + return; +} + +static void inputfifo_send_sol(void) +/* static inline void inputfifo_send_sol(void) */ +{ + hrt_data token = inputfifo_wrap_marker( + 1 << HIVE_STR_TO_MIPI_SOL_BIT); + + _sh_css_fifo_snd(token); + return; +} + +static void inputfifo_send_eol(void) +/* static inline void inputfifo_send_eol(void) */ +{ + hrt_data token = inputfifo_wrap_marker( + 1 << HIVE_STR_TO_MIPI_EOL_BIT); + _sh_css_fifo_snd(token); + return; +} + +static void inputfifo_send_sof(void) +/* static inline void inputfifo_send_sof(void) */ +{ + hrt_data token = inputfifo_wrap_marker( + 1 << HIVE_STR_TO_MIPI_SOF_BIT); + + _sh_css_fifo_snd(token); + return; +} + +static void inputfifo_send_eof(void) +/* static inline void inputfifo_send_eof(void) */ +{ + hrt_data token = inputfifo_wrap_marker( + 1 << HIVE_STR_TO_MIPI_EOF_BIT); + _sh_css_fifo_snd(token); + return; +} + +static void inputfifo_send_ch_id_and_fmt_type( + /* static inline + void inputfifo_send_ch_id_and_fmt_type( */ + unsigned int ch_id, + unsigned int fmt_type) +{ + hrt_data token; + + inputfifo_curr_ch_id = ch_id & _HIVE_ISP_CH_ID_MASK; + inputfifo_curr_fmt_type = fmt_type & _HIVE_ISP_FMT_TYPE_MASK; + /* we send an zero marker, this will wrap the ch_id and + * fmt_type automatically. + */ + token = inputfifo_wrap_marker(0); + _sh_css_fifo_snd(token); + return; +} + +static void inputfifo_send_empty_token(void) +/* static inline void inputfifo_send_empty_token(void) */ +{ + hrt_data token = inputfifo_wrap_marker(0); + + _sh_css_fifo_snd(token); + return; +} + +static void inputfifo_start_frame( + /* static inline void inputfifo_start_frame( */ + unsigned int ch_id, + unsigned int fmt_type) +{ + inputfifo_send_ch_id_and_fmt_type(ch_id, fmt_type); + inputfifo_send_sof(); + return; +} + +static void inputfifo_end_frame( + unsigned int marker_cycles) +{ + unsigned int i; + + for (i = 0; i < marker_cycles; i++) + inputfifo_send_empty_token(); + inputfifo_send_eof(); + return; +} + +static void inputfifo_send_line2( + const unsigned short *data, + unsigned int width, + const unsigned short *data2, + unsigned int width2, + unsigned int hblank_cycles, + unsigned int marker_cycles, + unsigned int two_ppc, + enum inputfifo_mipi_data_type type) +{ + unsigned int i, is_rgb = 0, is_legacy = 0; + + assert(data); + assert((data2) || (width2 == 0)); + if (type == inputfifo_mipi_data_type_rgb) + is_rgb = 1; + + if (type == inputfifo_mipi_data_type_yuv420_legacy) + is_legacy = 1; + + for (i = 0; i < hblank_cycles; i++) + inputfifo_send_empty_token(); + inputfifo_send_sol(); + for (i = 0; i < marker_cycles; i++) + inputfifo_send_empty_token(); + for (i = 0; i < width; i++, data++) { + /* for RGB in two_ppc, we only actually send 2 pixels per + * clock in the even pixels (0, 2 etc). In the other cycles, + * we only send 1 pixel, to data[0]. + */ + unsigned int send_two_pixels = two_ppc; + + if ((is_rgb || is_legacy) && (i % 3 == 2)) + send_two_pixels = 0; + if (send_two_pixels) { + if (i + 1 == width) { + /* for jpg (binary) copy, this can occur + * if the file contains an odd number of bytes. + */ + inputfifo_send_data( + data[0], 0); + } else { + inputfifo_send_data( + data[0], data[1]); + } + /* Additional increment because we send 2 pixels */ + data++; + i++; + } else if (two_ppc && is_legacy) { + inputfifo_send_data_b(data[0]); + } else { + inputfifo_send_data_a(data[0]); + } + } + + for (i = 0; i < width2; i++, data2++) { + /* for RGB in two_ppc, we only actually send 2 pixels per + * clock in the even pixels (0, 2 etc). In the other cycles, + * we only send 1 pixel, to data2[0]. + */ + unsigned int send_two_pixels = two_ppc; + + if ((is_rgb || is_legacy) && (i % 3 == 2)) + send_two_pixels = 0; + if (send_two_pixels) { + if (i + 1 == width2) { + /* for jpg (binary) copy, this can occur + * if the file contains an odd number of bytes. + */ + inputfifo_send_data( + data2[0], 0); + } else { + inputfifo_send_data( + data2[0], data2[1]); + } + /* Additional increment because we send 2 pixels */ + data2++; + i++; + } else if (two_ppc && is_legacy) { + inputfifo_send_data_b(data2[0]); + } else { + inputfifo_send_data_a(data2[0]); + } + } + for (i = 0; i < hblank_cycles; i++) + inputfifo_send_empty_token(); + inputfifo_send_eol(); + return; +} + +static void +inputfifo_send_line(const unsigned short *data, + unsigned int width, + unsigned int hblank_cycles, + unsigned int marker_cycles, + unsigned int two_ppc, + enum inputfifo_mipi_data_type type) +{ + assert(data); + inputfifo_send_line2(data, width, NULL, 0, + hblank_cycles, + marker_cycles, + two_ppc, + type); +} + +/* Send a frame of data into the input network via the GP FIFO. + * Parameters: + * - data: array of 16 bit values that contains all data for the frame. + * - width: width of a line in number of subpixels, for yuv420 it is the + * number of Y components per line. + * - height: height of the frame in number of lines. + * - ch_id: channel ID. + * - fmt_type: format type. + * - hblank_cycles: length of horizontal blanking in cycles. + * - marker_cycles: number of empty cycles after start-of-line and before + * end-of-frame. + * - two_ppc: boolean, describes whether to send one or two pixels per clock + * cycle. In this mode, we sent pixels N and N+1 in the same cycle, + * to IF_PRIM_A and IF_PRIM_B respectively. The caller must make + * sure the input data has been formatted correctly for this. + * For example, for RGB formats this means that unused values + * must be inserted. + * - yuv420: boolean, describes whether (non-legacy) yuv420 data is used. In + * this mode, the odd lines (1,3,5 etc) are half as long as the + * even lines (2,4,6 etc). + * Note that the first line is odd (1) and the second line is even + * (2). + * + * This function does not do any reordering of pixels, the caller must make + * sure the data is in the righ format. Please refer to the CSS receiver + * documentation for details on the data formats. + */ + +static void inputfifo_send_frame( + const unsigned short *data, + unsigned int width, + unsigned int height, + unsigned int ch_id, + unsigned int fmt_type, + unsigned int hblank_cycles, + unsigned int marker_cycles, + unsigned int two_ppc, + enum inputfifo_mipi_data_type type) +{ + unsigned int i; + + assert(data); + inputfifo_start_frame(ch_id, fmt_type); + + for (i = 0; i < height; i++) { + if ((type == inputfifo_mipi_data_type_yuv420) && + (i & 1) == 1) { + inputfifo_send_line(data, 2 * width, + hblank_cycles, + marker_cycles, + two_ppc, type); + data += 2 * width; + } else { + inputfifo_send_line(data, width, + hblank_cycles, + marker_cycles, + two_ppc, type); + data += width; + } + } + inputfifo_end_frame(marker_cycles); + return; +} + +static enum inputfifo_mipi_data_type inputfifo_determine_type( + enum atomisp_input_format input_format) +{ + enum inputfifo_mipi_data_type type; + + type = inputfifo_mipi_data_type_regular; + if (input_format == ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY) { + type = + inputfifo_mipi_data_type_yuv420_legacy; + } else if (input_format == ATOMISP_INPUT_FORMAT_YUV420_8 || + input_format == ATOMISP_INPUT_FORMAT_YUV420_10 || + input_format == ATOMISP_INPUT_FORMAT_YUV420_16) { + type = + inputfifo_mipi_data_type_yuv420; + } else if (input_format >= ATOMISP_INPUT_FORMAT_RGB_444 && + input_format <= ATOMISP_INPUT_FORMAT_RGB_888) { + type = + inputfifo_mipi_data_type_rgb; + } + return type; +} + +static struct inputfifo_instance *inputfifo_get_inst( + unsigned int ch_id) +{ + return &inputfifo_inst_admin[ch_id]; +} + +void ia_css_inputfifo_send_input_frame( + const unsigned short *data, + unsigned int width, + unsigned int height, + unsigned int ch_id, + enum atomisp_input_format input_format, + bool two_ppc) +{ + unsigned int fmt_type, hblank_cycles, marker_cycles; + enum inputfifo_mipi_data_type type; + + assert(data); + hblank_cycles = HBLANK_CYCLES; + marker_cycles = MARKER_CYCLES; + ia_css_isys_convert_stream_format_to_mipi_format(input_format, + MIPI_PREDICTOR_NONE, + &fmt_type); + + type = inputfifo_determine_type(input_format); + + inputfifo_send_frame(data, width, height, + ch_id, fmt_type, hblank_cycles, marker_cycles, + two_ppc, type); +} + +void ia_css_inputfifo_start_frame( + unsigned int ch_id, + enum atomisp_input_format input_format, + bool two_ppc) +{ + struct inputfifo_instance *s2mi; + + s2mi = inputfifo_get_inst(ch_id); + + s2mi->ch_id = ch_id; + ia_css_isys_convert_stream_format_to_mipi_format(input_format, + MIPI_PREDICTOR_NONE, + &s2mi->fmt_type); + s2mi->two_ppc = two_ppc; + s2mi->type = inputfifo_determine_type(input_format); + s2mi->hblank_cycles = HBLANK_CYCLES; + s2mi->marker_cycles = MARKER_CYCLES; + s2mi->streaming = true; + + inputfifo_start_frame(ch_id, s2mi->fmt_type); + return; +} + +void ia_css_inputfifo_send_line( + unsigned int ch_id, + const unsigned short *data, + unsigned int width, + const unsigned short *data2, + unsigned int width2) +{ + struct inputfifo_instance *s2mi; + + assert(data); + assert((data2) || (width2 == 0)); + s2mi = inputfifo_get_inst(ch_id); + + /* Set global variables that indicate channel_id and format_type */ + inputfifo_curr_ch_id = (s2mi->ch_id) & _HIVE_ISP_CH_ID_MASK; + inputfifo_curr_fmt_type = (s2mi->fmt_type) & _HIVE_ISP_FMT_TYPE_MASK; + + inputfifo_send_line2(data, width, data2, width2, + s2mi->hblank_cycles, + s2mi->marker_cycles, + s2mi->two_ppc, + s2mi->type); +} + +void ia_css_inputfifo_send_embedded_line( + unsigned int ch_id, + enum atomisp_input_format data_type, + const unsigned short *data, + unsigned int width) +{ + struct inputfifo_instance *s2mi; + unsigned int fmt_type; + + assert(data); + s2mi = inputfifo_get_inst(ch_id); + ia_css_isys_convert_stream_format_to_mipi_format(data_type, + MIPI_PREDICTOR_NONE, &fmt_type); + + /* Set format_type for metadata line. */ + inputfifo_curr_fmt_type = fmt_type & _HIVE_ISP_FMT_TYPE_MASK; + + inputfifo_send_line(data, width, s2mi->hblank_cycles, s2mi->marker_cycles, + s2mi->two_ppc, inputfifo_mipi_data_type_regular); +} + +void ia_css_inputfifo_end_frame( + unsigned int ch_id) +{ + struct inputfifo_instance *s2mi; + + s2mi = inputfifo_get_inst(ch_id); + + /* Set global variables that indicate channel_id and format_type */ + inputfifo_curr_ch_id = (s2mi->ch_id) & _HIVE_ISP_CH_ID_MASK; + inputfifo_curr_fmt_type = (s2mi->fmt_type) & _HIVE_ISP_FMT_TYPE_MASK; + + /* Call existing HRT function */ + inputfifo_end_frame(s2mi->marker_cycles); + + s2mi->streaming = false; + return; +} diff --git a/drivers/staging/media/atomisp/pci/runtime/isp_param/interface/ia_css_isp_param.h b/drivers/staging/media/atomisp/pci/runtime/isp_param/interface/ia_css_isp_param.h new file mode 100644 index 000000000..0ea5d6fdc --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/isp_param/interface/ia_css_isp_param.h @@ -0,0 +1,103 @@ +/* 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. + */ + +#ifndef _IA_CSS_ISP_PARAM_H_ +#define _IA_CSS_ISP_PARAM_H_ + +#include <ia_css_err.h> +#include "ia_css_isp_param_types.h" + +/* Set functions for parameter memory descriptors */ +void +ia_css_isp_param_set_mem_init( + struct ia_css_isp_param_host_segments *mem_init, + enum ia_css_param_class pclass, + enum ia_css_isp_memories mem, + char *address, size_t size); + +void +ia_css_isp_param_set_css_mem_init( + struct ia_css_isp_param_css_segments *mem_init, + enum ia_css_param_class pclass, + enum ia_css_isp_memories mem, + ia_css_ptr address, size_t size); + +void +ia_css_isp_param_set_isp_mem_init( + struct ia_css_isp_param_isp_segments *mem_init, + enum ia_css_param_class pclass, + enum ia_css_isp_memories mem, + u32 address, size_t size); + +/* Get functions for parameter memory descriptors */ +const struct ia_css_host_data * +ia_css_isp_param_get_mem_init( + const struct ia_css_isp_param_host_segments *mem_init, + enum ia_css_param_class pclass, + enum ia_css_isp_memories mem); + +const struct ia_css_data * +ia_css_isp_param_get_css_mem_init( + const struct ia_css_isp_param_css_segments *mem_init, + enum ia_css_param_class pclass, + enum ia_css_isp_memories mem); + +const struct ia_css_isp_data * +ia_css_isp_param_get_isp_mem_init( + const struct ia_css_isp_param_isp_segments *mem_init, + enum ia_css_param_class pclass, + enum ia_css_isp_memories mem); + +/* Initialize the memory interface sizes and addresses */ +void +ia_css_init_memory_interface( + struct ia_css_isp_param_css_segments *isp_mem_if, + const struct ia_css_isp_param_host_segments *mem_params, + const struct ia_css_isp_param_css_segments *css_params); + +/* Allocate memory parameters */ +int +ia_css_isp_param_allocate_isp_parameters( + struct ia_css_isp_param_host_segments *mem_params, + struct ia_css_isp_param_css_segments *css_params, + const struct ia_css_isp_param_isp_segments *mem_initializers); + +/* Destroy memory parameters */ +void +ia_css_isp_param_destroy_isp_parameters( + struct ia_css_isp_param_host_segments *mem_params, + struct ia_css_isp_param_css_segments *css_params); + +/* Load fw parameters */ +void +ia_css_isp_param_load_fw_params( + const char *fw, + union ia_css_all_memory_offsets *mem_offsets, + const struct ia_css_isp_param_memory_offsets *memory_offsets, + bool init); + +/* Copy host parameter images to ddr */ +int +ia_css_isp_param_copy_isp_mem_if_to_ddr( + struct ia_css_isp_param_css_segments *ddr, + const struct ia_css_isp_param_host_segments *host, + enum ia_css_param_class pclass); + +/* Enable a pipeline by setting the control field in the isp dmem parameters */ +void +ia_css_isp_param_enable_pipeline( + const struct ia_css_isp_param_host_segments *mem_params); + +#endif /* _IA_CSS_ISP_PARAM_H_ */ diff --git a/drivers/staging/media/atomisp/pci/runtime/isp_param/interface/ia_css_isp_param_types.h b/drivers/staging/media/atomisp/pci/runtime/isp_param/interface/ia_css_isp_param_types.h new file mode 100644 index 000000000..8cdeae98b --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/isp_param/interface/ia_css_isp_param_types.h @@ -0,0 +1,82 @@ +/* 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. +*/ + +#ifndef _IA_CSS_ISP_PARAM_TYPES_H_ +#define _IA_CSS_ISP_PARAM_TYPES_H_ + +#include "ia_css_types.h" +#include <platform_support.h> +#include <system_global.h> + +/* Short hands */ +#define IA_CSS_ISP_DMEM IA_CSS_ISP_DMEM0 +#define IA_CSS_ISP_VMEM IA_CSS_ISP_VMEM0 + +/* The driver depends on this, to be removed later. */ +#define IA_CSS_NUM_ISP_MEMORIES IA_CSS_NUM_MEMORIES + +/* Explicit member numbering to avoid fish type checker bug */ +enum ia_css_param_class { + IA_CSS_PARAM_CLASS_PARAM = 0, /* Late binding parameters, like 3A */ + IA_CSS_PARAM_CLASS_CONFIG = 1, /* Pipe config time parameters, like resolution */ + IA_CSS_PARAM_CLASS_STATE = 2, /* State parameters, like tnr buffer index */ +#if 0 /* Not yet implemented */ + IA_CSS_PARAM_CLASS_FRAME = 3, /* Frame time parameters, like output buffer */ +#endif +}; + +#define IA_CSS_NUM_PARAM_CLASSES (IA_CSS_PARAM_CLASS_STATE + 1) + +/* ISP parameter descriptor */ +struct ia_css_isp_parameter { + u32 offset; /* Offset in isp_<mem>)parameters, etc. */ + u32 size; /* Disabled if 0 */ +}; + +/* Address/size of each parameter class in each isp memory, host memory pointers */ +struct ia_css_isp_param_host_segments { + struct ia_css_host_data params[IA_CSS_NUM_PARAM_CLASSES][IA_CSS_NUM_MEMORIES]; +}; + +/* Address/size of each parameter class in each isp memory, css memory pointers */ +struct ia_css_isp_param_css_segments { + struct ia_css_data params[IA_CSS_NUM_PARAM_CLASSES][IA_CSS_NUM_MEMORIES]; +}; + +/* Address/size of each parameter class in each isp memory, isp memory pointers */ +struct ia_css_isp_param_isp_segments { + struct ia_css_isp_data params[IA_CSS_NUM_PARAM_CLASSES][IA_CSS_NUM_MEMORIES]; +}; + +/* Memory offsets in binary info */ +struct ia_css_isp_param_memory_offsets { + u32 offsets[IA_CSS_NUM_PARAM_CLASSES]; /** offset wrt hdr in bytes */ +}; + +/* Offsets for ISP kernel parameters per isp memory. + * Only relevant for standard ISP binaries, not ACC or SP. + */ +union ia_css_all_memory_offsets { + struct { + CSS_ALIGN(struct ia_css_memory_offsets *param, 8); + CSS_ALIGN(struct ia_css_config_memory_offsets *config, 8); + CSS_ALIGN(struct ia_css_state_memory_offsets *state, 8); + } offsets; + struct { + CSS_ALIGN(void *ptr, 8); + } array[IA_CSS_NUM_PARAM_CLASSES]; +}; + +#endif /* _IA_CSS_ISP_PARAM_TYPES_H_ */ diff --git a/drivers/staging/media/atomisp/pci/runtime/isp_param/src/isp_param.c b/drivers/staging/media/atomisp/pci/runtime/isp_param/src/isp_param.c new file mode 100644 index 000000000..99c2f3a53 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/isp_param/src/isp_param.c @@ -0,0 +1,219 @@ +// 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 "hmm.h" + +#include "ia_css_pipeline.h" +#include "ia_css_isp_param.h" + +/* Set functions for parameter memory descriptors */ + +void +ia_css_isp_param_set_mem_init( + struct ia_css_isp_param_host_segments *mem_init, + enum ia_css_param_class pclass, + enum ia_css_isp_memories mem, + char *address, size_t size) +{ + mem_init->params[pclass][mem].address = address; + mem_init->params[pclass][mem].size = (uint32_t)size; +} + +void +ia_css_isp_param_set_css_mem_init( + struct ia_css_isp_param_css_segments *mem_init, + enum ia_css_param_class pclass, + enum ia_css_isp_memories mem, + ia_css_ptr address, size_t size) +{ + mem_init->params[pclass][mem].address = address; + mem_init->params[pclass][mem].size = (uint32_t)size; +} + +void +ia_css_isp_param_set_isp_mem_init( + struct ia_css_isp_param_isp_segments *mem_init, + enum ia_css_param_class pclass, + enum ia_css_isp_memories mem, + u32 address, size_t size) +{ + mem_init->params[pclass][mem].address = address; + mem_init->params[pclass][mem].size = (uint32_t)size; +} + +/* Get functions for parameter memory descriptors */ +const struct ia_css_host_data * +ia_css_isp_param_get_mem_init( + const struct ia_css_isp_param_host_segments *mem_init, + enum ia_css_param_class pclass, + enum ia_css_isp_memories mem) +{ + return &mem_init->params[pclass][mem]; +} + +const struct ia_css_data * +ia_css_isp_param_get_css_mem_init( + const struct ia_css_isp_param_css_segments *mem_init, + enum ia_css_param_class pclass, + enum ia_css_isp_memories mem) +{ + return &mem_init->params[pclass][mem]; +} + +const struct ia_css_isp_data * +ia_css_isp_param_get_isp_mem_init( + const struct ia_css_isp_param_isp_segments *mem_init, + enum ia_css_param_class pclass, + enum ia_css_isp_memories mem) +{ + return &mem_init->params[pclass][mem]; +} + +void +ia_css_init_memory_interface( + struct ia_css_isp_param_css_segments *isp_mem_if, + const struct ia_css_isp_param_host_segments *mem_params, + const struct ia_css_isp_param_css_segments *css_params) +{ + unsigned int pclass, mem; + + for (pclass = 0; pclass < IA_CSS_NUM_PARAM_CLASSES; pclass++) { + memset(isp_mem_if->params[pclass], 0, sizeof(isp_mem_if->params[pclass])); + for (mem = 0; mem < IA_CSS_NUM_MEMORIES; mem++) { + if (!mem_params->params[pclass][mem].address) + continue; + isp_mem_if->params[pclass][mem].size = mem_params->params[pclass][mem].size; + if (pclass != IA_CSS_PARAM_CLASS_PARAM) + isp_mem_if->params[pclass][mem].address = + css_params->params[pclass][mem].address; + } + } +} + +int +ia_css_isp_param_allocate_isp_parameters( + struct ia_css_isp_param_host_segments *mem_params, + struct ia_css_isp_param_css_segments *css_params, + const struct ia_css_isp_param_isp_segments *mem_initializers) { + int err = 0; + unsigned int mem, pclass; + + pclass = IA_CSS_PARAM_CLASS_PARAM; + for (mem = 0; mem < IA_CSS_NUM_MEMORIES; mem++) + { + for (pclass = 0; pclass < IA_CSS_NUM_PARAM_CLASSES; pclass++) { + u32 size = 0; + + if (mem_initializers) + size = mem_initializers->params[pclass][mem].size; + mem_params->params[pclass][mem].size = size; + mem_params->params[pclass][mem].address = NULL; + css_params->params[pclass][mem].size = size; + css_params->params[pclass][mem].address = 0x0; + if (size) { + mem_params->params[pclass][mem].address = kvcalloc(1, + size, + GFP_KERNEL); + if (!mem_params->params[pclass][mem].address) { + err = -ENOMEM; + goto cleanup; + } + if (pclass != IA_CSS_PARAM_CLASS_PARAM) { + css_params->params[pclass][mem].address = hmm_alloc(size); + if (!css_params->params[pclass][mem].address) { + err = -ENOMEM; + goto cleanup; + } + } + } + } + } + return err; +cleanup: + ia_css_isp_param_destroy_isp_parameters(mem_params, css_params); + return err; +} + +void +ia_css_isp_param_destroy_isp_parameters( + struct ia_css_isp_param_host_segments *mem_params, + struct ia_css_isp_param_css_segments *css_params) +{ + unsigned int mem, pclass; + + for (mem = 0; mem < IA_CSS_NUM_MEMORIES; mem++) { + for (pclass = 0; pclass < IA_CSS_NUM_PARAM_CLASSES; pclass++) { + kvfree(mem_params->params[pclass][mem].address); + if (css_params->params[pclass][mem].address) + hmm_free(css_params->params[pclass][mem].address); + mem_params->params[pclass][mem].address = NULL; + css_params->params[pclass][mem].address = 0x0; + } + } +} + +void +ia_css_isp_param_load_fw_params( + const char *fw, + union ia_css_all_memory_offsets *mem_offsets, + const struct ia_css_isp_param_memory_offsets *memory_offsets, + bool init) +{ + unsigned int pclass; + + for (pclass = 0; pclass < IA_CSS_NUM_PARAM_CLASSES; pclass++) { + mem_offsets->array[pclass].ptr = NULL; + if (init) + mem_offsets->array[pclass].ptr = (void *)(fw + memory_offsets->offsets[pclass]); + } +} + +int +ia_css_isp_param_copy_isp_mem_if_to_ddr( + struct ia_css_isp_param_css_segments *ddr, + const struct ia_css_isp_param_host_segments *host, + enum ia_css_param_class pclass) { + unsigned int mem; + + for (mem = 0; mem < N_IA_CSS_ISP_MEMORIES; mem++) + { + size_t size = host->params[pclass][mem].size; + ia_css_ptr ddr_mem_ptr = ddr->params[pclass][mem].address; + char *host_mem_ptr = host->params[pclass][mem].address; + + if (size != ddr->params[pclass][mem].size) + return -EINVAL; + if (!size) + continue; + hmm_store(ddr_mem_ptr, host_mem_ptr, size); + } + return 0; +} + +void +ia_css_isp_param_enable_pipeline( + const struct ia_css_isp_param_host_segments *mem_params) +{ + /* By protocol b0 of the mandatory uint32_t first field of the + input parameter is a disable bit*/ + short dmem_offset = 0; + + if (mem_params->params[IA_CSS_PARAM_CLASS_PARAM][IA_CSS_ISP_DMEM0].size == 0) + return; + + *(uint32_t *) + &mem_params->params[IA_CSS_PARAM_CLASS_PARAM][IA_CSS_ISP_DMEM0].address[dmem_offset] + = 0x0; +} diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys.h b/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys.h new file mode 100644 index 000000000..711a321e9 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys.h @@ -0,0 +1,183 @@ +/* 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. + */ + +#ifndef __IA_CSS_ISYS_H__ +#define __IA_CSS_ISYS_H__ + +#include <type_support.h> +#include <input_system.h> +#include <ia_css_input_port.h> +#include <ia_css_stream_format.h> +#include <ia_css_stream_public.h> +#include <system_global.h> +#include "ia_css_isys_comm.h" + +#ifdef ISP2401 +/** + * Virtual Input System. (Input System 2401) + */ +typedef isp2401_input_system_cfg_t ia_css_isys_descr_t; +/* end of Virtual Input System */ +#endif + +input_system_err_t ia_css_isys_init(void); +void ia_css_isys_uninit(void); +enum mipi_port_id ia_css_isys_port_to_mipi_port( + enum mipi_port_id api_port); + +#if defined(ISP2401) + +/** + * @brief Register one (virtual) stream. This is used to track when all + * virtual streams are configured inside the input system. The CSI RX is + * only started when all registered streams are configured. + * + * @param[in] port CSI port + * @param[in] isys_stream_id Stream handle generated with ia_css_isys_generate_stream_id() + * Must be lower than SH_CSS_MAX_ISYS_CHANNEL_NODES + * @return 0 if successful, -EINVAL if + * there is already a stream registered with the same handle + */ +int ia_css_isys_csi_rx_register_stream( + enum mipi_port_id port, + uint32_t isys_stream_id); + +/** + * @brief Unregister one (virtual) stream. This is used to track when all + * virtual streams are configured inside the input system. The CSI RX is + * only started when all registered streams are configured. + * + * @param[in] port CSI port + * @param[in] isys_stream_id Stream handle generated with ia_css_isys_generate_stream_id() + * Must be lower than SH_CSS_MAX_ISYS_CHANNEL_NODES + * @return 0 if successful, -EINVAL if + * there is no stream registered with that handle + */ +int ia_css_isys_csi_rx_unregister_stream( + enum mipi_port_id port, + uint32_t isys_stream_id); + +int ia_css_isys_convert_compressed_format( + struct ia_css_csi2_compression *comp, + struct isp2401_input_system_cfg_s *cfg); +unsigned int ia_css_csi2_calculate_input_system_alignment( + enum atomisp_input_format fmt_type); +#endif + +#if !defined(ISP2401) +/* CSS Receiver */ +void ia_css_isys_rx_configure( + const rx_cfg_t *config, + const enum ia_css_input_mode input_mode); + +void ia_css_isys_rx_disable(void); + +void ia_css_isys_rx_enable_all_interrupts(enum mipi_port_id port); + +unsigned int ia_css_isys_rx_get_interrupt_reg(enum mipi_port_id port); +void ia_css_isys_rx_get_irq_info(enum mipi_port_id port, + unsigned int *irq_infos); +void ia_css_isys_rx_clear_irq_info(enum mipi_port_id port, + unsigned int irq_infos); +unsigned int ia_css_isys_rx_translate_irq_infos(unsigned int bits); + +#endif /* #if !defined(ISP2401) */ + +/* @brief Translate format and compression to format type. + * + * @param[in] input_format The input format. + * @param[in] compression The compression scheme. + * @param[out] fmt_type Pointer to the resulting format type. + * @return Error code. + * + * Translate an input format and mipi compression pair to the fmt_type. + * This is normally done by the sensor, but when using the input fifo, this + * format type must be sumitted correctly by the application. + */ +int ia_css_isys_convert_stream_format_to_mipi_format( + enum atomisp_input_format input_format, + mipi_predictor_t compression, + unsigned int *fmt_type); + +#ifdef ISP2401 +/** + * Virtual Input System. (Input System 2401) + */ +ia_css_isys_error_t ia_css_isys_stream_create( + ia_css_isys_descr_t *isys_stream_descr, + ia_css_isys_stream_h isys_stream, + uint32_t isys_stream_id); + +void ia_css_isys_stream_destroy( + ia_css_isys_stream_h isys_stream); + +ia_css_isys_error_t ia_css_isys_stream_calculate_cfg( + ia_css_isys_stream_h isys_stream, + ia_css_isys_descr_t *isys_stream_descr, + ia_css_isys_stream_cfg_t *isys_stream_cfg); + +void ia_css_isys_csi_rx_lut_rmgr_init(void); + +void ia_css_isys_csi_rx_lut_rmgr_uninit(void); + +bool ia_css_isys_csi_rx_lut_rmgr_acquire( + csi_rx_backend_ID_t backend, + csi_mipi_packet_type_t packet_type, + csi_rx_backend_lut_entry_t *entry); + +void ia_css_isys_csi_rx_lut_rmgr_release( + csi_rx_backend_ID_t backend, + csi_mipi_packet_type_t packet_type, + csi_rx_backend_lut_entry_t *entry); + +void ia_css_isys_ibuf_rmgr_init(void); + +void ia_css_isys_ibuf_rmgr_uninit(void); + +bool ia_css_isys_ibuf_rmgr_acquire( + u32 size, + uint32_t *start_addr); + +void ia_css_isys_ibuf_rmgr_release( + uint32_t *start_addr); + +void ia_css_isys_dma_channel_rmgr_init(void); + +void ia_css_isys_dma_channel_rmgr_uninit(void); + +bool ia_css_isys_dma_channel_rmgr_acquire( + isys2401_dma_ID_t dma_id, + isys2401_dma_channel *channel); + +void ia_css_isys_dma_channel_rmgr_release( + isys2401_dma_ID_t dma_id, + isys2401_dma_channel *channel); + +void ia_css_isys_stream2mmio_sid_rmgr_init(void); + +void ia_css_isys_stream2mmio_sid_rmgr_uninit(void); + +bool ia_css_isys_stream2mmio_sid_rmgr_acquire( + stream2mmio_ID_t stream2mmio, + stream2mmio_sid_ID_t *sid); + +void ia_css_isys_stream2mmio_sid_rmgr_release( + stream2mmio_ID_t stream2mmio, + stream2mmio_sid_ID_t *sid); + +/* end of Virtual Input System */ +#endif + +#endif /* __IA_CSS_ISYS_H__ */ diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys_comm.h b/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys_comm.h new file mode 100644 index 000000000..d80ef42c7 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys_comm.h @@ -0,0 +1,54 @@ +/* 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. + */ + +#ifndef __IA_CSS_ISYS_COMM_H +#define __IA_CSS_ISYS_COMM_H + +#include <type_support.h> +#include <input_system.h> + +#ifdef ISP2401 +#include <platform_support.h> /* inline */ +#include <input_system_global.h> +#include <ia_css_stream_public.h> /* IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH */ + +#define SH_CSS_NODES_PER_THREAD 2 +#define SH_CSS_MAX_ISYS_CHANNEL_NODES (SH_CSS_MAX_SP_THREADS * SH_CSS_NODES_PER_THREAD) + +/* + * a) ia_css_isys_stream_h & ia_css_isys_stream_cfg_t come from host. + * + * b) Here it is better to use actual structures for stream handle + * instead of opaque handles. Otherwise, we need to have another + * communication channel to interpret that opaque handle(this handle is + * maintained by host and needs to be populated to sp for every stream open) + * */ +typedef virtual_input_system_stream_t *ia_css_isys_stream_h; +typedef virtual_input_system_stream_cfg_t ia_css_isys_stream_cfg_t; + +/* + * error check for ISYS APIs. + * */ +typedef bool ia_css_isys_error_t; + +static inline uint32_t ia_css_isys_generate_stream_id( + u32 sp_thread_id, + uint32_t stream_id) +{ + return sp_thread_id * IA_CSS_STREAM_MAX_ISYS_STREAM_PER_CH + stream_id; +} + +#endif /* ISP2401*/ +#endif /*_IA_CSS_ISYS_COMM_H */ diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/csi_rx_rmgr.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/csi_rx_rmgr.c new file mode 100644 index 000000000..3fc9fed1e --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/csi_rx_rmgr.c @@ -0,0 +1,168 @@ +// 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" + +#ifdef ISP2401 + +#include "assert_support.h" +#include "platform_support.h" +#include "ia_css_isys.h" +#include "bitop_support.h" +#include "ia_css_pipeline.h" /* ia_css_pipeline_get_pipe_io_status() */ +#include "sh_css_internal.h" /* sh_css_sp_pipeline_io_status + * SH_CSS_MAX_SP_THREADS + */ +#include "csi_rx_rmgr.h" + +static isys_csi_rx_rsrc_t isys_csi_rx_rsrc[N_CSI_RX_BACKEND_ID]; + +void ia_css_isys_csi_rx_lut_rmgr_init(void) +{ + memset(isys_csi_rx_rsrc, 0, sizeof(isys_csi_rx_rsrc)); +} + +void ia_css_isys_csi_rx_lut_rmgr_uninit(void) +{ + memset(isys_csi_rx_rsrc, 0, sizeof(isys_csi_rx_rsrc)); +} + +bool ia_css_isys_csi_rx_lut_rmgr_acquire( + csi_rx_backend_ID_t backend, + csi_mipi_packet_type_t packet_type, + csi_rx_backend_lut_entry_t *entry) +{ + bool retval = false; + u32 max_num_packets_of_type; + u32 num_active_of_type; + isys_csi_rx_rsrc_t *cur_rsrc = NULL; + u16 i; + + assert(backend < N_CSI_RX_BACKEND_ID); + assert((packet_type == CSI_MIPI_PACKET_TYPE_LONG) || + (packet_type == CSI_MIPI_PACKET_TYPE_SHORT)); + assert(entry); + + if ((backend < N_CSI_RX_BACKEND_ID) && (entry)) { + cur_rsrc = &isys_csi_rx_rsrc[backend]; + if (packet_type == CSI_MIPI_PACKET_TYPE_LONG) { + max_num_packets_of_type = N_LONG_PACKET_LUT_ENTRIES[backend]; + num_active_of_type = cur_rsrc->num_long_packets; + } else { + max_num_packets_of_type = N_SHORT_PACKET_LUT_ENTRIES[backend]; + num_active_of_type = cur_rsrc->num_short_packets; + } + + if (num_active_of_type < max_num_packets_of_type) { + for (i = 0; i < max_num_packets_of_type; i++) { + if (bitop_getbit(cur_rsrc->active_table, i) == 0) { + bitop_setbit(cur_rsrc->active_table, i); + + if (packet_type == CSI_MIPI_PACKET_TYPE_LONG) { + entry->long_packet_entry = i; + entry->short_packet_entry = 0; + cur_rsrc->num_long_packets++; + } else { + entry->long_packet_entry = 0; + entry->short_packet_entry = i; + cur_rsrc->num_short_packets++; + } + cur_rsrc->num_active++; + retval = true; + break; + } + } + } + } + return retval; +} + +void ia_css_isys_csi_rx_lut_rmgr_release( + csi_rx_backend_ID_t backend, + csi_mipi_packet_type_t packet_type, + csi_rx_backend_lut_entry_t *entry) +{ + u32 max_num_packets; + isys_csi_rx_rsrc_t *cur_rsrc = NULL; + u32 packet_entry = 0; + + assert(backend < N_CSI_RX_BACKEND_ID); + assert(entry); + assert((packet_type >= CSI_MIPI_PACKET_TYPE_LONG) || + (packet_type <= CSI_MIPI_PACKET_TYPE_SHORT)); + + if ((backend < N_CSI_RX_BACKEND_ID) && (entry)) { + if (packet_type == CSI_MIPI_PACKET_TYPE_LONG) { + max_num_packets = N_LONG_PACKET_LUT_ENTRIES[backend]; + packet_entry = entry->long_packet_entry; + } else { + max_num_packets = N_SHORT_PACKET_LUT_ENTRIES[backend]; + packet_entry = entry->short_packet_entry; + } + + cur_rsrc = &isys_csi_rx_rsrc[backend]; + if ((packet_entry < max_num_packets) && (cur_rsrc->num_active > 0)) { + if (bitop_getbit(cur_rsrc->active_table, packet_entry) == 1) { + bitop_clearbit(cur_rsrc->active_table, packet_entry); + + if (packet_type == CSI_MIPI_PACKET_TYPE_LONG) + cur_rsrc->num_long_packets--; + else + cur_rsrc->num_short_packets--; + cur_rsrc->num_active--; + } + } + } +} + +int ia_css_isys_csi_rx_register_stream( + enum mipi_port_id port, + uint32_t isys_stream_id) +{ + int retval = -EINVAL; + + if ((port < N_INPUT_SYSTEM_CSI_PORT) && + (isys_stream_id < SH_CSS_MAX_ISYS_CHANNEL_NODES)) { + struct sh_css_sp_pipeline_io_status *pipe_io_status; + + pipe_io_status = ia_css_pipeline_get_pipe_io_status(); + if (bitop_getbit(pipe_io_status->active[port], isys_stream_id) == 0) { + bitop_setbit(pipe_io_status->active[port], isys_stream_id); + pipe_io_status->running[port] = 0; + retval = 0; + } + } + return retval; +} + +int ia_css_isys_csi_rx_unregister_stream( + enum mipi_port_id port, + uint32_t isys_stream_id) +{ + int retval = -EINVAL; + + if ((port < N_INPUT_SYSTEM_CSI_PORT) && + (isys_stream_id < SH_CSS_MAX_ISYS_CHANNEL_NODES)) { + struct sh_css_sp_pipeline_io_status *pipe_io_status; + + pipe_io_status = ia_css_pipeline_get_pipe_io_status(); + if (bitop_getbit(pipe_io_status->active[port], isys_stream_id) == 1) { + bitop_clearbit(pipe_io_status->active[port], isys_stream_id); + retval = 0; + } + } + return retval; +} +#endif diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/csi_rx_rmgr.h b/drivers/staging/media/atomisp/pci/runtime/isys/src/csi_rx_rmgr.h new file mode 100644 index 000000000..11f730dc1 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/csi_rx_rmgr.h @@ -0,0 +1,27 @@ +/* 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. + */ + +#ifndef __CSI_RX_RMGR_H_INCLUDED__ +#define __CSI_RX_RMGR_H_INCLUDED__ + +typedef struct isys_csi_rx_rsrc_s isys_csi_rx_rsrc_t; +struct isys_csi_rx_rsrc_s { + u32 active_table; + u32 num_active; + u16 num_long_packets; + u16 num_short_packets; +}; + +#endif /* __CSI_RX_RMGR_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/ibuf_ctrl_rmgr.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/ibuf_ctrl_rmgr.c new file mode 100644 index 000000000..9710493c4 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/ibuf_ctrl_rmgr.c @@ -0,0 +1,122 @@ +// 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 "system_global.h" + +#include "assert_support.h" +#include "platform_support.h" +#include "ia_css_isys.h" +#include "ibuf_ctrl_rmgr.h" + +static ibuf_rsrc_t ibuf_rsrc; + +static ibuf_handle_t *getHandle(uint16_t index) +{ + ibuf_handle_t *handle = NULL; + + if (index < MAX_IBUF_HANDLES) + handle = &ibuf_rsrc.handles[index]; + return handle; +} + +void ia_css_isys_ibuf_rmgr_init(void) +{ + memset(&ibuf_rsrc, 0, sizeof(ibuf_rsrc)); + ibuf_rsrc.free_size = MAX_INPUT_BUFFER_SIZE; +} + +void ia_css_isys_ibuf_rmgr_uninit(void) +{ + memset(&ibuf_rsrc, 0, sizeof(ibuf_rsrc)); + ibuf_rsrc.free_size = MAX_INPUT_BUFFER_SIZE; +} + +bool ia_css_isys_ibuf_rmgr_acquire( + u32 size, + uint32_t *start_addr) +{ + bool retval = false; + bool input_buffer_found = false; + u32 aligned_size; + ibuf_handle_t *handle = NULL; + u16 i; + + assert(start_addr); + assert(size > 0); + + aligned_size = (size + (IBUF_ALIGN - 1)) & ~(IBUF_ALIGN - 1); + + /* Check if there is an available un-used handle with the size + * that will fulfill the request. + */ + if (ibuf_rsrc.num_active < ibuf_rsrc.num_allocated) { + for (i = 0; i < ibuf_rsrc.num_allocated; i++) { + handle = getHandle(i); + if (!handle->active) { + if (handle->size >= aligned_size) { + handle->active = true; + input_buffer_found = true; + ibuf_rsrc.num_active++; + break; + } + } + } + } + + if (!input_buffer_found) { + /* There were no available handles that fulfilled the + * request. Allocate a new handle with the requested size. + */ + if ((ibuf_rsrc.num_allocated < MAX_IBUF_HANDLES) && + (ibuf_rsrc.free_size >= aligned_size)) { + handle = getHandle(ibuf_rsrc.num_allocated); + handle->start_addr = ibuf_rsrc.free_start_addr; + handle->size = aligned_size; + handle->active = true; + + ibuf_rsrc.free_start_addr += aligned_size; + ibuf_rsrc.free_size -= aligned_size; + ibuf_rsrc.num_active++; + ibuf_rsrc.num_allocated++; + + input_buffer_found = true; + } + } + + if (input_buffer_found && handle) { + *start_addr = handle->start_addr; + retval = true; + } + + return retval; +} + +void ia_css_isys_ibuf_rmgr_release( + uint32_t *start_addr) +{ + u16 i; + ibuf_handle_t *handle = NULL; + + assert(start_addr); + + for (i = 0; i < ibuf_rsrc.num_allocated; i++) { + handle = getHandle(i); + if (handle->active && handle->start_addr == *start_addr) { + handle->active = false; + ibuf_rsrc.num_active--; + break; + } + } +} diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/ibuf_ctrl_rmgr.h b/drivers/staging/media/atomisp/pci/runtime/isys/src/ibuf_ctrl_rmgr.h new file mode 100644 index 000000000..7c754ec72 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/ibuf_ctrl_rmgr.h @@ -0,0 +1,39 @@ +/* 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. + */ + +#ifndef __IBUF_CTRL_RMGR_H_INCLUDED__ +#define __IBUF_CTRL_RMGR_H_INCLUDED__ + +#define MAX_IBUF_HANDLES 24 +#define MAX_INPUT_BUFFER_SIZE (64 * 1024) +#define IBUF_ALIGN 8 + +typedef struct ibuf_handle_s ibuf_handle_t; +struct ibuf_handle_s { + u32 start_addr; + u32 size; + bool active; +}; + +typedef struct ibuf_rsrc_s ibuf_rsrc_t; +struct ibuf_rsrc_s { + u32 free_start_addr; + u32 free_size; + u16 num_active; + u16 num_allocated; + ibuf_handle_t handles[MAX_IBUF_HANDLES]; +}; + +#endif /* __IBUF_CTRL_RMGR_H_INCLUDED */ diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_dma_rmgr.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_dma_rmgr.c new file mode 100644 index 000000000..261c6460e --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_dma_rmgr.c @@ -0,0 +1,88 @@ +// 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" + +#ifdef ISP2401 + +#include "assert_support.h" +#include "platform_support.h" +#include "ia_css_isys.h" +#include "bitop_support.h" +#include "isys_dma_rmgr.h" + +static isys_dma_rsrc_t isys_dma_rsrc[N_ISYS2401_DMA_ID]; + +void ia_css_isys_dma_channel_rmgr_init(void) +{ + memset(&isys_dma_rsrc, 0, sizeof(isys_dma_rsrc_t)); +} + +void ia_css_isys_dma_channel_rmgr_uninit(void) +{ + memset(&isys_dma_rsrc, 0, sizeof(isys_dma_rsrc_t)); +} + +bool ia_css_isys_dma_channel_rmgr_acquire( + isys2401_dma_ID_t dma_id, + isys2401_dma_channel *channel) +{ + bool retval = false; + isys2401_dma_channel i; + isys2401_dma_channel max_dma_channel; + isys_dma_rsrc_t *cur_rsrc = NULL; + + assert(dma_id < N_ISYS2401_DMA_ID); + assert(channel); + + max_dma_channel = N_ISYS2401_DMA_CHANNEL_PROCS[dma_id]; + cur_rsrc = &isys_dma_rsrc[dma_id]; + + if (cur_rsrc->num_active < max_dma_channel) { + for (i = ISYS2401_DMA_CHANNEL_0; i < N_ISYS2401_DMA_CHANNEL; i++) { + if (bitop_getbit(cur_rsrc->active_table, i) == 0) { + bitop_setbit(cur_rsrc->active_table, i); + *channel = i; + cur_rsrc->num_active++; + retval = true; + break; + } + } + } + + return retval; +} + +void ia_css_isys_dma_channel_rmgr_release( + isys2401_dma_ID_t dma_id, + isys2401_dma_channel *channel) +{ + isys2401_dma_channel max_dma_channel; + isys_dma_rsrc_t *cur_rsrc = NULL; + + assert(dma_id < N_ISYS2401_DMA_ID); + assert(channel); + + max_dma_channel = N_ISYS2401_DMA_CHANNEL_PROCS[dma_id]; + cur_rsrc = &isys_dma_rsrc[dma_id]; + + if ((*channel < max_dma_channel) && (cur_rsrc->num_active > 0)) { + if (bitop_getbit(cur_rsrc->active_table, *channel) == 1) { + bitop_clearbit(cur_rsrc->active_table, *channel); + cur_rsrc->num_active--; + } + } +} +#endif diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_dma_rmgr.h b/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_dma_rmgr.h new file mode 100644 index 000000000..88c3d5581 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_dma_rmgr.h @@ -0,0 +1,25 @@ +/* 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. + */ + +#ifndef __ISYS_DMA_RMGR_H_INCLUDED__ +#define __ISYS_DMA_RMGR_H_INCLUDED__ + +typedef struct isys_dma_rsrc_s isys_dma_rsrc_t; +struct isys_dma_rsrc_s { + u32 active_table; + u16 num_active; +}; + +#endif /* __ISYS_DMA_RMGR_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_init.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_init.c new file mode 100644 index 000000000..d0a43c449 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_init.c @@ -0,0 +1,122 @@ +// 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 "input_system.h" + +#include "ia_css_isys.h" +#include "platform_support.h" + +#ifdef ISP2401 +#include "isys_dma_public.h" /* isys2401_dma_set_max_burst_size() */ +#include "isys_irq.h" +#endif + +#if !defined(ISP2401) +input_system_err_t ia_css_isys_init(void) +{ + backend_channel_cfg_t backend_ch0; + backend_channel_cfg_t backend_ch1; + target_cfg2400_t targetB; + target_cfg2400_t targetC; + u32 acq_mem_region_size = 24; + u32 acq_nof_mem_regions = 2; + input_system_err_t error = INPUT_SYSTEM_ERR_NO_ERROR; + + memset(&backend_ch0, 0, sizeof(backend_channel_cfg_t)); + memset(&backend_ch1, 0, sizeof(backend_channel_cfg_t)); + memset(&targetB, 0, sizeof(targetB)); + memset(&targetC, 0, sizeof(targetC)); + + error = input_system_configuration_reset(); + if (error != INPUT_SYSTEM_ERR_NO_ERROR) + return error; + + error = input_system_csi_xmem_channel_cfg( + 0, /*ch_id */ + INPUT_SYSTEM_PORT_A, /*port */ + backend_ch0, /*backend_ch */ + 32, /*mem_region_size */ + 6, /*nof_mem_regions */ + acq_mem_region_size, /*acq_mem_region_size */ + acq_nof_mem_regions, /*acq_nof_mem_regions */ + targetB, /*target */ + 3); /*nof_xmem_buffers */ + if (error != INPUT_SYSTEM_ERR_NO_ERROR) + return error; + + error = input_system_csi_xmem_channel_cfg( + 1, /*ch_id */ + INPUT_SYSTEM_PORT_B, /*port */ + backend_ch0, /*backend_ch */ + 16, /*mem_region_size */ + 3, /*nof_mem_regions */ + acq_mem_region_size, /*acq_mem_region_size */ + acq_nof_mem_regions, /*acq_nof_mem_regions */ + targetB, /*target */ + 3); /*nof_xmem_buffers */ + if (error != INPUT_SYSTEM_ERR_NO_ERROR) + return error; + + error = input_system_csi_xmem_channel_cfg( + 2, /*ch_id */ + INPUT_SYSTEM_PORT_C, /*port */ + backend_ch1, /*backend_ch */ + 32, /*mem_region_size */ + 3, /*nof_mem_regions */ + acq_mem_region_size, /*acq_mem_region_size */ + acq_nof_mem_regions, /*acq_nof_mem_regions */ + targetC, /*target */ + 2); /*nof_xmem_buffers */ + if (error != INPUT_SYSTEM_ERR_NO_ERROR) + return error; + + error = input_system_configuration_commit(); + + return error; +} +#elif defined(ISP2401) +input_system_err_t ia_css_isys_init(void) +{ + ia_css_isys_csi_rx_lut_rmgr_init(); + ia_css_isys_ibuf_rmgr_init(); + ia_css_isys_dma_channel_rmgr_init(); + ia_css_isys_stream2mmio_sid_rmgr_init(); + + isys2401_dma_set_max_burst_size(ISYS2401_DMA0_ID, + 1 /* Non Burst DMA transactions */); + + /* Enable 2401 input system IRQ status for driver to retrieve */ + isys_irqc_status_enable(ISYS_IRQ0_ID); + isys_irqc_status_enable(ISYS_IRQ1_ID); + isys_irqc_status_enable(ISYS_IRQ2_ID); + + return INPUT_SYSTEM_ERR_NO_ERROR; +} +#endif + +#if !defined(ISP2401) +void ia_css_isys_uninit(void) +{ +} +#elif defined(ISP2401) +void ia_css_isys_uninit(void) +{ + ia_css_isys_csi_rx_lut_rmgr_uninit(); + ia_css_isys_ibuf_rmgr_uninit(); + ia_css_isys_dma_channel_rmgr_uninit(); + ia_css_isys_stream2mmio_sid_rmgr_uninit(); +} +#endif + diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_stream2mmio_rmgr.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_stream2mmio_rmgr.c new file mode 100644 index 000000000..fb0cb183f --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_stream2mmio_rmgr.c @@ -0,0 +1,90 @@ +// 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" + +#ifdef ISP2401 + +#include "assert_support.h" +#include "platform_support.h" +#include "ia_css_isys.h" +#include "bitop_support.h" +#include "isys_stream2mmio_rmgr.h" + +static isys_stream2mmio_rsrc_t isys_stream2mmio_rsrc[N_STREAM2MMIO_ID]; + +void ia_css_isys_stream2mmio_sid_rmgr_init(void) +{ + memset(isys_stream2mmio_rsrc, 0, sizeof(isys_stream2mmio_rsrc)); +} + +void ia_css_isys_stream2mmio_sid_rmgr_uninit(void) +{ + memset(isys_stream2mmio_rsrc, 0, sizeof(isys_stream2mmio_rsrc)); +} + +bool ia_css_isys_stream2mmio_sid_rmgr_acquire( + stream2mmio_ID_t stream2mmio, + stream2mmio_sid_ID_t *sid) +{ + bool retval = false; + stream2mmio_sid_ID_t max_sid; + isys_stream2mmio_rsrc_t *cur_rsrc = NULL; + stream2mmio_sid_ID_t i; + + assert(stream2mmio < N_STREAM2MMIO_ID); + assert(sid); + + if ((stream2mmio < N_STREAM2MMIO_ID) && (sid)) { + max_sid = N_STREAM2MMIO_SID_PROCS[stream2mmio]; + cur_rsrc = &isys_stream2mmio_rsrc[stream2mmio]; + + if (cur_rsrc->num_active < max_sid) { + for (i = STREAM2MMIO_SID0_ID; i < max_sid; i++) { + if (bitop_getbit(cur_rsrc->active_table, i) == 0) { + bitop_setbit(cur_rsrc->active_table, i); + *sid = i; + cur_rsrc->num_active++; + retval = true; + break; + } + } + } + } + return retval; +} + +void ia_css_isys_stream2mmio_sid_rmgr_release( + stream2mmio_ID_t stream2mmio, + stream2mmio_sid_ID_t *sid) +{ + stream2mmio_sid_ID_t max_sid; + isys_stream2mmio_rsrc_t *cur_rsrc = NULL; + + assert(stream2mmio < N_STREAM2MMIO_ID); + assert(sid); + + if ((stream2mmio < N_STREAM2MMIO_ID) && (sid)) { + max_sid = N_STREAM2MMIO_SID_PROCS[stream2mmio]; + cur_rsrc = &isys_stream2mmio_rsrc[stream2mmio]; + if ((*sid < max_sid) && (cur_rsrc->num_active > 0)) { + if (bitop_getbit(cur_rsrc->active_table, *sid) == 1) { + bitop_clearbit(cur_rsrc->active_table, *sid); + cur_rsrc->num_active--; + } + } + } +} +#endif diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_stream2mmio_rmgr.h b/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_stream2mmio_rmgr.h new file mode 100644 index 000000000..78a4c867f --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/isys_stream2mmio_rmgr.h @@ -0,0 +1,25 @@ +/* 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. + */ + +#ifndef __ISYS_STREAM2MMIO_RMGR_H_INCLUDED__ +#define __ISYS_STREAM2MMIO_RMGR_H_INCLUDED__ + +typedef struct isys_stream2mmio_rsrc_s isys_stream2mmio_rsrc_t; +struct isys_stream2mmio_rsrc_s { + u32 active_table; + u16 num_active; +}; + +#endif /* __ISYS_STREAM2MMIO_RMGR_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c new file mode 100644 index 000000000..af153c3fb --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c @@ -0,0 +1,600 @@ +// 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. + */ + +#define __INLINE_INPUT_SYSTEM__ +#include "input_system.h" +#include "assert_support.h" +#include "ia_css_isys.h" +#include "ia_css_irq.h" +#include "sh_css_internal.h" + +#if !defined(ISP2401) +void ia_css_isys_rx_enable_all_interrupts(enum mipi_port_id port) +{ + hrt_data bits = receiver_port_reg_load(RX0_ID, + port, + _HRT_CSS_RECEIVER_IRQ_ENABLE_REG_IDX); + + bits |= (1U << _HRT_CSS_RECEIVER_IRQ_OVERRUN_BIT) | + (1U << _HRT_CSS_RECEIVER_IRQ_INIT_TIMEOUT_BIT) | + (1U << _HRT_CSS_RECEIVER_IRQ_SLEEP_MODE_ENTRY_BIT) | + (1U << _HRT_CSS_RECEIVER_IRQ_SLEEP_MODE_EXIT_BIT) | + (1U << _HRT_CSS_RECEIVER_IRQ_ERR_SOT_HS_BIT) | + (1U << _HRT_CSS_RECEIVER_IRQ_ERR_SOT_SYNC_HS_BIT) | + (1U << _HRT_CSS_RECEIVER_IRQ_ERR_CONTROL_BIT) | + (1U << _HRT_CSS_RECEIVER_IRQ_ERR_ECC_DOUBLE_BIT) | + (1U << _HRT_CSS_RECEIVER_IRQ_ERR_ECC_CORRECTED_BIT) | + /*(1U << _HRT_CSS_RECEIVER_IRQ_ERR_ECC_NO_CORRECTION_BIT) | */ + (1U << _HRT_CSS_RECEIVER_IRQ_ERR_CRC_BIT) | + (1U << _HRT_CSS_RECEIVER_IRQ_ERR_ID_BIT) | + (1U << _HRT_CSS_RECEIVER_IRQ_ERR_FRAME_SYNC_BIT) | + (1U << _HRT_CSS_RECEIVER_IRQ_ERR_FRAME_DATA_BIT) | + (1U << _HRT_CSS_RECEIVER_IRQ_DATA_TIMEOUT_BIT) | + (1U << _HRT_CSS_RECEIVER_IRQ_ERR_ESCAPE_BIT); + /*(1U << _HRT_CSS_RECEIVER_IRQ_ERR_LINE_SYNC_BIT); */ + + receiver_port_reg_store(RX0_ID, + port, + _HRT_CSS_RECEIVER_IRQ_ENABLE_REG_IDX, bits); + + /* + * The CSI is nested into the Iunit IRQ's + */ + ia_css_irq_enable(IA_CSS_IRQ_INFO_CSS_RECEIVER_ERROR, true); + + return; +} + +/* This function converts between the enum used on the CSS API and the + * internal DLI enum type. + * We do not use an array for this since we cannot use named array + * initializers in Windows. Without that there is no easy way to guarantee + * that the array values would be in the correct order. + * */ +enum mipi_port_id ia_css_isys_port_to_mipi_port(enum mipi_port_id api_port) +{ + /* In this module the validity of the inptu variable should + * have been checked already, so we do not check for erroneous + * values. */ + enum mipi_port_id port = MIPI_PORT0_ID; + + if (api_port == MIPI_PORT1_ID) + port = MIPI_PORT1_ID; + else if (api_port == MIPI_PORT2_ID) + port = MIPI_PORT2_ID; + + return port; +} + +unsigned int ia_css_isys_rx_get_interrupt_reg(enum mipi_port_id port) +{ + return receiver_port_reg_load(RX0_ID, + port, + _HRT_CSS_RECEIVER_IRQ_STATUS_REG_IDX); +} + +void ia_css_rx_get_irq_info(unsigned int *irq_infos) +{ + ia_css_rx_port_get_irq_info(MIPI_PORT1_ID, irq_infos); +} + +void ia_css_rx_port_get_irq_info(enum mipi_port_id api_port, + unsigned int *irq_infos) +{ + enum mipi_port_id port = ia_css_isys_port_to_mipi_port(api_port); + + ia_css_isys_rx_get_irq_info(port, irq_infos); +} + +void ia_css_isys_rx_get_irq_info(enum mipi_port_id port, + unsigned int *irq_infos) +{ + unsigned int bits; + + assert(irq_infos); + bits = ia_css_isys_rx_get_interrupt_reg(port); + *irq_infos = ia_css_isys_rx_translate_irq_infos(bits); +} + +/* Translate register bits to CSS API enum mask */ +unsigned int ia_css_isys_rx_translate_irq_infos(unsigned int bits) +{ + unsigned int infos = 0; + + if (bits & (1U << _HRT_CSS_RECEIVER_IRQ_OVERRUN_BIT)) + infos |= IA_CSS_RX_IRQ_INFO_BUFFER_OVERRUN; + if (bits & (1U << _HRT_CSS_RECEIVER_IRQ_INIT_TIMEOUT_BIT)) + infos |= IA_CSS_RX_IRQ_INFO_INIT_TIMEOUT; + if (bits & (1U << _HRT_CSS_RECEIVER_IRQ_SLEEP_MODE_ENTRY_BIT)) + infos |= IA_CSS_RX_IRQ_INFO_ENTER_SLEEP_MODE; + if (bits & (1U << _HRT_CSS_RECEIVER_IRQ_SLEEP_MODE_EXIT_BIT)) + infos |= IA_CSS_RX_IRQ_INFO_EXIT_SLEEP_MODE; + if (bits & (1U << _HRT_CSS_RECEIVER_IRQ_ERR_ECC_CORRECTED_BIT)) + infos |= IA_CSS_RX_IRQ_INFO_ECC_CORRECTED; + if (bits & (1U << _HRT_CSS_RECEIVER_IRQ_ERR_SOT_HS_BIT)) + infos |= IA_CSS_RX_IRQ_INFO_ERR_SOT; + if (bits & (1U << _HRT_CSS_RECEIVER_IRQ_ERR_SOT_SYNC_HS_BIT)) + infos |= IA_CSS_RX_IRQ_INFO_ERR_SOT_SYNC; + if (bits & (1U << _HRT_CSS_RECEIVER_IRQ_ERR_CONTROL_BIT)) + infos |= IA_CSS_RX_IRQ_INFO_ERR_CONTROL; + if (bits & (1U << _HRT_CSS_RECEIVER_IRQ_ERR_ECC_DOUBLE_BIT)) + infos |= IA_CSS_RX_IRQ_INFO_ERR_ECC_DOUBLE; + if (bits & (1U << _HRT_CSS_RECEIVER_IRQ_ERR_CRC_BIT)) + infos |= IA_CSS_RX_IRQ_INFO_ERR_CRC; + if (bits & (1U << _HRT_CSS_RECEIVER_IRQ_ERR_ID_BIT)) + infos |= IA_CSS_RX_IRQ_INFO_ERR_UNKNOWN_ID; + if (bits & (1U << _HRT_CSS_RECEIVER_IRQ_ERR_FRAME_SYNC_BIT)) + infos |= IA_CSS_RX_IRQ_INFO_ERR_FRAME_SYNC; + if (bits & (1U << _HRT_CSS_RECEIVER_IRQ_ERR_FRAME_DATA_BIT)) + infos |= IA_CSS_RX_IRQ_INFO_ERR_FRAME_DATA; + if (bits & (1U << _HRT_CSS_RECEIVER_IRQ_DATA_TIMEOUT_BIT)) + infos |= IA_CSS_RX_IRQ_INFO_ERR_DATA_TIMEOUT; + if (bits & (1U << _HRT_CSS_RECEIVER_IRQ_ERR_ESCAPE_BIT)) + infos |= IA_CSS_RX_IRQ_INFO_ERR_UNKNOWN_ESC; + if (bits & (1U << _HRT_CSS_RECEIVER_IRQ_ERR_LINE_SYNC_BIT)) + infos |= IA_CSS_RX_IRQ_INFO_ERR_LINE_SYNC; + + return infos; +} + +void ia_css_rx_clear_irq_info(unsigned int irq_infos) +{ + ia_css_rx_port_clear_irq_info(MIPI_PORT1_ID, irq_infos); +} + +void ia_css_rx_port_clear_irq_info(enum mipi_port_id api_port, + unsigned int irq_infos) +{ + enum mipi_port_id port = ia_css_isys_port_to_mipi_port(api_port); + + ia_css_isys_rx_clear_irq_info(port, irq_infos); +} + +void ia_css_isys_rx_clear_irq_info(enum mipi_port_id port, + unsigned int irq_infos) +{ + hrt_data bits = receiver_port_reg_load(RX0_ID, + port, + _HRT_CSS_RECEIVER_IRQ_ENABLE_REG_IDX); + + /* MW: Why do we remap the receiver bitmap */ + if (irq_infos & IA_CSS_RX_IRQ_INFO_BUFFER_OVERRUN) + bits |= 1U << _HRT_CSS_RECEIVER_IRQ_OVERRUN_BIT; + if (irq_infos & IA_CSS_RX_IRQ_INFO_INIT_TIMEOUT) + bits |= 1U << _HRT_CSS_RECEIVER_IRQ_INIT_TIMEOUT_BIT; + if (irq_infos & IA_CSS_RX_IRQ_INFO_ENTER_SLEEP_MODE) + bits |= 1U << _HRT_CSS_RECEIVER_IRQ_SLEEP_MODE_ENTRY_BIT; + if (irq_infos & IA_CSS_RX_IRQ_INFO_EXIT_SLEEP_MODE) + bits |= 1U << _HRT_CSS_RECEIVER_IRQ_SLEEP_MODE_EXIT_BIT; + if (irq_infos & IA_CSS_RX_IRQ_INFO_ECC_CORRECTED) + bits |= 1U << _HRT_CSS_RECEIVER_IRQ_ERR_ECC_CORRECTED_BIT; + if (irq_infos & IA_CSS_RX_IRQ_INFO_ERR_SOT) + bits |= 1U << _HRT_CSS_RECEIVER_IRQ_ERR_SOT_HS_BIT; + if (irq_infos & IA_CSS_RX_IRQ_INFO_ERR_SOT_SYNC) + bits |= 1U << _HRT_CSS_RECEIVER_IRQ_ERR_SOT_SYNC_HS_BIT; + if (irq_infos & IA_CSS_RX_IRQ_INFO_ERR_CONTROL) + bits |= 1U << _HRT_CSS_RECEIVER_IRQ_ERR_CONTROL_BIT; + if (irq_infos & IA_CSS_RX_IRQ_INFO_ERR_ECC_DOUBLE) + bits |= 1U << _HRT_CSS_RECEIVER_IRQ_ERR_ECC_DOUBLE_BIT; + if (irq_infos & IA_CSS_RX_IRQ_INFO_ERR_CRC) + bits |= 1U << _HRT_CSS_RECEIVER_IRQ_ERR_CRC_BIT; + if (irq_infos & IA_CSS_RX_IRQ_INFO_ERR_UNKNOWN_ID) + bits |= 1U << _HRT_CSS_RECEIVER_IRQ_ERR_ID_BIT; + if (irq_infos & IA_CSS_RX_IRQ_INFO_ERR_FRAME_SYNC) + bits |= 1U << _HRT_CSS_RECEIVER_IRQ_ERR_FRAME_SYNC_BIT; + if (irq_infos & IA_CSS_RX_IRQ_INFO_ERR_FRAME_DATA) + bits |= 1U << _HRT_CSS_RECEIVER_IRQ_ERR_FRAME_DATA_BIT; + if (irq_infos & IA_CSS_RX_IRQ_INFO_ERR_DATA_TIMEOUT) + bits |= 1U << _HRT_CSS_RECEIVER_IRQ_DATA_TIMEOUT_BIT; + if (irq_infos & IA_CSS_RX_IRQ_INFO_ERR_UNKNOWN_ESC) + bits |= 1U << _HRT_CSS_RECEIVER_IRQ_ERR_ESCAPE_BIT; + if (irq_infos & IA_CSS_RX_IRQ_INFO_ERR_LINE_SYNC) + bits |= 1U << _HRT_CSS_RECEIVER_IRQ_ERR_LINE_SYNC_BIT; + + receiver_port_reg_store(RX0_ID, + port, + _HRT_CSS_RECEIVER_IRQ_ENABLE_REG_IDX, bits); + + return; +} +#endif /* #if !defined(ISP2401) */ + +int ia_css_isys_convert_stream_format_to_mipi_format( + enum atomisp_input_format input_format, + mipi_predictor_t compression, + unsigned int *fmt_type) +{ + assert(fmt_type); + /* + * Custom (user defined) modes. Used for compressed + * MIPI transfers + * + * Checkpatch thinks the indent before "if" is suspect + * I think the only suspect part is the missing "else" + * because of the return. + */ + if (compression != MIPI_PREDICTOR_NONE) { + switch (input_format) { + case ATOMISP_INPUT_FORMAT_RAW_6: + *fmt_type = 6; + break; + case ATOMISP_INPUT_FORMAT_RAW_7: + *fmt_type = 7; + break; + case ATOMISP_INPUT_FORMAT_RAW_8: + *fmt_type = 8; + break; + case ATOMISP_INPUT_FORMAT_RAW_10: + *fmt_type = 10; + break; + case ATOMISP_INPUT_FORMAT_RAW_12: + *fmt_type = 12; + break; + case ATOMISP_INPUT_FORMAT_RAW_14: + *fmt_type = 14; + break; + case ATOMISP_INPUT_FORMAT_RAW_16: + *fmt_type = 16; + break; + default: + return -EINVAL; + } + return 0; + } + /* + * This mapping comes from the Arasan CSS function spec + * (CSS_func_spec1.08_ahb_sep29_08.pdf). + * + * MW: For some reason the mapping is not 1-to-1 + */ + switch (input_format) { + case ATOMISP_INPUT_FORMAT_RGB_888: + *fmt_type = MIPI_FORMAT_RGB888; + break; + case ATOMISP_INPUT_FORMAT_RGB_555: + *fmt_type = MIPI_FORMAT_RGB555; + break; + case ATOMISP_INPUT_FORMAT_RGB_444: + *fmt_type = MIPI_FORMAT_RGB444; + break; + case ATOMISP_INPUT_FORMAT_RGB_565: + *fmt_type = MIPI_FORMAT_RGB565; + break; + case ATOMISP_INPUT_FORMAT_RGB_666: + *fmt_type = MIPI_FORMAT_RGB666; + break; + case ATOMISP_INPUT_FORMAT_RAW_8: + *fmt_type = MIPI_FORMAT_RAW8; + break; + case ATOMISP_INPUT_FORMAT_RAW_10: + *fmt_type = MIPI_FORMAT_RAW10; + break; + case ATOMISP_INPUT_FORMAT_RAW_6: + *fmt_type = MIPI_FORMAT_RAW6; + break; + case ATOMISP_INPUT_FORMAT_RAW_7: + *fmt_type = MIPI_FORMAT_RAW7; + break; + case ATOMISP_INPUT_FORMAT_RAW_12: + *fmt_type = MIPI_FORMAT_RAW12; + break; + case ATOMISP_INPUT_FORMAT_RAW_14: + *fmt_type = MIPI_FORMAT_RAW14; + break; + case ATOMISP_INPUT_FORMAT_YUV420_8: + *fmt_type = MIPI_FORMAT_YUV420_8; + break; + case ATOMISP_INPUT_FORMAT_YUV420_10: + *fmt_type = MIPI_FORMAT_YUV420_10; + break; + case ATOMISP_INPUT_FORMAT_YUV422_8: + *fmt_type = MIPI_FORMAT_YUV422_8; + break; + case ATOMISP_INPUT_FORMAT_YUV422_10: + *fmt_type = MIPI_FORMAT_YUV422_10; + break; + case ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY: + *fmt_type = MIPI_FORMAT_YUV420_8_LEGACY; + break; + case ATOMISP_INPUT_FORMAT_EMBEDDED: + *fmt_type = MIPI_FORMAT_EMBEDDED; + break; +#ifndef ISP2401 + case ATOMISP_INPUT_FORMAT_RAW_16: + /* This is not specified by Arasan, so we use + * 17 for now. + */ + *fmt_type = MIPI_FORMAT_RAW16; + break; + case ATOMISP_INPUT_FORMAT_BINARY_8: + *fmt_type = MIPI_FORMAT_BINARY_8; + break; +#else + case ATOMISP_INPUT_FORMAT_USER_DEF1: + *fmt_type = MIPI_FORMAT_CUSTOM0; + break; + case ATOMISP_INPUT_FORMAT_USER_DEF2: + *fmt_type = MIPI_FORMAT_CUSTOM1; + break; + case ATOMISP_INPUT_FORMAT_USER_DEF3: + *fmt_type = MIPI_FORMAT_CUSTOM2; + break; + case ATOMISP_INPUT_FORMAT_USER_DEF4: + *fmt_type = MIPI_FORMAT_CUSTOM3; + break; + case ATOMISP_INPUT_FORMAT_USER_DEF5: + *fmt_type = MIPI_FORMAT_CUSTOM4; + break; + case ATOMISP_INPUT_FORMAT_USER_DEF6: + *fmt_type = MIPI_FORMAT_CUSTOM5; + break; + case ATOMISP_INPUT_FORMAT_USER_DEF7: + *fmt_type = MIPI_FORMAT_CUSTOM6; + break; + case ATOMISP_INPUT_FORMAT_USER_DEF8: + *fmt_type = MIPI_FORMAT_CUSTOM7; + break; +#endif + + case ATOMISP_INPUT_FORMAT_YUV420_16: + case ATOMISP_INPUT_FORMAT_YUV422_16: + default: + return -EINVAL; + } + return 0; +} + +#if defined(ISP2401) +static mipi_predictor_t sh_css_csi2_compression_type_2_mipi_predictor( + enum ia_css_csi2_compression_type type) +{ + mipi_predictor_t predictor = MIPI_PREDICTOR_NONE; + + switch (type) { + case IA_CSS_CSI2_COMPRESSION_TYPE_1: + predictor = MIPI_PREDICTOR_TYPE1 - 1; + break; + case IA_CSS_CSI2_COMPRESSION_TYPE_2: + predictor = MIPI_PREDICTOR_TYPE2 - 1; + break; + default: + break; + } + return predictor; +} + +int ia_css_isys_convert_compressed_format( + struct ia_css_csi2_compression *comp, + struct isp2401_input_system_cfg_s *cfg) +{ + int err = 0; + + assert(comp); + assert(cfg); + + if (comp->type != IA_CSS_CSI2_COMPRESSION_TYPE_NONE) { + /* compression register bit slicing + 4 bit for each user defined data type + 3 bit indicate compression scheme + 000 No compression + 001 10-6-10 + 010 10-7-10 + 011 10-8-10 + 100 12-6-12 + 101 12-6-12 + 100 12-7-12 + 110 12-8-12 + 1 bit indicate predictor + */ + if (comp->uncompressed_bits_per_pixel == UNCOMPRESSED_BITS_PER_PIXEL_10) { + switch (comp->compressed_bits_per_pixel) { + case COMPRESSED_BITS_PER_PIXEL_6: + cfg->csi_port_attr.comp_scheme = MIPI_COMPRESSOR_10_6_10; + break; + case COMPRESSED_BITS_PER_PIXEL_7: + cfg->csi_port_attr.comp_scheme = MIPI_COMPRESSOR_10_7_10; + break; + case COMPRESSED_BITS_PER_PIXEL_8: + cfg->csi_port_attr.comp_scheme = MIPI_COMPRESSOR_10_8_10; + break; + default: + err = -EINVAL; + } + } else if (comp->uncompressed_bits_per_pixel == + UNCOMPRESSED_BITS_PER_PIXEL_12) { + switch (comp->compressed_bits_per_pixel) { + case COMPRESSED_BITS_PER_PIXEL_6: + cfg->csi_port_attr.comp_scheme = MIPI_COMPRESSOR_12_6_12; + break; + case COMPRESSED_BITS_PER_PIXEL_7: + cfg->csi_port_attr.comp_scheme = MIPI_COMPRESSOR_12_7_12; + break; + case COMPRESSED_BITS_PER_PIXEL_8: + cfg->csi_port_attr.comp_scheme = MIPI_COMPRESSOR_12_8_12; + break; + default: + err = -EINVAL; + } + } else + err = -EINVAL; + cfg->csi_port_attr.comp_predictor = + sh_css_csi2_compression_type_2_mipi_predictor(comp->type); + cfg->csi_port_attr.comp_enable = true; + } else /* No compression */ + cfg->csi_port_attr.comp_enable = false; + return err; +} + +unsigned int ia_css_csi2_calculate_input_system_alignment( + enum atomisp_input_format fmt_type) +{ + unsigned int memory_alignment_in_bytes = HIVE_ISP_DDR_WORD_BYTES; + + switch (fmt_type) { + 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: + case ATOMISP_INPUT_FORMAT_RAW_14: + memory_alignment_in_bytes = 2 * ISP_VEC_NELEMS; + break; + case ATOMISP_INPUT_FORMAT_YUV420_8: + case ATOMISP_INPUT_FORMAT_YUV422_8: + 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: + /* Planar YUV formats need to have all planes aligned, this means + * double the alignment for the Y plane if the horizontal decimation is 2. */ + memory_alignment_in_bytes = 2 * HIVE_ISP_DDR_WORD_BYTES; + break; + case ATOMISP_INPUT_FORMAT_EMBEDDED: + default: + memory_alignment_in_bytes = HIVE_ISP_DDR_WORD_BYTES; + break; + } + return memory_alignment_in_bytes; +} + +#endif + +#if !defined(ISP2401) +static const mipi_lane_cfg_t MIPI_PORT_LANES[N_RX_MODE][N_MIPI_PORT_ID] = { + {MIPI_4LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, + {MIPI_3LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, + {MIPI_2LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, + {MIPI_1LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, + {MIPI_2LANE_CFG, MIPI_1LANE_CFG, MIPI_2LANE_CFG}, + {MIPI_3LANE_CFG, MIPI_1LANE_CFG, MIPI_1LANE_CFG}, + {MIPI_2LANE_CFG, MIPI_1LANE_CFG, MIPI_1LANE_CFG}, + {MIPI_1LANE_CFG, MIPI_1LANE_CFG, MIPI_1LANE_CFG} +}; + +void ia_css_isys_rx_configure(const rx_cfg_t *config, + const enum ia_css_input_mode input_mode) +{ + bool any_port_enabled = false; + enum mipi_port_id port; + + if ((!config) + || (config->mode >= N_RX_MODE) + || (config->port >= N_MIPI_PORT_ID)) { + assert(0); + return; + } + for (port = (enum mipi_port_id)0; port < N_MIPI_PORT_ID; port++) { + if (is_receiver_port_enabled(RX0_ID, port)) + any_port_enabled = true; + } + /* AM: Check whether this is a problem with multiple + * streams. MS: This is the case. */ + + port = config->port; + receiver_port_enable(RX0_ID, port, false); + + port = config->port; + + /* AM: Check whether this is a problem with multiple streams. */ + if (MIPI_PORT_LANES[config->mode][port] != MIPI_0LANE_CFG) { + receiver_port_reg_store(RX0_ID, port, + _HRT_CSS_RECEIVER_FUNC_PROG_REG_IDX, + config->timeout); + receiver_port_reg_store(RX0_ID, port, + _HRT_CSS_RECEIVER_2400_INIT_COUNT_REG_IDX, + config->initcount); + receiver_port_reg_store(RX0_ID, port, + _HRT_CSS_RECEIVER_2400_SYNC_COUNT_REG_IDX, + config->synccount); + receiver_port_reg_store(RX0_ID, port, + _HRT_CSS_RECEIVER_2400_RX_COUNT_REG_IDX, + config->rxcount); + + if (input_mode != IA_CSS_INPUT_MODE_BUFFERED_SENSOR) { + /* MW: A bit of a hack, straight wiring of the capture + * units,assuming they are linearly enumerated. */ + input_system_sub_system_reg_store(INPUT_SYSTEM0_ID, + GPREGS_UNIT0_ID, + HIVE_ISYS_GPREG_MULTICAST_A_IDX + + (unsigned int)port, + INPUT_SYSTEM_CSI_BACKEND); + /* MW: Like the integration test example we overwite, + * the GPREG_MUX register */ + input_system_sub_system_reg_store(INPUT_SYSTEM0_ID, + GPREGS_UNIT0_ID, + HIVE_ISYS_GPREG_MUX_IDX, + (input_system_multiplex_t)port); + } else { + /* + * AM: A bit of a hack, wiring the input system. + */ + input_system_sub_system_reg_store(INPUT_SYSTEM0_ID, + GPREGS_UNIT0_ID, + HIVE_ISYS_GPREG_MULTICAST_A_IDX + + (unsigned int)port, + INPUT_SYSTEM_INPUT_BUFFER); + input_system_sub_system_reg_store(INPUT_SYSTEM0_ID, + GPREGS_UNIT0_ID, + HIVE_ISYS_GPREG_MUX_IDX, + INPUT_SYSTEM_ACQUISITION_UNIT); + } + } + /* + * The 2ppc is shared for all ports, so we cannot + * disable->configure->enable individual ports + */ + /* AM: Check whether this is a problem with multiple streams. */ + /* MS: 2ppc should be a property per binary and should be + * enabled/disabled per binary. + * Currently it is implemented as a system wide setting due + * to effort and risks. */ + if (!any_port_enabled) { + receiver_reg_store(RX0_ID, + _HRT_CSS_RECEIVER_TWO_PIXEL_EN_REG_IDX, + config->is_two_ppc); + receiver_reg_store(RX0_ID, _HRT_CSS_RECEIVER_BE_TWO_PPC_REG_IDX, + config->is_two_ppc); + } + receiver_port_enable(RX0_ID, port, true); + /* TODO: JB: need to add the beneath used define to mizuchi */ + /* sh_css_sw_hive_isp_css_2400_system_20121224_0125\css + * \hrt\input_system_defs.h + * #define INPUT_SYSTEM_CSI_RECEIVER_SELECT_BACKENG 0X207 + */ + /* TODO: need better name for define + * input_system_reg_store(INPUT_SYSTEM0_ID, + * INPUT_SYSTEM_CSI_RECEIVER_SELECT_BACKENG, 1); + */ + input_system_reg_store(INPUT_SYSTEM0_ID, 0x207, 1); + + return; +} + +void ia_css_isys_rx_disable(void) +{ + enum mipi_port_id port; + + for (port = (enum mipi_port_id)0; port < N_MIPI_PORT_ID; port++) { + receiver_port_reg_store(RX0_ID, port, + _HRT_CSS_RECEIVER_DEVICE_READY_REG_IDX, + false); + } + return; +} +#endif /* if !defined(ISP2401) */ diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/virtual_isys.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/virtual_isys.c new file mode 100644 index 000000000..8fc7746f8 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/virtual_isys.c @@ -0,0 +1,869 @@ +// 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 <linux/string.h> /* for memcpy() */ + +#include "system_global.h" + +#ifdef ISP2401 + +#include "ia_css_isys.h" +#include "ia_css_debug.h" +#include "math_support.h" +#include "virtual_isys.h" +#include "isp.h" +#include "sh_css_defs.h" + +/************************************************* + * + * Forwarded Declaration + * + *************************************************/ + +static bool create_input_system_channel( + isp2401_input_system_cfg_t *cfg, + bool metadata, + input_system_channel_t *channel); + +static void destroy_input_system_channel( + input_system_channel_t *channel); + +static bool create_input_system_input_port( + isp2401_input_system_cfg_t *cfg, + input_system_input_port_t *input_port); + +static void destroy_input_system_input_port( + input_system_input_port_t *input_port); + +static bool calculate_input_system_channel_cfg( + input_system_channel_t *channel, + input_system_input_port_t *input_port, + isp2401_input_system_cfg_t *isys_cfg, + input_system_channel_cfg_t *channel_cfg, + bool metadata); + +static bool calculate_input_system_input_port_cfg( + input_system_channel_t *channel, + input_system_input_port_t *input_port, + isp2401_input_system_cfg_t *isys_cfg, + input_system_input_port_cfg_t *input_port_cfg); + +static bool acquire_sid( + stream2mmio_ID_t stream2mmio, + stream2mmio_sid_ID_t *sid); + +static void release_sid( + stream2mmio_ID_t stream2mmio, + stream2mmio_sid_ID_t *sid); + +static bool acquire_ib_buffer( + s32 bits_per_pixel, + s32 pixels_per_line, + s32 lines_per_frame, + s32 align_in_bytes, + bool online, + isp2401_ib_buffer_t *buf); + +static void release_ib_buffer( + isp2401_ib_buffer_t *buf); + +static bool acquire_dma_channel( + isys2401_dma_ID_t dma_id, + isys2401_dma_channel *channel); + +static void release_dma_channel( + isys2401_dma_ID_t dma_id, + isys2401_dma_channel *channel); + +static bool acquire_be_lut_entry( + csi_rx_backend_ID_t backend, + csi_mipi_packet_type_t packet_type, + csi_rx_backend_lut_entry_t *entry); + +static void release_be_lut_entry( + csi_rx_backend_ID_t backend, + csi_mipi_packet_type_t packet_type, + csi_rx_backend_lut_entry_t *entry); + +static bool calculate_tpg_cfg( + input_system_channel_t *channel, + input_system_input_port_t *input_port, + isp2401_input_system_cfg_t *isys_cfg, + pixelgen_tpg_cfg_t *cfg); + +static bool calculate_prbs_cfg( + input_system_channel_t *channel, + input_system_input_port_t *input_port, + isp2401_input_system_cfg_t *isys_cfg, + pixelgen_prbs_cfg_t *cfg); + +static bool calculate_fe_cfg( + const isp2401_input_system_cfg_t *isys_cfg, + csi_rx_frontend_cfg_t *cfg); + +static bool calculate_be_cfg( + const input_system_input_port_t *input_port, + const isp2401_input_system_cfg_t *isys_cfg, + bool metadata, + csi_rx_backend_cfg_t *cfg); + +static bool calculate_stream2mmio_cfg( + const isp2401_input_system_cfg_t *isys_cfg, + bool metadata, + stream2mmio_cfg_t *cfg); + +static bool calculate_ibuf_ctrl_cfg( + const input_system_channel_t *channel, + const input_system_input_port_t *input_port, + const isp2401_input_system_cfg_t *isys_cfg, + ibuf_ctrl_cfg_t *cfg); + +static bool calculate_isys2401_dma_cfg( + const input_system_channel_t *channel, + const isp2401_input_system_cfg_t *isys_cfg, + isys2401_dma_cfg_t *cfg); + +static bool calculate_isys2401_dma_port_cfg( + const isp2401_input_system_cfg_t *isys_cfg, + bool raw_packed, + bool metadata, + isys2401_dma_port_cfg_t *cfg); + +static csi_mipi_packet_type_t get_csi_mipi_packet_type( + int32_t data_type); + +static int32_t calculate_stride( + s32 bits_per_pixel, + s32 pixels_per_line, + bool raw_packed, + int32_t align_in_bytes); + +/* end of Forwarded Declaration */ + +/************************************************** + * + * Public Methods + * + **************************************************/ +ia_css_isys_error_t ia_css_isys_stream_create( + ia_css_isys_descr_t *isys_stream_descr, + ia_css_isys_stream_h isys_stream, + uint32_t isys_stream_id) +{ + ia_css_isys_error_t rc; + + if (!isys_stream_descr || !isys_stream || + isys_stream_id >= SH_CSS_MAX_ISYS_CHANNEL_NODES) + return false; + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, + "ia_css_isys_stream_create() enter:\n"); + + /*Reset isys_stream to 0*/ + memset(isys_stream, 0, sizeof(*isys_stream)); + isys_stream->enable_metadata = isys_stream_descr->metadata.enable; + isys_stream->id = isys_stream_id; + + isys_stream->linked_isys_stream_id = isys_stream_descr->linked_isys_stream_id; + rc = create_input_system_input_port(isys_stream_descr, + &isys_stream->input_port); + if (!rc) + return false; + + rc = create_input_system_channel(isys_stream_descr, false, + &isys_stream->channel); + if (!rc) { + destroy_input_system_input_port(&isys_stream->input_port); + return false; + } + + /* create metadata channel */ + if (isys_stream_descr->metadata.enable) { + rc = create_input_system_channel(isys_stream_descr, true, + &isys_stream->md_channel); + if (!rc) { + destroy_input_system_input_port(&isys_stream->input_port); + destroy_input_system_channel(&isys_stream->channel); + return false; + } + } + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, + "ia_css_isys_stream_create() leave:\n"); + + return true; +} + +void ia_css_isys_stream_destroy( + ia_css_isys_stream_h isys_stream) +{ + destroy_input_system_input_port(&isys_stream->input_port); + destroy_input_system_channel(&isys_stream->channel); + if (isys_stream->enable_metadata) { + /* Destroy metadata channel only if its allocated*/ + destroy_input_system_channel(&isys_stream->md_channel); + } +} + +ia_css_isys_error_t ia_css_isys_stream_calculate_cfg( + ia_css_isys_stream_h isys_stream, + ia_css_isys_descr_t *isys_stream_descr, + ia_css_isys_stream_cfg_t *isys_stream_cfg) +{ + ia_css_isys_error_t rc; + + if (!isys_stream_cfg || + !isys_stream_descr || + !isys_stream) + return false; + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, + "ia_css_isys_stream_calculate_cfg() enter:\n"); + + rc = calculate_input_system_channel_cfg( + &isys_stream->channel, + &isys_stream->input_port, + isys_stream_descr, + &isys_stream_cfg->channel_cfg, + false); + if (!rc) + return false; + + /* configure metadata channel */ + if (isys_stream_descr->metadata.enable) { + isys_stream_cfg->enable_metadata = true; + rc = calculate_input_system_channel_cfg( + &isys_stream->md_channel, + &isys_stream->input_port, + isys_stream_descr, + &isys_stream_cfg->md_channel_cfg, + true); + if (!rc) + return false; + } + + rc = calculate_input_system_input_port_cfg( + &isys_stream->channel, + &isys_stream->input_port, + isys_stream_descr, + &isys_stream_cfg->input_port_cfg); + if (!rc) + return false; + + isys_stream->valid = 1; + isys_stream_cfg->valid = 1; + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, + "ia_css_isys_stream_calculate_cfg() leave:\n"); + return rc; +} + +/* end of Public Methods */ + +/************************************************** + * + * Private Methods + * + **************************************************/ +static bool create_input_system_channel( + isp2401_input_system_cfg_t *cfg, + bool metadata, + input_system_channel_t *me) +{ + bool rc = true; + + me->dma_id = ISYS2401_DMA0_ID; + + switch (cfg->input_port_id) { + case INPUT_SYSTEM_CSI_PORT0_ID: + case INPUT_SYSTEM_PIXELGEN_PORT0_ID: + me->stream2mmio_id = STREAM2MMIO0_ID; + me->ibuf_ctrl_id = IBUF_CTRL0_ID; + break; + + case INPUT_SYSTEM_CSI_PORT1_ID: + case INPUT_SYSTEM_PIXELGEN_PORT1_ID: + me->stream2mmio_id = STREAM2MMIO1_ID; + me->ibuf_ctrl_id = IBUF_CTRL1_ID; + break; + + case INPUT_SYSTEM_CSI_PORT2_ID: + case INPUT_SYSTEM_PIXELGEN_PORT2_ID: + me->stream2mmio_id = STREAM2MMIO2_ID; + me->ibuf_ctrl_id = IBUF_CTRL2_ID; + break; + default: + rc = false; + break; + } + + if (!rc) + return false; + + if (!acquire_sid(me->stream2mmio_id, &me->stream2mmio_sid_id)) { + return false; + } + + if (!acquire_ib_buffer( + metadata ? cfg->metadata.bits_per_pixel : + cfg->input_port_resolution.bits_per_pixel, + metadata ? cfg->metadata.pixels_per_line : + cfg->input_port_resolution.pixels_per_line, + metadata ? cfg->metadata.lines_per_frame : + cfg->input_port_resolution.lines_per_frame, + metadata ? cfg->metadata.align_req_in_bytes : + cfg->input_port_resolution.align_req_in_bytes, + cfg->online, + &me->ib_buffer)) { + release_sid(me->stream2mmio_id, &me->stream2mmio_sid_id); + return false; + } + + if (!acquire_dma_channel(me->dma_id, &me->dma_channel)) { + release_sid(me->stream2mmio_id, &me->stream2mmio_sid_id); + release_ib_buffer(&me->ib_buffer); + return false; + } + + return true; +} + +static void destroy_input_system_channel( + input_system_channel_t *me) +{ + release_sid(me->stream2mmio_id, + &me->stream2mmio_sid_id); + + release_ib_buffer(&me->ib_buffer); + + release_dma_channel(me->dma_id, &me->dma_channel); +} + +static bool create_input_system_input_port( + isp2401_input_system_cfg_t *cfg, + input_system_input_port_t *me) +{ + csi_mipi_packet_type_t packet_type; + bool rc = true; + + switch (cfg->input_port_id) { + case INPUT_SYSTEM_CSI_PORT0_ID: + me->csi_rx.frontend_id = CSI_RX_FRONTEND0_ID; + me->csi_rx.backend_id = CSI_RX_BACKEND0_ID; + + packet_type = get_csi_mipi_packet_type(cfg->csi_port_attr.fmt_type); + me->csi_rx.packet_type = packet_type; + + rc = acquire_be_lut_entry( + me->csi_rx.backend_id, + packet_type, + &me->csi_rx.backend_lut_entry); + break; + case INPUT_SYSTEM_PIXELGEN_PORT0_ID: + me->pixelgen.pixelgen_id = PIXELGEN0_ID; + break; + case INPUT_SYSTEM_CSI_PORT1_ID: + me->csi_rx.frontend_id = CSI_RX_FRONTEND1_ID; + me->csi_rx.backend_id = CSI_RX_BACKEND1_ID; + + packet_type = get_csi_mipi_packet_type(cfg->csi_port_attr.fmt_type); + me->csi_rx.packet_type = packet_type; + + rc = acquire_be_lut_entry( + me->csi_rx.backend_id, + packet_type, + &me->csi_rx.backend_lut_entry); + break; + case INPUT_SYSTEM_PIXELGEN_PORT1_ID: + me->pixelgen.pixelgen_id = PIXELGEN1_ID; + + break; + case INPUT_SYSTEM_CSI_PORT2_ID: + me->csi_rx.frontend_id = CSI_RX_FRONTEND2_ID; + me->csi_rx.backend_id = CSI_RX_BACKEND2_ID; + + packet_type = get_csi_mipi_packet_type(cfg->csi_port_attr.fmt_type); + me->csi_rx.packet_type = packet_type; + + rc = acquire_be_lut_entry( + me->csi_rx.backend_id, + packet_type, + &me->csi_rx.backend_lut_entry); + break; + case INPUT_SYSTEM_PIXELGEN_PORT2_ID: + me->pixelgen.pixelgen_id = PIXELGEN2_ID; + break; + default: + rc = false; + break; + } + + me->source_type = cfg->mode; + + /* for metadata */ + me->metadata.packet_type = CSI_MIPI_PACKET_TYPE_UNDEFINED; + if (rc && cfg->metadata.enable) { + me->metadata.packet_type = get_csi_mipi_packet_type( + cfg->metadata.fmt_type); + rc = acquire_be_lut_entry( + me->csi_rx.backend_id, + me->metadata.packet_type, + &me->metadata.backend_lut_entry); + } + + return rc; +} + +static void destroy_input_system_input_port( + input_system_input_port_t *me) +{ + if (me->source_type == INPUT_SYSTEM_SOURCE_TYPE_SENSOR) { + release_be_lut_entry( + me->csi_rx.backend_id, + me->csi_rx.packet_type, + &me->csi_rx.backend_lut_entry); + } + + if (me->metadata.packet_type != CSI_MIPI_PACKET_TYPE_UNDEFINED) { + /*Free the backend lut allocated for metadata*/ + release_be_lut_entry( + me->csi_rx.backend_id, + me->metadata.packet_type, + &me->metadata.backend_lut_entry); + } +} + +static bool calculate_input_system_channel_cfg( + input_system_channel_t *channel, + input_system_input_port_t *input_port, + isp2401_input_system_cfg_t *isys_cfg, + input_system_channel_cfg_t *channel_cfg, + bool metadata) +{ + bool rc; + + rc = calculate_stream2mmio_cfg(isys_cfg, metadata, + &channel_cfg->stream2mmio_cfg); + if (!rc) + return false; + + rc = calculate_ibuf_ctrl_cfg( + channel, + input_port, + isys_cfg, + &channel_cfg->ibuf_ctrl_cfg); + if (!rc) + return false; + if (metadata) + channel_cfg->ibuf_ctrl_cfg.stores_per_frame = + isys_cfg->metadata.lines_per_frame; + + rc = calculate_isys2401_dma_cfg( + channel, + isys_cfg, + &channel_cfg->dma_cfg); + if (!rc) + return false; + + rc = calculate_isys2401_dma_port_cfg( + isys_cfg, + false, + metadata, + &channel_cfg->dma_src_port_cfg); + if (!rc) + return false; + + rc = calculate_isys2401_dma_port_cfg( + isys_cfg, + isys_cfg->raw_packed, + metadata, + &channel_cfg->dma_dest_port_cfg); + if (!rc) + return false; + + return true; +} + +static bool calculate_input_system_input_port_cfg( + input_system_channel_t *channel, + input_system_input_port_t *input_port, + isp2401_input_system_cfg_t *isys_cfg, + input_system_input_port_cfg_t *input_port_cfg) +{ + bool rc; + + switch (input_port->source_type) { + case INPUT_SYSTEM_SOURCE_TYPE_SENSOR: + rc = calculate_fe_cfg( + isys_cfg, + &input_port_cfg->csi_rx_cfg.frontend_cfg); + + rc &= calculate_be_cfg( + input_port, + isys_cfg, + false, + &input_port_cfg->csi_rx_cfg.backend_cfg); + + if (rc && isys_cfg->metadata.enable) + rc &= calculate_be_cfg(input_port, isys_cfg, true, + &input_port_cfg->csi_rx_cfg.md_backend_cfg); + break; + case INPUT_SYSTEM_SOURCE_TYPE_TPG: + rc = calculate_tpg_cfg( + channel, + input_port, + isys_cfg, + &input_port_cfg->pixelgen_cfg.tpg_cfg); + break; + case INPUT_SYSTEM_SOURCE_TYPE_PRBS: + rc = calculate_prbs_cfg( + channel, + input_port, + isys_cfg, + &input_port_cfg->pixelgen_cfg.prbs_cfg); + break; + default: + rc = false; + break; + } + + return rc; +} + +static bool acquire_sid( + stream2mmio_ID_t stream2mmio, + stream2mmio_sid_ID_t *sid) +{ + return ia_css_isys_stream2mmio_sid_rmgr_acquire(stream2mmio, sid); +} + +static void release_sid( + stream2mmio_ID_t stream2mmio, + stream2mmio_sid_ID_t *sid) +{ + ia_css_isys_stream2mmio_sid_rmgr_release(stream2mmio, sid); +} + +/* See also: ia_css_dma_configure_from_info() */ +static int32_t calculate_stride( + s32 bits_per_pixel, + s32 pixels_per_line, + bool raw_packed, + int32_t align_in_bytes) +{ + s32 bytes_per_line; + s32 pixels_per_word; + s32 words_per_line; + s32 pixels_per_line_padded; + + pixels_per_line_padded = CEIL_MUL(pixels_per_line, align_in_bytes); + + if (!raw_packed) + bits_per_pixel = CEIL_MUL(bits_per_pixel, 8); + + pixels_per_word = HIVE_ISP_DDR_WORD_BITS / bits_per_pixel; + words_per_line = ceil_div(pixels_per_line_padded, pixels_per_word); + bytes_per_line = HIVE_ISP_DDR_WORD_BYTES * words_per_line; + + return bytes_per_line; +} + +static bool acquire_ib_buffer( + s32 bits_per_pixel, + s32 pixels_per_line, + s32 lines_per_frame, + s32 align_in_bytes, + bool online, + isp2401_ib_buffer_t *buf) +{ + buf->stride = calculate_stride(bits_per_pixel, pixels_per_line, false, + align_in_bytes); + if (online) + buf->lines = 4; /* use double buffering for online usecases */ + else + buf->lines = 2; + + (void)(lines_per_frame); + return ia_css_isys_ibuf_rmgr_acquire(buf->stride * buf->lines, + &buf->start_addr); +} + +static void release_ib_buffer( + isp2401_ib_buffer_t *buf) +{ + ia_css_isys_ibuf_rmgr_release(&buf->start_addr); +} + +static bool acquire_dma_channel( + isys2401_dma_ID_t dma_id, + isys2401_dma_channel *channel) +{ + return ia_css_isys_dma_channel_rmgr_acquire(dma_id, channel); +} + +static void release_dma_channel( + isys2401_dma_ID_t dma_id, + isys2401_dma_channel *channel) +{ + ia_css_isys_dma_channel_rmgr_release(dma_id, channel); +} + +static bool acquire_be_lut_entry( + csi_rx_backend_ID_t backend, + csi_mipi_packet_type_t packet_type, + csi_rx_backend_lut_entry_t *entry) +{ + return ia_css_isys_csi_rx_lut_rmgr_acquire(backend, packet_type, entry); +} + +static void release_be_lut_entry( + csi_rx_backend_ID_t backend, + csi_mipi_packet_type_t packet_type, + csi_rx_backend_lut_entry_t *entry) +{ + ia_css_isys_csi_rx_lut_rmgr_release(backend, packet_type, entry); +} + +static bool calculate_tpg_cfg( + input_system_channel_t *channel, + input_system_input_port_t *input_port, + isp2401_input_system_cfg_t *isys_cfg, + pixelgen_tpg_cfg_t *cfg) +{ + memcpy(cfg, &isys_cfg->tpg_port_attr, sizeof(pixelgen_tpg_cfg_t)); + + return true; +} + +static bool calculate_prbs_cfg( + input_system_channel_t *channel, + input_system_input_port_t *input_port, + isp2401_input_system_cfg_t *isys_cfg, + pixelgen_prbs_cfg_t *cfg) +{ + memcpy(cfg, &isys_cfg->prbs_port_attr, sizeof(pixelgen_prbs_cfg_t)); + + return true; +} + +static bool calculate_fe_cfg( + const isp2401_input_system_cfg_t *isys_cfg, + csi_rx_frontend_cfg_t *cfg) +{ + cfg->active_lanes = isys_cfg->csi_port_attr.active_lanes; + return true; +} + +static bool calculate_be_cfg( + const input_system_input_port_t *input_port, + const isp2401_input_system_cfg_t *isys_cfg, + bool metadata, + csi_rx_backend_cfg_t *cfg) +{ + memcpy(&cfg->lut_entry, + metadata ? &input_port->metadata.backend_lut_entry : + &input_port->csi_rx.backend_lut_entry, + sizeof(csi_rx_backend_lut_entry_t)); + + cfg->csi_mipi_cfg.virtual_channel = isys_cfg->csi_port_attr.ch_id; + if (metadata) { + cfg->csi_mipi_packet_type = get_csi_mipi_packet_type( + isys_cfg->metadata.fmt_type); + cfg->csi_mipi_cfg.comp_enable = false; + cfg->csi_mipi_cfg.data_type = isys_cfg->metadata.fmt_type; + } else { + cfg->csi_mipi_packet_type = get_csi_mipi_packet_type( + isys_cfg->csi_port_attr.fmt_type); + cfg->csi_mipi_cfg.data_type = isys_cfg->csi_port_attr.fmt_type; + cfg->csi_mipi_cfg.comp_enable = isys_cfg->csi_port_attr.comp_enable; + cfg->csi_mipi_cfg.comp_scheme = isys_cfg->csi_port_attr.comp_scheme; + cfg->csi_mipi_cfg.comp_predictor = isys_cfg->csi_port_attr.comp_predictor; + cfg->csi_mipi_cfg.comp_bit_idx = cfg->csi_mipi_cfg.data_type - + MIPI_FORMAT_CUSTOM0; + } + + return true; +} + +static bool calculate_stream2mmio_cfg( + const isp2401_input_system_cfg_t *isys_cfg, + bool metadata, + stream2mmio_cfg_t *cfg +) +{ + cfg->bits_per_pixel = metadata ? isys_cfg->metadata.bits_per_pixel : + isys_cfg->input_port_resolution.bits_per_pixel; + + cfg->enable_blocking = + ((isys_cfg->mode == INPUT_SYSTEM_SOURCE_TYPE_TPG) || + (isys_cfg->mode == INPUT_SYSTEM_SOURCE_TYPE_PRBS)); + + return true; +} + +static bool calculate_ibuf_ctrl_cfg( + const input_system_channel_t *channel, + const input_system_input_port_t *input_port, + const isp2401_input_system_cfg_t *isys_cfg, + ibuf_ctrl_cfg_t *cfg) +{ + const s32 bits_per_byte = 8; + s32 bits_per_pixel; + s32 bytes_per_pixel; + s32 left_padding; + + (void)input_port; + + bits_per_pixel = isys_cfg->input_port_resolution.bits_per_pixel; + bytes_per_pixel = ceil_div(bits_per_pixel, bits_per_byte); + + left_padding = CEIL_MUL(isys_cfg->output_port_attr.left_padding, ISP_VEC_NELEMS) + * bytes_per_pixel; + + cfg->online = isys_cfg->online; + + cfg->dma_cfg.channel = channel->dma_channel; + cfg->dma_cfg.cmd = _DMA_V2_MOVE_A2B_NO_SYNC_CHK_COMMAND; + + cfg->dma_cfg.shift_returned_items = 0; + cfg->dma_cfg.elems_per_word_in_ibuf = 0; + cfg->dma_cfg.elems_per_word_in_dest = 0; + + cfg->ib_buffer.start_addr = channel->ib_buffer.start_addr; + cfg->ib_buffer.stride = channel->ib_buffer.stride; + cfg->ib_buffer.lines = channel->ib_buffer.lines; + + /* + #ifndef ISP2401 + * zhengjie.lu@intel.com: + #endif + * "dest_buf_cfg" should be part of the input system output + * port configuration. + * + * TODO: move "dest_buf_cfg" to the input system output + * port configuration. + */ + + /* input_buf addr only available in sched mode; + this buffer is allocated in isp, crun mode addr + can be passed by after ISP allocation */ + if (cfg->online) { + cfg->dest_buf_cfg.start_addr = ISP_INPUT_BUF_START_ADDR + left_padding; + cfg->dest_buf_cfg.stride = bytes_per_pixel + * isys_cfg->output_port_attr.max_isp_input_width; + cfg->dest_buf_cfg.lines = LINES_OF_ISP_INPUT_BUF; + } else if (isys_cfg->raw_packed) { + cfg->dest_buf_cfg.stride = calculate_stride(bits_per_pixel, + isys_cfg->input_port_resolution.pixels_per_line, + isys_cfg->raw_packed, + isys_cfg->input_port_resolution.align_req_in_bytes); + } else { + cfg->dest_buf_cfg.stride = channel->ib_buffer.stride; + } + + /* + #ifndef ISP2401 + * zhengjie.lu@intel.com: + #endif + * "items_per_store" is hard coded as "1", which is ONLY valid + * when the CSI-MIPI long packet is transferred. + * + * TODO: After the 1st stage of MERR+, make the proper solution to + * configure "items_per_store" so that it can also handle the CSI-MIPI + * short packet. + */ + cfg->items_per_store = 1; + + cfg->stores_per_frame = isys_cfg->input_port_resolution.lines_per_frame; + + cfg->stream2mmio_cfg.sync_cmd = _STREAM2MMIO_CMD_TOKEN_SYNC_FRAME; + + /* TODO: Define conditions as when to use store words vs store packets */ + cfg->stream2mmio_cfg.store_cmd = _STREAM2MMIO_CMD_TOKEN_STORE_PACKETS; + + return true; +} + +static bool calculate_isys2401_dma_cfg( + const input_system_channel_t *channel, + const isp2401_input_system_cfg_t *isys_cfg, + isys2401_dma_cfg_t *cfg) +{ + cfg->channel = channel->dma_channel; + + /* only online/sensor mode goto vmem + offline/buffered_sensor, tpg and prbs will go to ddr */ + if (isys_cfg->online) + cfg->connection = isys2401_dma_ibuf_to_vmem_connection; + else + cfg->connection = isys2401_dma_ibuf_to_ddr_connection; + + cfg->extension = isys2401_dma_zero_extension; + cfg->height = 1; + + return true; +} + +/* See also: ia_css_dma_configure_from_info() */ +static bool calculate_isys2401_dma_port_cfg( + const isp2401_input_system_cfg_t *isys_cfg, + bool raw_packed, + bool metadata, + isys2401_dma_port_cfg_t *cfg) +{ + s32 bits_per_pixel; + s32 pixels_per_line; + s32 align_req_in_bytes; + + /* TODO: Move metadata away from isys_cfg to application layer */ + if (metadata) { + bits_per_pixel = isys_cfg->metadata.bits_per_pixel; + pixels_per_line = isys_cfg->metadata.pixels_per_line; + align_req_in_bytes = isys_cfg->metadata.align_req_in_bytes; + } else { + bits_per_pixel = isys_cfg->input_port_resolution.bits_per_pixel; + pixels_per_line = isys_cfg->input_port_resolution.pixels_per_line; + align_req_in_bytes = isys_cfg->input_port_resolution.align_req_in_bytes; + } + + cfg->stride = calculate_stride(bits_per_pixel, pixels_per_line, raw_packed, + align_req_in_bytes); + + if (!raw_packed) + bits_per_pixel = CEIL_MUL(bits_per_pixel, 8); + + cfg->elements = HIVE_ISP_DDR_WORD_BITS / bits_per_pixel; + cfg->cropping = 0; + cfg->width = CEIL_DIV(cfg->stride, HIVE_ISP_DDR_WORD_BYTES); + + return true; +} + +static csi_mipi_packet_type_t get_csi_mipi_packet_type( + int32_t data_type) +{ + csi_mipi_packet_type_t packet_type; + + packet_type = CSI_MIPI_PACKET_TYPE_RESERVED; + + if (data_type >= 0 && data_type <= MIPI_FORMAT_SHORT8) + packet_type = CSI_MIPI_PACKET_TYPE_SHORT; + + if (data_type > MIPI_FORMAT_SHORT8 && data_type <= N_MIPI_FORMAT) + packet_type = CSI_MIPI_PACKET_TYPE_LONG; + + return packet_type; +} + +/* end of Private Methods */ +#endif diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/virtual_isys.h b/drivers/staging/media/atomisp/pci/runtime/isys/src/virtual_isys.h new file mode 100644 index 000000000..fbdbca0cf --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/virtual_isys.h @@ -0,0 +1,25 @@ +/* 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. + */ + +#ifndef __VIRTUAL_ISYS_H_INCLUDED__ +#define __VIRTUAL_ISYS_H_INCLUDED__ + +/* cmd for storing a number of packets indicated by reg _STREAM2MMIO_NUM_ITEMS*/ +#define _STREAM2MMIO_CMD_TOKEN_STORE_PACKETS 1 + +/* command for waiting for a frame start */ +#define _STREAM2MMIO_CMD_TOKEN_SYNC_FRAME 2 + +#endif /* __VIRTUAL_ISYS_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h b/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h new file mode 100644 index 000000000..de2c526a5 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h @@ -0,0 +1,286 @@ +/* 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. + */ + +#ifndef __IA_CSS_PIPELINE_H__ +#define __IA_CSS_PIPELINE_H__ + +#include "sh_css_internal.h" +#include "ia_css_pipe_public.h" +#include "ia_css_pipeline_common.h" + +#define IA_CSS_PIPELINE_NUM_MAX (20) + +/* Pipeline stage to be executed on SP/ISP */ +struct ia_css_pipeline_stage { + unsigned int stage_num; + struct ia_css_binary *binary; /* built-in binary */ + struct ia_css_binary_info *binary_info; + const struct ia_css_fw_info *firmware; /* acceleration binary */ + /* SP function for SP stage */ + enum ia_css_pipeline_stage_sp_func sp_func; + unsigned int max_input_width; /* For SP raw copy */ + struct sh_css_binary_args args; + int mode; + bool out_frame_allocated[IA_CSS_BINARY_MAX_OUTPUT_PORTS]; + bool vf_frame_allocated; + struct ia_css_pipeline_stage *next; + bool enable_zoom; +}; + +/* Pipeline of n stages to be executed on SP/ISP per stage */ +struct ia_css_pipeline { + enum ia_css_pipe_id pipe_id; + u8 pipe_num; + bool stop_requested; + struct ia_css_pipeline_stage *stages; + struct ia_css_pipeline_stage *current_stage; + unsigned int num_stages; + struct ia_css_frame in_frame; + struct ia_css_frame out_frame[IA_CSS_PIPE_MAX_OUTPUT_STAGE]; + struct ia_css_frame vf_frame[IA_CSS_PIPE_MAX_OUTPUT_STAGE]; + unsigned int dvs_frame_delay; + unsigned int inout_port_config; + int num_execs; + bool acquire_isp_each_stage; + u32 pipe_qos_config; +}; + +#define DEFAULT_PIPELINE { \ + .pipe_id = IA_CSS_PIPE_ID_PREVIEW, \ + .in_frame = DEFAULT_FRAME, \ + .out_frame = {DEFAULT_FRAME}, \ + .vf_frame = {DEFAULT_FRAME}, \ + .dvs_frame_delay = IA_CSS_FRAME_DELAY_1, \ + .num_execs = -1, \ + .acquire_isp_each_stage = true, \ + .pipe_qos_config = QOS_INVALID \ +} + +/* Stage descriptor used to create a new stage in the pipeline */ +struct ia_css_pipeline_stage_desc { + struct ia_css_binary *binary; + const struct ia_css_fw_info *firmware; + enum ia_css_pipeline_stage_sp_func sp_func; + unsigned int max_input_width; + unsigned int mode; + struct ia_css_frame *in_frame; + struct ia_css_frame *out_frame[IA_CSS_BINARY_MAX_OUTPUT_PORTS]; + struct ia_css_frame *vf_frame; +}; + +/* @brief initialize the pipeline module + * + * @return None + * + * Initializes the pipeline module. This API has to be called + * before any operation on the pipeline module is done + */ +void ia_css_pipeline_init(void); + +/* @brief initialize the pipeline structure with default values + * + * @param[out] pipeline structure to be initialized with defaults + * @param[in] pipe_id + * @param[in] pipe_num Number that uniquely identifies a pipeline. + * @return 0 or error code upon error. + * + * Initializes the pipeline structure with a set of default values. + * This API is expected to be used when a pipeline structure is allocated + * externally and needs sane defaults + */ +int ia_css_pipeline_create( + struct ia_css_pipeline *pipeline, + enum ia_css_pipe_id pipe_id, + unsigned int pipe_num, + unsigned int dvs_frame_delay); + +/* @brief destroy a pipeline + * + * @param[in] pipeline + * @return None + * + */ +void ia_css_pipeline_destroy(struct ia_css_pipeline *pipeline); + +/* @brief Starts a pipeline + * + * @param[in] pipe_id + * @param[in] pipeline + * @return None + * + */ +void ia_css_pipeline_start(enum ia_css_pipe_id pipe_id, + struct ia_css_pipeline *pipeline); + +/* @brief Request to stop a pipeline + * + * @param[in] pipeline + * @return 0 or error code upon error. + * + */ +int ia_css_pipeline_request_stop(struct ia_css_pipeline *pipeline); + +/* @brief Check whether pipeline has stopped + * + * @param[in] pipeline + * @return true if the pipeline has stopped + * + */ +bool ia_css_pipeline_has_stopped(struct ia_css_pipeline *pipe); + +/* @brief clean all the stages pipeline and make it as new + * + * @param[in] pipeline + * @return None + * + */ +void ia_css_pipeline_clean(struct ia_css_pipeline *pipeline); + +/* @brief Add a stage to pipeline. + * + * @param pipeline Pointer to the pipeline to be added to. + * @param[in] stage_desc The description of the stage + * @param[out] stage The successor of the stage. + * @return 0 or error code upon error. + * + * Add a new stage to a non-NULL pipeline. + * The stage consists of an ISP binary or firmware and input and output + * arguments. +*/ +int ia_css_pipeline_create_and_add_stage( + struct ia_css_pipeline *pipeline, + struct ia_css_pipeline_stage_desc *stage_desc, + struct ia_css_pipeline_stage **stage); + +/* @brief Finalize the stages in a pipeline + * + * @param pipeline Pointer to the pipeline to be added to. + * @return None + * + * This API is expected to be called after adding all stages +*/ +void ia_css_pipeline_finalize_stages(struct ia_css_pipeline *pipeline, + bool continuous); + +/* @brief gets a stage from the pipeline + * + * @param[in] pipeline + * @return 0 or error code upon error. + * + */ +int ia_css_pipeline_get_stage(struct ia_css_pipeline *pipeline, + int mode, + struct ia_css_pipeline_stage **stage); + +/* @brief Gets a pipeline stage corresponding Firmware handle from the pipeline + * + * @param[in] pipeline + * @param[in] fw_handle + * @param[out] stage Pointer to Stage + * + * @return 0 or error code upon error. + * + */ +int ia_css_pipeline_get_stage_from_fw(struct ia_css_pipeline + *pipeline, + u32 fw_handle, + struct ia_css_pipeline_stage **stage); + +/* @brief Gets the Firmware handle corresponding the stage num from the pipeline + * + * @param[in] pipeline + * @param[in] stage_num + * @param[out] fw_handle + * + * @return 0 or error code upon error. + * + */ +int ia_css_pipeline_get_fw_from_stage(struct ia_css_pipeline + *pipeline, + u32 stage_num, + uint32_t *fw_handle); + +/* @brief gets the output stage from the pipeline + * + * @param[in] pipeline + * @return 0 or error code upon error. + * + */ +int ia_css_pipeline_get_output_stage( + struct ia_css_pipeline *pipeline, + int mode, + struct ia_css_pipeline_stage **stage); + +/* @brief Checks whether the pipeline uses params + * + * @param[in] pipeline + * @return true if the pipeline uses params + * + */ +bool ia_css_pipeline_uses_params(struct ia_css_pipeline *pipeline); + +/** + * @brief get the SP thread ID. + * + * @param[in] key The query key, typical use is pipe_num. + * @param[out] val The query value. + * + * @return + * true, if the query succeeds; + * false, if the query fails. + */ +bool ia_css_pipeline_get_sp_thread_id(unsigned int key, unsigned int *val); + +#if defined(ISP2401) +/** + * @brief Get the pipeline io status + * + * @param[in] None + * @return + * Pointer to pipe_io_status + */ +struct sh_css_sp_pipeline_io_status *ia_css_pipeline_get_pipe_io_status(void); +#endif + +/** + * @brief Map an SP thread to this pipeline + * + * @param[in] pipe_num + * @param[in] map true for mapping and false for unmapping sp threads. + * + */ +void ia_css_pipeline_map(unsigned int pipe_num, bool map); + +/** + * @brief Checks whether the pipeline is mapped to SP threads + * + * @param[in] Query key, typical use is pipe_num + * + * return + * true, pipeline is mapped to SP threads + * false, pipeline is not mapped to SP threads + */ +bool ia_css_pipeline_is_mapped(unsigned int key); + +/** + * @brief Print pipeline thread mapping + * + * @param[in] none + * + * return none + */ +void ia_css_pipeline_dump_thread_map_info(void); + +#endif /*__IA_CSS_PIPELINE_H__*/ diff --git a/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline_common.h b/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline_common.h new file mode 100644 index 000000000..cc44f03c3 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline_common.h @@ -0,0 +1,28 @@ +/* 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. + */ + +#ifndef __IA_CSS_PIPELINE_COMMON_H__ +#define __IA_CSS_PIPELINE_COMMON_H__ + +enum ia_css_pipeline_stage_sp_func { + IA_CSS_PIPELINE_RAW_COPY = 0, + IA_CSS_PIPELINE_BIN_COPY = 1, + IA_CSS_PIPELINE_ISYS_COPY = 2, + IA_CSS_PIPELINE_NO_FUNC = 3, +}; + +#define IA_CSS_PIPELINE_NUM_STAGE_FUNCS 3 + +#endif /*__IA_CSS_PIPELINE_COMMON_H__*/ diff --git a/drivers/staging/media/atomisp/pci/runtime/pipeline/src/pipeline.c b/drivers/staging/media/atomisp/pci/runtime/pipeline/src/pipeline.c new file mode 100644 index 000000000..dfc50247e --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/pipeline/src/pipeline.c @@ -0,0 +1,791 @@ +// 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 "hmm.h" + +#include "ia_css_debug.h" +#include "sw_event_global.h" /* encode_sw_event */ +#include "sp.h" /* cnd_sp_irq_enable() */ +#include "assert_support.h" +#include "sh_css_sp.h" +#include "ia_css_pipeline.h" +#include "ia_css_isp_param.h" +#include "ia_css_bufq.h" + +#define PIPELINE_NUM_UNMAPPED (~0U) +#define PIPELINE_SP_THREAD_EMPTY_TOKEN (0x0) +#define PIPELINE_SP_THREAD_RESERVED_TOKEN (0x1) + +/******************************************************* +*** Static variables +********************************************************/ +static unsigned int pipeline_num_to_sp_thread_map[IA_CSS_PIPELINE_NUM_MAX]; +static unsigned int pipeline_sp_thread_list[SH_CSS_MAX_SP_THREADS]; + +/******************************************************* +*** Static functions +********************************************************/ +static void pipeline_init_sp_thread_map(void); +static void pipeline_map_num_to_sp_thread(unsigned int pipe_num); +static void pipeline_unmap_num_to_sp_thread(unsigned int pipe_num); +static void pipeline_init_defaults( + struct ia_css_pipeline *pipeline, + enum ia_css_pipe_id pipe_id, + unsigned int pipe_num, + unsigned int dvs_frame_delay); + +static void pipeline_stage_destroy(struct ia_css_pipeline_stage *stage); +static int pipeline_stage_create( + struct ia_css_pipeline_stage_desc *stage_desc, + struct ia_css_pipeline_stage **new_stage); +static void ia_css_pipeline_set_zoom_stage(struct ia_css_pipeline *pipeline); +static void ia_css_pipeline_configure_inout_port(struct ia_css_pipeline *me, + bool continuous); + +/******************************************************* +*** Public functions +********************************************************/ +void ia_css_pipeline_init(void) +{ + pipeline_init_sp_thread_map(); +} + +int ia_css_pipeline_create( + struct ia_css_pipeline *pipeline, + enum ia_css_pipe_id pipe_id, + unsigned int pipe_num, + unsigned int dvs_frame_delay) +{ + assert(pipeline); + IA_CSS_ENTER_PRIVATE("pipeline = %p, pipe_id = %d, pipe_num = %d, dvs_frame_delay = %d", + pipeline, pipe_id, pipe_num, dvs_frame_delay); + if (!pipeline) { + IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); + return -EINVAL; + } + + pipeline_init_defaults(pipeline, pipe_id, pipe_num, dvs_frame_delay); + + IA_CSS_LEAVE_ERR_PRIVATE(0); + return 0; +} + +void ia_css_pipeline_map(unsigned int pipe_num, bool map) +{ + assert(pipe_num < IA_CSS_PIPELINE_NUM_MAX); + IA_CSS_ENTER_PRIVATE("pipe_num = %d, map = %d", pipe_num, map); + + if (pipe_num >= IA_CSS_PIPELINE_NUM_MAX) { + IA_CSS_ERROR("Invalid pipe number"); + IA_CSS_LEAVE_PRIVATE("void"); + return; + } + if (map) + pipeline_map_num_to_sp_thread(pipe_num); + else + pipeline_unmap_num_to_sp_thread(pipe_num); + IA_CSS_LEAVE_PRIVATE("void"); +} + +/* @brief destroy a pipeline + * + * @param[in] pipeline + * @return None + * + */ +void ia_css_pipeline_destroy(struct ia_css_pipeline *pipeline) +{ + assert(pipeline); + IA_CSS_ENTER_PRIVATE("pipeline = %p", pipeline); + + if (!pipeline) { + IA_CSS_ERROR("NULL input parameter"); + IA_CSS_LEAVE_PRIVATE("void"); + return; + } + + IA_CSS_LOG("pipe_num = %d", pipeline->pipe_num); + + /* Free the pipeline number */ + ia_css_pipeline_clean(pipeline); + + IA_CSS_LEAVE_PRIVATE("void"); +} + +/* Run a pipeline and wait till it completes. */ +void ia_css_pipeline_start(enum ia_css_pipe_id pipe_id, + struct ia_css_pipeline *pipeline) +{ + u8 pipe_num = 0; + unsigned int thread_id; + + assert(pipeline); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_pipeline_start() enter: pipe_id=%d, pipeline=%p\n", + pipe_id, pipeline); + pipeline->pipe_id = pipe_id; + sh_css_sp_init_pipeline(pipeline, pipe_id, pipe_num, + false, false, false, true, SH_CSS_BDS_FACTOR_1_00, + SH_CSS_PIPE_CONFIG_OVRD_NO_OVRD, + IA_CSS_INPUT_MODE_MEMORY, NULL, NULL, + (enum mipi_port_id)0); + + ia_css_pipeline_get_sp_thread_id(pipe_num, &thread_id); + if (!sh_css_sp_is_running()) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_pipeline_start() error,leaving\n"); + /* queues are invalid*/ + return; + } + ia_css_bufq_enqueue_psys_event(IA_CSS_PSYS_SW_EVENT_START_STREAM, + (uint8_t)thread_id, + 0, + 0); + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_pipeline_start() leave: return_void\n"); +} + +/* + * @brief Query the SP thread ID. + * Refer to "sh_css_internal.h" for details. + */ +bool ia_css_pipeline_get_sp_thread_id(unsigned int key, unsigned int *val) +{ + IA_CSS_ENTER("key=%d, val=%p", key, val); + + if ((!val) || (key >= IA_CSS_PIPELINE_NUM_MAX) || (key >= IA_CSS_PIPE_ID_NUM)) { + IA_CSS_LEAVE("return value = false"); + return false; + } + + *val = pipeline_num_to_sp_thread_map[key]; + + if (*val == (unsigned int)PIPELINE_NUM_UNMAPPED) { + IA_CSS_LOG("unmapped pipeline number"); + IA_CSS_LEAVE("return value = false"); + return false; + } + IA_CSS_LEAVE("return value = true"); + return true; +} + +void ia_css_pipeline_dump_thread_map_info(void) +{ + unsigned int i; + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "pipeline_num_to_sp_thread_map:\n"); + for (i = 0; i < IA_CSS_PIPELINE_NUM_MAX; i++) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "pipe_num: %u, tid: 0x%x\n", i, pipeline_num_to_sp_thread_map[i]); + } +} + +int ia_css_pipeline_request_stop(struct ia_css_pipeline *pipeline) +{ + int err = 0; + unsigned int thread_id; + + assert(pipeline); + + if (!pipeline) + return -EINVAL; + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_pipeline_request_stop() enter: pipeline=%p\n", + pipeline); + pipeline->stop_requested = true; + + /* Send stop event to the sp*/ + /* This needs improvement, stop on all the pipes available + * in the stream*/ + ia_css_pipeline_get_sp_thread_id(pipeline->pipe_num, &thread_id); + if (!sh_css_sp_is_running()) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_pipeline_request_stop() leaving\n"); + /* queues are invalid */ + return -EBUSY; + } + ia_css_bufq_enqueue_psys_event(IA_CSS_PSYS_SW_EVENT_STOP_STREAM, + (uint8_t)thread_id, + 0, + 0); + sh_css_sp_uninit_pipeline(pipeline->pipe_num); + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_pipeline_request_stop() leave: return_err=%d\n", + err); + return err; +} + +void ia_css_pipeline_clean(struct ia_css_pipeline *pipeline) +{ + struct ia_css_pipeline_stage *s; + + assert(pipeline); + IA_CSS_ENTER_PRIVATE("pipeline = %p", pipeline); + + if (!pipeline) { + IA_CSS_ERROR("NULL input parameter"); + IA_CSS_LEAVE_PRIVATE("void"); + return; + } + s = pipeline->stages; + + while (s) { + struct ia_css_pipeline_stage *next = s->next; + + pipeline_stage_destroy(s); + s = next; + } + pipeline_init_defaults(pipeline, pipeline->pipe_id, pipeline->pipe_num, + pipeline->dvs_frame_delay); + + IA_CSS_LEAVE_PRIVATE("void"); +} + +/* @brief Add a stage to pipeline. + * + * @param pipeline Pointer to the pipeline to be added to. + * @param[in] stage_desc The description of the stage + * @param[out] stage The successor of the stage. + * @return 0 or error code upon error. + * + * Add a new stage to a non-NULL pipeline. + * The stage consists of an ISP binary or firmware and input and + * output arguments. +*/ +int ia_css_pipeline_create_and_add_stage( + struct ia_css_pipeline *pipeline, + struct ia_css_pipeline_stage_desc *stage_desc, + struct ia_css_pipeline_stage **stage) +{ + struct ia_css_pipeline_stage *last, *new_stage = NULL; + int err; + + /* other arguments can be NULL */ + assert(pipeline); + assert(stage_desc); + last = pipeline->stages; + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_pipeline_create_and_add_stage() enter:\n"); + if (!stage_desc->binary && !stage_desc->firmware + && (stage_desc->sp_func == IA_CSS_PIPELINE_NO_FUNC)) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_pipeline_create_and_add_stage() done: Invalid args\n"); + + return -EINVAL; + } + + /* Find the last stage */ + while (last && last->next) + last = last->next; + + /* if in_frame is not set, we use the out_frame from the previous + * stage, if no previous stage, it's an error. + */ + if ((stage_desc->sp_func == IA_CSS_PIPELINE_NO_FUNC) + && (!stage_desc->in_frame) + && (!stage_desc->firmware) + && (!stage_desc->binary->online)) { + /* Do this only for ISP stages*/ + if (last && last->args.out_frame[0]) + stage_desc->in_frame = last->args.out_frame[0]; + + if (!stage_desc->in_frame) + return -EINVAL; + } + + /* Create the new stage */ + err = pipeline_stage_create(stage_desc, &new_stage); + if (err) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_pipeline_create_and_add_stage() done: stage_create_failed\n"); + return err; + } + + if (last) + last->next = new_stage; + else + pipeline->stages = new_stage; + + /* Output the new stage */ + if (stage) + *stage = new_stage; + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_pipeline_create_and_add_stage() done:\n"); + return 0; +} + +void ia_css_pipeline_finalize_stages(struct ia_css_pipeline *pipeline, + bool continuous) +{ + unsigned int i = 0; + struct ia_css_pipeline_stage *stage; + + assert(pipeline); + for (stage = pipeline->stages; stage; stage = stage->next) { + stage->stage_num = i; + i++; + } + pipeline->num_stages = i; + + ia_css_pipeline_set_zoom_stage(pipeline); + ia_css_pipeline_configure_inout_port(pipeline, continuous); +} + +int ia_css_pipeline_get_stage(struct ia_css_pipeline *pipeline, + int mode, + struct ia_css_pipeline_stage **stage) +{ + struct ia_css_pipeline_stage *s; + + assert(pipeline); + assert(stage); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_pipeline_get_stage() enter:\n"); + for (s = pipeline->stages; s; s = s->next) { + if (s->mode == mode) { + *stage = s; + return 0; + } + } + return -EINVAL; +} + +int ia_css_pipeline_get_stage_from_fw(struct ia_css_pipeline + *pipeline, + u32 fw_handle, + struct ia_css_pipeline_stage **stage) +{ + struct ia_css_pipeline_stage *s; + + assert(pipeline); + assert(stage); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "%s()\n", __func__); + for (s = pipeline->stages; s; s = s->next) { + if ((s->firmware) && (s->firmware->handle == fw_handle)) { + *stage = s; + return 0; + } + } + return -EINVAL; +} + +int ia_css_pipeline_get_fw_from_stage(struct ia_css_pipeline + *pipeline, + u32 stage_num, + uint32_t *fw_handle) +{ + struct ia_css_pipeline_stage *s; + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "%s()\n", __func__); + if ((!pipeline) || (!fw_handle)) + return -EINVAL; + + for (s = pipeline->stages; s; s = s->next) { + if ((s->stage_num == stage_num) && (s->firmware)) { + *fw_handle = s->firmware->handle; + return 0; + } + } + return -EINVAL; +} + +int ia_css_pipeline_get_output_stage( + struct ia_css_pipeline *pipeline, + int mode, + struct ia_css_pipeline_stage **stage) +{ + struct ia_css_pipeline_stage *s; + + assert(pipeline); + assert(stage); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_pipeline_get_output_stage() enter:\n"); + + *stage = NULL; + /* First find acceleration firmware at end of pipe */ + for (s = pipeline->stages; s; s = s->next) { + if (s->firmware && s->mode == mode && + s->firmware->info.isp.sp.enable.output) + *stage = s; + } + if (*stage) + return 0; + /* If no firmware, find binary in pipe */ + return ia_css_pipeline_get_stage(pipeline, mode, stage); +} + +bool ia_css_pipeline_has_stopped(struct ia_css_pipeline *pipeline) +{ + /* Android compilation files if made an local variable + stack size on android is limited to 2k and this structure + is around 2.5K, in place of static malloc can be done but + if this call is made too often it will lead to fragment memory + versus a fixed allocation */ + static struct sh_css_sp_group sp_group; + unsigned int thread_id; + const struct ia_css_fw_info *fw; + unsigned int HIVE_ADDR_sp_group; + + fw = &sh_css_sp_fw; + HIVE_ADDR_sp_group = fw->info.sp.group; + + ia_css_pipeline_get_sp_thread_id(pipeline->pipe_num, &thread_id); + sp_dmem_load(SP0_ID, + (unsigned int)sp_address_of(sp_group), + &sp_group, sizeof(struct sh_css_sp_group)); + return sp_group.pipe[thread_id].num_stages == 0; +} + +#if defined(ISP2401) +struct sh_css_sp_pipeline_io_status *ia_css_pipeline_get_pipe_io_status(void) +{ + return(&sh_css_sp_group.pipe_io_status); +} +#endif + +bool ia_css_pipeline_is_mapped(unsigned int key) +{ + bool ret = false; + + IA_CSS_ENTER_PRIVATE("key = %d", key); + + if ((key >= IA_CSS_PIPELINE_NUM_MAX) || (key >= IA_CSS_PIPE_ID_NUM)) { + IA_CSS_ERROR("Invalid key!!"); + IA_CSS_LEAVE_PRIVATE("return = %d", false); + return false; + } + + ret = (bool)(pipeline_num_to_sp_thread_map[key] != (unsigned int) + PIPELINE_NUM_UNMAPPED); + + IA_CSS_LEAVE_PRIVATE("return = %d", ret); + return ret; +} + +/******************************************************* +*** Static functions +********************************************************/ + +/* Pipeline: + * To organize the several different binaries for each type of mode, + * we use a pipeline. A pipeline contains a number of stages, each with + * their own binary and frame pointers. + * When stages are added to a pipeline, output frames that are not passed + * from outside are automatically allocated. + * When input frames are not passed from outside, each stage will use the + * output frame of the previous stage as input (the full resolution output, + * not the viewfinder output). + * Pipelines must be cleaned and re-created when settings of the binaries + * change. + */ +static void pipeline_stage_destroy(struct ia_css_pipeline_stage *stage) +{ + unsigned int i; + + for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) { + if (stage->out_frame_allocated[i]) { + ia_css_frame_free(stage->args.out_frame[i]); + stage->args.out_frame[i] = NULL; + } + } + if (stage->vf_frame_allocated) { + ia_css_frame_free(stage->args.out_vf_frame); + stage->args.out_vf_frame = NULL; + } + kvfree(stage); +} + +static void pipeline_init_sp_thread_map(void) +{ + unsigned int i; + + for (i = 1; i < SH_CSS_MAX_SP_THREADS; i++) + pipeline_sp_thread_list[i] = PIPELINE_SP_THREAD_EMPTY_TOKEN; + + for (i = 0; i < IA_CSS_PIPELINE_NUM_MAX; i++) + pipeline_num_to_sp_thread_map[i] = PIPELINE_NUM_UNMAPPED; +} + +static void pipeline_map_num_to_sp_thread(unsigned int pipe_num) +{ + unsigned int i; + bool found_sp_thread = false; + + /* pipe is not mapped to any thread */ + assert(pipeline_num_to_sp_thread_map[pipe_num] + == (unsigned int)PIPELINE_NUM_UNMAPPED); + + for (i = 0; i < SH_CSS_MAX_SP_THREADS; i++) { + if (pipeline_sp_thread_list[i] == + PIPELINE_SP_THREAD_EMPTY_TOKEN) { + pipeline_sp_thread_list[i] = + PIPELINE_SP_THREAD_RESERVED_TOKEN; + pipeline_num_to_sp_thread_map[pipe_num] = i; + found_sp_thread = true; + break; + } + } + + /* Make sure a mapping is found */ + /* I could do: + assert(i < SH_CSS_MAX_SP_THREADS); + + But the below is more descriptive. + */ + assert(found_sp_thread); +} + +static void pipeline_unmap_num_to_sp_thread(unsigned int pipe_num) +{ + unsigned int thread_id; + + assert(pipeline_num_to_sp_thread_map[pipe_num] + != (unsigned int)PIPELINE_NUM_UNMAPPED); + + thread_id = pipeline_num_to_sp_thread_map[pipe_num]; + pipeline_num_to_sp_thread_map[pipe_num] = PIPELINE_NUM_UNMAPPED; + pipeline_sp_thread_list[thread_id] = PIPELINE_SP_THREAD_EMPTY_TOKEN; +} + +static int pipeline_stage_create( + struct ia_css_pipeline_stage_desc *stage_desc, + struct ia_css_pipeline_stage **new_stage) +{ + int err = 0; + struct ia_css_pipeline_stage *stage = NULL; + struct ia_css_binary *binary; + struct ia_css_frame *vf_frame; + struct ia_css_frame *out_frame[IA_CSS_BINARY_MAX_OUTPUT_PORTS]; + const struct ia_css_fw_info *firmware; + unsigned int i; + + /* Verify input parameters*/ + if (!(stage_desc->in_frame) && !(stage_desc->firmware) + && (stage_desc->binary) && !(stage_desc->binary->online)) { + err = -EINVAL; + goto ERR; + } + + binary = stage_desc->binary; + firmware = stage_desc->firmware; + vf_frame = stage_desc->vf_frame; + for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) { + out_frame[i] = stage_desc->out_frame[i]; + } + + stage = kvzalloc(sizeof(*stage), GFP_KERNEL); + if (!stage) { + err = -ENOMEM; + goto ERR; + } + + if (firmware) { + stage->binary = NULL; + stage->binary_info = + (struct ia_css_binary_info *)&firmware->info.isp; + } else { + stage->binary = binary; + if (binary) + stage->binary_info = + (struct ia_css_binary_info *)binary->info; + else + stage->binary_info = NULL; + } + + stage->firmware = firmware; + stage->sp_func = stage_desc->sp_func; + stage->max_input_width = stage_desc->max_input_width; + stage->mode = stage_desc->mode; + for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) + stage->out_frame_allocated[i] = false; + stage->vf_frame_allocated = false; + stage->next = NULL; + sh_css_binary_args_reset(&stage->args); + + for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) { + if (!(out_frame[i]) && (binary) + && (binary->out_frame_info[i].res.width)) { + err = ia_css_frame_allocate_from_info(&out_frame[i], + &binary->out_frame_info[i]); + if (err) + goto ERR; + stage->out_frame_allocated[i] = true; + } + } + /* VF frame is not needed in case of need_pp + However, the capture binary needs a vf frame to write to. + */ + if (!vf_frame) { + if ((binary && binary->vf_frame_info.res.width) || + (firmware && firmware->info.isp.sp.enable.vf_veceven) + ) { + err = ia_css_frame_allocate_from_info(&vf_frame, + &binary->vf_frame_info); + if (err) + goto ERR; + stage->vf_frame_allocated = true; + } + } else if (vf_frame && binary && binary->vf_frame_info.res.width + && !firmware) { + /* only mark as allocated if buffer pointer available */ + if (vf_frame->data != mmgr_NULL) + stage->vf_frame_allocated = true; + } + + stage->args.in_frame = stage_desc->in_frame; + for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) + stage->args.out_frame[i] = out_frame[i]; + stage->args.out_vf_frame = vf_frame; + *new_stage = stage; + return err; +ERR: + if (stage) + pipeline_stage_destroy(stage); + return err; +} + +static const struct ia_css_frame ia_css_default_frame = DEFAULT_FRAME; + +static void pipeline_init_defaults( + struct ia_css_pipeline *pipeline, + enum ia_css_pipe_id pipe_id, + unsigned int pipe_num, + unsigned int dvs_frame_delay) +{ + unsigned int i; + + pipeline->pipe_id = pipe_id; + pipeline->stages = NULL; + pipeline->stop_requested = false; + pipeline->current_stage = NULL; + + memcpy(&pipeline->in_frame, &ia_css_default_frame, + sizeof(ia_css_default_frame)); + + for (i = 0; i < IA_CSS_PIPE_MAX_OUTPUT_STAGE; i++) { + memcpy(&pipeline->out_frame[i], &ia_css_default_frame, + sizeof(ia_css_default_frame)); + memcpy(&pipeline->vf_frame[i], &ia_css_default_frame, + sizeof(ia_css_default_frame)); + } + pipeline->num_execs = -1; + pipeline->acquire_isp_each_stage = true; + pipeline->pipe_num = (uint8_t)pipe_num; + pipeline->dvs_frame_delay = dvs_frame_delay; +} + +static void ia_css_pipeline_set_zoom_stage(struct ia_css_pipeline *pipeline) +{ + struct ia_css_pipeline_stage *stage = NULL; + int err = 0; + + assert(pipeline); + if (pipeline->pipe_id == IA_CSS_PIPE_ID_PREVIEW) { + /* in preview pipeline, vf_pp stage should do zoom */ + err = ia_css_pipeline_get_stage(pipeline, IA_CSS_BINARY_MODE_VF_PP, &stage); + if (!err) + stage->enable_zoom = true; + } else if (pipeline->pipe_id == IA_CSS_PIPE_ID_CAPTURE) { + /* in capture pipeline, capture_pp stage should do zoom */ + err = ia_css_pipeline_get_stage(pipeline, IA_CSS_BINARY_MODE_CAPTURE_PP, + &stage); + if (!err) + stage->enable_zoom = true; + } else if (pipeline->pipe_id == IA_CSS_PIPE_ID_VIDEO) { + /* in video pipeline, video stage should do zoom */ + err = ia_css_pipeline_get_stage(pipeline, IA_CSS_BINARY_MODE_VIDEO, &stage); + if (!err) + stage->enable_zoom = true; + } else if (pipeline->pipe_id == IA_CSS_PIPE_ID_YUVPP) { + /* in yuvpp pipeline, first yuv_scaler stage should do zoom */ + err = ia_css_pipeline_get_stage(pipeline, IA_CSS_BINARY_MODE_CAPTURE_PP, + &stage); + if (!err) + stage->enable_zoom = true; + } +} + +static void +ia_css_pipeline_configure_inout_port(struct ia_css_pipeline *me, + bool continuous) +{ + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, + "ia_css_pipeline_configure_inout_port() enter: pipe_id(%d) continuous(%d)\n", + me->pipe_id, continuous); + switch (me->pipe_id) { + case IA_CSS_PIPE_ID_PREVIEW: + case IA_CSS_PIPE_ID_VIDEO: + SH_CSS_PIPE_PORT_CONFIG_SET(me->inout_port_config, + (uint8_t)SH_CSS_PORT_INPUT, + (uint8_t)(continuous ? SH_CSS_COPYSINK_TYPE : SH_CSS_HOST_TYPE), 1); + SH_CSS_PIPE_PORT_CONFIG_SET(me->inout_port_config, + (uint8_t)SH_CSS_PORT_OUTPUT, + (uint8_t)SH_CSS_HOST_TYPE, 1); + break; + case IA_CSS_PIPE_ID_COPY: /*Copy pipe ports configured to "offline" mode*/ + SH_CSS_PIPE_PORT_CONFIG_SET(me->inout_port_config, + (uint8_t)SH_CSS_PORT_INPUT, + (uint8_t)SH_CSS_HOST_TYPE, 1); + if (continuous) { + SH_CSS_PIPE_PORT_CONFIG_SET(me->inout_port_config, + (uint8_t)SH_CSS_PORT_OUTPUT, + (uint8_t)SH_CSS_COPYSINK_TYPE, 1); + SH_CSS_PIPE_PORT_CONFIG_SET(me->inout_port_config, + (uint8_t)SH_CSS_PORT_OUTPUT, + (uint8_t)SH_CSS_TAGGERSINK_TYPE, 1); + } else { + SH_CSS_PIPE_PORT_CONFIG_SET(me->inout_port_config, + (uint8_t)SH_CSS_PORT_OUTPUT, + (uint8_t)SH_CSS_HOST_TYPE, 1); + } + break; + case IA_CSS_PIPE_ID_CAPTURE: + SH_CSS_PIPE_PORT_CONFIG_SET(me->inout_port_config, + (uint8_t)SH_CSS_PORT_INPUT, + (uint8_t)(continuous ? SH_CSS_TAGGERSINK_TYPE : SH_CSS_HOST_TYPE), + 1); + SH_CSS_PIPE_PORT_CONFIG_SET(me->inout_port_config, + (uint8_t)SH_CSS_PORT_OUTPUT, + (uint8_t)SH_CSS_HOST_TYPE, 1); + break; + case IA_CSS_PIPE_ID_YUVPP: + SH_CSS_PIPE_PORT_CONFIG_SET(me->inout_port_config, + (uint8_t)SH_CSS_PORT_INPUT, + (uint8_t)(SH_CSS_HOST_TYPE), 1); + SH_CSS_PIPE_PORT_CONFIG_SET(me->inout_port_config, + (uint8_t)SH_CSS_PORT_OUTPUT, + (uint8_t)SH_CSS_HOST_TYPE, 1); + break; + case IA_CSS_PIPE_ID_ACC: + SH_CSS_PIPE_PORT_CONFIG_SET(me->inout_port_config, + (uint8_t)SH_CSS_PORT_INPUT, + (uint8_t)SH_CSS_HOST_TYPE, 1); + SH_CSS_PIPE_PORT_CONFIG_SET(me->inout_port_config, + (uint8_t)SH_CSS_PORT_OUTPUT, + (uint8_t)SH_CSS_HOST_TYPE, 1); + break; + default: + break; + } + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, + "ia_css_pipeline_configure_inout_port() leave: inout_port_config(%x)\n", + me->inout_port_config); +} diff --git a/drivers/staging/media/atomisp/pci/runtime/queue/interface/ia_css_queue.h b/drivers/staging/media/atomisp/pci/runtime/queue/interface/ia_css_queue.h new file mode 100644 index 000000000..08112be46 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/queue/interface/ia_css_queue.h @@ -0,0 +1,176 @@ +/* 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. + */ + +#ifndef __IA_CSS_QUEUE_H +#define __IA_CSS_QUEUE_H + +#include <platform_support.h> +#include <type_support.h> + +#include "ia_css_queue_comm.h" +#include "../src/queue_access.h" + +/* Local Queue object descriptor */ +struct ia_css_queue_local { + ia_css_circbuf_desc_t *cb_desc; /*Circbuf desc for local queues*/ + ia_css_circbuf_elem_t *cb_elems; /*Circbuf elements*/ +}; + +typedef struct ia_css_queue_local ia_css_queue_local_t; + +/* Handle for queue object*/ +typedef struct ia_css_queue ia_css_queue_t; + +/***************************************************************************** + * Queue Public APIs + *****************************************************************************/ +/* @brief Initialize a local queue instance. + * + * @param[out] qhandle. Handle to queue instance for use with API + * @param[in] desc. Descriptor with queue properties filled-in + * @return 0 - Successful init of local queue instance. + * @return -EINVAL - Invalid argument. + * + */ +int ia_css_queue_local_init( + ia_css_queue_t *qhandle, + ia_css_queue_local_t *desc); + +/* @brief Initialize a remote queue instance + * + * @param[out] qhandle. Handle to queue instance for use with API + * @param[in] desc. Descriptor with queue properties filled-in + * @return 0 - Successful init of remote queue instance. + * @return -EINVAL - Invalid argument. + */ +int ia_css_queue_remote_init( + ia_css_queue_t *qhandle, + ia_css_queue_remote_t *desc); + +/* @brief Uninitialize a queue instance + * + * @param[in] qhandle. Handle to queue instance + * @return 0 - Successful uninit. + * + */ +int ia_css_queue_uninit( + ia_css_queue_t *qhandle); + +/* @brief Enqueue an item in the queue instance + * + * @param[in] qhandle. Handle to queue instance + * @param[in] item. Object to be enqueued. + * @return 0 - Successful enqueue. + * @return -EINVAL - Invalid argument. + * @return -ENOBUFS - Queue is full. + * + */ +int ia_css_queue_enqueue( + ia_css_queue_t *qhandle, + uint32_t item); + +/* @brief Dequeue an item from the queue instance + * + * @param[in] qhandle. Handle to queue instance + * @param[out] item. Object to be dequeued into this item. + + * @return 0 - Successful dequeue. + * @return -EINVAL - Invalid argument. + * @return -ENODATA - Queue is empty. + * + */ +int ia_css_queue_dequeue( + ia_css_queue_t *qhandle, + uint32_t *item); + +/* @brief Check if the queue is empty + * + * @param[in] qhandle. Handle to queue instance + * @param[in] is_empty True if empty, False if not. + * @return 0 - Successful access state. + * @return -EINVAL - Invalid argument. + * @return -ENOSYS - Function not implemented. + * + */ +int ia_css_queue_is_empty( + ia_css_queue_t *qhandle, + bool *is_empty); + +/* @brief Check if the queue is full + * + * @param[in] qhandle. Handle to queue instance + * @param[in] is_full True if Full, False if not. + * @return 0 - Successfully access state. + * @return -EINVAL - Invalid argument. + * @return -ENOSYS - Function not implemented. + * + */ +int ia_css_queue_is_full( + ia_css_queue_t *qhandle, + bool *is_full); + +/* @brief Get used space in the queue + * + * @param[in] qhandle. Handle to queue instance + * @param[in] size Number of available elements in the queue + * @return 0 - Successfully access state. + * @return -EINVAL - Invalid argument. + * + */ +int ia_css_queue_get_used_space( + ia_css_queue_t *qhandle, + uint32_t *size); + +/* @brief Get free space in the queue + * + * @param[in] qhandle. Handle to queue instance + * @param[in] size Number of free elements in the queue + * @return 0 - Successfully access state. + * @return -EINVAL - Invalid argument. + * + */ +int ia_css_queue_get_free_space( + ia_css_queue_t *qhandle, + uint32_t *size); + +/* @brief Peek at an element in the queue + * + * @param[in] qhandle. Handle to queue instance + * @param[in] offset Offset of element to peek, + * starting from head of queue + * @param[in] element Value of element returned + * @return 0 - Successfully access state. + * @return -EINVAL - Invalid argument. + * + */ +int ia_css_queue_peek( + ia_css_queue_t *qhandle, + u32 offset, + uint32_t *element); + +/* @brief Get the usable size for the queue + * + * @param[in] qhandle. Handle to queue instance + * @param[out] size Size value to be returned here. + * @return 0 - Successful get size. + * @return -EINVAL - Invalid argument. + * @return -ENOSYS - Function not implemented. + * + */ +int ia_css_queue_get_size( + ia_css_queue_t *qhandle, + uint32_t *size); + +#endif /* __IA_CSS_QUEUE_H */ diff --git a/drivers/staging/media/atomisp/pci/runtime/queue/interface/ia_css_queue_comm.h b/drivers/staging/media/atomisp/pci/runtime/queue/interface/ia_css_queue_comm.h new file mode 100644 index 000000000..1379ae8f8 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/queue/interface/ia_css_queue_comm.h @@ -0,0 +1,54 @@ +/* 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. + */ + +#ifndef __IA_CSS_QUEUE_COMM_H +#define __IA_CSS_QUEUE_COMM_H + +#include "type_support.h" +#include "ia_css_circbuf.h" +/***************************************************************************** + * Queue Public Data Structures + *****************************************************************************/ + +/* Queue location specifier */ +/* Avoiding enums to save space */ +#define IA_CSS_QUEUE_LOC_HOST 0 +#define IA_CSS_QUEUE_LOC_SP 1 +#define IA_CSS_QUEUE_LOC_ISP 2 + +/* Queue type specifier */ +/* Avoiding enums to save space */ +#define IA_CSS_QUEUE_TYPE_LOCAL 0 +#define IA_CSS_QUEUE_TYPE_REMOTE 1 + +/* for DDR Allocated queues, +allocate minimum these many elements. +DDR->SP' DMEM DMA transfer needs 32byte aligned address. +Since each element size is 4 bytes, 8 elements need to be +DMAed to access single element.*/ +#define IA_CSS_MIN_ELEM_COUNT 8 +#define IA_CSS_DMA_XFER_MASK (IA_CSS_MIN_ELEM_COUNT - 1) + +/* Remote Queue object descriptor */ +struct ia_css_queue_remote { + u32 cb_desc_addr; /*Circbuf desc address for remote queues*/ + u32 cb_elems_addr; /*Circbuf elements addr for remote queue*/ + u8 location; /* Cell location for queue */ + u8 proc_id; /* Processor id for queue access */ +}; + +typedef struct ia_css_queue_remote ia_css_queue_remote_t; + +#endif /* __IA_CSS_QUEUE_COMM_H */ diff --git a/drivers/staging/media/atomisp/pci/runtime/queue/src/queue.c b/drivers/staging/media/atomisp/pci/runtime/queue/src/queue.c new file mode 100644 index 000000000..2f1c2df59 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/queue/src/queue.c @@ -0,0 +1,401 @@ +// 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_queue.h" +#include <math_support.h> +#include <ia_css_circbuf.h> +#include <ia_css_circbuf_desc.h> +#include "queue_access.h" + +/***************************************************************************** + * Queue Public APIs + *****************************************************************************/ +int ia_css_queue_local_init(ia_css_queue_t *qhandle, ia_css_queue_local_t *desc) +{ + if (NULL == qhandle || NULL == desc + || NULL == desc->cb_elems || NULL == desc->cb_desc) { + /* Invalid parameters, return error*/ + return -EINVAL; + } + + /* Mark the queue as Local */ + qhandle->type = IA_CSS_QUEUE_TYPE_LOCAL; + + /* Create a local circular buffer queue*/ + ia_css_circbuf_create(&qhandle->desc.cb_local, + desc->cb_elems, + desc->cb_desc); + + return 0; +} + +int ia_css_queue_remote_init(ia_css_queue_t *qhandle, ia_css_queue_remote_t *desc) +{ + if (NULL == qhandle || NULL == desc) { + /* Invalid parameters, return error*/ + return -EINVAL; + } + + /* Mark the queue as remote*/ + qhandle->type = IA_CSS_QUEUE_TYPE_REMOTE; + + /* Copy over the local queue descriptor*/ + qhandle->location = desc->location; + qhandle->proc_id = desc->proc_id; + qhandle->desc.remote.cb_desc_addr = desc->cb_desc_addr; + qhandle->desc.remote.cb_elems_addr = desc->cb_elems_addr; + + /* If queue is remote, we let the local processor + * do its init, before using it. This is just to get us + * started, we can remove this restriction as we go ahead + */ + + return 0; +} + +int ia_css_queue_uninit(ia_css_queue_t *qhandle) +{ + if (!qhandle) + return -EINVAL; + + /* Load the required queue object */ + if (qhandle->type == IA_CSS_QUEUE_TYPE_LOCAL) { + /* Local queues are created. Destroy it*/ + ia_css_circbuf_destroy(&qhandle->desc.cb_local); + } + + return 0; +} + +int ia_css_queue_enqueue(ia_css_queue_t *qhandle, uint32_t item) +{ + int error = 0; + + if (!qhandle) + return -EINVAL; + + /* 1. Load the required queue object */ + if (qhandle->type == IA_CSS_QUEUE_TYPE_LOCAL) { + /* Directly de-ref the object and + * operate on the queue + */ + if (ia_css_circbuf_is_full(&qhandle->desc.cb_local)) { + /* Cannot push the element. Return*/ + return -ENOBUFS; + } + + /* Push the element*/ + ia_css_circbuf_push(&qhandle->desc.cb_local, item); + } else if (qhandle->type == IA_CSS_QUEUE_TYPE_REMOTE) { + ia_css_circbuf_desc_t cb_desc; + ia_css_circbuf_elem_t cb_elem; + u32 ignore_desc_flags = QUEUE_IGNORE_STEP_FLAG; + + /* a. Load the queue cb_desc from remote */ + QUEUE_CB_DESC_INIT(&cb_desc); + error = ia_css_queue_load(qhandle, &cb_desc, ignore_desc_flags); + if (error != 0) + return error; + + /* b. Operate on the queue */ + if (ia_css_circbuf_desc_is_full(&cb_desc)) + return -ENOBUFS; + + cb_elem.val = item; + + error = ia_css_queue_item_store(qhandle, cb_desc.end, &cb_elem); + if (error != 0) + return error; + + cb_desc.end = (cb_desc.end + 1) % cb_desc.size; + + /* c. Store the queue object */ + /* Set only fields requiring update with + * valid value. Avoids uncessary calls + * to load/store functions + */ + ignore_desc_flags = QUEUE_IGNORE_SIZE_START_STEP_FLAGS; + + error = ia_css_queue_store(qhandle, &cb_desc, ignore_desc_flags); + if (error != 0) + return error; + } + + return 0; +} + +int ia_css_queue_dequeue(ia_css_queue_t *qhandle, uint32_t *item) +{ + int error = 0; + + if (!qhandle || NULL == item) + return -EINVAL; + + /* 1. Load the required queue object */ + if (qhandle->type == IA_CSS_QUEUE_TYPE_LOCAL) { + /* Directly de-ref the object and + * operate on the queue + */ + if (ia_css_circbuf_is_empty(&qhandle->desc.cb_local)) { + /* Nothing to pop. Return empty queue*/ + return -ENODATA; + } + + *item = ia_css_circbuf_pop(&qhandle->desc.cb_local); + } else if (qhandle->type == IA_CSS_QUEUE_TYPE_REMOTE) { + /* a. Load the queue from remote */ + ia_css_circbuf_desc_t cb_desc; + ia_css_circbuf_elem_t cb_elem; + u32 ignore_desc_flags = QUEUE_IGNORE_STEP_FLAG; + + QUEUE_CB_DESC_INIT(&cb_desc); + + error = ia_css_queue_load(qhandle, &cb_desc, ignore_desc_flags); + if (error != 0) + return error; + + /* b. Operate on the queue */ + if (ia_css_circbuf_desc_is_empty(&cb_desc)) + return -ENODATA; + + error = ia_css_queue_item_load(qhandle, cb_desc.start, &cb_elem); + if (error != 0) + return error; + + *item = cb_elem.val; + + cb_desc.start = OP_std_modadd(cb_desc.start, 1, cb_desc.size); + + /* c. Store the queue object */ + /* Set only fields requiring update with + * valid value. Avoids uncessary calls + * to load/store functions + */ + ignore_desc_flags = QUEUE_IGNORE_SIZE_END_STEP_FLAGS; + error = ia_css_queue_store(qhandle, &cb_desc, ignore_desc_flags); + if (error != 0) + return error; + } + return 0; +} + +int ia_css_queue_is_full(ia_css_queue_t *qhandle, bool *is_full) +{ + int error = 0; + + if ((!qhandle) || (!is_full)) + return -EINVAL; + + /* 1. Load the required queue object */ + if (qhandle->type == IA_CSS_QUEUE_TYPE_LOCAL) { + /* Directly de-ref the object and + * operate on the queue + */ + *is_full = ia_css_circbuf_is_full(&qhandle->desc.cb_local); + return 0; + } else if (qhandle->type == IA_CSS_QUEUE_TYPE_REMOTE) { + /* a. Load the queue from remote */ + ia_css_circbuf_desc_t cb_desc; + u32 ignore_desc_flags = QUEUE_IGNORE_STEP_FLAG; + + QUEUE_CB_DESC_INIT(&cb_desc); + error = ia_css_queue_load(qhandle, &cb_desc, ignore_desc_flags); + if (error != 0) + return error; + + /* b. Operate on the queue */ + *is_full = ia_css_circbuf_desc_is_full(&cb_desc); + return 0; + } + + return -EINVAL; +} + +int ia_css_queue_get_free_space(ia_css_queue_t *qhandle, uint32_t *size) +{ + int error = 0; + + if ((!qhandle) || (!size)) + return -EINVAL; + + /* 1. Load the required queue object */ + if (qhandle->type == IA_CSS_QUEUE_TYPE_LOCAL) { + /* Directly de-ref the object and + * operate on the queue + */ + *size = ia_css_circbuf_get_free_elems(&qhandle->desc.cb_local); + return 0; + } else if (qhandle->type == IA_CSS_QUEUE_TYPE_REMOTE) { + /* a. Load the queue from remote */ + ia_css_circbuf_desc_t cb_desc; + u32 ignore_desc_flags = QUEUE_IGNORE_STEP_FLAG; + + QUEUE_CB_DESC_INIT(&cb_desc); + error = ia_css_queue_load(qhandle, &cb_desc, ignore_desc_flags); + if (error != 0) + return error; + + /* b. Operate on the queue */ + *size = ia_css_circbuf_desc_get_free_elems(&cb_desc); + return 0; + } + + return -EINVAL; +} + +int ia_css_queue_get_used_space(ia_css_queue_t *qhandle, uint32_t *size) +{ + int error = 0; + + if ((!qhandle) || (!size)) + return -EINVAL; + + /* 1. Load the required queue object */ + if (qhandle->type == IA_CSS_QUEUE_TYPE_LOCAL) { + /* Directly de-ref the object and + * operate on the queue + */ + *size = ia_css_circbuf_get_num_elems(&qhandle->desc.cb_local); + return 0; + } else if (qhandle->type == IA_CSS_QUEUE_TYPE_REMOTE) { + /* a. Load the queue from remote */ + ia_css_circbuf_desc_t cb_desc; + u32 ignore_desc_flags = QUEUE_IGNORE_STEP_FLAG; + + QUEUE_CB_DESC_INIT(&cb_desc); + error = ia_css_queue_load(qhandle, &cb_desc, ignore_desc_flags); + if (error != 0) + return error; + + /* b. Operate on the queue */ + *size = ia_css_circbuf_desc_get_num_elems(&cb_desc); + return 0; + } + + return -EINVAL; +} + +int ia_css_queue_peek(ia_css_queue_t *qhandle, u32 offset, uint32_t *element) +{ + u32 num_elems = 0; + int error = 0; + + if ((!qhandle) || (!element)) + return -EINVAL; + + /* 1. Load the required queue object */ + if (qhandle->type == IA_CSS_QUEUE_TYPE_LOCAL) { + /* Directly de-ref the object and + * operate on the queue + */ + /* Check if offset is valid */ + num_elems = ia_css_circbuf_get_num_elems(&qhandle->desc.cb_local); + if (offset > num_elems) + return -EINVAL; + + *element = ia_css_circbuf_peek_from_start(&qhandle->desc.cb_local, (int)offset); + return 0; + } else if (qhandle->type == IA_CSS_QUEUE_TYPE_REMOTE) { + /* a. Load the queue from remote */ + ia_css_circbuf_desc_t cb_desc; + ia_css_circbuf_elem_t cb_elem; + u32 ignore_desc_flags = QUEUE_IGNORE_STEP_FLAG; + + QUEUE_CB_DESC_INIT(&cb_desc); + + error = ia_css_queue_load(qhandle, &cb_desc, ignore_desc_flags); + if (error != 0) + return error; + + /* Check if offset is valid */ + num_elems = ia_css_circbuf_desc_get_num_elems(&cb_desc); + if (offset > num_elems) + return -EINVAL; + + offset = OP_std_modadd(cb_desc.start, offset, cb_desc.size); + error = ia_css_queue_item_load(qhandle, (uint8_t)offset, &cb_elem); + if (error != 0) + return error; + + *element = cb_elem.val; + return 0; + } + + return -EINVAL; +} + +int ia_css_queue_is_empty(ia_css_queue_t *qhandle, bool *is_empty) +{ + int error = 0; + + if ((!qhandle) || (!is_empty)) + return -EINVAL; + + /* 1. Load the required queue object */ + if (qhandle->type == IA_CSS_QUEUE_TYPE_LOCAL) { + /* Directly de-ref the object and + * operate on the queue + */ + *is_empty = ia_css_circbuf_is_empty(&qhandle->desc.cb_local); + return 0; + } else if (qhandle->type == IA_CSS_QUEUE_TYPE_REMOTE) { + /* a. Load the queue from remote */ + ia_css_circbuf_desc_t cb_desc; + u32 ignore_desc_flags = QUEUE_IGNORE_STEP_FLAG; + + QUEUE_CB_DESC_INIT(&cb_desc); + error = ia_css_queue_load(qhandle, &cb_desc, ignore_desc_flags); + if (error != 0) + return error; + + /* b. Operate on the queue */ + *is_empty = ia_css_circbuf_desc_is_empty(&cb_desc); + return 0; + } + + return -EINVAL; +} + +int ia_css_queue_get_size(ia_css_queue_t *qhandle, uint32_t *size) +{ + int error = 0; + + if ((!qhandle) || (!size)) + return -EINVAL; + + /* 1. Load the required queue object */ + if (qhandle->type == IA_CSS_QUEUE_TYPE_LOCAL) { + /* Directly de-ref the object and + * operate on the queue + */ + /* Return maximum usable capacity */ + *size = ia_css_circbuf_get_size(&qhandle->desc.cb_local); + } else if (qhandle->type == IA_CSS_QUEUE_TYPE_REMOTE) { + /* a. Load the queue from remote */ + ia_css_circbuf_desc_t cb_desc; + u32 ignore_desc_flags = QUEUE_IGNORE_START_END_STEP_FLAGS; + + QUEUE_CB_DESC_INIT(&cb_desc); + + error = ia_css_queue_load(qhandle, &cb_desc, ignore_desc_flags); + if (error != 0) + return error; + + /* Return maximum usable capacity */ + *size = cb_desc.size; + } + + return 0; +} diff --git a/drivers/staging/media/atomisp/pci/runtime/queue/src/queue_access.c b/drivers/staging/media/atomisp/pci/runtime/queue/src/queue_access.c new file mode 100644 index 000000000..424e7a15a --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/queue/src/queue_access.c @@ -0,0 +1,178 @@ +// 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 "hmm.h" + +#include "type_support.h" +#include "queue_access.h" +#include "ia_css_circbuf.h" +#include "sp.h" +#include "assert_support.h" + +int ia_css_queue_load( + struct ia_css_queue *rdesc, + ia_css_circbuf_desc_t *cb_desc, + uint32_t ignore_desc_flags) +{ + if (!rdesc || !cb_desc) + return -EINVAL; + + if (rdesc->location == IA_CSS_QUEUE_LOC_SP) { + assert(ignore_desc_flags <= QUEUE_IGNORE_DESC_FLAGS_MAX); + + if (0 == (ignore_desc_flags & QUEUE_IGNORE_SIZE_FLAG)) { + cb_desc->size = sp_dmem_load_uint8(rdesc->proc_id, + rdesc->desc.remote.cb_desc_addr + + offsetof(ia_css_circbuf_desc_t, size)); + + if (cb_desc->size == 0) { + /* Adding back the workaround which was removed + while refactoring queues. When reading size + through sp_dmem_load_*, sometimes we get back + the value as zero. This causes division by 0 + exception as the size is used in a modular + division operation. */ + return -EDOM; + } + } + + if (0 == (ignore_desc_flags & QUEUE_IGNORE_START_FLAG)) + cb_desc->start = sp_dmem_load_uint8(rdesc->proc_id, + rdesc->desc.remote.cb_desc_addr + + offsetof(ia_css_circbuf_desc_t, start)); + + if (0 == (ignore_desc_flags & QUEUE_IGNORE_END_FLAG)) + cb_desc->end = sp_dmem_load_uint8(rdesc->proc_id, + rdesc->desc.remote.cb_desc_addr + + offsetof(ia_css_circbuf_desc_t, end)); + + if (0 == (ignore_desc_flags & QUEUE_IGNORE_STEP_FLAG)) + cb_desc->step = sp_dmem_load_uint8(rdesc->proc_id, + rdesc->desc.remote.cb_desc_addr + + offsetof(ia_css_circbuf_desc_t, step)); + + } else if (rdesc->location == IA_CSS_QUEUE_LOC_HOST) { + /* doing DMA transfer of entire structure */ + hmm_load(rdesc->desc.remote.cb_desc_addr, + (void *)cb_desc, + sizeof(ia_css_circbuf_desc_t)); + } else if (rdesc->location == IA_CSS_QUEUE_LOC_ISP) { + /* Not supported yet */ + return -ENOTSUPP; + } + + return 0; +} + +int ia_css_queue_store( + struct ia_css_queue *rdesc, + ia_css_circbuf_desc_t *cb_desc, + uint32_t ignore_desc_flags) +{ + if (!rdesc || !cb_desc) + return -EINVAL; + + if (rdesc->location == IA_CSS_QUEUE_LOC_SP) { + assert(ignore_desc_flags <= QUEUE_IGNORE_DESC_FLAGS_MAX); + + if (0 == (ignore_desc_flags & QUEUE_IGNORE_SIZE_FLAG)) + sp_dmem_store_uint8(rdesc->proc_id, + rdesc->desc.remote.cb_desc_addr + + offsetof(ia_css_circbuf_desc_t, size), + cb_desc->size); + + if (0 == (ignore_desc_flags & QUEUE_IGNORE_START_FLAG)) + sp_dmem_store_uint8(rdesc->proc_id, + rdesc->desc.remote.cb_desc_addr + + offsetof(ia_css_circbuf_desc_t, start), + cb_desc->start); + + if (0 == (ignore_desc_flags & QUEUE_IGNORE_END_FLAG)) + sp_dmem_store_uint8(rdesc->proc_id, + rdesc->desc.remote.cb_desc_addr + + offsetof(ia_css_circbuf_desc_t, end), + cb_desc->end); + + if (0 == (ignore_desc_flags & QUEUE_IGNORE_STEP_FLAG)) + sp_dmem_store_uint8(rdesc->proc_id, + rdesc->desc.remote.cb_desc_addr + + offsetof(ia_css_circbuf_desc_t, step), + cb_desc->step); + } else if (rdesc->location == IA_CSS_QUEUE_LOC_HOST) { + /* doing DMA transfer of entire structure */ + hmm_store(rdesc->desc.remote.cb_desc_addr, + (void *)cb_desc, + sizeof(ia_css_circbuf_desc_t)); + } else if (rdesc->location == IA_CSS_QUEUE_LOC_ISP) { + /* Not supported yet */ + return -ENOTSUPP; + } + + return 0; +} + +int ia_css_queue_item_load( + struct ia_css_queue *rdesc, + u8 position, + ia_css_circbuf_elem_t *item) +{ + if (!rdesc || !item) + return -EINVAL; + + if (rdesc->location == IA_CSS_QUEUE_LOC_SP) { + sp_dmem_load(rdesc->proc_id, + rdesc->desc.remote.cb_elems_addr + + position * sizeof(ia_css_circbuf_elem_t), + item, + sizeof(ia_css_circbuf_elem_t)); + } else if (rdesc->location == IA_CSS_QUEUE_LOC_HOST) { + hmm_load(rdesc->desc.remote.cb_elems_addr + + position * sizeof(ia_css_circbuf_elem_t), + (void *)item, + sizeof(ia_css_circbuf_elem_t)); + } else if (rdesc->location == IA_CSS_QUEUE_LOC_ISP) { + /* Not supported yet */ + return -ENOTSUPP; + } + + return 0; +} + +int ia_css_queue_item_store( + struct ia_css_queue *rdesc, + u8 position, + ia_css_circbuf_elem_t *item) +{ + if (!rdesc || !item) + return -EINVAL; + + if (rdesc->location == IA_CSS_QUEUE_LOC_SP) { + sp_dmem_store(rdesc->proc_id, + rdesc->desc.remote.cb_elems_addr + + position * sizeof(ia_css_circbuf_elem_t), + item, + sizeof(ia_css_circbuf_elem_t)); + } else if (rdesc->location == IA_CSS_QUEUE_LOC_HOST) { + hmm_store(rdesc->desc.remote.cb_elems_addr + + position * sizeof(ia_css_circbuf_elem_t), + (void *)item, + sizeof(ia_css_circbuf_elem_t)); + } else if (rdesc->location == IA_CSS_QUEUE_LOC_ISP) { + /* Not supported yet */ + return -ENOTSUPP; + } + + return 0; +} diff --git a/drivers/staging/media/atomisp/pci/runtime/queue/src/queue_access.h b/drivers/staging/media/atomisp/pci/runtime/queue/src/queue_access.h new file mode 100644 index 000000000..d5107adcc --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/queue/src/queue_access.h @@ -0,0 +1,87 @@ +/* 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. + */ + +#ifndef __QUEUE_ACCESS_H +#define __QUEUE_ACCESS_H + +#include <linux/errno.h> + +#include <type_support.h> +#include <ia_css_queue_comm.h> +#include <ia_css_circbuf.h> + +#define QUEUE_IGNORE_START_FLAG 0x0001 +#define QUEUE_IGNORE_END_FLAG 0x0002 +#define QUEUE_IGNORE_SIZE_FLAG 0x0004 +#define QUEUE_IGNORE_STEP_FLAG 0x0008 +#define QUEUE_IGNORE_DESC_FLAGS_MAX 0x000f + +#define QUEUE_IGNORE_SIZE_START_STEP_FLAGS \ + (QUEUE_IGNORE_SIZE_FLAG | \ + QUEUE_IGNORE_START_FLAG | \ + QUEUE_IGNORE_STEP_FLAG) + +#define QUEUE_IGNORE_SIZE_END_STEP_FLAGS \ + (QUEUE_IGNORE_SIZE_FLAG | \ + QUEUE_IGNORE_END_FLAG | \ + QUEUE_IGNORE_STEP_FLAG) + +#define QUEUE_IGNORE_START_END_STEP_FLAGS \ + (QUEUE_IGNORE_START_FLAG | \ + QUEUE_IGNORE_END_FLAG | \ + QUEUE_IGNORE_STEP_FLAG) + +#define QUEUE_CB_DESC_INIT(cb_desc) \ + do { \ + (cb_desc)->size = 0; \ + (cb_desc)->step = 0; \ + (cb_desc)->start = 0; \ + (cb_desc)->end = 0; \ + } while (0) + +struct ia_css_queue { + u8 type; /* Specify remote/local type of access */ + u8 location; /* Cell location for queue */ + u8 proc_id; /* Processor id for queue access */ + union { + ia_css_circbuf_t cb_local; + struct { + u32 cb_desc_addr; /*Circbuf desc address for remote queues*/ + u32 cb_elems_addr; /*Circbuf elements addr for remote queue*/ + } remote; + } desc; +}; + +int ia_css_queue_load( + struct ia_css_queue *rdesc, + ia_css_circbuf_desc_t *cb_desc, + uint32_t ignore_desc_flags); + +int ia_css_queue_store( + struct ia_css_queue *rdesc, + ia_css_circbuf_desc_t *cb_desc, + uint32_t ignore_desc_flags); + +int ia_css_queue_item_load( + struct ia_css_queue *rdesc, + u8 position, + ia_css_circbuf_elem_t *item); + +int ia_css_queue_item_store( + struct ia_css_queue *rdesc, + u8 position, + ia_css_circbuf_elem_t *item); + +#endif /* __QUEUE_ACCESS_H */ diff --git a/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr.h b/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr.h new file mode 100644 index 000000000..9cd3d92b3 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr.h @@ -0,0 +1,73 @@ +/* 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. + */ + +#ifndef _IA_CSS_RMGR_H +#define _IA_CSS_RMGR_H + +#include <ia_css_err.h> + +#ifndef __INLINE_RMGR__ +#define STORAGE_CLASS_RMGR_H extern +#define STORAGE_CLASS_RMGR_C +#else /* __INLINE_RMGR__ */ +#define STORAGE_CLASS_RMGR_H static inline +#define STORAGE_CLASS_RMGR_C static inline +#endif /* __INLINE_RMGR__ */ + +/** + * @brief Initialize resource manager (host/common) + */ +int ia_css_rmgr_init(void); + +/** + * @brief Uninitialize resource manager (host/common) + */ +void ia_css_rmgr_uninit(void); + +/***************************************************************** + * Interface definition - resource type (host/common) + ***************************************************************** + * + * struct ia_css_rmgr_<type>_pool; + * struct ia_css_rmgr_<type>_handle; + * + * STORAGE_CLASS_RMGR_H void ia_css_rmgr_init_<type>( + * struct ia_css_rmgr_<type>_pool *pool); + * + * STORAGE_CLASS_RMGR_H void ia_css_rmgr_uninit_<type>( + * struct ia_css_rmgr_<type>_pool *pool); + * + * STORAGE_CLASS_RMGR_H void ia_css_rmgr_acq_<type>( + * struct ia_css_rmgr_<type>_pool *pool, + * struct ia_css_rmgr_<type>_handle **handle); + * + * STORAGE_CLASS_RMGR_H void ia_css_rmgr_rel_<type>( + * struct ia_css_rmgr_<type>_pool *pool, + * struct ia_css_rmgr_<type>_handle **handle); + * + ***************************************************************** + * Interface definition - refcounting (host/common) + ***************************************************************** + * + * void ia_css_rmgr_refcount_retain_<type>( + * struct ia_css_rmgr_<type>_handle **handle); + * + * void ia_css_rmgr_refcount_release_<type>( + * struct ia_css_rmgr_<type>_handle **handle); + */ + +#include "ia_css_rmgr_vbuf.h" + +#endif /* _IA_CSS_RMGR_H */ diff --git a/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr_vbuf.h b/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr_vbuf.h new file mode 100644 index 000000000..ac969afc8 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr_vbuf.h @@ -0,0 +1,101 @@ +/* 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. + */ + +#ifndef _IA_CSS_RMGR_VBUF_H +#define _IA_CSS_RMGR_VBUF_H + +#include "ia_css_rmgr.h" +#include <type_support.h> +#include <ia_css_types.h> +#include <system_local.h> + +/** + * @brief Data structure for the resource handle (host, vbuf) + */ +struct ia_css_rmgr_vbuf_handle { + ia_css_ptr vptr; + u8 count; + u32 size; +}; + +/** + * @brief Data structure for the resource pool (host, vbuf) + */ +struct ia_css_rmgr_vbuf_pool { + u8 copy_on_write; + u8 recycle; + u32 size; + u32 index; + struct ia_css_rmgr_vbuf_handle **handles; +}; + +/** + * @brief VBUF resource pools + */ +extern struct ia_css_rmgr_vbuf_pool *vbuf_ref; +extern struct ia_css_rmgr_vbuf_pool *vbuf_write; +extern struct ia_css_rmgr_vbuf_pool *hmm_buffer_pool; + +/** + * @brief Initialize the resource pool (host, vbuf) + * + * @param pool The pointer to the pool + */ +STORAGE_CLASS_RMGR_H int ia_css_rmgr_init_vbuf( + struct ia_css_rmgr_vbuf_pool *pool); + +/** + * @brief Uninitialize the resource pool (host, vbuf) + * + * @param pool The pointer to the pool + */ +STORAGE_CLASS_RMGR_H void ia_css_rmgr_uninit_vbuf( + struct ia_css_rmgr_vbuf_pool *pool); + +/** + * @brief Acquire a handle from the pool (host, vbuf) + * + * @param pool The pointer to the pool + * @param handle The pointer to the handle + */ +STORAGE_CLASS_RMGR_H void ia_css_rmgr_acq_vbuf( + struct ia_css_rmgr_vbuf_pool *pool, + struct ia_css_rmgr_vbuf_handle **handle); + +/** + * @brief Release a handle to the pool (host, vbuf) + * + * @param pool The pointer to the pool + * @param handle The pointer to the handle + */ +STORAGE_CLASS_RMGR_H void ia_css_rmgr_rel_vbuf( + struct ia_css_rmgr_vbuf_pool *pool, + struct ia_css_rmgr_vbuf_handle **handle); + +/** + * @brief Retain the reference count for a handle (host, vbuf) + * + * @param handle The pointer to the handle + */ +void ia_css_rmgr_refcount_retain_vbuf(struct ia_css_rmgr_vbuf_handle **handle); + +/** + * @brief Release the reference count for a handle (host, vbuf) + * + * @param handle The pointer to the handle + */ +void ia_css_rmgr_refcount_release_vbuf(struct ia_css_rmgr_vbuf_handle **handle); + +#endif /* _IA_CSS_RMGR_VBUF_H */ diff --git a/drivers/staging/media/atomisp/pci/runtime/rmgr/src/rmgr.c b/drivers/staging/media/atomisp/pci/runtime/rmgr/src/rmgr.c new file mode 100644 index 000000000..c94a428aa --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/rmgr/src/rmgr.c @@ -0,0 +1,40 @@ +// 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 "ia_css_rmgr.h" + +int ia_css_rmgr_init(void) +{ + int err = 0; + + err = ia_css_rmgr_init_vbuf(vbuf_ref); + if (!err) + err = ia_css_rmgr_init_vbuf(vbuf_write); + if (!err) + err = ia_css_rmgr_init_vbuf(hmm_buffer_pool); + if (err) + ia_css_rmgr_uninit(); + return err; +} + +/* + * @brief Uninitialize resource pool (host) + */ +void ia_css_rmgr_uninit(void) +{ + ia_css_rmgr_uninit_vbuf(hmm_buffer_pool); + ia_css_rmgr_uninit_vbuf(vbuf_write); + ia_css_rmgr_uninit_vbuf(vbuf_ref); +} diff --git a/drivers/staging/media/atomisp/pci/runtime/rmgr/src/rmgr_vbuf.c b/drivers/staging/media/atomisp/pci/runtime/rmgr/src/rmgr_vbuf.c new file mode 100644 index 000000000..2e07dab8b --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/rmgr/src/rmgr_vbuf.c @@ -0,0 +1,329 @@ +// 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 "hmm.h" +#include "ia_css_rmgr.h" + +#include <type_support.h> +#include <assert_support.h> +#include <platform_support.h> /* memset */ +#include <ia_css_debug.h> + +/* + * @brief VBUF resource handles + */ +#define NUM_HANDLES 1000 +static struct ia_css_rmgr_vbuf_handle handle_table[NUM_HANDLES]; + +/* + * @brief VBUF resource pool - refpool + */ +static struct ia_css_rmgr_vbuf_pool refpool; + +/* + * @brief VBUF resource pool - writepool + */ +static struct ia_css_rmgr_vbuf_pool writepool = { + .copy_on_write = true, +}; + +/* + * @brief VBUF resource pool - hmmbufferpool + */ +static struct ia_css_rmgr_vbuf_pool hmmbufferpool = { + .copy_on_write = true, + .recycle = true, + .size = 32, +}; + +struct ia_css_rmgr_vbuf_pool *vbuf_ref = &refpool; +struct ia_css_rmgr_vbuf_pool *vbuf_write = &writepool; +struct ia_css_rmgr_vbuf_pool *hmm_buffer_pool = &hmmbufferpool; + +/* + * @brief Initialize the reference count (host, vbuf) + */ +static void rmgr_refcount_init_vbuf(void) +{ + /* initialize the refcount table */ + memset(&handle_table, 0, sizeof(handle_table)); +} + +/* + * @brief Retain the reference count for a handle (host, vbuf) + * + * @param handle The pointer to the handle + */ +void ia_css_rmgr_refcount_retain_vbuf(struct ia_css_rmgr_vbuf_handle **handle) +{ + int i; + struct ia_css_rmgr_vbuf_handle *h; + + if ((!handle) || (!*handle)) { + IA_CSS_LOG("Invalid inputs"); + return; + } + /* new vbuf to count on */ + if ((*handle)->count == 0) { + h = *handle; + *handle = NULL; + for (i = 0; i < NUM_HANDLES; i++) { + if (handle_table[i].count == 0) { + *handle = &handle_table[i]; + break; + } + } + /* if the loop dus not break and *handle == NULL + * this is an error handle and report it. + */ + if (!*handle) { + ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR, + "ia_css_i_host_refcount_retain_vbuf() failed to find empty slot!\n"); + return; + } + (*handle)->vptr = h->vptr; + (*handle)->size = h->size; + } + (*handle)->count++; +} + +/* + * @brief Release the reference count for a handle (host, vbuf) + * + * @param handle The pointer to the handle + */ +void ia_css_rmgr_refcount_release_vbuf(struct ia_css_rmgr_vbuf_handle **handle) +{ + if ((!handle) || ((*handle) == NULL) || (((*handle)->count) == 0)) { + ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR, "%s invalid arguments!\n", __func__); + return; + } + /* decrease reference count */ + (*handle)->count--; + /* remove from admin */ + if ((*handle)->count == 0) { + (*handle)->vptr = 0x0; + (*handle)->size = 0; + *handle = NULL; + } +} + +/* + * @brief Initialize the resource pool (host, vbuf) + * + * @param pool The pointer to the pool + */ +int ia_css_rmgr_init_vbuf(struct ia_css_rmgr_vbuf_pool *pool) +{ + int err = 0; + size_t bytes_needed; + + rmgr_refcount_init_vbuf(); + assert(pool); + if (!pool) + return -EINVAL; + /* initialize the recycle pool if used */ + if (pool->recycle && pool->size) { + /* allocate memory for storing the handles */ + bytes_needed = + sizeof(void *) * + pool->size; + pool->handles = kvmalloc(bytes_needed, GFP_KERNEL); + if (pool->handles) + memset(pool->handles, 0, bytes_needed); + else + err = -ENOMEM; + } else { + /* just in case, set the size to 0 */ + pool->size = 0; + pool->handles = NULL; + } + return err; +} + +/* + * @brief Uninitialize the resource pool (host, vbuf) + * + * @param pool The pointer to the pool + */ +void ia_css_rmgr_uninit_vbuf(struct ia_css_rmgr_vbuf_pool *pool) +{ + u32 i; + + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "%s\n", __func__); + if (!pool) { + ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR, "%s NULL argument\n", __func__); + return; + } + if (pool->handles) { + /* free the hmm buffers */ + for (i = 0; i < pool->size; i++) { + if (pool->handles[i]) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + " freeing/releasing %x (count=%d)\n", + pool->handles[i]->vptr, + pool->handles[i]->count); + /* free memory */ + hmm_free(pool->handles[i]->vptr); + /* remove from refcount admin */ + ia_css_rmgr_refcount_release_vbuf(&pool->handles[i]); + } + } + /* now free the pool handles list */ + kvfree(pool->handles); + pool->handles = NULL; + } +} + +/* + * @brief Push a handle to the pool + * + * @param pool The pointer to the pool + * @param handle The pointer to the handle + */ +static +void rmgr_push_handle(struct ia_css_rmgr_vbuf_pool *pool, + struct ia_css_rmgr_vbuf_handle **handle) +{ + u32 i; + bool succes = false; + + assert(pool); + assert(pool->recycle); + assert(pool->handles); + assert(handle); + for (i = 0; i < pool->size; i++) { + if (!pool->handles[i]) { + ia_css_rmgr_refcount_retain_vbuf(handle); + pool->handles[i] = *handle; + succes = true; + break; + } + } + assert(succes); +} + +/* + * @brief Pop a handle from the pool + * + * @param pool The pointer to the pool + * @param handle The pointer to the handle + */ +static +void rmgr_pop_handle(struct ia_css_rmgr_vbuf_pool *pool, + struct ia_css_rmgr_vbuf_handle **handle) +{ + u32 i; + + assert(pool); + assert(pool->recycle); + assert(pool->handles); + assert(handle); + assert(*handle); + for (i = 0; i < pool->size; i++) { + if ((pool->handles[i]) && + (pool->handles[i]->size == (*handle)->size)) { + *handle = pool->handles[i]; + pool->handles[i] = NULL; + /* dont release, we are returning it... + * ia_css_rmgr_refcount_release_vbuf(handle); + */ + return; + } + } +} + +/* + * @brief Acquire a handle from the pool (host, vbuf) + * + * @param pool The pointer to the pool + * @param handle The pointer to the handle + */ +void ia_css_rmgr_acq_vbuf(struct ia_css_rmgr_vbuf_pool *pool, + struct ia_css_rmgr_vbuf_handle **handle) +{ + if ((!pool) || (!handle) || (!*handle)) { + IA_CSS_LOG("Invalid inputs"); + return; + } + + if (pool->copy_on_write) { + struct ia_css_rmgr_vbuf_handle *new_handle; + struct ia_css_rmgr_vbuf_handle h = { 0 }; + + /* only one reference, reuse (no new retain) */ + if ((*handle)->count == 1) + return; + /* more than one reference, release current buffer */ + if ((*handle)->count > 1) { + /* store current values */ + h.vptr = 0x0; + h.size = (*handle)->size; + /* release ref to current buffer */ + ia_css_rmgr_refcount_release_vbuf(handle); + new_handle = &h; + } else { + new_handle = *handle; + } + /* get new buffer for needed size */ + if (new_handle->vptr == 0x0) { + if (pool->recycle) { + /* try and pop from pool */ + rmgr_pop_handle(pool, &new_handle); + } + if (new_handle->vptr == 0x0) { + /* we need to allocate */ + new_handle->vptr = hmm_alloc(new_handle->size); + } else { + /* we popped a buffer */ + *handle = new_handle; + return; + } + } + /* Note that new_handle will change to an internally maintained one */ + ia_css_rmgr_refcount_retain_vbuf(&new_handle); + *handle = new_handle; + return; + } + /* Note that handle will change to an internally maintained one */ + ia_css_rmgr_refcount_retain_vbuf(handle); +} + +/* + * @brief Release a handle to the pool (host, vbuf) + * + * @param pool The pointer to the pool + * @param handle The pointer to the handle + */ +void ia_css_rmgr_rel_vbuf(struct ia_css_rmgr_vbuf_pool *pool, + struct ia_css_rmgr_vbuf_handle **handle) +{ + if ((!pool) || (!handle) || (!*handle)) { + IA_CSS_LOG("Invalid inputs"); + return; + } + /* release the handle */ + if ((*handle)->count == 1) { + if (!pool->recycle) { + /* non recycling pool, free mem */ + hmm_free((*handle)->vptr); + } else { + /* recycle to pool */ + rmgr_push_handle(pool, handle); + } + } + ia_css_rmgr_refcount_release_vbuf(handle); + *handle = NULL; +} diff --git a/drivers/staging/media/atomisp/pci/runtime/spctrl/interface/ia_css_spctrl.h b/drivers/staging/media/atomisp/pci/runtime/spctrl/interface/ia_css_spctrl.h new file mode 100644 index 000000000..efe6c4a82 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/spctrl/interface/ia_css_spctrl.h @@ -0,0 +1,69 @@ +/* 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. + */ + +#ifndef __IA_CSS_SPCTRL_H__ +#define __IA_CSS_SPCTRL_H__ + +#include <system_global.h> +#include <ia_css_err.h> +#include "ia_css_spctrl_comm.h" + +typedef struct { + u32 ddr_data_offset; /** posistion of data in DDR */ + u32 dmem_data_addr; /** data segment address in dmem */ + u32 dmem_bss_addr; /** bss segment address in dmem */ + u32 data_size; /** data segment size */ + u32 bss_size; /** bss segment size */ + u32 spctrl_config_dmem_addr; /* <location of dmem_cfg in SP dmem */ + u32 spctrl_state_dmem_addr; /* < location of state in SP dmem */ + unsigned int sp_entry; /* < entry function ptr on SP */ + const void *code; /** location of firmware */ + u32 code_size; + char *program_name; /** not used on hardware, only for simulation */ +} ia_css_spctrl_cfg; + +/* Get the code addr in DDR of SP */ +ia_css_ptr get_sp_code_addr(sp_ID_t sp_id); + +/* ! Load firmware on to specfied SP +*/ +int ia_css_spctrl_load_fw(sp_ID_t sp_id, + ia_css_spctrl_cfg *spctrl_cfg); + +/* ISP2401 */ +/*! Setup registers for reloading FW */ +void sh_css_spctrl_reload_fw(sp_ID_t sp_id); + +/*! Unload/release any memory allocated to hold the firmware +*/ +int ia_css_spctrl_unload_fw(sp_ID_t sp_id); + +/*! Intilaize dmem_cfg in SP dmem and start SP program +*/ +int ia_css_spctrl_start(sp_ID_t sp_id); + +/*! stop spctrl +*/ +int ia_css_spctrl_stop(sp_ID_t sp_id); + +/*! Query the state of SP +*/ +ia_css_spctrl_sp_sw_state ia_css_spctrl_get_state(sp_ID_t sp_id); + +/*! Check if SP is idle/ready +*/ +int ia_css_spctrl_is_idle(sp_ID_t sp_id); + +#endif /* __IA_CSS_SPCTRL_H__ */ diff --git a/drivers/staging/media/atomisp/pci/runtime/spctrl/interface/ia_css_spctrl_comm.h b/drivers/staging/media/atomisp/pci/runtime/spctrl/interface/ia_css_spctrl_comm.h new file mode 100644 index 000000000..78e0f3096 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/spctrl/interface/ia_css_spctrl_comm.h @@ -0,0 +1,46 @@ +/* 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. + */ + +#ifndef __IA_CSS_SPCTRL_COMM_H__ +#define __IA_CSS_SPCTRL_COMM_H__ + +#include <type_support.h> + +/* state of SP */ +typedef enum { + IA_CSS_SP_SW_TERMINATED = 0, + IA_CSS_SP_SW_INITIALIZED, + IA_CSS_SP_SW_CONNECTED, + IA_CSS_SP_SW_RUNNING +} ia_css_spctrl_sp_sw_state; + +/* Structure to encapsulate required arguments for + * initialization of SP DMEM using the SP itself + */ +struct ia_css_sp_init_dmem_cfg { + ia_css_ptr ddr_data_addr; /** data segment address in ddr */ + u32 dmem_data_addr; /** data segment address in dmem */ + u32 dmem_bss_addr; /** bss segment address in dmem */ + u32 data_size; /** data segment size */ + u32 bss_size; /** bss segment size */ + sp_ID_t sp_id; /* <sp Id */ +}; + +#define SIZE_OF_IA_CSS_SP_INIT_DMEM_CFG_STRUCT \ + (1 * SIZE_OF_IA_CSS_PTR) + \ + (4 * sizeof(uint32_t)) + \ + (1 * sizeof(sp_ID_t)) + +#endif /* __IA_CSS_SPCTRL_COMM_H__ */ diff --git a/drivers/staging/media/atomisp/pci/runtime/spctrl/src/spctrl.c b/drivers/staging/media/atomisp/pci/runtime/spctrl/src/spctrl.c new file mode 100644 index 000000000..c34bfc5f9 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/spctrl/src/spctrl.c @@ -0,0 +1,185 @@ +// 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 "hmm.h" + +#include "ia_css_types.h" +#define __INLINE_SP__ +#include "sp.h" + +#include "assert_support.h" +#include "ia_css_spctrl.h" +#include "ia_css_debug.h" + +struct spctrl_context_info { + struct ia_css_sp_init_dmem_cfg dmem_config; + u32 spctrl_config_dmem_addr; /* location of dmem_cfg in SP dmem */ + u32 spctrl_state_dmem_addr; + unsigned int sp_entry; /* entry function ptr on SP */ + ia_css_ptr code_addr; /* sp firmware location in host mem-DDR*/ + u32 code_size; + char *program_name; /* used in case of PLATFORM_SIM */ +}; + +static struct spctrl_context_info spctrl_cofig_info[N_SP_ID]; +static bool spctrl_loaded[N_SP_ID] = {0}; + +/* Load firmware */ +int ia_css_spctrl_load_fw(sp_ID_t sp_id, ia_css_spctrl_cfg *spctrl_cfg) +{ + ia_css_ptr code_addr = mmgr_NULL; + struct ia_css_sp_init_dmem_cfg *init_dmem_cfg; + + if ((sp_id >= N_SP_ID) || (!spctrl_cfg)) + return -EINVAL; + + spctrl_cofig_info[sp_id].code_addr = mmgr_NULL; + + init_dmem_cfg = &spctrl_cofig_info[sp_id].dmem_config; + init_dmem_cfg->dmem_data_addr = spctrl_cfg->dmem_data_addr; + init_dmem_cfg->dmem_bss_addr = spctrl_cfg->dmem_bss_addr; + init_dmem_cfg->data_size = spctrl_cfg->data_size; + init_dmem_cfg->bss_size = spctrl_cfg->bss_size; + init_dmem_cfg->sp_id = sp_id; + + spctrl_cofig_info[sp_id].spctrl_config_dmem_addr = + spctrl_cfg->spctrl_config_dmem_addr; + spctrl_cofig_info[sp_id].spctrl_state_dmem_addr = + spctrl_cfg->spctrl_state_dmem_addr; + + /* store code (text + icache) and data to DDR + * + * Data used to be stored separately, because of access alignment constraints, + * fix the FW generation instead + */ + code_addr = hmm_alloc(spctrl_cfg->code_size); + if (code_addr == mmgr_NULL) + return -ENOMEM; + hmm_store(code_addr, spctrl_cfg->code, spctrl_cfg->code_size); + + if (sizeof(ia_css_ptr) > sizeof(hrt_data)) { + ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR, + "size of ia_css_ptr can not be greater than hrt_data\n"); + hmm_free(code_addr); + code_addr = mmgr_NULL; + return -EINVAL; + } + + init_dmem_cfg->ddr_data_addr = code_addr + spctrl_cfg->ddr_data_offset; + if ((init_dmem_cfg->ddr_data_addr % HIVE_ISP_DDR_WORD_BYTES) != 0) { + ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR, + "DDR address pointer is not properly aligned for DMA transfer\n"); + hmm_free(code_addr); + code_addr = mmgr_NULL; + return -EINVAL; + } + + spctrl_cofig_info[sp_id].sp_entry = spctrl_cfg->sp_entry; + spctrl_cofig_info[sp_id].code_addr = code_addr; + spctrl_cofig_info[sp_id].program_name = spctrl_cfg->program_name; + + /* now we program the base address into the icache and + * invalidate the cache. + */ + sp_ctrl_store(sp_id, SP_ICACHE_ADDR_REG, + (hrt_data)spctrl_cofig_info[sp_id].code_addr); + sp_ctrl_setbit(sp_id, SP_ICACHE_INV_REG, SP_ICACHE_INV_BIT); + spctrl_loaded[sp_id] = true; + return 0; +} + +/* ISP2401 */ +/* reload pre-loaded FW */ +void sh_css_spctrl_reload_fw(sp_ID_t sp_id) +{ + /* now we program the base address into the icache and + * invalidate the cache. + */ + sp_ctrl_store(sp_id, SP_ICACHE_ADDR_REG, + (hrt_data)spctrl_cofig_info[sp_id].code_addr); + sp_ctrl_setbit(sp_id, SP_ICACHE_INV_REG, SP_ICACHE_INV_BIT); + spctrl_loaded[sp_id] = true; +} + +ia_css_ptr get_sp_code_addr(sp_ID_t sp_id) +{ + return spctrl_cofig_info[sp_id].code_addr; +} + +int ia_css_spctrl_unload_fw(sp_ID_t sp_id) +{ + if ((sp_id >= N_SP_ID) || ((sp_id < N_SP_ID) && (!spctrl_loaded[sp_id]))) + return -EINVAL; + + /* freeup the resource */ + if (spctrl_cofig_info[sp_id].code_addr) { + hmm_free(spctrl_cofig_info[sp_id].code_addr); + spctrl_cofig_info[sp_id].code_addr = mmgr_NULL; + } + spctrl_loaded[sp_id] = false; + return 0; +} + +/* Initialize dmem_cfg in SP dmem and start SP program*/ +int ia_css_spctrl_start(sp_ID_t sp_id) +{ + if ((sp_id >= N_SP_ID) || ((sp_id < N_SP_ID) && (!spctrl_loaded[sp_id]))) + return -EINVAL; + + /* Set descr in the SP to initialize the SP DMEM */ + /* + * The FW stores user-space pointers to the FW, the ISP pointer + * is only available here + * + */ + assert(sizeof(unsigned int) <= sizeof(hrt_data)); + + sp_dmem_store(sp_id, + spctrl_cofig_info[sp_id].spctrl_config_dmem_addr, + &spctrl_cofig_info[sp_id].dmem_config, + sizeof(spctrl_cofig_info[sp_id].dmem_config)); + /* set the start address */ + sp_ctrl_store(sp_id, SP_START_ADDR_REG, + (hrt_data)spctrl_cofig_info[sp_id].sp_entry); + sp_ctrl_setbit(sp_id, SP_SC_REG, SP_RUN_BIT); + sp_ctrl_setbit(sp_id, SP_SC_REG, SP_START_BIT); + return 0; +} + +/* Query the state of SP1 */ +ia_css_spctrl_sp_sw_state ia_css_spctrl_get_state(sp_ID_t sp_id) +{ + ia_css_spctrl_sp_sw_state state = 0; + unsigned int HIVE_ADDR_sp_sw_state; + + if (sp_id >= N_SP_ID) + return IA_CSS_SP_SW_TERMINATED; + + HIVE_ADDR_sp_sw_state = spctrl_cofig_info[sp_id].spctrl_state_dmem_addr; + (void)HIVE_ADDR_sp_sw_state; /* Suppres warnings in CRUN */ + if (sp_id == SP0_ID) + state = sp_dmem_load_uint32(sp_id, (unsigned int)sp_address_of(sp_sw_state)); + return state; +} + +int ia_css_spctrl_is_idle(sp_ID_t sp_id) +{ + int state = 0; + + assert(sp_id < N_SP_ID); + + state = sp_ctrl_getbit(sp_id, SP_SC_REG, SP_IDLE_BIT); + return state; +} diff --git a/drivers/staging/media/atomisp/pci/runtime/tagger/interface/ia_css_tagger_common.h b/drivers/staging/media/atomisp/pci/runtime/tagger/interface/ia_css_tagger_common.h new file mode 100644 index 000000000..49801fbc1 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/tagger/interface/ia_css_tagger_common.h @@ -0,0 +1,40 @@ +/* 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. + */ + +#ifndef __IA_CSS_TAGGER_COMMON_H__ +#define __IA_CSS_TAGGER_COMMON_H__ + +#include <system_local.h> +#include <type_support.h> + +/** + * @brief The tagger's circular buffer. + * + * Should be one less than NUM_CONTINUOUS_FRAMES in sh_css_internal.h + */ +#define MAX_CB_ELEMS_FOR_TAGGER 14 + +/** + * @brief Data structure for the tagger buffer element. + */ +typedef struct { + u32 frame; /* the frame value stored in the element */ + u32 param; /* the param value stored in the element */ + u8 mark; /* the mark on the element */ + u8 lock; /* the lock on the element */ + u8 exp_id; /* exp_id of frame, for debugging only */ +} ia_css_tagger_buf_sp_elem_t; + +#endif /* __IA_CSS_TAGGER_COMMON_H__ */ diff --git a/drivers/staging/media/atomisp/pci/runtime/timer/src/timer.c b/drivers/staging/media/atomisp/pci/runtime/timer/src/timer.c new file mode 100644 index 000000000..08f5c3ea6 --- /dev/null +++ b/drivers/staging/media/atomisp/pci/runtime/timer/src/timer.c @@ -0,0 +1,29 @@ +// 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 <type_support.h> /* for uint32_t */ +#include "ia_css_timer.h" /*struct ia_css_clock_tick */ +#include "sh_css_legacy.h" /* IA_CSS_PIPE_ID_NUM*/ +#include "gp_timer.h" /*gp_timer_read()*/ +#include "assert_support.h" + +int ia_css_timer_get_current_tick(struct ia_css_clock_tick *curr_ts) +{ + assert(curr_ts); + if (!curr_ts) + return -EINVAL; + curr_ts->ticks = (clock_value_t)gp_timer_read(GP_TIMER_SEL); + return 0; +} |