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;
}
Example #8
0
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;
}