void ia_css_frame_info_set_width(struct ia_css_frame_info *info, unsigned int width, unsigned int min_padded_width) { unsigned int align; assert(info != NULL); ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_frame_info_set_width() enter: " "width=%d, min_padded_width=%d\n", width, min_padded_width); if (min_padded_width > width) align = min_padded_width; else align = 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->padded_width = CEIL_MUL(align, 2 * HIVE_ISP_DDR_WORD_BYTES); else if (info->format == IA_CSS_FRAME_FORMAT_YUV_LINE) info->padded_width = CEIL_MUL(align, 2 * ISP_VEC_NELEMS); 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); } }
static void frame_init_nv_planes(struct ia_css_frame *frame, unsigned int horizontal_decimation, unsigned int vertical_decimation) { unsigned int y_width = frame->info.padded_width, y_height = frame->info.res.height, uv_width = 2 * (y_width / horizontal_decimation), uv_height = y_height / vertical_decimation, y_bytes, uv_bytes; if (IA_CSS_FRAME_FORMAT_NV12_TILEY == frame->info.format) { 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_bytes = y_width * y_height; uv_bytes = uv_width * uv_height; frame->data_bytes = y_bytes + uv_bytes; frame_init_plane(&frame->planes.nv.y, y_width, y_width, y_height, 0); frame_init_plane(&frame->planes.nv.uv, uv_width, uv_width, uv_height, y_bytes); return; }
/* See also: ia_css_dma_configure_from_info() */ static bool calculate_isys2401_dma_port_cfg( const input_system_cfg_t *isys_cfg, bool raw_packed, bool metadata, isys2401_dma_port_cfg_t *cfg) { int32_t bits_per_pixel; int32_t pixels_per_line; int32_t 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 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(USE_INPUT_SYSTEM_VERSION_2401) /* 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 defined(HAS_RES_MGR) (void)dvs_env_width; #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. */ #if !defined(HAS_RES_MGR) /* dvs env is included already */ in_frame_width += dvs_env_width; #endif rval = CEIL_MUL(in_frame_width + (left_cropping ? nr_of_left_paddings : 0), 2*ISP_VEC_NELEMS); } } else { rval = isp_internal_width; } return rval; }
static bool calculate_isys2401_dma_port_cfg( input_system_channel_t *channel, input_system_input_port_t *input_port, input_system_cfg_t *isys_cfg, bool is_compact_mode, isys2401_dma_port_cfg_t *cfg) { const int32_t bits_per_byte = 8; const int32_t bits_per_word = 256; int32_t memory_alignment_in_bytes = 32; int32_t bits_per_pixel; int32_t pixels_per_line; int32_t bytes_per_pixel; int32_t bytes_per_line; int32_t pixels_per_word; int32_t words_per_line; int32_t bytes_per_word; int32_t fmt_type; (void)channel; (void)input_port; bits_per_pixel = isys_cfg->input_port_resolution.bits_per_pixel; pixels_per_line = isys_cfg->input_port_resolution.pixels_per_line; fmt_type = isys_cfg->csi_port_attr.fmt_type; bytes_per_word = bits_per_word / bits_per_byte; if (is_compact_mode) { /* compact as many pixels as possible into a word */ pixels_per_word = bits_per_word / bits_per_pixel; words_per_line = ceil_div(pixels_per_line, pixels_per_word); bytes_per_line = bytes_per_word * words_per_line; } else { /* up-round "bits_per_pixel" to N times of 8-bit */ bytes_per_pixel = ceil_div(bits_per_pixel, bits_per_byte); bits_per_pixel = bytes_per_pixel * bits_per_byte; bytes_per_line = bytes_per_pixel * pixels_per_line; pixels_per_word = bits_per_word / bits_per_pixel; words_per_line = ceil_div(pixels_per_line, pixels_per_word); memory_alignment_in_bytes = calculate_input_system_alignment(fmt_type, bytes_per_pixel); } cfg->stride = CEIL_MUL(bytes_per_line, memory_alignment_in_bytes); cfg->elements = pixels_per_word; cfg->cropping = 0; cfg->width = words_per_line; return true; }
void ia_css_frame_info_set_format(struct ia_css_frame_info *info, enum ia_css_frame_format format) { assert(info != NULL); ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_frame_info_set_format() enter:\n"); /* yuv_line has 2*NWAY alignment */ info->format = format; /* HACK: this resets the padded width incorrectly. Lex needs to fix this in the vf_veceven module. */ info->padded_width = CEIL_MUL(info->padded_width, 2 * ISP_VEC_NELEMS); }
/* See also: ia_css_dma_configure_from_info() */ static int32_t calculate_stride( int32_t bits_per_pixel, int32_t pixels_per_line, bool raw_packed, int32_t align_in_bytes) { int32_t bytes_per_line; int32_t pixels_per_word; int32_t words_per_line; int32_t 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; }
void * sh_css_load_blob(const unsigned char *blob, unsigned size) { void *target_addr = hrt_isp_css_mm_alloc(size); /* this will allocate memory aligned to a DDR word boundary which is required for the CSS DMA to read the instructions. */ hrt_isp_css_mm_store(target_addr, blob, size); if (SH_CSS_PREVENT_UNINIT_READS) { unsigned i; unsigned padded_size = CEIL_MUL(size, HIVE_ISP_DDR_WORD_BYTES); for (i = 0; i < padded_size - size; i++) hrt_isp_css_mm_store_char(target_addr + size + i, 0); } return target_addr; }
hrt_vaddress sh_css_load_blob(const unsigned char *blob, unsigned size) { hrt_vaddress target_addr = mmgr_malloc(size); /* this will allocate memory aligned to a DDR word boundary which is required for the CSS DMA to read the instructions. */ assert(blob != NULL); if (target_addr) { mmgr_store(target_addr, blob, size); #ifdef HRT_CSIM { unsigned padded_size = CEIL_MUL(size, HIVE_ISP_DDR_WORD_BYTES); mmgr_clear(target_addr + size, padded_size - size); } #endif } return target_addr; }
static bool acquire_ib_buffer( int32_t bits_per_pixel, int32_t pixels_per_line, int32_t lines_per_frame, int32_t fmt_type, ib_buffer_t *buf) { const int32_t bits_per_byte = 8; int32_t memory_alignment_in_bytes; int32_t bytes_per_pixel; int32_t bytes_per_line; bytes_per_pixel = ceil_div(bits_per_pixel, bits_per_byte); bytes_per_line = bytes_per_pixel * pixels_per_line; memory_alignment_in_bytes = calculate_input_system_alignment(fmt_type, bytes_per_pixel); buf->stride = CEIL_MUL(bytes_per_line, memory_alignment_in_bytes); buf->lines = 2; /* ISYS2401 hardware can handle at most 4 lines */ (void)(lines_per_frame); return ia_css_isys_ibuf_rmgr_acquire(buf->stride * buf->lines, &buf->start_addr); }
static bool calculate_ibuf_ctrl_cfg( const input_system_channel_t *channel, const input_system_input_port_t *input_port, const input_system_cfg_t *isys_cfg, ibuf_ctrl_cfg_t *cfg) { const int32_t bits_per_byte = 8; int32_t bits_per_pixel; int32_t bytes_per_pixel; int32_t 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; /* * [email protected]: * "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; } /* * [email protected]: * "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; }
enum ia_css_err ia_css_binary_fill_info(const struct ia_css_binary_xinfo *xinfo, bool online, bool two_ppc, enum ia_css_stream_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; enum ia_css_err err; unsigned int i; const struct ia_css_frame_info *bin_out_info = NULL; assert(info != NULL); assert(binary != NULL); 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 != IA_CSS_SUCCESS) { 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 != NULL && bin_out_info != NULL) { 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 != NULL) /* { */ 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 != NULL) { 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; #if !defined(HAS_RES_MGR) /* dvs env is included already */ binary->in_frame_info.res.width += dvs_env_width; binary->in_frame_info.res.height += dvs_env_height; #endif 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] != NULL) { 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; } } #ifndef IS_ISP_2500_SYSTEM 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 != IA_CSS_SUCCESS) { if (!accelerator) { ia_css_isp_param_destroy_isp_parameters( &binary->mem_params, &binary->css_params); } return err; } } #else (void)err; #endif binary->vf_downscale_log2 = vf_log_ds; binary->online = online; binary->input_format = stream_format; /* viewfinder output info */ if ((vf_info != NULL) && (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 == NULL) return IA_CSS_ERR_INTERNAL_ERROR; 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 {
void prepare_shading_table(const struct ia_css_shading_table *in_table, unsigned int sensor_binning, struct ia_css_shading_table **target_table, const struct ia_css_binary *binary, unsigned int bds_factor) { unsigned int input_width, input_height, table_width, table_height, left_padding, top_padding, padded_width, left_cropping, i; unsigned int bds_numerator, bds_denominator; int right_padding; struct ia_css_shading_table *result; assert(target_table != NULL); assert(binary != NULL); if (!in_table) { sh_css_params_shading_id_table_generate(target_table, binary); return; } padded_width = binary->in_frame_info.padded_width; /* We use the ISP input resolution for the shading table because shading correction is performed in the bayer domain (before bayer down scaling). */ #if defined(USE_INPUT_SYSTEM_VERSION_2401) padded_width = CEIL_MUL(binary->effective_in_frame_res.width + 2*ISP_VEC_NELEMS, 2*ISP_VEC_NELEMS); #endif input_height = binary->in_frame_info.res.height; input_width = binary->in_frame_info.res.width; left_padding = binary->left_padding; left_cropping = (binary->info->sp.pipeline.left_cropping == 0) ? binary->dvs_envelope.width : 2*ISP_VEC_NELEMS; sh_css_bds_factor_get_numerator_denominator (bds_factor, &bds_numerator, &bds_denominator); left_padding = (left_padding + binary->info->sp.pipeline.left_cropping) * bds_numerator / bds_denominator - binary->info->sp.pipeline.left_cropping; right_padding = (binary->internal_frame_info.res.width - binary->effective_in_frame_res.width * bds_denominator / bds_numerator - left_cropping) * bds_numerator / bds_denominator; top_padding = binary->info->sp.pipeline.top_cropping * bds_numerator / bds_denominator - binary->info->sp.pipeline.top_cropping; /* We take into account the binning done by the sensor. We do this by cropping the non-binned part of the shading table and then increasing the size of a grid cell with this same binning factor. */ input_width <<= sensor_binning; input_height <<= sensor_binning; /* We also scale the padding by the same binning factor. This will make it much easier later on to calculate the padding of the shading table. */ left_padding <<= sensor_binning; right_padding <<= sensor_binning; top_padding <<= sensor_binning; /* during simulation, the used resolution can exceed the sensor resolution, so we clip it. */ input_width = min(input_width, in_table->sensor_width); input_height = min(input_height, in_table->sensor_height); table_width = binary->sctbl_width_per_color; table_height = binary->sctbl_height; result = ia_css_shading_table_alloc(table_width, table_height); if (result == NULL) { *target_table = NULL; return; } result->sensor_width = in_table->sensor_width; result->sensor_height = in_table->sensor_height; result->fraction_bits = in_table->fraction_bits; /* now we crop the original shading table and then interpolate to the requested resolution and decimation factor. */ for (i = 0; i < IA_CSS_SC_NUM_COLORS; i++) { crop_and_interpolate(input_width, input_height, left_padding, right_padding, top_padding, in_table, result, i); } *target_table = result; }
enum ia_css_err 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 ia_css_stream_format input_format; enum ia_css_err err = IA_CSS_SUCCESS; uint8_t if_config_index; /* Determine which input formatter config set is targeted. */ /* Index is equal to the CSI-2 port used. */ enum ia_css_csi2_port port; assert(binary != NULL); 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.mode != IA_CSS_BINARY_MODE_COPY) buffer_width = MAX_VECTORS_PER_INPUT_LINE_CONT * ISP_VEC_NELEMS; else buffer_width = binary->info->sp.max_input_width; input_format = binary->input_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 - IA_CSS_CSI2_PORT0); } 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 != IA_CSS_SUCCESS) return err; err = ifmtr_start_column(config, cropped_width, &start_column); if (err != IA_CSS_SUCCESS) return err; if (config->left_padding == -1) 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 IA_CSS_STREAM_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 IA_CSS_STREAM_FORMAT_YUV420_8: case IA_CSS_STREAM_FORMAT_YUV420_10: 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 IA_CSS_STREAM_FORMAT_YUV422_8: case IA_CSS_STREAM_FORMAT_YUV422_10: 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 IA_CSS_STREAM_FORMAT_RGB_444: case IA_CSS_STREAM_FORMAT_RGB_555: case IA_CSS_STREAM_FORMAT_RGB_565: case IA_CSS_STREAM_FORMAT_RGB_666: case IA_CSS_STREAM_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 IA_CSS_STREAM_FORMAT_RAW_6: case IA_CSS_STREAM_FORMAT_RAW_7: case IA_CSS_STREAM_FORMAT_RAW_8: case IA_CSS_STREAM_FORMAT_RAW_10: case IA_CSS_STREAM_FORMAT_RAW_12: if (two_ppc) { vmem_increment = 2; deinterleaving = 1; width_a = width_b = cropped_width / 2; /* When two_ppc is enabled, if_a and if_b gets separate * bayer components. Therefore, it is not possible to * correct the bayer order to GRBG in horizontal direction * by shifting start_column. * Instead, if_a and if_b output (VMEM) addresses should be * swapped for this purpose. */ if ((start_column % 2) == 1) { /* Swap buffer start address */ buf_offset_a = 1; buf_offset_b = 0; } else { buf_offset_a = 0; buf_offset_b = 1; } start_column /= 2; start_column_b = start_column; } else { vmem_increment = 1; deinterleaving = 2; if (config->continuous && binary->info->sp.mode == IA_CSS_BINARY_MODE_COPY) { /* No deinterleaving for sp copy */ deinterleaving = 1; } width_a = cropped_width; /* Must be multiple of deinterleaving */ num_vectors = CEIL_MUL(num_vectors, deinterleaving); } buffer_height *= 2; if (config->continuous) buffer_height *= 2; vectors_per_line = CEIL_DIV(cropped_width, ISP_VEC_NELEMS); vectors_per_line = CEIL_MUL(vectors_per_line, deinterleaving); break; case IA_CSS_STREAM_FORMAT_RAW_14: case IA_CSS_STREAM_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 IA_CSS_STREAM_FORMAT_BINARY_8: case IA_CSS_STREAM_FORMAT_GENERIC_SHORT1: case IA_CSS_STREAM_FORMAT_GENERIC_SHORT2: case IA_CSS_STREAM_FORMAT_GENERIC_SHORT3: case IA_CSS_STREAM_FORMAT_GENERIC_SHORT4: case IA_CSS_STREAM_FORMAT_GENERIC_SHORT5: case IA_CSS_STREAM_FORMAT_GENERIC_SHORT6: case IA_CSS_STREAM_FORMAT_GENERIC_SHORT7: case IA_CSS_STREAM_FORMAT_GENERIC_SHORT8: case IA_CSS_STREAM_FORMAT_YUV420_8_SHIFT: case IA_CSS_STREAM_FORMAT_YUV420_10_SHIFT: case IA_CSS_STREAM_FORMAT_EMBEDDED: case IA_CSS_STREAM_FORMAT_USER_DEF1: case IA_CSS_STREAM_FORMAT_USER_DEF2: case IA_CSS_STREAM_FORMAT_USER_DEF3: case IA_CSS_STREAM_FORMAT_USER_DEF4: case IA_CSS_STREAM_FORMAT_USER_DEF5: case IA_CSS_STREAM_FORMAT_USER_DEF6: case IA_CSS_STREAM_FORMAT_USER_DEF7: case IA_CSS_STREAM_FORMAT_USER_DEF8: break; } if (width_a == 0) return IA_CSS_ERR_INVALID_ARGUMENTS; 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->info->sp.mode == IA_CSS_BINARY_MODE_VIDEO) { /* 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 == IA_CSS_STREAM_FORMAT_YUV420_8) || (input_format == IA_CSS_STREAM_FORMAT_YUV420_10); 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 == IA_CSS_STREAM_FORMAT_YUV420_8 || input_format == IA_CSS_STREAM_FORMAT_YUV420_10; if_b_config.block_no_reqs = (config->mode != IA_CSS_INPUT_MODE_SENSOR); if (SH_CSS_IF_CONFIG_NOT_NEEDED != if_config_index) { 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 (SH_CSS_IF_CONFIG_NOT_NEEDED != if_config_index) { 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 IA_CSS_SUCCESS; }
static void construct_ispstage( struct sh_css_sp_pipeline *pipeline, struct sh_css_isp_stage *isp_stage, ia_css_process_group_t *process_group, ia_css_psys_pgpoc_context_t *context, struct ia_css_binary *binary, struct ia_css_binary_xinfo *binary_xinfo, const struct ia_css_pg_param *params, struct ia_css_frame **delay_frames, struct ia_css_frame **tnr_frames) { struct sh_css_isp_stage *this_isp_stage = isp_stage; struct ia_css_isp_param_css_segments mem_if; struct ia_css_frame_info effective_in_info; const struct ia_css_frame_info *ptr_out_info[IA_CSS_BINARY_MAX_OUTPUT_PORTS], *vf_info, *bds_info; struct ia_css_frame_info *allocated_in_info, *out_info, *out_vf_info; struct ia_css_frame_info ref_info, tnr_info; enum ia_css_stream_format stream_format = 0; struct ia_css_resolution dvs_env; bool two_ppc = true, deinterleaved = false; enum ia_css_err err; uint32_t i = 0; ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "construct_ispstage(): enter\n"); assert(this_isp_stage != NULL); assert(process_group != NULL && context != NULL); assert(binary != NULL); assert(binary_xinfo != NULL); assert(params != NULL); allocated_in_info = &context->allocated_in_info; out_info = &context->out_info; out_vf_info = &context->out_vf_info; vf_info = NULL; bds_info = NULL; this_isp_stage->blob_info = binary_xinfo->blob->header.blob; this_isp_stage->binary_info = binary_xinfo->sp; if(binary_xinfo->blob->name) { memcpy(this_isp_stage->binary_name, binary_xinfo->blob->name, strlen(binary_xinfo->blob->name)+1); } /* TODO Move this to user space? */ memset(&mem_if, 0, sizeof(struct ia_css_isp_param_css_segments)); dvs_env.width = params->dvs_envelope[IA_CSS_COL_DIMENSION]; dvs_env.height = params->dvs_envelope[IA_CSS_ROW_DIMENSION]; effective_in_info = *allocated_in_info; if ( allocated_in_info->format == IA_CSS_FRAME_FORMAT_RAW ) { /*CSS expects raw buffers size less by left/top cropping*/ effective_in_info.res.width -= (binary_xinfo->sp.pipeline.left_cropping + dvs_env.width); effective_in_info.res.height -= (binary_xinfo->sp.pipeline.top_cropping + dvs_env.height); effective_in_info.padded_width = CEIL_MUL(effective_in_info.res.width, 2 * ISP_VEC_NELEMS); /* Binary cropping requirement is known to be 12. * Assert if it changes */ assert(binary_xinfo->sp.pipeline.left_cropping+dvs_env.width==12); assert(binary_xinfo->sp.pipeline.top_cropping+dvs_env.height==12); } ptr_out_info[i] = out_info; for (i = 1; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) { ptr_out_info[i] = NULL; } stream_format = get_stream_format(allocated_in_info); /* TODO: Fix this for other binaries */ if ((binary_xinfo->sp.pipeline.mode == IA_CSS_BINARY_MODE_PREVIEW) || (binary_xinfo->sp.pipeline.mode == IA_CSS_BINARY_MODE_VIDEO)) { vf_info = ptr_out_info[0]; /* assuming raw_binning is false */ bds_info = &effective_in_info; } else if (binary_xinfo->sp.pipeline.mode == IA_CSS_BINARY_MODE_PRIMARY) { vf_info = out_vf_info; assert(context->enable_vf_output); } /* destroy any existing isp_param structures, just in case */ ia_css_binary_destroy_isp_parameters(binary); /* isp params are allocated here. We only need * ia_css_isp_param_allocate_isp_parameters but some of the isp host * configure functions take a binary, so we might as well use it. */ err = ia_css_binary_fill_info(binary_xinfo, false, two_ppc, stream_format, &effective_in_info, bds_info, ptr_out_info, vf_info, binary, &dvs_env, -1, false); assert(err == IA_CSS_SUCCESS); ia_css_init_memory_interface(&mem_if, &binary->mem_params, &binary->css_params); /* Configure ISP via ISP specific host side functions. TODO: Add other host configure's here. */ ia_css_fpn_configure (binary, &binary->in_frame_info); ia_css_output0_configure(binary, out_info); ia_css_output1_configure(binary, out_vf_info); ia_css_copy_output_configure(binary, params->copy_output); ia_css_output0_configure(binary, out_info); ia_css_iterator_configure (binary, allocated_in_info); ia_css_output_configure(binary, out_info); ia_css_raw_configure(pipeline, binary, allocated_in_info, &binary->in_frame_info, two_ppc, deinterleaved); ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "construct_ispstage(): init state configuration\n"); if (binary_xinfo->sp.pipeline.mode == IA_CSS_BINARY_MODE_VIDEO) { ref_info = binary->internal_frame_info; ref_info.format = IA_CSS_FRAME_FORMAT_YUV420; ref_info.raw_bit_depth = SH_CSS_REF_BIT_DEPTH; for (i = 0; i < NUM_VIDEO_DELAY_FRAMES ; i++){ if (delay_frames[i]) { ia_css_frame_free(delay_frames[i]); delay_frames[i] = NULL; } ia_css_frame_allocate_from_info( &delay_frames[i], &ref_info); #ifdef HRT_CSIM ia_css_frame_zero(delay_frames[i]); #endif } ia_css_ref_configure (binary, (const struct ia_css_frame **)delay_frames, pipeline->dvs_frame_delay); if (binary_xinfo->sp.enable.block_output){ tnr_info = binary->out_frame_info[0]; /* Make tnr reference buffers output block height align */ tnr_info.res.height = CEIL_MUL(tnr_info.res.height, binary_xinfo->sp.block.output_block_height); } else { tnr_info = binary->internal_frame_info; } tnr_info.format = IA_CSS_FRAME_FORMAT_YUV_LINE; tnr_info.raw_bit_depth = SH_CSS_TNR_BIT_DEPTH; for (i = 0; i < NUM_VIDEO_TNR_FRAMES; i++) { if (tnr_frames[i]) { ia_css_frame_free(tnr_frames[i]); tnr_frames[i] = NULL; } ia_css_frame_allocate_from_info( &tnr_frames[i], &tnr_info); #ifdef HRT_CSIM ia_css_frame_zero(tnr_frames[i]); #endif } ia_css_tnr_configure(binary, (const struct ia_css_frame **)tnr_frames); } for (i = 0; i < IA_CSS_NUM_STATE_IDS; i++) { ia_css_kernel_init_state[i](binary); } ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "construct_ispstage(): commit config and state to iunit address\n"); err = ia_css_isp_param_copy_isp_mem_if_to_ddr( &binary->css_params, &binary->mem_params, IA_CSS_PARAM_CLASS_CONFIG); assert(err == IA_CSS_SUCCESS); err = ia_css_isp_param_copy_isp_mem_if_to_ddr( &binary->css_params, &binary->mem_params, IA_CSS_PARAM_CLASS_STATE); assert(err == IA_CSS_SUCCESS); this_isp_stage->mem_initializers = mem_if; ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "construct_ispstage(): exit\n"); return; }