linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 04/12] intel-ipu3: Add user space ABI definitions
@ 2017-10-18  3:54 Yong Zhi
  2017-10-18  3:54 ` [PATCH v4 06/12] intel-ipu3: css: imgu dma buff pool Yong Zhi
                   ` (6 more replies)
  0 siblings, 7 replies; 19+ messages in thread
From: Yong Zhi @ 2017-10-18  3:54 UTC (permalink / raw)
  To: linux-media, sakari.ailus
  Cc: jian.xu.zheng, rajmohan.mani, tuukka.toivonen, jerry.w.hu, Yong Zhi

The UAPI header defines the structures and macros
to be used by user space.

Signed-off-by: Rajmohan Mani <rajmohan.mani@intel.com>
Signed-off-by: Yong Zhi <yong.zhi@intel.com>
---
 include/uapi/linux/intel-ipu3.h | 2199 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 2199 insertions(+)
 create mode 100644 include/uapi/linux/intel-ipu3.h

diff --git a/include/uapi/linux/intel-ipu3.h b/include/uapi/linux/intel-ipu3.h
new file mode 100644
index 000000000000..e27a449b4ec1
--- /dev/null
+++ b/include/uapi/linux/intel-ipu3.h
@@ -0,0 +1,2199 @@
+/*
+ * Copyright (c) 2017 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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 __IPU3_UAPI_H
+#define __IPU3_UAPI_H
+
+#include <linux/types.h>
+
+#define IPU3_UAPI_ISP_VEC_ELEMS				64
+
+#define IMGU_ABI_PAD	__aligned(IPU3_UAPI_ISP_WORD_BYTES)
+#define IPU3_ALIGN	__attribute__((aligned(IPU3_UAPI_ISP_WORD_BYTES)))
+
+#define IPU3_UAPI_ISP_WORD_BYTES			32
+#define IPU3_UAPI_MAX_STRIPES				2
+
+/******************* ipu3_uapi_stats_3a *******************/
+
+#define IPU3_UAPI_MAX_BUBBLE_SIZE			10
+
+#define IPU3_UAPI_AE_COLORS				4
+#define IPU3_UAPI_AE_BINS				256
+
+#define IPU3_UAPI_AWB_MD_ITEM_SIZE			8
+#define IPU3_UAPI_AWB_MAX_SETS				60
+#define IPU3_UAPI_AWB_SET_SIZE				0x500
+#define IPU3_UAPI_AWB_SPARE_FOR_BUBBLES \
+		(IPU3_UAPI_MAX_BUBBLE_SIZE * IPU3_UAPI_MAX_STRIPES * \
+		 IPU3_UAPI_AWB_MD_ITEM_SIZE)
+#define IPU3_UAPI_AWB_MAX_BUFFER_SIZE \
+		(IPU3_UAPI_AWB_MAX_SETS * \
+		 (IPU3_UAPI_AWB_SET_SIZE + IPU3_UAPI_AWB_SPARE_FOR_BUBBLES))
+
+#define IPU3_UAPI_AF_MAX_SETS				24
+#define IPU3_UAPI_AF_MD_ITEM_SIZE			4
+#define IPU3_UAPI_AF_SPARE_FOR_BUBBLES \
+		(IPU3_UAPI_MAX_BUBBLE_SIZE * IPU3_UAPI_MAX_STRIPES * \
+		 IPU3_UAPI_AF_MD_ITEM_SIZE)
+#define IPU3_UAPI_AF_Y_TABLE_SET_SIZE			0x80
+#define IPU3_UAPI_AF_Y_TABLE_MAX_SIZE \
+	(IPU3_UAPI_AF_MAX_SETS * \
+	 (IPU3_UAPI_AF_Y_TABLE_SET_SIZE + IPU3_UAPI_AF_SPARE_FOR_BUBBLES) * \
+	 IPU3_UAPI_MAX_STRIPES)
+
+#define IPU3_UAPI_AWB_FR_MAX_SETS			24
+#define IPU3_UAPI_AWB_FR_MD_ITEM_SIZE			8
+#define IPU3_UAPI_AWB_FR_BAYER_TBL_SIZE			0x100
+#define IPU3_UAPI_AWB_FR_SPARE_FOR_BUBBLES \
+		(IPU3_UAPI_MAX_BUBBLE_SIZE * IPU3_UAPI_MAX_STRIPES * \
+		IPU3_UAPI_AWB_FR_MD_ITEM_SIZE)
+#define IPU3_UAPI_AWB_FR_BAYER_TABLE_MAX_SIZE \
+	(IPU3_UAPI_AWB_FR_MAX_SETS * \
+	(IPU3_UAPI_AWB_FR_BAYER_TBL_SIZE + \
+	 IPU3_UAPI_AWB_FR_SPARE_FOR_BUBBLES) * \
+	IPU3_UAPI_MAX_STRIPES)
+
+struct ipu3_uapi_grid_config {
+	__u8 width;				/* 6 or 7 (rgbs_grd_cfg) bits */
+	__u8 height;
+	__u16 block_width_log2:3;
+	__u16 block_height_log2:3;
+	__u16 height_per_slice:8;			/* default value 1 */
+	__u16 x_start;					/* 12 bits */
+	__u16 y_start;
+#define IPU3_UAPI_GRID_START_MASK			((1 << 12) - 1)
+#define IPU3_UAPI_GRID_Y_START_EN			(1 << 15)
+	__u16 x_end;					/* 12 bits */
+	__u16 y_end;
+} __packed;
+
+struct ipu3_uapi_awb_meta_data {
+	__u8 meta_data_buffer[IPU3_UAPI_AWB_MAX_BUFFER_SIZE];
+} __packed;
+
+struct ipu3_uapi_awb_raw_buffer {
+	struct ipu3_uapi_awb_meta_data meta_data;
+} __packed;
+
+struct IPU3_ALIGN ipu3_uapi_awb_config_s {
+	__u16 rgbs_thr_gr;
+	__u16 rgbs_thr_r;
+	__u16 rgbs_thr_gb;
+	__u16 rgbs_thr_b;
+/* controls generation of meta_data (like FF enable/disable) */
+#define IPU3_UAPI_AWB_RGBS_THR_B_EN		(1 << 14)
+#define IPU3_UAPI_AWB_RGBS_THR_B_INCL_SAT	(1 << 15)
+
+	struct ipu3_uapi_grid_config grid;
+} __packed;
+
+struct ipu3_uapi_ae_raw_buffer {
+	__u32 vals[IPU3_UAPI_AE_BINS * IPU3_UAPI_AE_COLORS];
+} __packed;
+
+struct ipu3_uapi_ae_raw_buffer_aligned {
+	struct ipu3_uapi_ae_raw_buffer buff IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_ae_grid_config {
+	__u8 width;
+	__u8 height;
+	__u8 block_width_log2:4;
+	__u8 block_height_log2:4;
+	__u8 __reserved0:5;
+	__u8 ae_en:1;
+	__u8 rst_hist_array:1;
+	__u8 done_rst_hist_array:1;
+	__u16 x_start;			/* 12 bits */
+	__u16 y_start;
+	__u16 x_end;
+	__u16 y_end;
+} __packed;
+
+struct ipu3_uapi_af_filter_config {
+	struct {
+		__u8 a1;
+		__u8 a2;
+		__u8 a3;
+		__u8 a4;
+	} y1_coeff_0;
+	struct {
+		__u8 a5;
+		__u8 a6;
+		__u8 a7;
+		__u8 a8;
+	} y1_coeff_1;
+	struct {
+		__u8 a9;
+		__u8 a10;
+		__u8 a11;
+		__u8 a12;
+	} y1_coeff_2;
+
+	__u32 y1_sign_vec;
+
+	struct {
+		__u8 a1;
+		__u8 a2;
+		__u8 a3;
+		__u8 a4;
+	} y2_coeff_0;
+	struct {
+		__u8 a5;
+		__u8 a6;
+		__u8 a7;
+		__u8 a8;
+	} y2_coeff_1;
+	struct {
+		__u8 a9;
+		__u8 a10;
+		__u8 a11;
+		__u8 a12;
+	} y2_coeff_2;
+
+	__u32 y2_sign_vec;
+
+	struct {
+		__u8 y_gen_rate_gr;	/* 6 bits */
+		__u8 y_gen_rate_r;
+		__u8 y_gen_rate_b;
+		__u8 y_gen_rate_gb;
+	} y_calc;
+
+	struct {
+		__u32 __reserved0:8;
+		__u32 y1_nf:4;
+		__u32 __reserved1:4;
+		__u32 y2_nf:4;
+		__u32 __reserved2:12;
+	} nf;
+} __packed;
+
+struct ipu3_uapi_af_meta_data {
+	__u8 y_table[IPU3_UAPI_AF_Y_TABLE_MAX_SIZE] IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_af_raw_buffer {
+	struct ipu3_uapi_af_meta_data meta_data IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_af_frame_size {
+	__u16 width;
+	__u16 height;
+} __packed;
+
+struct ipu3_uapi_af_config_s {
+	struct ipu3_uapi_af_filter_config filter_config IPU3_ALIGN;
+	struct ipu3_uapi_af_frame_size frame_size;
+	struct ipu3_uapi_grid_config grid_cfg IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_awb_fr_meta_data {
+	__u8 bayer_table[IPU3_UAPI_AWB_FR_BAYER_TABLE_MAX_SIZE] IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_awb_fr_raw_buffer {
+	struct ipu3_uapi_awb_fr_meta_data meta_data;
+} __packed;
+
+struct IPU3_ALIGN ipu3_uapi_awb_fr_config_s {
+	struct ipu3_uapi_grid_config grid_cfg;
+	__u8 bayer_coeff[6];
+	__u16 __reserved1;
+	__u32 bayer_sign;		/* 11 bits */
+	__u8 bayer_nf;			/* 4 bits */
+	__u8 __reserved2[3];
+} __packed;
+
+struct ipu3_uapi_4a_config {
+	struct ipu3_uapi_awb_config_s awb_config IPU3_ALIGN;
+	struct ipu3_uapi_ae_grid_config ae_grd_config IPU3_ALIGN;
+	__u8 padding[20];
+	struct ipu3_uapi_af_config_s af_config IPU3_ALIGN;
+	struct ipu3_uapi_awb_fr_config_s awb_fr_config IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_bubble_info {
+	__u32 num_of_stripes IPU3_ALIGN;
+	__u8 padding[28];
+	__u32 num_sets IPU3_ALIGN;
+	__u8 padding1[28];
+	__u32 size_of_set IPU3_ALIGN;
+	__u8 padding2[28];
+	__u32 bubble_size IPU3_ALIGN;
+	__u8 padding3[28];
+} __packed;
+
+struct ipu3_uapi_stats_3a_bubble_info_per_stripe {
+	struct ipu3_uapi_bubble_info awb[IPU3_UAPI_MAX_STRIPES];
+	struct ipu3_uapi_bubble_info af[IPU3_UAPI_MAX_STRIPES];
+	struct ipu3_uapi_bubble_info awb_fr[IPU3_UAPI_MAX_STRIPES];
+} __packed;
+
+struct ipu3_uapi_ff_status {
+	__u32 awb_en IPU3_ALIGN;
+	__u8 padding[28];
+	__u32 ae_en IPU3_ALIGN;
+	__u8 padding1[28];
+	__u32 af_en IPU3_ALIGN;
+	__u8 padding2[28];
+	__u32 awb_fr_en IPU3_ALIGN;
+	__u8 padding3[28];
+} __packed;
+
+struct ipu3_uapi_stats_3a {
+	struct ipu3_uapi_awb_raw_buffer awb_raw_buffer IPU3_ALIGN;
+	struct ipu3_uapi_ae_raw_buffer_aligned
+			ae_raw_buffer[IPU3_UAPI_MAX_STRIPES] IPU3_ALIGN;
+	struct ipu3_uapi_af_raw_buffer af_raw_buffer IPU3_ALIGN;
+	struct ipu3_uapi_awb_fr_raw_buffer awb_fr_raw_buffer IPU3_ALIGN;
+	struct ipu3_uapi_4a_config stats_4a_config IPU3_ALIGN;
+	__u32 ae_join_buffers IPU3_ALIGN;
+	__u8 padding[28];
+	struct ipu3_uapi_stats_3a_bubble_info_per_stripe
+			stats_3a_bubble_per_stripe IPU3_ALIGN;
+	struct ipu3_uapi_ff_status stats_3a_status IPU3_ALIGN;
+} __packed;
+
+/******************* ipu3_uapi_stats_dvs *******************/
+
+#define IPU3_UAPI_DVS_STAT_LEVELS			3
+#define IPU3_UAPI_DVS_STAT_L0_MV_VEC_PER_SET		12
+#define IPU3_UAPI_DVS_STAT_L1_MV_VEC_PER_SET		11
+#define IPU3_UAPI_DVS_STAT_L2_MV_VEC_PER_SET		9
+#define IPU3_UAPI_DVS_STAT_STRIPE_ALIGN_GAP		IPU3_UAPI_MAX_STRIPES
+#define IPU3_UAPI_DVS_STAT_MAX_VERTICAL_FEATURES		16
+
+struct ipu3_uapi_dvs_stat_mv {
+	__u16 vec_fe_x_pos;		/* 12 bits */
+	__u16 vec_fe_y_pos;
+	__u16 vec_fm_x_pos;		/* 12 bits */
+	__u16 vec_fm_y_pos;
+	__u32 harris_grade;		/* 28 bits */
+	__u16 match_grade;		/* 15 bits */
+	__u16 level;			/* 3 bits */
+} __packed;
+
+struct ipu3_uapi_dvs_stat_mv_single_set_l0 {
+	struct ipu3_uapi_dvs_stat_mv
+		mv_entry[IPU3_UAPI_DVS_STAT_L0_MV_VEC_PER_SET +
+		IPU3_UAPI_DVS_STAT_STRIPE_ALIGN_GAP] IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_dvs_stat_mv_single_set_l1 {
+	struct ipu3_uapi_dvs_stat_mv
+		mv_entry[IPU3_UAPI_DVS_STAT_L1_MV_VEC_PER_SET +
+		IPU3_UAPI_DVS_STAT_STRIPE_ALIGN_GAP] IPU3_ALIGN;
+	__u8 padding[16];
+} __packed;
+
+struct ipu3_uapi_dvs_stat_mv_single_set_l2 {
+	struct ipu3_uapi_dvs_stat_mv
+		mv_entry[IPU3_UAPI_DVS_STAT_L2_MV_VEC_PER_SET +
+		IPU3_UAPI_DVS_STAT_STRIPE_ALIGN_GAP] IPU3_ALIGN;
+	__u8 padding[16];
+} __packed;
+
+struct ipu3_uapi_dvs_stat_motion_vec {
+	struct ipu3_uapi_dvs_stat_mv_single_set_l0
+		dvs_mv_output_l0[IPU3_UAPI_DVS_STAT_MAX_VERTICAL_FEATURES]
+		IPU3_ALIGN;
+	struct ipu3_uapi_dvs_stat_mv_single_set_l1
+		dvs_mv_output_l1[IPU3_UAPI_DVS_STAT_MAX_VERTICAL_FEATURES]
+		IPU3_ALIGN;
+	struct ipu3_uapi_dvs_stat_mv_single_set_l2
+		dvs_mv_output_l2[IPU3_UAPI_DVS_STAT_MAX_VERTICAL_FEATURES]
+		IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_dvs_stat_stripe_data {
+	__u8 grid_width[IPU3_UAPI_MAX_STRIPES][IPU3_UAPI_DVS_STAT_LEVELS];
+	__u16 stripe_offset;
+} __packed;
+
+struct ipu3_uapi_dvs_stat_gbl_config {
+	__u8 kappa;					/* 4 bits */
+	__u8 match_shift:4;
+	__u8 ybin_mode:1;
+	__u16 __reserved1;
+} __packed;
+
+struct ipu3_uapi_dvs_stat_grd_config {
+	__u8 grid_width;				/* 5 bits */
+	__u8 grid_height;
+	__u8 block_width;				/* 8 bits */
+	__u8 block_height;
+	__u16 x_start;					/* 12 bits */
+	__u16 y_start;
+	__u16 enable;
+	__u16 x_end;					/* 12 bits */
+	__u16 y_end;
+} __packed;
+
+struct ipu3_uapi_dvs_stat_fe_roi_cfg {
+	__u8 x_start;
+	__u8 y_start;
+	__u8 x_end;
+	__u8 y_end;
+} __packed;
+
+struct ipu3_uapi_dvs_stat_cfg {
+	struct ipu3_uapi_dvs_stat_gbl_config gbl_cfg;
+	struct ipu3_uapi_dvs_stat_grd_config
+					grd_config[IPU3_UAPI_DVS_STAT_LEVELS];
+	struct ipu3_uapi_dvs_stat_fe_roi_cfg
+					fe_roi_cfg[IPU3_UAPI_DVS_STAT_LEVELS];
+	__u8 __reserved[IPU3_UAPI_ISP_WORD_BYTES -
+		 (sizeof(struct ipu3_uapi_dvs_stat_gbl_config) +
+		  (sizeof(struct ipu3_uapi_dvs_stat_grd_config) +
+		   sizeof(struct ipu3_uapi_dvs_stat_fe_roi_cfg)) *
+		  IPU3_UAPI_DVS_STAT_LEVELS) % IPU3_UAPI_ISP_WORD_BYTES];
+} __packed;
+
+struct ipu3_uapi_stats_dvs {
+	struct ipu3_uapi_dvs_stat_motion_vec motion_vec IPU3_ALIGN;
+	struct ipu3_uapi_dvs_stat_cfg cfg IPU3_ALIGN;
+	struct ipu3_uapi_dvs_stat_stripe_data stripe_data IPU3_ALIGN;
+} __packed;
+
+/******************* ipu3_uapi_stats_lace *******************/
+
+#define IPU3_UAPI_LACE_STAT_REGS_PER_SET		320
+#define IPU3_UAPI_LACE_STAT_MAX_OPERATIONS		41
+
+struct ipu3_uapi_lace_stat_stats_regs {
+	__u8 bin[4];					/* the bins 0-3 */
+} __packed;
+
+struct ipu3_uapi_lace_stat_hist_single_set {
+	struct ipu3_uapi_lace_stat_stats_regs
+		lace_hist_set[IPU3_UAPI_LACE_STAT_REGS_PER_SET] IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_lace_stat_hist_vec {
+	struct ipu3_uapi_lace_stat_hist_single_set
+	       lace_hist_output[IPU3_UAPI_LACE_STAT_MAX_OPERATIONS] IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_lace_stat_gbl_cfg {
+	__u32 lh_mode:3;
+	__u32 __reserved:3;
+	__u32 y_ds_mode:2;
+	__u32 uv_ds_mode_unsupported:1;
+	__u32 uv_input_unsupported:1;
+	__u32 __reserved1:10;
+	__u32 rst_loc_hist:1;
+	__u32 done_rst_loc_hist:1;
+	__u32 __reserved2:10;
+} __packed;
+
+struct ipu3_uapi_lace_stat_y_grd_hor_cfg {
+	__u32 grid_width:6;
+	__u32 __reserved:10;
+	__u32 block_width:4;
+	__u32 __reserved1:12;
+} __packed;
+
+struct ipu3_uapi_lace_stat_y_grd_hor_roi {
+	__u32 x_start:12;
+	__u32 __reserved:4;
+	__u32 x_end:12;
+	__u32 __reserved1:4;
+} __packed;
+
+struct ipu3_uapi_lace_stat_uv_grd_hor_cfg {
+	__u32 not_supported;
+} __packed;
+
+struct ipu3_uapi_lace_stat_uv_grd_hor_roi {
+	__u32 not_supported;
+} __packed;
+
+struct ipu3_uapi_lace_stat_grd_vrt_cfg {
+	__u32 __reserved:8;
+	__u32 grid_h:6;
+	__u32 __reserved1:6;
+	__u32 block_h:4;
+	__u32 grid_h_per_slice:7;
+	__u32 __reserved2:1;
+} __packed;
+
+struct ipu3_uapi_lace_stat_grd_vrt_roi {
+	__u32 y_start:12;
+	__u32 __reserved:4;
+	__u32 y_end:12;
+	__u32 __reserved1:4;
+} __packed;
+
+struct ipu3_uapi_lace_stat_cfg {
+	struct ipu3_uapi_lace_stat_gbl_cfg lace_stat_gbl_cfg;
+	struct ipu3_uapi_lace_stat_y_grd_hor_cfg lace_stat_y_grd_hor_cfg;
+	struct ipu3_uapi_lace_stat_y_grd_hor_roi lace_stat_y_grd_hor_roi;
+	struct ipu3_uapi_lace_stat_uv_grd_hor_cfg lace_stat_uv_grd_hor_cfg;
+	struct ipu3_uapi_lace_stat_uv_grd_hor_roi lace_stat_uv_grd_hor_roi;
+	struct ipu3_uapi_lace_stat_grd_vrt_cfg lace_stat_grd_vrt_cfg;
+	struct ipu3_uapi_lace_stat_grd_vrt_roi lace_stat_grd_vrt_roi;
+} __packed;
+
+struct ipu3_uapi_stats_lace {
+	struct ipu3_uapi_lace_stat_hist_vec lace_hist_vec IPU3_ALIGN;
+	struct ipu3_uapi_lace_stat_cfg lace_stat_cfg IPU3_ALIGN;
+	__u8 padding[4];
+} __packed;
+
+/******************* ipu3_uapi_acc_param *******************/
+
+#define IPU3_UAPI_BNR_LUT_SIZE				32
+
+/* number of elements in gamma correction LUT */
+#define IPU3_UAPI_GAMMA_CORR_LUT_ENTRIES		256
+
+#define IPU3_UAPI_SHD_MAX_OPERATIONS \
+		(IPU3_UAPI_SHD_MAX_PROCESS_LINES + IPU3_UAPI_SHD_MAX_TRANSFERS)
+#define IPU3_UAPI_SHD_MAX_PROCESS_LINES			31
+#define IPU3_UAPI_SHD_MAX_TRANSFERS			31
+#define IPU3_UAPI_SHD_MAX_CELLS_PER_SET			146
+/* largest grid is 73x56 */
+#define IPU3_UAPI_SHD_MAX_CFG_SETS			28
+
+#define IPU3_UAPI_DVS_STAT_L0_MD_ENTRIES		84
+#define IPU3_UAPI_DVS_STAT_PARTS_IN_MD_ENTRY		10
+#define IPU3_UAPI_DVS_STAT_L1_MD_ENTRIES		66
+#define IPU3_UAPI_DVS_STAT_L2_MD_ENTRIES		45
+#define IPU3_UAPI_DVS_STAT_MAX_OPERATIONS		100
+#define IPU3_UAPI_DVS_STAT_MAX_PROCESS_LINES		52
+#define IPU3_UAPI_DVS_STAT_MAX_TRANSFERS		52
+
+#define IPU3_UAPI_YUVP2_YTM_LUT_ENTRIES			256
+#define IPU3_UAPI_YUVP2_TCC_MACC_TABLE_ELEMENTS		16
+#define IPU3_UAPI_YUVP2_TCC_INV_Y_LUT_ELEMENTS		14
+#define IPU3_UAPI_YUVP2_TCC_GAIN_PCWL_LUT_ELEMENTS	258
+#define IPU3_UAPI_YUVP2_TCC_R_SQR_LUT_ELEMENTS		24
+
+#define IPU3_UAPI_DPC_COMMANDS_PER_TRANSFER		2
+#define IPU3_UAPI_DPC_MAX_SUPPORTED_HEIGHT		3840
+#define IPU3_UAPI_DPC_STRIPE_SIZE			50
+#define IPU3_UAPI_DPC_MAX_OPERATIONS \
+	(IPU3_UAPI_DPC_COMMANDS_PER_TRANSFER * IPU3_UAPI_DPC_MAX_CFG_SETS)
+#define IPU3_UAPI_DPC_MAX_PROCESS_LINES		IPU3_UAPI_DPC_MAX_CFG_SETS
+#define IPU3_UAPI_DPC_MAX_TRANSFERS		IPU3_UAPI_DPC_MAX_CFG_SETS
+#define IPU3_UAPI_DPC_MAX_DP_FIRST_LINES_PAIR		70
+#define IPU3_UAPI_DPC_MAX_DP_PER_SET			192
+#define IPU3_UAPI_DPC_MAX_CFG_SETS \
+	((IPU3_UAPI_DPC_MAX_SUPPORTED_HEIGHT + IPU3_UAPI_DPC_STRIPE_SIZE - 1) \
+	/ IPU3_UAPI_DPC_STRIPE_SIZE)
+
+#define IPU3_UAPI_BDS_SAMPLE_PATTERN_ARRAY_SIZE		8
+#define IPU3_UAPI_BDS_PHASE_COEFFS_ARRAY_SIZE		32
+
+#define IPU3_UAPI_ANR_LUT_SIZE				26
+#define IPU3_UAPI_ANR_PYRAMID_SIZE			22
+
+#define IPU3_UAPI_AWB_FR_MAX_TRANSFERS			30
+#define IPU3_UAPI_AWB_FR_MAX_PROCESS_LINES		30
+#define IPU3_UAPI_AWB_FR_MAX_OPERATIONS \
+	(IPU3_UAPI_AWB_FR_MAX_TRANSFERS + IPU3_UAPI_AWB_FR_MAX_PROCESS_LINES)
+
+#define IPU3_UAPI_AE_WEIGHTS				96
+
+#define IPU3_UAPI_AF_MAX_TRANSFERS			30
+#define IPU3_UAPI_AF_MAX_PROCESS_LINES			30
+#define IPU3_UAPI_AF_MAX_OPERATIONS \
+		(IPU3_UAPI_AF_MAX_TRANSFERS + IPU3_UAPI_AF_MAX_PROCESS_LINES)
+
+#define IPU3_UAPI_AWB_MAX_PROCESS_LINES			68
+#define IPU3_UAPI_AWB_MAX_TRANSFERS			68
+#define IPU3_UAPI_AWB_MAX_OPERATIONS \
+		(IPU3_UAPI_AWB_MAX_PROCESS_LINES + IPU3_UAPI_AWB_MAX_TRANSFERS)
+
+#define IPU3_UAPI_OSYS_PIN_VF				0
+#define IPU3_UAPI_OSYS_PIN_OUT				1
+#define IPU3_UAPI_OSYS_PINS				2
+
+typedef __u32 imgu_addr_t;
+
+struct ipu3_uapi_stripe_input_frame_resolution {
+	__u16 width;
+	__u16 height;
+	__u32 bayer_order;		/* enum ipu3_uapi_bayer_order */
+	__u32 raw_bit_depth;
+} __packed;
+
+struct ipu3_uapi_acc_operation {
+	/*
+	 * zero means on init,
+	 * others mean upon receiving an ack signal from the BC acc.
+	 */
+	__u8 op_indicator;
+	__u8 op_type;
+} __packed;
+
+struct ipu3_uapi_acc_process_lines_cmd_data {
+	__u16 lines;
+	__u8 cfg_set;
+	__u8 __reserved;		/* Align to 4 bytes */
+} __packed;
+
+struct ipu3_uapi_stripes {
+	/* offset from start of frame - measured in pixels */
+	__u16 offset;
+	/* stripe width - measured in pixels */
+	__u16 width;
+	/* stripe width - measured in pixels */
+	__u16 height;
+} __packed;
+
+struct ipu3_uapi_stripe_data {
+	/*
+	 * number of stripes for current processing source
+	 * - VLIW binary parameter we currently support 1 or 2 stripes
+	 */
+	__u16 num_of_stripes;
+
+	__u8 padding[2];
+
+	/*
+	 * the following data is derived from resolution-related
+	 * pipe config and from num_of_stripes
+	 */
+
+	/*
+	 *'input-stripes' - before input cropping
+	 * used by input feeder
+	 */
+	struct ipu3_uapi_stripe_input_frame_resolution input_frame;
+
+	/*'effective-stripes' - after input cropping used dpc, bds */
+	struct ipu3_uapi_stripes effective_stripes[IPU3_UAPI_MAX_STRIPES];
+
+	/* 'down-scaled-stripes' - after down-scaling ONLY. used by BDS */
+	struct ipu3_uapi_stripes down_scaled_stripes[IPU3_UAPI_MAX_STRIPES];
+
+	/*
+	 *'bds-out-stripes' - after bayer down-scaling and padding.
+	 * used by all algos starting with norm up to the ref-frame for GDC
+	 * (currently up to the output kernel)
+	 */
+	struct ipu3_uapi_stripes bds_out_stripes[IPU3_UAPI_MAX_STRIPES];
+
+	/* 'bds-out-stripes (no overlap)' - used for ref kernel */
+	struct ipu3_uapi_stripes
+			bds_out_stripes_no_overlap[IPU3_UAPI_MAX_STRIPES];
+
+	/*
+	 * input resolution for output system (equal to bds_out - envelope)
+	 * output-system input frame width as configured by user
+	 */
+	__u16 output_system_in_frame_width;
+	/* output-system input frame height as configured by user */
+	__u16 output_system_in_frame_height;
+
+	/*
+	 * 'output-stripes' - accounts for stiching on the output (no overlap)
+	 * used by the output kernel
+	 */
+	struct ipu3_uapi_stripes output_stripes[IPU3_UAPI_MAX_STRIPES];
+
+	/*
+	 * 'block-stripes' - accounts for stiching by the output system
+	 * (1 or more blocks overlap)
+	 * used by DVS, TNR and the output system kernel
+	 */
+	struct ipu3_uapi_stripes block_stripes[IPU3_UAPI_MAX_STRIPES];
+
+	__u16 effective_frame_width;	/* Needed for vertical cropping */
+	__u16 bds_frame_width;
+	__u16 out_frame_width;	/* Output frame width as configured by user */
+	__u16 out_frame_height;	/* Output frame height as configured by user */
+
+	/* GDC in buffer (A.K.A delay frame,ref buffer) info */
+	__u16 gdc_in_buffer_width;	/* GDC in buffer width  */
+	__u16 gdc_in_buffer_height;	/* GDC in buffer height */
+	/* GDC in buffer first valid pixel x offset */
+	__u16 gdc_in_buffer_offset_x;
+	/* GDC in buffer first valid pixel y offset */
+	__u16 gdc_in_buffer_offset_y;
+
+	/* Display frame width as configured by user */
+	__u16 display_frame_width;
+	/* Display frame height as configured by user */
+	__u16 display_frame_height;
+	__u16 bds_aligned_frame_width;
+	/* Number of vectors to left-crop when writing stripes (not stripe 0) */
+	__u16 half_overlap_vectors;
+	/* Decimate ISP and fixed func resolutions after BDS (ir_extraction) */
+	__u16 ir_ext_decimation;
+	__u8 padding1[2];
+} __packed;
+
+struct ipu3_uapi_input_feeder_data {
+	__u32 row_stride;				/* row stride */
+	__u32 start_row_address;			/* start row address */
+	__u32 start_pixel;				/* start pixel */
+} __packed;
+
+struct ipu3_uapi_input_feeder_data_aligned {
+	struct ipu3_uapi_input_feeder_data data IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_input_feeder_data_per_stripe {
+	struct ipu3_uapi_input_feeder_data_aligned
+		input_feeder_data[IPU3_UAPI_MAX_STRIPES];
+} __packed;
+
+struct ipu3_uapi_input_feeder_config {
+	struct ipu3_uapi_input_feeder_data data;
+	struct ipu3_uapi_input_feeder_data_per_stripe data_per_stripe
+		IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_bnr_static_config_wb_gains_config {
+	__u16 gr;
+	__u16 r;
+	__u16 b;
+	__u16 gb;
+} __packed;
+
+struct ipu3_uapi_bnr_static_config_wb_gains_thr_config {
+	__u8 gr;
+	__u8 r;
+	__u8 b;
+	__u8 gb;
+} __packed;
+
+struct ipu3_uapi_bnr_static_config_thr_coeffs_config {
+	__u32 cf:13;
+	__u32 __reserved0:3;
+	__u32 cg:5;
+	__u32 ci:5;
+	__u32 __reserved1:1;
+	__u32 r_nf:5;
+} __packed;
+
+struct ipu3_uapi_bnr_static_config_thr_ctrl_shd_config {
+	__u8 gr;
+	__u8 r;
+	__u8 b;
+	__u8 gb;
+} __packed;
+
+struct ipu3_uapi_bnr_static_config_opt_center_config {
+	__s32 x_reset:13;
+	__u32 __reserved0:3;
+	__s32 y_reset:13;
+	__u32 __reserved2:3;
+} __packed;
+
+struct ipu3_uapi_bnr_static_config_lut_config {
+	__u8 values[IPU3_UAPI_BNR_LUT_SIZE];
+} __packed;
+
+struct ipu3_uapi_bnr_static_config_bp_ctrl_config {
+	__u32 bp_thr_gain:5;
+	__u32 __reserved0:2;
+	__u32 defect_mode:1;
+	__u32 bp_gain:6;
+	__u32 __reserved1:18;
+	__u32 w0_coeff:4;
+	__u32 __reserved2:4;
+	__u32 w1_coeff:4;
+	__u32 __reserved3:20;
+} __packed;
+
+struct ipu3_uapi_bnr_static_config_dn_detect_ctrl_config {
+	__u32 alpha:4;
+	__u32 beta:4;
+	__u32 gamma:4;
+	__u32 __reserved0:4;
+	__u32 max_inf:4;
+	__u32 __reserved1:7;
+	/* aka 'green disparity enable' */
+	__u32 gd_enable:1;
+	__u32 bpc_enable:1;
+	__u32 bnr_enable:1;
+	__u32 ff_enable:1;
+	__u32 __reserved2:1;
+} __packed;
+
+struct ipu3_uapi_bnr_static_config_opt_center_sqr_config {
+	__u32 x_sqr_reset;
+	__u32 y_sqr_reset;
+} __packed;
+
+struct ipu3_uapi_bnr_static_config {
+	struct ipu3_uapi_bnr_static_config_wb_gains_config wb_gains;
+	struct ipu3_uapi_bnr_static_config_wb_gains_thr_config wb_gains_thr;
+	struct ipu3_uapi_bnr_static_config_thr_coeffs_config thr_coeffs;
+	struct ipu3_uapi_bnr_static_config_thr_ctrl_shd_config thr_ctrl_shd;
+	struct ipu3_uapi_bnr_static_config_opt_center_config opt_center;
+	struct ipu3_uapi_bnr_static_config_lut_config lut;
+	struct ipu3_uapi_bnr_static_config_bp_ctrl_config bp_ctrl;
+	struct ipu3_uapi_bnr_static_config_dn_detect_ctrl_config dn_detect_ctrl;
+	__u32 column_size;				/* 0x44 */
+	struct ipu3_uapi_bnr_static_config_opt_center_sqr_config opt_center_sqr;
+} __packed;
+
+struct ipu3_uapi_bnr_static_config_green_disparity {
+	__u32 gd_red:6;
+	__u32 __reserved0:2;
+	__u32 gd_green:6;
+	__u32 __reserved1:2;
+	__u32 gd_blue:6;
+	__u32 __reserved2:10;
+	__u32 gd_black:14;
+	__u32 __reserved3:2;
+	__u32 gd_shading:7;
+	__u32 __reserved4:1;
+	__u32 gd_support:2;
+	__u32 __reserved5:1;
+	__u32 gd_clip:1;			/* central weights variables */
+	__u32 gd_central_weight:4;
+} __packed;
+
+struct ipu3_uapi_dm_config {
+	/* DWORD0 */
+	__u32 dm_en:1;
+	__u32 ch_ar_en:1;
+	__u32 fcc_en:1;
+	__u32 __reserved0:13;
+	__u32 frame_width:16;
+
+	/* DWORD1 */
+	__u32 gamma_sc:5;
+	__u32 __reserved1:3;
+	__u32 lc_ctrl:5;
+	__u32 __reserved2:3;
+	__u32 cr_param1:5;
+	__u32 __reserved3:3;
+	__u32 cr_param2:5;
+	__u32 __reserved4:3;
+
+	/* DWORD2 */
+	__u32 coring_param:5;
+	__u32 __reserved5:27;
+} __packed;
+
+struct ipu3_uapi_ccm_mat_config {
+	__s16 coeff_m11;
+	__s16 coeff_m12;
+	__s16 coeff_m13;
+	__s16 coeff_o_r;
+	__s16 coeff_m21;
+	__s16 coeff_m22;
+	__s16 coeff_m23;
+	__s16 coeff_o_g;
+	__s16 coeff_m31;
+	__s16 coeff_m32;
+	__s16 coeff_m33;
+	__s16 coeff_o_b;
+} __packed;
+
+struct ipu3_uapi_gamma_corr_ctrl {
+	__u32 enable:1;
+	__u32 __reserved:31;
+} __packed;
+
+struct ipu3_uapi_gamma_corr_lut {
+	__u16 lut[IPU3_UAPI_GAMMA_CORR_LUT_ENTRIES];
+} __packed;
+
+struct ipu3_uapi_gamma_config {
+	struct ipu3_uapi_gamma_corr_ctrl gc_ctrl IPU3_ALIGN;
+	struct ipu3_uapi_gamma_corr_lut gc_lut IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_csc_mat_config {
+	__s16 coeff_c11;
+	__s16 coeff_c12;
+	__s16 coeff_c13;
+	__s16 coeff_b1;
+	__s16 coeff_c21;
+	__s16 coeff_c22;
+	__s16 coeff_c23;
+	__s16 coeff_b2;
+	__s16 coeff_c31;
+	__s16 coeff_c32;
+	__s16 coeff_c33;
+	__s16 coeff_b3;
+} __packed;
+
+struct ipu3_uapi_cds_params {
+	__u32 ds_c00:2;
+	__u32 ds_c01:2;
+	__u32 ds_c02:2;
+	__u32 ds_c03:2;
+	__u32 ds_c10:2;
+	__u32 ds_c11:2;
+	__u32 ds_c12:2;
+	__u32 ds_c13:2;
+	__u32 ds_nf:5;
+	__u32 __reserved0:3;
+	__u32 csc_en:1;
+	__u32 uv_bin_output:1;
+	__u32 __reserved1:6;
+} __packed;
+
+struct ipu3_uapi_shd_grid_config {
+	/* reg 0 */
+	__u8 width;
+	__u8 height;
+	__u8 block_width_log2:3;
+	__u8 __reserved0:1;
+	__u8 block_height_log2:3;
+	__u8 __reserved1:1;
+	__u8 grid_height_per_slice;
+	/* reg 1 */
+	__s16 x_start;			/* 13 bits */
+	__s16 y_start;
+} __packed;
+
+struct ipu3_uapi_shd_general_config {
+	__u32 init_set_vrt_offst_ul:8;
+	__u32 shd_enable:1;
+	/* aka 'gf' */
+	__u32 gain_factor:2;
+	__u32 __reserved:21;
+} __packed;
+
+struct ipu3_uapi_shd_black_level_config {
+	__s16 bl_r;			/* 12 bits */
+	__s16 bl_gr;
+#define IPU3_UAPI_SHD_BLGR_NF_SHIFT	13	/* Normalization shift aka nf */
+#define IPU3_UAPI_SHD_BLGR_NF_MASK	0x7
+	__s16 bl_gb;			/* 12 bits */
+	__s16 bl_b;
+} __packed;
+
+struct ipu3_uapi_shd_config_static {
+	/* B0: Fixed order: one transfer to GAC */
+	struct ipu3_uapi_shd_grid_config grid;
+	struct ipu3_uapi_shd_general_config general;
+	struct ipu3_uapi_shd_black_level_config black_level;
+} __packed;
+
+struct ipu3_uapi_shd_transfer_luts_set_data {
+	__u8 set_number;
+	__u8 padding[3];
+	imgu_addr_t rg_lut_ddr_addr;
+	imgu_addr_t bg_lut_ddr_addr;
+	__u32 align_dummy;
+} __packed;
+
+struct ipu3_uapi_shd_intra_frame_operations_data {
+	struct ipu3_uapi_acc_operation
+		operation_list[IPU3_UAPI_SHD_MAX_OPERATIONS] IPU3_ALIGN;
+	struct ipu3_uapi_acc_process_lines_cmd_data
+		process_lines_data[IPU3_UAPI_SHD_MAX_PROCESS_LINES] IPU3_ALIGN;
+	struct ipu3_uapi_shd_transfer_luts_set_data
+		transfer_data[IPU3_UAPI_SHD_MAX_TRANSFERS] IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_shd_lut {
+	struct {
+		struct {
+			__u16 r;
+			__u16 gr;
+		} r_and_gr[IPU3_UAPI_SHD_MAX_CELLS_PER_SET];
+		__u8 __reserved1[24];
+		struct {
+			__u16 gb;
+			__u16 b;
+		} gb_and_b[IPU3_UAPI_SHD_MAX_CELLS_PER_SET];
+		__u8 __reserved2[24];
+	} sets[IPU3_UAPI_SHD_MAX_CFG_SETS];
+} __packed;
+
+struct ipu3_uapi_shd_config {
+	struct ipu3_uapi_shd_config_static shd IPU3_ALIGN;
+	struct ipu3_uapi_shd_intra_frame_operations_data shd_ops IPU3_ALIGN;
+	struct ipu3_uapi_shd_lut shd_lut IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_dvs_stat_stripe_cfg {
+	struct ipu3_uapi_dvs_stat_cfg stripe_cfg[IPU3_UAPI_MAX_STRIPES];
+} __packed;
+
+struct ipu3_uapi_dvs_stat_transfer_op_data {
+	__u8 set_number;
+} __packed;
+
+struct ipu3_uapi_dvs_stat_intra_frame_operations_data {
+	struct ipu3_uapi_acc_operation
+		ops[IPU3_UAPI_DVS_STAT_MAX_OPERATIONS] IPU3_ALIGN;
+	struct ipu3_uapi_acc_process_lines_cmd_data
+		process_lines_data[IPU3_UAPI_DVS_STAT_MAX_PROCESS_LINES]
+		IPU3_ALIGN;
+	struct ipu3_uapi_dvs_stat_transfer_op_data
+		transfer_data[IPU3_UAPI_DVS_STAT_MAX_TRANSFERS] IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_dvs_stat_meta_data_align_p {
+	imgu_addr_t p_meta_data IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_dvs_stat_config {
+	struct ipu3_uapi_dvs_stat_cfg cfg IPU3_ALIGN;
+	struct ipu3_uapi_dvs_stat_stripe_cfg stripe IPU3_ALIGN;
+	struct ipu3_uapi_dvs_stat_intra_frame_operations_data
+		operations_data IPU3_ALIGN;
+	struct ipu3_uapi_dvs_stat_meta_data_align_p
+		meta_data[IPU3_UAPI_MAX_STRIPES];
+} __packed;
+
+struct ipu3_uapi_lace_stat_operation {
+	__u8 op_indicator;
+	__u8 padding;
+	__u16 lines;
+} __packed;
+
+struct ipu3_uapi_lace_stat_intra_frame_op_data {
+	struct ipu3_uapi_lace_stat_operation
+		ops[IPU3_UAPI_LACE_STAT_MAX_OPERATIONS] IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_lace_stat_config {
+	struct ipu3_uapi_lace_stat_cfg lace_stat_cfg IPU3_ALIGN;
+	struct ipu3_uapi_lace_stat_intra_frame_op_data operations_data
+		IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_iefd_cux2 {
+	__u32 x0:9;
+	__u32 x1:9;
+	__u32 a01:9;
+	__u32 b01:5;				/* NOTE: hardcoded to zero */
+} __packed;
+
+struct ipu3_uapi_iefd_cux6_ed {
+	__u32 x0:9;
+	__u32 x1:9;
+	__u32 x2:9;
+	__u32 __reserved0:5;
+
+	__u32 x3:9;
+	__u32 x4:9;
+	__u32 x5:9;
+	__u32 __reserved1:5;
+
+	__u32 a01:9;
+	__u32 a12:9;
+	__u32 a23:9;
+	__u32 __reserved2:5;
+
+	__u32 a34:9;
+	__u32 a45:9;
+	__u32 __reserved3:14;
+
+	__u32 b01:9;
+	__u32 b12:9;
+	__u32 b23:9;
+	__u32 __reserved4:5;
+
+	__u32 b34:9;
+	__u32 b45:9;
+	__u32 __reserved5:14;
+} __packed;
+
+struct ipu3_uapi_iefd_cux2_1 {
+	__u32 x0:9;
+	__u32 x1:9;
+	__u32 a01:9;
+	__u32 __reserved1:5;
+
+	__u32 b01:8;
+	__u32 __reserved2:24;
+} __packed;
+
+struct ipu3_uapi_iefd_cux4 {
+	__u32 x0:9;
+	__u32 x1:9;
+	__u32 x2:9;
+	__u32 __reserved0:5;
+
+	__u32 x3:9;
+	__u32 a01:9;
+	__u32 a12:9;
+	__u32 __reserved1:5;
+
+	__u32 a23:9;
+	__u32 b01:8;
+	__u32 b12:8;
+	__u32 __reserved2:7;
+
+	__u32 b23:8;
+	__u32 __reserved3:24;
+} __packed;
+
+struct ipu3_uapi_iefd_cux6_rad {
+	__u32 x0:8;
+	__u32 x1:8;
+	__u32 x2:8;
+	__u32 x3:8;
+
+	__u32 x4:8;
+	__u32 x5:8;
+	__u32 __reserved1:16;
+
+	__u32 a01:16;
+	__u32 a12:16;
+
+	__u32 a23:16;
+	__u32 a34:16;
+
+	__u32 a45:16;
+	__u32 __reserved2:16;
+
+	__u32 b01:10;
+	__u32 b12:10;
+	__u32 b23:10;
+	__u32 __reserved4:2;
+
+	__u32 b34:10;
+	__u32 b45:10;
+	__u32 __reserved5:12;
+} __packed;
+
+struct ipu3_uapi_yuvp1_iefd_cfg_units {
+	struct ipu3_uapi_iefd_cux2 cu_1;
+	struct ipu3_uapi_iefd_cux6_ed cu_ed;
+	struct ipu3_uapi_iefd_cux2 cu_3;
+	struct ipu3_uapi_iefd_cux2_1 cu_5;
+	struct ipu3_uapi_iefd_cux4 cu_6;
+	struct ipu3_uapi_iefd_cux2 cu_7;
+	struct ipu3_uapi_iefd_cux4 cu_unsharp;
+	struct ipu3_uapi_iefd_cux6_rad cu_radial;
+	struct ipu3_uapi_iefd_cux2 cu_vssnlm;
+} __packed;
+
+struct ipu3_uapi_yuvp1_iefd_config_s {
+	__u32 horver_diag_coeff:7;	/* Gradiant compensation */
+	__u32 __reserved0:1;
+	__u32 clamp_stitch:6;		/* Slope to stitch edge */
+	__u32 __reserved1:2;
+	__u32 direct_metric_update:5;	/* Update coeff for direction metric */
+	__u32 __reserved2:3;
+	__u32 ed_horver_diag_coeff:7;
+	__u32 __reserved3:1;
+} __packed;
+
+struct ipu3_uapi_yuvp1_iefd_control {
+	__u32 iefd_en:1;		/* Enable IEFD */
+	__u32 denoise_en:1;		/* Enable denoise */
+	__u32 direct_smooth_en:1;	/* Enable directional smooth */
+	__u32 rad_en:1;			/* Enable radial update */
+	__u32 vssnlm_en:1;		/* Enable VSSNLM output filter */
+	__u32 __reserved:27;
+} __packed;
+
+struct ipu3_uapi_sharp_cfg {
+	__u32 nega_lmt_txt:13;
+	__u32 __reserved0:19;
+	__u32 posi_lmt_txt:13;
+	__u32 __reserved1:19;
+	__u32 nega_lmt_dir:13;
+	__u32 __reserved2:19;
+	__u32 posi_lmt_dir:13;
+	__u32 __reserved3:19;
+} __packed;
+
+struct ipu3_uapi_far_w {
+	__u32 dir_shrp:7;
+	__u32 __reserved0:1;
+	__u32 dir_dns:7;
+	__u32 __reserved1:1;
+	__u32 ndir_dns_powr:7;
+	__u32 __reserved2:9;
+} __packed;
+
+struct ipu3_uapi_unsharp_cfg {
+	__u32 unsharp_weight:7;
+	__u32 __reserved0:1;
+	__u32 unsharp_amount:9;
+	__u32 __reserved1:15;
+} __packed;
+
+struct ipu3_uapi_yuvp1_iefd_shrp_cfg {
+	struct ipu3_uapi_sharp_cfg cfg;
+	struct ipu3_uapi_far_w far_w;
+	struct ipu3_uapi_unsharp_cfg unshrp_cfg;
+} __packed;
+
+struct ipu3_uapi_unsharp_coef0 {
+	__u32 c00:9;			/* Coeff11 */
+	__u32 c01:9;			/* Coeff12 */
+	__u32 c02:9;			/* Coeff13 */
+	__u32 __reserved:5;
+} __packed;
+
+struct ipu3_uapi_unsharp_coef1 {
+	__u32 c11:9;			/* Coeff22 */
+	__u32 c12:9;			/* Coeff23 */
+	__u32 c22:9;			/* Coeff33 */
+	__u32 __reserved:5;
+} __packed;
+
+struct ipu3_uapi_yuvp1_iefd_unshrp_cfg {
+	struct ipu3_uapi_unsharp_coef0 unsharp_coef0;
+	struct ipu3_uapi_unsharp_coef1 unsharp_coef1;
+} __packed;
+
+struct ipu3_uapi_radial_reset_xy {
+	__s32 x:13;
+	__u32 __reserved0:3;
+	__s32 y:13;
+	__u32 __reserved1:3;
+} __packed;
+
+struct ipu3_uapi_radial_reset_x2 {
+	__u32 x2:24;
+	__u32 __reserved:8;
+} __packed;
+
+struct ipu3_uapi_radial_reset_y2 {
+	__u32 y2:24;
+	__u32 __reserved:8;
+} __packed;
+
+struct ipu3_uapi_radial_cfg {
+	__u32 rad_nf:4;
+	__u32 __reserved0:4;
+	__u32 rad_inv_r2:7;
+	__u32 __reserved1:17;
+} __packed;
+
+struct ipu3_uapi_rad_far_w {
+	__u32 rad_dir_far_sharp_w:8;
+	__u32 rad_dir_far_dns_w:8;
+	__u32 rad_ndir_far_dns_power:8;
+	__u32 __reserved:8;
+} __packed;
+
+struct ipu3_uapi_cu_cfg0 {
+	__u32 cu6_pow:7;
+	__u32 __reserved0:1;
+	__u32 cu_unsharp_pow:7;
+	__u32 __reserved1:1;
+	__u32 rad_cu6_pow:7;
+	__u32 __reserved2:1;
+	__u32 rad_cu_unsharp_pow:6;
+	__u32 __reserved3:2;
+} __packed;
+
+struct ipu3_uapi_cu_cfg1 {
+	__u32 rad_cu6_x1:9;
+	__u32 __reserved0:1;
+	__u32 rad_cu_unsharp_x1:9;
+	__u32 __reserved1:13;
+} __packed;
+
+struct ipu3_uapi_yuvp1_iefd_rad_cfg {
+	struct ipu3_uapi_radial_reset_xy reset_xy;
+	struct ipu3_uapi_radial_reset_x2 reset_x2;
+	struct ipu3_uapi_radial_reset_y2 reset_y2;
+	struct ipu3_uapi_radial_cfg cfg;
+	struct ipu3_uapi_rad_far_w rad_far_w;
+	struct ipu3_uapi_cu_cfg0 cu_cfg0;
+	struct ipu3_uapi_cu_cfg1 cu_cfg1;
+} __packed;
+
+struct ipu3_uapi_vss_lut_x {
+	__u32 vs_x0:8;
+	__u32 vs_x1:8;
+	__u32 vs_x2:8;
+	__u32 __reserved2:8;
+} __packed;
+
+struct ipu3_uapi_vss_lut_y {
+	__u32 vs_y1:4;
+	__u32 __reserved0:4;
+	__u32 vs_y2:4;
+	__u32 __reserved1:4;
+	__u32 vs_y3:4;
+	__u32 __reserved2:12;
+} __packed;
+
+struct ipu3_uapi_yuvp1_iefd_vssnlm_cfg {
+	struct ipu3_uapi_vss_lut_x vss_lut_x;
+	struct ipu3_uapi_vss_lut_y vss_lut_y;
+} __packed;
+
+struct ipu3_uapi_yuvp1_iefd_config {
+	struct ipu3_uapi_yuvp1_iefd_cfg_units units;
+	struct ipu3_uapi_yuvp1_iefd_config_s config;
+	struct ipu3_uapi_yuvp1_iefd_control control;
+	struct ipu3_uapi_yuvp1_iefd_shrp_cfg sharp;
+	struct ipu3_uapi_yuvp1_iefd_unshrp_cfg unsharp;
+	struct ipu3_uapi_yuvp1_iefd_rad_cfg rad;
+	struct ipu3_uapi_yuvp1_iefd_vssnlm_cfg vsslnm;
+} __packed;
+
+struct ipu3_uapi_yuvp1_yds_config {
+	__u32 c00:2;
+	__u32 c01:2;
+	__u32 c02:2;
+	__u32 c03:2;
+	__u32 c10:2;
+	__u32 c11:2;
+	__u32 c12:2;
+	__u32 c13:2;
+	__u32 norm_factor:5;
+	__u32 __reserved0:4;
+	__u32 bin_output:1;
+	__u32 __reserved1:6;
+} __packed;
+
+struct ipu3_uapi_yuvp1_chnr_enable_config {
+	__u32 enable:1;
+	__u32 yuv_mode:1;
+	__u32 __reserved0:14;
+	__u32 col_size:12;
+	__u32 __reserved1:4;
+} __packed;
+
+struct ipu3_uapi_yuvp1_chnr_coring_config {
+	__u32 u:13;
+	__u32 __reserved0:3;
+	__u32 v:13;
+	__u32 __reserved1:3;
+} __packed;
+
+struct ipu3_uapi_yuvp1_chnr_sense_gain_config {
+	__u32 vy:8;
+	__u32 vu:8;
+	__u32 vv:8;
+	__u32 __reserved0:8;
+
+	__u32 hy:8;
+	__u32 hu:8;
+	__u32 hv:8;
+	__u32 __reserved1:8;
+} __packed;
+
+struct ipu3_uapi_yuvp1_chnr_iir_fir_config {
+	__u32 fir_0h:6;
+	__u32 __reserved0:2;
+	__u32 fir_1h:6;
+	__u32 __reserved1:2;
+	__u32 fir_2h:6;
+	__u32 dalpha_clip_val:9;
+	__u32 __reserved2:1;
+} __packed;
+
+struct ipu3_uapi_yuvp1_chnr_config {
+	struct ipu3_uapi_yuvp1_chnr_enable_config enable;
+	struct ipu3_uapi_yuvp1_chnr_coring_config coring;
+	struct ipu3_uapi_yuvp1_chnr_sense_gain_config sense_gain;
+	struct ipu3_uapi_yuvp1_chnr_iir_fir_config iir_fir;
+} __packed;
+
+struct ipu3_uapi_yuvp1_y_ee_nr_lpf_config {
+	__u32 a_diag:5;
+	__u32 __reserved0:3;
+	__u32 a_periph:5;
+	__u32 __reserved1:3;
+	__u32 a_cent:5;
+	__u32 __reserved2:9;
+	__u32 enable:1;
+} __packed;
+
+struct ipu3_uapi_yuvp1_y_ee_nr_sense_config {
+	__u32 edge_sense_0:13;
+	__u32 __reserved0:3;
+	__u32 delta_edge_sense:13;
+	__u32 __reserved1:3;
+	__u32 corner_sense_0:13;
+	__u32 __reserved2:3;
+	__u32 delta_corner_sense:13;
+	__u32 __reserved3:3;
+} __packed;
+
+struct ipu3_uapi_yuvp1_y_ee_nr_gain_config {
+	__u32 gain_pos_0:5;
+	__u32 __reserved0:3;
+	__u32 delta_gain_posi:5;
+	__u32 __reserved1:3;
+	__u32 gain_neg_0:5;
+	__u32 __reserved2:3;
+	__u32 delta_gain_neg:5;
+	__u32 __reserved3:3;
+} __packed;
+
+struct ipu3_uapi_yuvp1_y_ee_nr_clip_config {
+	__u32 clip_pos_0:5;
+	__u32 __reserved0:3;
+	__u32 delta_clip_posi:5;
+	__u32 __reserved1:3;
+	__u32 clip_neg_0:5;
+	__u32 __reserved2:3;
+	__u32 delta_clip_neg:5;
+	__u32 __reserved3:3;
+} __packed;
+
+struct ipu3_uapi_yuvp1_y_ee_nr_frng_config {
+	__u32 gain_exp:4;
+	__u32 __reserved0:28;
+	__u32 min_edge:13;
+	__u32 __reserved1:3;
+	__u32 lin_seg_param:4;
+	__u32 __reserved2:4;
+	__u32 t1:1;
+	__u32 t2:1;
+	__u32 __reserved3:6;
+} __packed;
+
+struct ipu3_uapi_yuvp1_y_ee_nr_diag_config {
+	__u32 diag_disc_g:4;
+	__u32 __reserved0:4;
+	__u32 hvw_hor:4;
+	__u32 dw_hor:4;
+	__u32 hvw_diag:4;
+	__u32 dw_diag:4;
+	__u32 __reserved1:8;
+} __packed;
+
+struct ipu3_uapi_yuvp1_y_ee_nr_fc_coring_config {
+	__u32 pos_0:13;
+	__u32 __reserved0:3;
+	__u32 pos_delta:13;
+	__u32 __reserved1:3;
+	__u32 neg_0:13;
+	__u32 __reserved2:3;
+	__u32 neg_delta:13;
+	__u32 __reserved3:3;
+} __packed;
+
+struct ipu3_uapi_yuvp1_y_ee_nr_config {
+	struct ipu3_uapi_yuvp1_y_ee_nr_lpf_config lpf;
+	struct ipu3_uapi_yuvp1_y_ee_nr_sense_config sense;
+	struct ipu3_uapi_yuvp1_y_ee_nr_gain_config gain;
+	struct ipu3_uapi_yuvp1_y_ee_nr_clip_config clip;
+	struct ipu3_uapi_yuvp1_y_ee_nr_frng_config frng;
+	struct ipu3_uapi_yuvp1_y_ee_nr_diag_config diag;
+	struct ipu3_uapi_yuvp1_y_ee_nr_fc_coring_config fc_coring;
+} __packed;
+
+struct ipu3_uapi_yuvp2_y_tm_lut_static_config {
+	__u16 entries[IPU3_UAPI_YUVP2_YTM_LUT_ENTRIES]; /* 13 significand bits*/
+	__u32 enable;
+} __packed;
+
+struct ipu3_uapi_yuvp2_tcc_gen_control_static_config {
+	__u32 en:1;
+	__u32 blend_shift:3;
+	__u32 gain_according_to_y_only:1;
+	__u32 __reserved0:11;
+	__s32 gamma:5;
+	__u32 __reserved1:3;
+	__s32 delta:5;
+	__u32 __reserved2:3;
+} __packed;
+
+struct ipu3_uapi_yuvp2_tcc_macc_elem_static_config {
+	__s32 a:12;
+	__u32 __reserved0:4;
+	__s32 b:12;
+	__u32 __reserved1:4;
+	__s32 c:12;
+	__u32 __reserved2:4;
+	__s32 d:12;
+	__u32 __reserved3:4;
+} __packed;
+
+struct ipu3_uapi_yuvp2_tcc_macc_table_static_config {
+	struct ipu3_uapi_yuvp2_tcc_macc_elem_static_config
+		entries[IPU3_UAPI_YUVP2_TCC_MACC_TABLE_ELEMENTS];
+} __packed;
+
+struct ipu3_uapi_yuvp2_tcc_inv_y_lut_static_config {
+	__u16 entries[IPU3_UAPI_YUVP2_TCC_INV_Y_LUT_ELEMENTS];	/* 10 bits */
+} __packed;
+
+struct ipu3_uapi_yuvp2_tcc_gain_pcwl_lut_static_config {
+	__u16 entries[IPU3_UAPI_YUVP2_TCC_GAIN_PCWL_LUT_ELEMENTS];/* 12 bits */
+} __packed;
+
+struct ipu3_uapi_yuvp2_tcc_r_sqr_lut_static_config {
+	__s16 entries[IPU3_UAPI_YUVP2_TCC_R_SQR_LUT_ELEMENTS];	/* 11 bits */
+} __packed;
+
+struct ipu3_uapi_yuvp2_tcc_static_config {
+	struct ipu3_uapi_yuvp2_tcc_gen_control_static_config gen_control;
+	struct ipu3_uapi_yuvp2_tcc_macc_table_static_config macc_table;
+	struct ipu3_uapi_yuvp2_tcc_inv_y_lut_static_config inv_y_lut;
+	struct ipu3_uapi_yuvp2_tcc_gain_pcwl_lut_static_config gain_pcwl;
+	struct ipu3_uapi_yuvp2_tcc_r_sqr_lut_static_config r_sqr_lut;
+} __packed;
+
+struct ipu3_uapi_dpc_num_of_dp {
+	__u8 dp_gr;
+	__u8 dp_bg;
+	__u16 __reserved;
+} __packed;
+
+struct ipu3_uapi_dpc_params {
+	__u16 enable;
+	__u16 grad_threshold;		/* 13 bits */
+	struct ipu3_uapi_dpc_num_of_dp set[2];
+	struct ipu3_uapi_dpc_num_of_dp first_line_pair;
+} __packed;
+
+struct ipu3_uapi_dpc_transfer_luts_set_data {
+	__u8 set_number;
+	__u8 num_of_dp_gr;
+	__u8 num_of_dp_bg;
+	__u8 align_dummy;
+
+} __packed;
+
+struct ipu3_uapi_dpc_intra_frame_operations_data {
+	struct ipu3_uapi_acc_operation
+		operation_list[IPU3_UAPI_DPC_MAX_OPERATIONS] IPU3_ALIGN;
+	struct ipu3_uapi_acc_process_lines_cmd_data
+		process_lines_data[IPU3_UAPI_DPC_MAX_PROCESS_LINES] IPU3_ALIGN;
+	struct ipu3_uapi_dpc_transfer_luts_set_data
+		transfer_data[IPU3_UAPI_DPC_MAX_TRANSFERS] IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_dpc_1st_pair_of_lines_lut_elem {
+	__u32 column:13;
+	__u32 nghbr_sts:5;
+	__u32 p0:14;
+	__u32 p1:14;
+	__u32 __reserved0:2;
+	__u32 p2:14;
+	__u32 nghbr_order:1;
+	__u32 __reserved1:1;
+} __packed;
+
+struct ipu3_uapi_dpc_1st_pair_of_lines_lut {
+	struct ipu3_uapi_dpc_1st_pair_of_lines_lut_elem
+		entries[IPU3_UAPI_DPC_MAX_DP_FIRST_LINES_PAIR];
+
+} __packed;
+
+struct ipu3_uapi_dpc_lut_elem {
+	__u32 nghbr_sts:5;
+	__u32 skip:1;
+	__u32 nghbr_order:1;
+	__u32 column:13;
+	__u32 row_pair_delta:4;
+	__u32 __reserved0:8;
+} __packed;
+
+struct ipu3_uapi_dpc_lut_set {
+	struct ipu3_uapi_dpc_lut_elem
+		elems[IPU3_UAPI_DPC_MAX_DP_PER_SET] IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_dpc_lut {
+	struct ipu3_uapi_dpc_lut_set sets[IPU3_UAPI_DPC_MAX_CFG_SETS];
+} __packed;
+
+struct ipu3_uapi_dpc_stripe_config {
+	struct ipu3_uapi_dpc_params params IPU3_ALIGN;
+	struct ipu3_uapi_dpc_intra_frame_operations_data ops IPU3_ALIGN;
+	struct ipu3_uapi_dpc_1st_pair_of_lines_lut first_lines_lut_gr
+		IPU3_ALIGN;
+	struct ipu3_uapi_dpc_1st_pair_of_lines_lut first_lines_lut_bg
+		IPU3_ALIGN;
+	struct ipu3_uapi_dpc_lut lut_bg IPU3_ALIGN;
+	struct ipu3_uapi_dpc_lut lut_gr IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_dpc_config_per_stripe {
+	struct ipu3_uapi_dpc_stripe_config
+		dpc_config[IPU3_UAPI_MAX_STRIPES] IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_dpc_config {
+	struct ipu3_uapi_dpc_config_per_stripe config_per_stripe
+		IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_bds_hor_ctrl0 {
+	__u32 sample_patrn_length:9;
+	__u32 __reserved0:3;
+	__u32 hor_ds_en:1;
+	__u32 min_clip_val:1;
+	__u32 max_clip_val:2;
+	__u32 out_frame_width:13;
+	__u32 __reserved1:3;
+} __packed;
+
+struct ipu3_uapi_bds_ptrn_arr {
+	__u32 elems[IPU3_UAPI_BDS_SAMPLE_PATTERN_ARRAY_SIZE];
+} __packed;
+
+struct ipu3_uapi_bds_phase_entry {
+	__s8 coeff_min2;
+	__s8 coeff_min1;
+	__s8 coeff_0;
+	__s8 nf;
+	__s8 coeff_pls1;
+	__s8 coeff_pls2;
+	__s8 coeff_pls3;
+	__u8 __reserved;
+} __packed;
+
+struct ipu3_uapi_bds_phase_arr {
+	struct ipu3_uapi_bds_phase_entry
+		even[IPU3_UAPI_BDS_PHASE_COEFFS_ARRAY_SIZE];
+	struct ipu3_uapi_bds_phase_entry
+		odd[IPU3_UAPI_BDS_PHASE_COEFFS_ARRAY_SIZE];
+} __packed;
+
+struct ipu3_uapi_bds_hor_ctrl1 {
+	__u32 hor_crop_start:13;
+	__u32 __reserved0:3;
+	__u32 hor_crop_end:13;
+	__u32 __reserved1:1;
+	__u32 hor_crop_en:1;
+	__u32 __reserved2:1;
+} __packed;
+
+struct ipu3_uapi_bds_hor_ctrl2 {
+	__u32 input_frame_height:13;
+	__u32 __reserved0:19;
+} __packed;
+
+struct ipu3_uapi_bds_hor {
+	struct ipu3_uapi_bds_hor_ctrl0 hor_ctrl0;
+	struct ipu3_uapi_bds_ptrn_arr hor_ptrn_arr;
+	struct ipu3_uapi_bds_phase_arr hor_phase_arr;
+	struct ipu3_uapi_bds_hor_ctrl1 hor_ctrl1;
+	struct ipu3_uapi_bds_hor_ctrl2 hor_ctrl2;
+} __packed;
+
+struct ipu3_uapi_bds_ver_ctrl0 {
+	__u32 sample_patrn_length:9;
+	__u32 __reserved0:3;
+	__u32 ver_ds_en:1;
+	__u32 min_clip_val:1;
+	__u32 max_clip_val:2;
+	__u32 __reserved1:16;
+} __packed;
+
+struct ipu3_uapi_bds_ver_ctrl1 {
+	__u32 out_frame_width:13;
+	__u32 __reserved0:3;
+	__u32 out_frame_height:13;
+	__u32 __reserved1:3;
+} __packed;
+
+struct ipu3_uapi_bds_ver {
+	struct ipu3_uapi_bds_ver_ctrl0 ver_ctrl0;
+	struct ipu3_uapi_bds_ptrn_arr ver_ptrn_arr;
+	struct ipu3_uapi_bds_phase_arr ver_phase_arr;
+	struct ipu3_uapi_bds_ver_ctrl1 ver_ctrl1;
+
+} __packed;
+
+struct ipu3_uapi_bds_per_stripe_data {
+	struct ipu3_uapi_bds_hor_ctrl0 hor_ctrl0;
+	struct ipu3_uapi_bds_ver_ctrl1 ver_ctrl1;
+	struct ipu3_uapi_bds_hor_ctrl1 crop;
+} __packed;
+
+struct ipu3_uapi_ipu3_uapi_bds_per_stripe_data_aligned {
+	struct ipu3_uapi_bds_per_stripe_data data IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_bds_per_stripe {
+	struct ipu3_uapi_ipu3_uapi_bds_per_stripe_data_aligned
+		aligned_data[IPU3_UAPI_MAX_STRIPES];
+} __packed;
+
+struct ipu3_uapi_bds_config {
+	struct ipu3_uapi_bds_hor hor IPU3_ALIGN;
+	struct ipu3_uapi_bds_ver ver IPU3_ALIGN;
+	struct ipu3_uapi_bds_per_stripe per_stripe IPU3_ALIGN;
+	__u32 enabled;
+} __packed;
+
+struct ipu3_uapi_anr_search_config {
+	__u32 enable;
+	__u16 frame_width;
+	__u16 frame_height;
+} __packed;
+
+struct ipu3_uapi_anr_alpha {
+	__u16 gr;					/* 9 bits */
+	__u16 r;
+	__u16 b;
+	__u16 gb;
+	__u16 dc_gr;
+	__u16 dc_r;
+	__u16 dc_b;
+	__u16 dc_gb;
+} __packed;
+
+struct ipu3_uapi_anr_beta {
+	__u16 beta_gr;					/* 11 bits */
+	__u16 beta_r;
+	__u16 beta_b;
+	__u16 beta_gb;
+} __packed;
+
+struct ipu3_uapi_anr_plain_color {
+	__u16 reg_w_gr[16];				/* 12 bits */
+	__u16 reg_w_r[16];
+	__u16 reg_w_b[16];
+	__u16 reg_w_gb[16];
+} __packed;
+
+struct ipu3_uapi_anr_transform_config {
+	__u32 enable:1;			/* 0 or 1, disabled or enabled */
+	__u32 adaptive_treshhold_en:1;	/* On IPU3, always enabled */
+
+	__u32 __reserved1:30;
+	__u8 __reserved2[40+4];
+
+	struct ipu3_uapi_anr_alpha alpha[3];
+	struct ipu3_uapi_anr_beta beta[3];
+	struct ipu3_uapi_anr_plain_color color[3];
+
+	__u16 sqrt_lut[IPU3_UAPI_ANR_LUT_SIZE];	/* 11 bits per element */
+
+	__s16 xreset:13;
+#define IPU3_UAPI_ANR_MAX_XRESET		((1 << 12) - 1)
+	__u16 __reserved3:3;
+	__s16 yreset:13;
+	__u16 __reserved4:3;
+
+	__u32 x_sqr_reset:24;
+	__u32 r_normfactor:5;
+	__u32 __reserved5:3;
+
+	__u32 y_sqr_reset:24;
+	__u32 gain_scale:8;
+} __packed;
+
+struct ipu3_uapi_anr_stitch_pyramid {
+	__u32 entry0:6;
+	__u32 entry1:6;
+	__u32 entry2:6;
+	__u32 __reserved:14;
+} __packed;
+
+struct ipu3_uapi_anr_stitch_config {
+	__u32 anr_stitch_en;
+	__u16 frame_width;
+	__u16 frame_height;
+	__u8 __reserved[40];
+	struct ipu3_uapi_anr_stitch_pyramid pyramid[IPU3_UAPI_ANR_PYRAMID_SIZE];
+} __packed;
+
+struct ipu3_uapi_anr_tile2strm_config {
+	__u32 enable;
+	__u16 frame_width;
+	__u16 frame_height;
+} __packed;
+
+struct ipu3_uapi_anr_config {
+	struct ipu3_uapi_anr_search_config search IPU3_ALIGN;
+	struct ipu3_uapi_anr_transform_config transform IPU3_ALIGN;
+	struct ipu3_uapi_anr_stitch_config stitch IPU3_ALIGN;
+	struct ipu3_uapi_anr_tile2strm_config tile2strm IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_awb_fr_intra_frame_operations_data {
+	struct ipu3_uapi_acc_operation ops[IPU3_UAPI_AWB_FR_MAX_OPERATIONS]
+								IPU3_ALIGN;
+	struct ipu3_uapi_acc_process_lines_cmd_data
+	      process_lines_data[IPU3_UAPI_AWB_FR_MAX_PROCESS_LINES] IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_awb_fr_config {
+	struct ipu3_uapi_awb_fr_config_s config;
+	struct ipu3_uapi_awb_fr_intra_frame_operations_data operations_data;
+	struct ipu3_uapi_awb_fr_config_s stripes[IPU3_UAPI_MAX_STRIPES];
+} __packed;
+
+struct ipu3_uapi_ae_weight_elem {
+	__u32 cell0:4;
+	__u32 cell1:4;
+	__u32 cell2:4;
+	__u32 cell3:4;
+	__u32 cell4:4;
+	__u32 cell5:4;
+	__u32 cell6:4;
+	__u32 cell7:4;
+} __packed;
+
+struct ipu3_uapi_ae_ccm {
+	__u16 gain_gr;			/* 11 bits */
+	__u16 gain_r;
+	__u16 gain_b;
+	__u16 gain_gb;
+	__s16 mat[16];
+} __packed;
+
+struct ipu3_uapi_ae_config {
+	struct ipu3_uapi_ae_grid_config grid_cfg IPU3_ALIGN;
+	struct ipu3_uapi_ae_weight_elem weights[IPU3_UAPI_AE_WEIGHTS]
+								IPU3_ALIGN;
+	struct ipu3_uapi_ae_ccm ae_ccm IPU3_ALIGN;
+	struct {
+		struct ipu3_uapi_ae_grid_config grid IPU3_ALIGN;
+	} stripes[IPU3_UAPI_MAX_STRIPES];
+} __packed;
+
+struct ipu3_uapi_af_intra_frame_operations_data {
+	struct ipu3_uapi_acc_operation ops[IPU3_UAPI_AF_MAX_OPERATIONS]
+		IPU3_ALIGN;
+	struct ipu3_uapi_acc_process_lines_cmd_data
+		process_lines_data[IPU3_UAPI_AF_MAX_PROCESS_LINES] IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_af_stripe_config {
+	struct ipu3_uapi_af_frame_size frame_size IPU3_ALIGN;
+	struct ipu3_uapi_grid_config grid_cfg IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_af_config {
+	struct ipu3_uapi_af_config_s config;
+	struct ipu3_uapi_af_intra_frame_operations_data operations_data;
+	struct ipu3_uapi_af_stripe_config stripes[IPU3_UAPI_MAX_STRIPES];
+} __packed;
+
+struct ipu3_uapi_acc_transfer_op_data {
+	__u8 set_number;
+} __packed;
+
+struct IPU3_ALIGN ipu3_uapi_awb_intra_frame_operations_data {
+	struct ipu3_uapi_acc_operation ops[IPU3_UAPI_AWB_MAX_OPERATIONS]
+		IPU3_ALIGN;
+	struct ipu3_uapi_acc_process_lines_cmd_data
+		process_lines_data[IPU3_UAPI_AWB_MAX_PROCESS_LINES] IPU3_ALIGN;
+	struct ipu3_uapi_acc_transfer_op_data
+		transfer_data[IPU3_UAPI_AWB_MAX_TRANSFERS] IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_awb_config {
+	struct ipu3_uapi_awb_config_s config IPU3_ALIGN;
+	struct ipu3_uapi_awb_intra_frame_operations_data operations_data;
+	struct ipu3_uapi_awb_config_s stripes[IPU3_UAPI_MAX_STRIPES];
+} __packed;
+
+struct ipu3_uapi_osys_formatter_params {
+	__u32 format;
+	__u32 flip;
+	__u32 mirror;
+	__u32 tiling;
+	__u32 reduce_range;
+	__u32 alpha_blending;	/* FIXME: To figure out the unknown register */
+	__u32 release_inp_addr;
+	__u32 release_inp_en;
+	__u32 process_out_buf_addr;
+	__u32 image_width_vecs;
+	__u32 image_height_lines;
+	__u32 inp_buff_y_st_addr;
+	__u32 inp_buff_y_line_stride;
+	__u32 inp_buff_y_buffer_stride;
+	__u32 int_buff_u_st_addr;
+	__u32 int_buff_v_st_addr;
+	__u32 inp_buff_uv_line_stride;
+	__u32 inp_buff_uv_buffer_stride;
+	__u32 out_buff_level;
+	__u32 out_buff_nr_y_lines;
+	__u32 out_buff_u_st_offset;
+	__u32 out_buff_v_st_offset;
+	__u32 out_buff_y_line_stride;
+	__u32 out_buff_uv_line_stride;
+	__u32 hist_buff_st_addr;
+	__u32 hist_buff_line_stride;
+	__u32 hist_buff_nr_lines;
+} __packed;
+
+struct ipu3_uapi_osys_formatter {
+	struct ipu3_uapi_osys_formatter_params param IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_osys_scaler_params {
+	__u32 inp_buf_y_st_addr;
+	__u32 inp_buf_y_line_stride;
+	__u32 inp_buf_y_buffer_stride;
+	__u32 inp_buf_u_st_addr;
+	__u32 inp_buf_v_st_addr;
+	__u32 inp_buf_uv_line_stride;
+	__u32 inp_buf_uv_buffer_stride;
+	__u32 inp_buf_chunk_width;
+	__u32 inp_buf_nr_buffers;
+	/* Output buffers */
+	__u32 out_buf_y_st_addr;
+	__u32 out_buf_y_line_stride;
+	__u32 out_buf_y_buffer_stride;
+	__u32 out_buf_u_st_addr;
+	__u32 out_buf_v_st_addr;
+	__u32 out_buf_uv_line_stride;
+	__u32 out_buf_uv_buffer_stride;
+	__u32 out_buf_nr_buffers;
+	/* Intermediate buffers */
+	__u32 int_buf_y_st_addr;
+	__u32 int_buf_y_line_stride;
+	__u32 int_buf_u_st_addr;
+	__u32 int_buf_v_st_addr;
+	__u32 int_buf_uv_line_stride;
+	__u32 int_buf_height;
+	__u32 int_buf_chunk_width;
+	__u32 int_buf_chunk_height;
+	/* Context buffers */
+	__u32 ctx_buf_hor_y_st_addr;
+	__u32 ctx_buf_hor_u_st_addr;
+	__u32 ctx_buf_hor_v_st_addr;
+	__u32 ctx_buf_ver_y_st_addr;
+	__u32 ctx_buf_ver_u_st_addr;
+	__u32 ctx_buf_ver_v_st_addr;
+	/* Addresses for release-input and process-output tokens */
+	__u32 release_inp_buf_addr;
+	__u32 release_inp_buf_en;
+	__u32 release_out_buf_en;
+	__u32 process_out_buf_addr;
+	/* Settings dimensions, padding, cropping */
+	__u32 input_image_y_width;
+	__u32 input_image_y_height;
+	__u32 input_image_y_start_column;
+	__u32 input_image_uv_start_column;
+	__u32 input_image_y_left_pad;
+	__u32 input_image_uv_left_pad;
+	__u32 input_image_y_right_pad;
+	__u32 input_image_uv_right_pad;
+	__u32 input_image_y_top_pad;
+	__u32 input_image_uv_top_pad;
+	__u32 input_image_y_bottom_pad;
+	__u32 input_image_uv_bottom_pad;
+	__u32 processing_mode;
+#define IPU3_UAPI_OSYS_PROCMODE_BYPASS		0
+#define IPU3_UAPI_OSYS_PROCMODE_UPSCALE		1
+#define IPU3_UAPI_OSYS_PROCMODE_DOWNSCALE	2
+	__u32 scaling_ratio;
+	__u32 y_left_phase_init;
+	__u32 uv_left_phase_init;
+	__u32 y_top_phase_init;
+	__u32 uv_top_phase_init;
+	__u32 coeffs_exp_shift;
+	__u32 out_y_left_crop;
+	__u32 out_uv_left_crop;
+	__u32 out_y_top_crop;
+	__u32 out_uv_top_crop;
+} __packed;
+
+struct ipu3_uapi_osys_scaler {
+	struct ipu3_uapi_osys_scaler_params param IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_osys_frame_params {
+	/* Output pins */
+	__u32 enable;
+	__u32 format;			/* enum ipu3_uapi_osys_format */
+	__u32 flip;
+	__u32 mirror;
+	__u32 tiling;			/* enum ipu3_uapi_osys_tiling */
+	__u32 width;
+	__u32 height;
+	__u32 stride;
+	__u32 scaled;
+} __packed;
+
+struct ipu3_uapi_osys_frame {
+	struct ipu3_uapi_osys_frame_params param IPU3_ALIGN;
+} __packed;
+
+struct ipu3_uapi_osys_stripe {
+	/* Input resolution */
+	__u32 input_width;
+	__u32 input_height;
+	/* Output Stripe */
+	__u32 output_width[IPU3_UAPI_OSYS_PINS];
+	__u32 output_height[IPU3_UAPI_OSYS_PINS];
+	__u32 output_offset[IPU3_UAPI_OSYS_PINS];
+	__u32 buf_stride[IPU3_UAPI_OSYS_PINS];
+	/* Scaler params */
+	__u32 block_width;
+	__u32 block_height;
+	/* Output Crop factor */
+	__u32 crop_top[IPU3_UAPI_OSYS_PINS];
+	__u32 crop_left[IPU3_UAPI_OSYS_PINS];
+} __packed;
+
+struct ipu3_uapi_osys_config {
+	struct ipu3_uapi_osys_formatter
+		formatter[IPU3_UAPI_MAX_STRIPES][IPU3_UAPI_OSYS_PINS];
+	struct ipu3_uapi_osys_scaler scaler[IPU3_UAPI_MAX_STRIPES];
+	struct ipu3_uapi_osys_frame frame[IPU3_UAPI_OSYS_PINS];
+	struct ipu3_uapi_osys_stripe stripe[IPU3_UAPI_MAX_STRIPES];
+	/* 32 packed coefficients for luma and chroma */
+	__s8 scaler_coeffs_chroma[128];
+	__s8 scaler_coeffs_luma[128];
+} __packed;
+
+struct ipu3_uapi_acc_param {
+	struct ipu3_uapi_stripe_data stripe;
+	__u8 padding[8];
+	struct ipu3_uapi_input_feeder_config input_feeder;
+	struct ipu3_uapi_bnr_static_config bnr;
+	struct ipu3_uapi_bnr_static_config_green_disparity green_disparity
+		IPU3_ALIGN;
+	struct ipu3_uapi_dm_config dm IPU3_ALIGN;
+	struct ipu3_uapi_ccm_mat_config ccm IPU3_ALIGN;
+	struct ipu3_uapi_gamma_config gamma IPU3_ALIGN;
+	struct ipu3_uapi_csc_mat_config csc IPU3_ALIGN;
+	struct ipu3_uapi_cds_params cds IPU3_ALIGN;
+	struct ipu3_uapi_shd_config shd IPU3_ALIGN;
+	struct ipu3_uapi_dvs_stat_config dvs_stat IPU3_ALIGN;
+	struct ipu3_uapi_lace_stat_config lace_stat IPU3_ALIGN;
+	struct ipu3_uapi_yuvp1_iefd_config iefd IPU3_ALIGN;
+	struct ipu3_uapi_yuvp1_yds_config yds_c0 IPU3_ALIGN;
+	struct ipu3_uapi_yuvp1_chnr_config chnr_c0 IPU3_ALIGN;
+	struct ipu3_uapi_yuvp1_y_ee_nr_config y_ee_nr IPU3_ALIGN;
+	struct ipu3_uapi_yuvp1_yds_config yds IPU3_ALIGN;
+	struct ipu3_uapi_yuvp1_chnr_config chnr IPU3_ALIGN;
+	struct ipu3_uapi_yuvp2_y_tm_lut_static_config ytm IPU3_ALIGN;
+	struct ipu3_uapi_yuvp1_yds_config yds2 IPU3_ALIGN;
+	struct ipu3_uapi_yuvp2_tcc_static_config tcc IPU3_ALIGN;
+	struct ipu3_uapi_dpc_config dpc IPU3_ALIGN;
+	struct ipu3_uapi_bds_config bds IPU3_ALIGN;
+	struct ipu3_uapi_anr_config anr IPU3_ALIGN;
+	struct ipu3_uapi_awb_fr_config awb_fr IPU3_ALIGN;
+	struct ipu3_uapi_ae_config ae IPU3_ALIGN;
+	struct ipu3_uapi_af_config af IPU3_ALIGN;
+	struct ipu3_uapi_awb_config awb IPU3_ALIGN;
+	struct ipu3_uapi_osys_config osys IPU3_ALIGN;
+} __packed;
+
+/* Linearization parameters */
+
+#define IPU3_UAPI_LIN_LUT_SIZE			64
+
+struct ipu3_uapi_isp_lin_vmem_params {
+	__s16 lin_lutlow_gr[IPU3_UAPI_LIN_LUT_SIZE];
+	__s16 lin_lutlow_r[IPU3_UAPI_LIN_LUT_SIZE];
+	__s16 lin_lutlow_b[IPU3_UAPI_LIN_LUT_SIZE];
+	__s16 lin_lutlow_gb[IPU3_UAPI_LIN_LUT_SIZE];
+	__s16 lin_lutdif_gr[IPU3_UAPI_LIN_LUT_SIZE];
+	__s16 lin_lutdif_r[IPU3_UAPI_LIN_LUT_SIZE];
+	__s16 lin_lutdif_b[IPU3_UAPI_LIN_LUT_SIZE];
+	__s16 lin_lutdif_gb[IPU3_UAPI_LIN_LUT_SIZE];
+} __packed;
+
+/* TNR3 VMEM parameters */
+
+#define IPU3_UAPI_ISP_TNR3_VMEM_LEN	9
+
+struct ipu3_uapi_isp_tnr3_vmem_params {
+	__u16 slope[IPU3_UAPI_ISP_TNR3_VMEM_LEN];
+	__u16 __reserved1[IPU3_UAPI_ISP_VEC_ELEMS
+						- IPU3_UAPI_ISP_TNR3_VMEM_LEN];
+	__u16 sigma[IPU3_UAPI_ISP_TNR3_VMEM_LEN];
+	__u16 __reserved2[IPU3_UAPI_ISP_VEC_ELEMS
+						- IPU3_UAPI_ISP_TNR3_VMEM_LEN];
+} __packed;
+
+/* XNR3 VMEM parameters */
+
+struct ipu3_uapi_isp_xnr3_vmem_params {
+	__u16 x[IPU3_UAPI_ISP_VEC_ELEMS];
+	__u16 a[IPU3_UAPI_ISP_VEC_ELEMS];
+	__u16 b[IPU3_UAPI_ISP_VEC_ELEMS];
+	__u16 c[IPU3_UAPI_ISP_VEC_ELEMS];
+} __packed;
+
+/* TNR3 DMEM parameters */
+
+struct ipu3_uapi_isp_tnr3_params {
+	__u32 knee_y1;
+	__u32 knee_y2;
+	__u32 maxfb_y;
+	__u32 maxfb_u;
+	__u32 maxfb_v;
+	__u32 round_adj_y;
+	__u32 round_adj_u;
+	__u32 round_adj_v;
+	__u32 ref_buf_select;
+} __packed;
+
+/* XNR3 DMEM parameters */
+
+struct ipu3_uapi_xnr3_alpha_params {
+	__u32 y0;
+	__u32 u0;
+	__u32 v0;
+	__u32 ydiff;
+	__u32 udiff;
+	__u32 vdiff;
+} __packed;
+
+struct ipu3_uapi_xnr3_coring_params {
+	__u32 u0;
+	__u32 v0;
+	__u32 udiff;
+	__u32 vdiff;
+} __packed;
+
+struct ipu3_uapi_xnr3_blending_params {
+	__u32 strength;
+} __packed;
+
+struct ipu3_uapi_isp_xnr3_params {
+	struct ipu3_uapi_xnr3_alpha_params alpha;
+	struct ipu3_uapi_xnr3_coring_params coring;
+	struct ipu3_uapi_xnr3_blending_params blending;
+} __packed;
+
+/* RGBIR DMEM parameters */
+
+#define IPU3_UAPI_RGBIR_LUT_WIDTH	17
+#define IPU3_UAPI_RGBIR_LUT_HEIGHT	10
+#define IPU3_UAPI_RGBIR_LUT_SIZE	(IPU3_UAPI_RGBIR_LUT_WIDTH * \
+					 IPU3_UAPI_RGBIR_LUT_HEIGHT)
+
+struct ipu3_uapi_isp_rgbir_params {
+	__u16 ob;					/* optical black level*/
+	__u16 ir_height;				/* lut table height */
+	__u16 ir_width;					/* lut table width */
+	__u16 ir_weights_r[IPU3_UAPI_RGBIR_LUT_SIZE];	/* lut values for red */
+	__u16 ir_weights_g[IPU3_UAPI_RGBIR_LUT_SIZE];	/* lut for green */
+	__u16 ir_weights_b[IPU3_UAPI_RGBIR_LUT_SIZE];	/* lut for blue */
+	__u16 ir_gain;					/* digital gain */
+} __packed;
+
+/***** Morphing table entry *****/
+
+#define IPU3_UAPI_GDC_FRAC_BITS		8
+
+struct ipu3_uapi_gdc_warp_param {
+	__u32 origin_x;
+	__u32 origin_y;
+	__u32 in_addr_offset;
+	__u32 in_block_width;
+	__u32 in_block_height;
+	__u32 p0_x;
+	__u32 p0_y;
+	__u32 p1_x;
+	__u32 p1_y;
+	__u32 p2_x;
+	__u32 p2_y;
+	__u32 p3_x;
+	__u32 p3_y;
+	__u32 in_block_width_a;
+	__u32 in_block_width_b;
+	__u32 padding;			/* struct size multiple of DDR word */
+} __packed;
+
+/***** Obgrid (optical black level compensation) table entry *****/
+
+struct ipu3_uapi_obgrid_param {
+	__u16 gr;
+	__u16 r;
+	__u16 b;
+	__u16 gb;
+} __packed;
+
+/******************* V4L2_PIX_FMT_IPU3_PARAMS *******************/
+
+/*
+ * The video queue "parameters" is of format V4L2_PIX_FMT_IPU3_PARAMS.
+ * It is a multiplanar output queue with three planes and type
+ * V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE. User may also configure the
+ * video queue as V4L2_BUF_TYPE_VIDEO_OUTPUT with a single plane, in which
+ * case GDC and Obgrid tables can not be set.
+ *
+ * Plane 0: Defined below in struct ipu3_params, size 288064 bytes.
+ *          This contains a lot of parameters and flags selecting which
+ *          parameters to apply. Its size and resolution (1x1) are fixed.
+ *
+ * Plane 1: Contains geometric distortion correction grid coordinates.
+ *          Each entry in the grid is defined in
+ *          struct ipu3_uapi_gdc_warp_param.
+ *          The plane size is the grid entry size times the number of entries,
+ *          which depends on the main output image resolution and block size.
+ *
+ * Plane 2: Contains Obgrid grid. Each entry in the grid is 8 bytes.
+ *          The plane size depends on user parameters (internally, on chosen
+ *          firmware binary which depends on user parameters).
+ */
+
+struct ipu3_uapi_flags {
+	/* Flags which of the settings below are to be applied */
+	__u32 gdc:1;		/* Whether to apply GDC and */
+	__u32 obgrid:1;		/* Obgrid planes */
+	__u32 __reserved1:30;
+
+	__u32 __acc_stripe:1;	/* Whether to apply these fields from */
+	__u32 __acc_input_feeder:1;	/* acc_param. Fields beginning with */
+	__u32 acc_bnr:1;		/* two underscores are reserved and */
+	__u32 acc_green_disparity:1;/* must not be enabled */
+	__u32 acc_dm:1;
+	__u32 acc_ccm:1;
+	__u32 acc_gamma:1;
+	__u32 acc_csc:1;
+	__u32 acc_cds:1;
+	__u32 acc_shd:1;
+	__u32 acc_dvs_stat:1;
+	__u32 acc_lace_stat:1;
+	__u32 acc_iefd:1;
+	__u32 acc_yds_c0:1;
+	__u32 acc_chnr_c0:1;
+	__u32 acc_y_ee_nr:1;
+	__u32 acc_yds:1;
+	__u32 acc_chnr:1;
+	__u32 acc_ytm:1;
+	__u32 acc_yds2:1;
+	__u32 acc_tcc:1;
+	__u32 acc_dpc:1;
+	__u32 acc_bds:1;
+	__u32 acc_anr:1;
+	__u32 acc_awb_fr:1;
+	__u32 acc_ae:1;
+	__u32 acc_af:1;
+	__u32 acc_awb:1;
+	__u32 __acc_osys:1;
+	__u32 __reserved2:3;
+
+	__u32 lin_vmem_params:1;	/* Whether to apply these structs */
+	__u32 tnr3_vmem_params:1;
+	__u32 xnr3_vmem_params:1;
+	__u32 tnr3_dmem_params:1;
+	__u32 xnr3_dmem_params:1;
+	__u32 __rgbir_dmem_params:1;
+	__u32 obgrid_param:1;
+	__u32 __reserved3:25;
+} __packed;
+
+struct ipu3_uapi_params {
+	__u32 fourcc;			/* V4L2_PIX_FMT_IPU3_PARAMS */
+	__u32 version;			/* Must be 0x100 */
+
+	struct ipu3_uapi_flags use;
+
+	__u8 __reserved4[32 - 4 * 5];	/* Must be zero */
+
+	/* Acceleration cluster parameters */
+	struct ipu3_uapi_acc_param acc_param;
+
+	/* VMEM parameters */
+	struct ipu3_uapi_isp_lin_vmem_params lin_vmem_params;
+	struct ipu3_uapi_isp_tnr3_vmem_params tnr3_vmem_params;
+	struct ipu3_uapi_isp_xnr3_vmem_params xnr3_vmem_params;
+
+	/* DMEM parameters */
+	struct ipu3_uapi_isp_tnr3_params tnr3_dmem_params;
+	struct ipu3_uapi_isp_xnr3_params xnr3_dmem_params;
+	struct ipu3_uapi_isp_rgbir_params rgbir_dmem_params;
+
+	struct ipu3_uapi_obgrid_param obgrid_param;
+	__u8 padding[4];
+} __packed;
+
+#endif
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v4 06/12] intel-ipu3: css: imgu dma buff pool
  2017-10-18  3:54 [PATCH v4 04/12] intel-ipu3: Add user space ABI definitions Yong Zhi
@ 2017-10-18  3:54 ` Yong Zhi
  2017-10-20 10:38   ` Sakari Ailus
  2017-10-18  3:54 ` [PATCH v4 07/12] intel-ipu3: css: firmware management Yong Zhi
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 19+ messages in thread
From: Yong Zhi @ 2017-10-18  3:54 UTC (permalink / raw)
  To: linux-media, sakari.ailus
  Cc: jian.xu.zheng, rajmohan.mani, tuukka.toivonen, jerry.w.hu,
	Yong Zhi, Tomasz Figa

The pools are used to store previous parameters set by
user with the parameter queue. Due to pipelining,
there needs to be multiple sets (up to four)
of parameters which are queued in a host-to-sp queue.

Signed-off-by: Yong Zhi <yong.zhi@intel.com>
Signed-off-by: Tomasz Figa <tfiga@chromium.org>
---
 drivers/media/pci/intel/ipu3/ipu3-css-pool.c | 132 +++++++++++++++++++++++++++
 drivers/media/pci/intel/ipu3/ipu3-css-pool.h |  54 +++++++++++
 2 files changed, 186 insertions(+)
 create mode 100644 drivers/media/pci/intel/ipu3/ipu3-css-pool.c
 create mode 100644 drivers/media/pci/intel/ipu3/ipu3-css-pool.h

diff --git a/drivers/media/pci/intel/ipu3/ipu3-css-pool.c b/drivers/media/pci/intel/ipu3/ipu3-css-pool.c
new file mode 100644
index 000000000000..d08e2a8b68ed
--- /dev/null
+++ b/drivers/media/pci/intel/ipu3/ipu3-css-pool.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2017 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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/dma-direction.h>
+#include <linux/scatterlist.h>
+#include <linux/types.h>
+
+#include "ipu3-css-pool.h"
+#include "ipu3-dmamap.h"
+
+int ipu3_css_dma_alloc(struct device *dev,
+		       struct ipu3_css_map *map, size_t size)
+{
+	struct imgu_device *imgu = dev_get_drvdata(dev);
+
+	if (size == 0) {
+		map->vaddr = NULL;
+		return 0;
+	}
+
+	if (!ipu3_dmamap_alloc(imgu, map, size))
+		return -ENOMEM;
+
+	return 0;
+}
+
+void ipu3_css_dma_free(struct device *dev, struct ipu3_css_map *map)
+{
+	struct imgu_device *imgu = dev_get_drvdata(dev);
+
+	ipu3_dmamap_free(imgu, map);
+}
+
+void ipu3_css_pool_cleanup(struct device *dev, struct ipu3_css_pool *pool)
+{
+	int i;
+
+	for (i = 0; i < IPU3_CSS_POOL_SIZE; i++)
+		ipu3_css_dma_free(dev, &pool->entry[i].param);
+}
+
+int ipu3_css_pool_init(struct device *dev, struct ipu3_css_pool *pool,
+		       int size)
+{
+	int i;
+
+	for (i = 0; i < IPU3_CSS_POOL_SIZE; i++) {
+		pool->entry[i].framenum = INT_MIN;
+		if (ipu3_css_dma_alloc(dev, &pool->entry[i].param, size))
+			goto fail;
+	}
+
+	pool->last = IPU3_CSS_POOL_SIZE;
+
+	return 0;
+
+fail:
+	ipu3_css_pool_cleanup(dev, pool);
+	return -ENOMEM;
+}
+
+/*
+ * Check that the following call to pool_get succeeds.
+ * Return negative on error.
+ */
+static int ipu3_css_pool_check(struct ipu3_css_pool *pool, long framenum)
+{
+	/* Get the oldest entry */
+	int n = (pool->last + 1) % IPU3_CSS_POOL_SIZE;
+
+	/*
+	 * pool->entry[n].framenum stores the frame number where that
+	 * entry was allocated. If that was allocated more than POOL_SIZE
+	 * frames back, it is old enough that we know it is no more in
+	 * use by firmware.
+	 */
+	if (pool->entry[n].framenum + IPU3_CSS_POOL_SIZE > framenum)
+		return -ENOSPC;
+
+	return n;
+}
+
+/*
+ * Allocate a new parameter from pool at frame number `framenum'.
+ * Release the oldest entry in the pool to make space for the new entry.
+ * Return negative on error.
+ */
+int ipu3_css_pool_get(struct ipu3_css_pool *pool, long framenum)
+{
+	int n = ipu3_css_pool_check(pool, framenum);
+
+	if (n < 0)
+		return n;
+
+	pool->entry[n].framenum = framenum;
+	pool->last = n;
+
+	return n;
+}
+
+/*
+ * Undo, for all practical purposes, the effect of pool_get().
+ */
+void ipu3_css_pool_put(struct ipu3_css_pool *pool)
+{
+	pool->entry[pool->last].framenum = INT_MIN;
+	pool->last = (pool->last + IPU3_CSS_POOL_SIZE - 1) % IPU3_CSS_POOL_SIZE;
+}
+
+const struct ipu3_css_map *
+ipu3_css_pool_last(struct ipu3_css_pool *pool, unsigned int n)
+{
+	static const struct ipu3_css_map null_map = { 0 };
+	int i = (pool->last + IPU3_CSS_POOL_SIZE - n) % IPU3_CSS_POOL_SIZE;
+
+	WARN_ON(n >= IPU3_CSS_POOL_SIZE);
+
+	if (pool->entry[i].framenum < 0)
+		return &null_map;
+
+	return &pool->entry[i].param;
+}
diff --git a/drivers/media/pci/intel/ipu3/ipu3-css-pool.h b/drivers/media/pci/intel/ipu3/ipu3-css-pool.h
new file mode 100644
index 000000000000..9b6ac14acfb2
--- /dev/null
+++ b/drivers/media/pci/intel/ipu3/ipu3-css-pool.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2017 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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 __IPU3_UTIL_H
+#define __IPU3_UTIL_H
+
+#include <linux/device.h>
+
+#define sqr(x)				((x) * (x))
+#define DIV_ROUND_CLOSEST_DOWN(a, b)	(((a) + (b / 2) - 1) / (b))
+#define roundclosest_down(a, b)		(DIV_ROUND_CLOSEST_DOWN(a, b) * (b))
+#define roundclosest(n, di)				\
+	({ typeof(n) __n = (n); typeof(di) __di = (di); \
+	DIV_ROUND_CLOSEST(__n, __di) * __di; })
+
+#define IPU3_CSS_POOL_SIZE		4
+
+struct ipu3_css_map {
+	size_t size;
+	void *vaddr;
+	dma_addr_t daddr;
+	struct vm_struct *vma;
+};
+
+struct ipu3_css_pool {
+	struct {
+		struct ipu3_css_map param;
+		long framenum;
+	} entry[IPU3_CSS_POOL_SIZE];
+	unsigned int last; /* Latest entry */
+};
+
+int ipu3_css_dma_alloc(struct device *dev, struct ipu3_css_map *map,
+		       size_t size);
+void ipu3_css_dma_free(struct device *dev, struct ipu3_css_map *map);
+void ipu3_css_pool_cleanup(struct device *dev, struct ipu3_css_pool *pool);
+int ipu3_css_pool_init(struct device *dev, struct ipu3_css_pool *pool,
+		       int size);
+int ipu3_css_pool_get(struct ipu3_css_pool *pool, long framenum);
+void ipu3_css_pool_put(struct ipu3_css_pool *pool);
+const struct ipu3_css_map *ipu3_css_pool_last(struct ipu3_css_pool *pool,
+					      unsigned int last);
+
+#endif
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v4 07/12] intel-ipu3: css: firmware management
  2017-10-18  3:54 [PATCH v4 04/12] intel-ipu3: Add user space ABI definitions Yong Zhi
  2017-10-18  3:54 ` [PATCH v4 06/12] intel-ipu3: css: imgu dma buff pool Yong Zhi
@ 2017-10-18  3:54 ` Yong Zhi
  2017-10-18  3:54 ` [PATCH v4 08/12] intel-ipu3: params: compute and program ccs Yong Zhi
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 19+ messages in thread
From: Yong Zhi @ 2017-10-18  3:54 UTC (permalink / raw)
  To: linux-media, sakari.ailus
  Cc: jian.xu.zheng, rajmohan.mani, tuukka.toivonen, jerry.w.hu,
	Yong Zhi, Tomasz Figa

Functions to load and install imgu FW blobs

Signed-off-by: Yong Zhi <yong.zhi@intel.com>
Signed-off-by: Tomasz Figa <tfiga@chromium.org>
---
 drivers/media/pci/intel/ipu3/ipu3-abi.h    | 1579 ++++++++++++++++++++++++++++
 drivers/media/pci/intel/ipu3/ipu3-css-fw.c |  270 +++++
 drivers/media/pci/intel/ipu3/ipu3-css-fw.h |  206 ++++
 drivers/media/pci/intel/ipu3/ipu3-css.h    |   54 +
 4 files changed, 2109 insertions(+)
 create mode 100644 drivers/media/pci/intel/ipu3/ipu3-abi.h
 create mode 100644 drivers/media/pci/intel/ipu3/ipu3-css-fw.c
 create mode 100644 drivers/media/pci/intel/ipu3/ipu3-css-fw.h
 create mode 100644 drivers/media/pci/intel/ipu3/ipu3-css.h

diff --git a/drivers/media/pci/intel/ipu3/ipu3-abi.h b/drivers/media/pci/intel/ipu3/ipu3-abi.h
new file mode 100644
index 000000000000..33e7eaca598e
--- /dev/null
+++ b/drivers/media/pci/intel/ipu3/ipu3-abi.h
@@ -0,0 +1,1579 @@
+/*
+ * Copyright (c) 2017 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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 __IPU3_ABI_H
+#define __IPU3_ABI_H
+
+#include <uapi/linux/intel-ipu3.h>
+
+/******************* IMGU Hardware information *******************/
+
+#define IMGU_ISP_VMEM_ALIGN			128
+#define IMGU_DVS_BLOCK_W			64
+#define IMGU_DVS_BLOCK_H			32
+#define IMGU_GDC_BUF_X				(2 * IMGU_DVS_BLOCK_W)
+#define IMGU_GDC_BUF_Y				IMGU_DVS_BLOCK_H
+/* n = 0..1 */
+#define IMGU_SP_PMEM_BASE(n)			(0x20000 + (n) * 0x4000)
+#define IMGU_MAX_BQ_GRID_WIDTH			80
+#define IMGU_MAX_BQ_GRID_HEIGHT			60
+#define IMGU_OBGRID_TILE_SIZE			16
+#define IMGU_PIXELS_PER_WORD			50
+#define IMGU_BYTES_PER_WORD			64
+#define IMGU_STRIPE_FIXED_HALF_OVERLAP		2
+#define IMGU_SHD_SETS				3
+#define IMGU_BDS_MIN_CLIP_VAL			0
+#define IMGU_BDS_MAX_CLIP_VAL			2
+#define IPU3_ABI_AWB_MAX_CELLS_PER_SET		160
+#define IPU3_ABI_AF_MAX_CELLS_PER_SET		32
+#define IPU3_ABI_AWB_FR_MAX_CELLS_PER_SET	32
+
+#define IMGU_ABI_ACC_OP_IDLE			0
+#define IMGU_ABI_ACC_OP_END_OF_ACK		1
+#define IMGU_ABI_ACC_OP_END_OF_OPS		2
+#define IMGU_ABI_ACC_OP_NO_OPS			3
+
+#define IMGU_ABI_ACC_OPTYPE_PROCESS_LINES	0
+#define IMGU_ABI_ACC_OPTYPE_TRANSFER_DATA	1
+
+#define IMGU_MMU_PADDR_SHIFT			12
+
+/* Register definitions */
+
+/* PM_CTRL_0_5_0_IMGHMMADR */
+#define IMGU_REG_PM_CTRL			0x0
+#define IMGU_PM_CTRL_START			BIT(0)
+#define IMGU_PM_CTRL_CFG_DONE			BIT(1)
+#define IMGU_PM_CTRL_RACE_TO_HALT		BIT(2)
+#define IMGU_PM_CTRL_NACK_ALL			BIT(3)
+#define IMGU_PM_CTRL_CSS_PWRDN			BIT(4)
+#define IMGU_PM_CTRL_RST_AT_EOF			BIT(5)
+#define IMGU_PM_CTRL_FORCE_HALT			BIT(6)
+#define IMGU_PM_CTRL_FORCE_UNHALT		BIT(7)
+#define IMGU_PM_CTRL_FORCE_PWRDN		BIT(8)
+#define IMGU_PM_CTRL_FORCE_RESET		BIT(9)
+#define IMGU_PM_CTRL_RETURN_LICENSE_AT_EOF	BIT(10)
+#define IMGU_PM_CTRL_POWER_DOWN_AT_EOF		(IMGU_PM_CTRL_CSS_PWRDN | \
+					IMGU_PM_CTRL_RACE_TO_HALT | \
+					IMGU_PM_CTRL_RETURN_LICENSE_AT_EOF)
+#define IMGU_PM_CTRL_RESET_AT_EOF		(IMGU_PM_CTRL_RST_AT_EOF | \
+					IMGU_PM_CTRL_RACE_TO_HALT | \
+					IMGU_PM_CTRL_RETURN_LICENSE_AT_EOF)
+/* SYSTEM_REQ_0_5_0_IMGHMMADR */
+#define IMGU_REG_SYSTEM_REQ			0x18
+#define IMGU_SYSTEM_REQ_FREQ_MASK		0x3f
+#define IMGU_SYSTEM_REQ_FREQ_DIVIDER		25
+#define IMGU_REG_INT_STATUS			0x30
+#define IMGU_REG_INT_ENABLE			0x34
+#define IMGU_REG_INT_CSS_IRQ			(1 << 31)
+/* STATE_0_5_0_IMGHMMADR */
+#define IMGU_REG_STATE				0x130
+#define IMGU_STATE_HALT_STS			BIT(0)
+#define IMGU_STATE_IDLE_STS			BIT(1)
+#define IMGU_STATE_POWER_UP			BIT(2)
+#define IMGU_STATE_POWER_DOWN			BIT(3)
+#define IMGU_STATE_CSS_BUSY_MASK		0xc0
+#define IMGU_STATE_PM_FSM_MASK			0x180
+#define IMGU_STATE_PWRDNM_FSM_MASK		0x1E00000
+/* PM_STS_0_5_0_IMGHMMADR */
+#define IMGU_REG_PM_STS				0x140
+
+#define IMGU_REG_BASE				0x4000
+
+#define IMGU_REG_ISP_CTRL			(IMGU_REG_BASE + 0x00)
+#define IMGU_CTRL_RST				BIT(0)
+#define IMGU_CTRL_START				BIT(1)
+#define IMGU_CTRL_BREAK				BIT(2)
+#define IMGU_CTRL_RUN				BIT(3)
+#define IMGU_CTRL_BROKEN			BIT(4)
+#define IMGU_CTRL_IDLE				BIT(5)
+#define IMGU_CTRL_SLEEPING			BIT(6)
+#define IMGU_CTRL_STALLING			BIT(7)
+#define IMGU_CTRL_IRQ_CLEAR			BIT(8)
+#define IMGU_CTRL_IRQ_READY			BIT(10)
+#define IMGU_CTRL_IRQ_SLEEPING			BIT(11)
+#define IMGU_CTRL_ICACHE_INV			BIT(12)
+#define IMGU_CTRL_IPREFETCH_EN			BIT(13)
+#define IMGU_REG_ISP_START_ADDR			(IMGU_REG_BASE + 0x04)
+#define IMGU_REG_ISP_ICACHE_ADDR		(IMGU_REG_BASE + 0x10)
+#define IMGU_REG_ISP_PC				(IMGU_REG_BASE + 0x1c)
+
+/* SP Registers, sp = 0:SP0; 1:SP1 */
+#define IMGU_REG_SP_CTRL(sp)		(IMGU_REG_BASE + (sp) * 0x100 + 0x100)
+	/* For bits in IMGU_REG_SP_CTRL, see IMGU_CTRL_* */
+#define IMGU_REG_SP_START_ADDR(sp)	(IMGU_REG_BASE + (sp) * 0x100 + 0x104)
+#define IMGU_REG_SP_ICACHE_ADDR(sp)	(IMGU_REG_BASE + (sp) * 0x100 + 0x11c)
+#define IMGU_REG_SP_CTRL_SINK(sp)	(IMGU_REG_BASE + (sp) * 0x100 + 0x130)
+#define IMGU_REG_SP_PC(sp)		(IMGU_REG_BASE + (sp) * 0x100 + 0x134)
+
+#define IMGU_REG_TLB_INVALIDATE		(IMGU_REG_BASE + 0x300)
+#define IMGU_TLB_INVALIDATE			1
+#define IMGU_REG_L1_PHYS		(IMGU_REG_BASE + 0x304) /* 27-bit pfn */
+
+#define IMGU_REG_CIO_GATE_BURST_STATE	(IMGU_REG_BASE + 0x404)
+#define IMGU_CIO_GATE_BURST_MASK        0x80
+
+#define IMGU_REG_GP_BUSY		(IMGU_REG_BASE + 0x500)
+#define IMGU_REG_GP_STARVING		(IMGU_REG_BASE + 0x504)
+#define IMGU_REG_GP_WORKLOAD		(IMGU_REG_BASE + 0x508)
+#define IMGU_REG_GP_IRQ(n)	(IMGU_REG_BASE + (n) * 4 + 0x50c) /* n = 0..4 */
+#define IMGU_REG_GP_SP1_STRMON_STAT	(IMGU_REG_BASE + 0x520)
+#define IMGU_REG_GP_SP2_STRMON_STAT	(IMGU_REG_BASE + 0x524)
+#define IMGU_REG_GP_ISP_STRMON_STAT	(IMGU_REG_BASE + 0x528)
+#define IMGU_REG_GP_MOD_STRMON_STAT	(IMGU_REG_BASE + 0x52c)
+
+/* Port definitions for the streaming monitors. */
+/* For each definition there is signal pair : valid [bit 0]- accept [bit 1] */
+#define IMGU_GP_STRMON_STAT_SP1_PORT_SP12DMA		BIT(0)
+#define IMGU_GP_STRMON_STAT_SP1_PORT_DMA2SP1		BIT(2)
+#define IMGU_GP_STRMON_STAT_SP1_PORT_SP12SP2		BIT(4)
+#define IMGU_GP_STRMON_STAT_SP1_PORT_SP22SP1		BIT(6)
+#define IMGU_GP_STRMON_STAT_SP1_PORT_SP12ISP		BIT(8)
+#define IMGU_GP_STRMON_STAT_SP1_PORT_ISP2SP1		BIT(10)
+#define IMGU_GP_STRMON_STAT_SP1_PORT_SP12GDC		BIT(12)
+#define IMGU_GP_STRMON_STAT_SP1_PORT_GDC2SP1		BIT(14)
+#define IMGU_GP_STRMON_STAT_SP1_PORT_SP12DECOMP		BIT(16)
+#define IMGU_GP_STRMON_STAT_SP1_PORT_DECOMP2SP1		BIT(18)
+#define IMGU_GP_STRMON_STAT_SP1_PORT_OUTFORMACC		BIT(20)
+#define IMGU_GP_STRMON_STAT_SP1_PORT_OUTSCALER		BIT(22)
+
+#define IMGU_GP_STRMON_STAT_SP2_PORT_SP22DMA		BIT(0)
+#define IMGU_GP_STRMON_STAT_SP2_PORT_DMA2SP2		BIT(2)
+#define IMGU_GP_STRMON_STAT_SP2_PORT_SP22SP1		BIT(4)
+#define IMGU_GP_STRMON_STAT_SP2_PORT_SP12SP2		BIT(6)
+#define IMGU_GP_STRMON_STAT_SP2_PORT_SP22ISP		BIT(8)
+#define IMGU_GP_STRMON_STAT_SP2_PORT_ISP2SP2		BIT(10)
+#define IMGU_GP_STRMON_STAT_SP2_PORT_SP22GDC		BIT(12)
+#define IMGU_GP_STRMON_STAT_SP2_PORT_GDC2SP2		BIT(14)
+#define IMGU_GP_STRMON_STAT_SP2_PORT_SP22DECOMP		BIT(16)
+#define IMGU_GP_STRMON_STAT_SP2_PORT_DECOMP2SP2		BIT(18)
+#define IMGU_GP_STRMON_STAT_SP2_PORT_OUTFORMACC		BIT(20)
+#define IMGU_GP_STRMON_STAT_SP2_PORT_OUTSCALER		BIT(22)
+
+#define IMGU_GP_STRMON_STAT_ISP_PORT_ISP2DMA		BIT(0)
+#define IMGU_GP_STRMON_STAT_ISP_PORT_DMA2ISP		BIT(2)
+#define IMGU_GP_STRMON_STAT_ISP_PORT_ISP2SP1		BIT(4)
+#define IMGU_GP_STRMON_STAT_ISP_PORT_SP12ISP		BIT(6)
+#define IMGU_GP_STRMON_STAT_ISP_PORT_ISP2SP2		BIT(8)
+#define IMGU_GP_STRMON_STAT_ISP_PORT_SP22ISP		BIT(10)
+#define IMGU_GP_STRMON_STAT_ISP_PORT_ISP2GDC		BIT(12)
+#define IMGU_GP_STRMON_STAT_ISP_PORT_GDC2ISP		BIT(14)
+#define IMGU_GP_STRMON_STAT_ISP_PORT_ISP2DECOMP		BIT(16)
+#define IMGU_GP_STRMON_STAT_ISP_PORT_DECOMP2ISP		BIT(18)
+#define IMGU_GP_STRMON_STAT_ISP_PORT_S2V1		BIT(20)
+#define IMGU_GP_STRMON_STAT_ISP_PORT_S2V2		BIT(22)
+#define IMGU_GP_STRMON_STAT_ISP_PORT_S2V3		BIT(24)
+#define IMGU_GP_STRMON_STAT_ISP_PORT_S2V4		BIT(26)
+#define IMGU_GP_STRMON_STAT_ISP_PORT_S2V5		BIT(28)
+#define IMGU_GP_STRMON_STAT_ISP_PORT_S2V6		BIT(30)
+
+/* Between the devices and the fifo */
+#define IMGU_GP_STRMON_STAT_MOD_PORT_SP12DMA		BIT(0)
+#define IMGU_GP_STRMON_STAT_MOD_PORT_DMA2SP1		BIT(2)
+#define IMGU_GP_STRMON_STAT_MOD_PORT_SP22DMA		BIT(4)
+#define IMGU_GP_STRMON_STAT_MOD_PORT_DMA2SP2		BIT(6)
+#define IMGU_GP_STRMON_STAT_MOD_PORT_ISP2DMA		BIT(8)
+#define IMGU_GP_STRMON_STAT_MOD_PORT_DMA2ISP		BIT(10)
+#define IMGU_GP_STRMON_STAT_MOD_PORT_CELLS2GDC		BIT(12)
+#define IMGU_GP_STRMON_STAT_MOD_PORT_GDC2CELLS		BIT(14)
+#define IMGU_GP_STRMON_STAT_MOD_PORT_CELLS2DECOMP	BIT(16)
+#define IMGU_GP_STRMON_STAT_MOD_PORT_DECOMP2CELLS	BIT(18)
+/* n = 1..6 */
+#define IMGU_GP_STRMON_STAT_MOD_PORT_S2V(n)	(1 << (((n) - 1) * 2 + 20))
+
+/* n = 1..15 */
+#define IMGU_GP_STRMON_STAT_ACCS_PORT_ACC(n)		(1 << (((n) - 1) * 2))
+
+/* After FIFO and demux before SP1, n = 1..15 */
+#define IMGU_GP_STRMON_STAT_ACCS2SP1_MON_PORT_ACC(n)	(1 << (((n) - 1) * 2))
+
+/* After FIFO and demux before SP2, n = 1..15 */
+#define IMGU_GP_STRMON_STAT_ACCS2SP2_MON_PORT_ACC(n)	(1 << (((n) - 1) * 2))
+
+#define IMGU_REG_GP_MOD_ISP_STRMON_STAT			(IMGU_REG_BASE + 0x530)
+#define IMGU_REG_GP_ACCS_STRMON_STAT			(IMGU_REG_BASE + 0x534)
+#define IMGU_REG_GP_ACCS_SP1_STRMON_STAT		(IMGU_REG_BASE + 0x538)
+#define IMGU_REG_GP_ACCS_SP2_STRMON_STAT		(IMGU_REG_BASE + 0x53c)
+#define IMGU_REG_GP_SP1_STRMON_STAT_IRQ_COND		(IMGU_REG_BASE + 0x540)
+#define IMGU_REG_GP_SP2_STRMON_STAT_IRQ_COND		(IMGU_REG_BASE + 0x544)
+#define IMGU_REG_GP_ISP_STRMON_STAT_IRQ_COND		(IMGU_REG_BASE + 0x548)
+#define IMGU_REG_GP_MOD_STRMON_STAT_IRQ_COND		(IMGU_REG_BASE + 0x54c)
+#define IMGU_REG_GP_MOD_ISP_STRMON_STAT_IRQ_COND	(IMGU_REG_BASE + 0x550)
+#define IMGU_REG_GP_ACCS_STRMON_STAT_IRQ_COND		(IMGU_REG_BASE + 0x554)
+#define IMGU_REG_GP_ACCS_SP1_STRMON_STAT_IRQ_COND	(IMGU_REG_BASE + 0x558)
+#define IMGU_REG_GP_ACCS_SP2_STRMON_STAT_IRQ_COND	(IMGU_REG_BASE + 0x55c)
+#define IMGU_REG_GP_SP1_STRMON_STAT_IRQ_ENABLE		(IMGU_REG_BASE + 0x560)
+#define IMGU_REG_GP_SP2_STRMON_STAT_IRQ_ENABLE		(IMGU_REG_BASE + 0x564)
+#define IMGU_REG_GP_ISP_STRMON_STAT_IRQ_ENABLE		(IMGU_REG_BASE + 0x568)
+#define IMGU_REG_GP_MOD_STRMON_STAT_IRQ_ENABLE		(IMGU_REG_BASE + 0x56c)
+#define IMGU_REG_GP_MOD_ISP_STRMON_STAT_IRQ_ENABLE	(IMGU_REG_BASE + 0x570)
+#define IMGU_REG_GP_ACCS_STRMON_STAT_IRQ_ENABLE		(IMGU_REG_BASE + 0x574)
+#define IMGU_REG_GP_ACCS_SP1_STRMON_STAT_IRQ_ENABLE	(IMGU_REG_BASE + 0x578)
+#define IMGU_REG_GP_ACCS_SP2_STRMON_STAT_IRQ_ENABLE_IDX (IMGU_REG_BASE + 0x57c)
+#define IMGU_REG_GP_SWITCH_GDC				(IMGU_REG_BASE + 0x580)
+#define IMGU_REG_GP_SWITCH_DECOMP			(IMGU_REG_BASE + 0x584)
+#define IMGU_REG_GP_SWITCH_MAIN_IRQ_CTRL_MAIN		(IMGU_REG_BASE + 0x588)
+#define IMGU_REG_GP_SWITCH_ACC1				(IMGU_REG_BASE + 0x58c)
+#define IMGU_REG_GP_SWITCH_ACC2				(IMGU_REG_BASE + 0x590)
+#define IMGU_REG_GP_SWITCH_ACC3				(IMGU_REG_BASE + 0x594)
+#define IMGU_REG_GP_SWITCH_ACC4				(IMGU_REG_BASE + 0x598)
+#define IMGU_REG_GP_SWITCH_ACC5				(IMGU_REG_BASE + 0x59c)
+#define IMGU_REG_GP_SWITCH_ACC6				(IMGU_REG_BASE + 0x5a0)
+#define IMGU_REG_GP_SWITCH_ACC7				(IMGU_REG_BASE + 0x5a4)
+#define IMGU_REG_GP_SWITCH_ACC8				(IMGU_REG_BASE + 0x5a8)
+#define IMGU_REG_GP_SWITCH_ACC9				(IMGU_REG_BASE + 0x5ac)
+#define IMGU_REG_GP_SWITCH_ACC10			(IMGU_REG_BASE + 0x5b0)
+#define IMGU_REG_GP_SWITCH_ACC11			(IMGU_REG_BASE + 0x5b4)
+#define IMGU_REG_GP_SWITCH_ACC12			(IMGU_REG_BASE + 0x5b8)
+#define IMGU_REG_GP_SWITCH_ACC13			(IMGU_REG_BASE + 0x5bc)
+#define IMGU_REG_GP_SWITCH_ACC14			(IMGU_REG_BASE + 0x5c0)
+#define IMGU_REG_GP_SWITCH_ACC15			(IMGU_REG_BASE + 0x5c4)
+#define IMGU_REG_GP_SWITCH_OUT_FORM_ACC			(IMGU_REG_BASE + 0x5c8)
+#define IMGU_REG_GP_SWITCH_OUT_FORM_SCALER		(IMGU_REG_BASE + 0x5cc)
+#define IMGU_REG_GP_SRST				(IMGU_REG_BASE + 0x5d0)
+#define IMGU_REG_GP_GACC_SRST				(IMGU_REG_BASE + 0x5d4)
+#define IMGU_REG_GP_SLV_REG_SRST			(IMGU_REG_BASE + 0x5d8)
+#define IMGU_REG_GP_HALT				(IMGU_REG_BASE + 0x5dc)
+#define IMGU_REG_GP_HALTED				(IMGU_REG_BASE + 0x5e0)
+
+					/* n = 0..2 (main ctrl, SP0, SP1) */
+#define IMGU_REG_IRQCTRL_BASE(n)	(IMGU_REG_BASE + (n) * 0x100 + 0x700)
+#define IMGU_IRQCTRL_MAIN			0
+#define IMGU_IRQCTRL_SP0			1
+#define IMGU_IRQCTRL_SP1			2
+#define IMGU_IRQCTRL_NUM			3
+#define IMGU_IRQCTRL_IRQ_SP1			BIT(0)
+#define IMGU_IRQCTRL_IRQ_SP2			BIT(1)
+#define IMGU_IRQCTRL_IRQ_ISP			BIT(2)
+#define IMGU_IRQCTRL_IRQ_SP1_STREAM_MON		BIT(3)
+#define IMGU_IRQCTRL_IRQ_SP2_STREAM_MON		BIT(4)
+#define IMGU_IRQCTRL_IRQ_ISP_STREAM_MON		BIT(5)
+#define IMGU_IRQCTRL_IRQ_MOD_STREAM_MON		BIT(6)
+#define IMGU_IRQCTRL_IRQ_MOD_ISP_STREAM_MON	BIT(7)
+#define IMGU_IRQCTRL_IRQ_ACCS_STREAM_MON	BIT(8)
+#define IMGU_IRQCTRL_IRQ_ACCS_SP1_STREAM_MON	BIT(9)
+#define IMGU_IRQCTRL_IRQ_ACCS_SP2_STREAM_MON	BIT(10)
+#define IMGU_IRQCTRL_IRQ_ISP_PMEM_ERROR		BIT(11)
+#define IMGU_IRQCTRL_IRQ_ISP_BAMEM_ERROR	BIT(12)
+#define IMGU_IRQCTRL_IRQ_ISP_VMEM_ERROR		BIT(13)
+#define IMGU_IRQCTRL_IRQ_ISP_DMEM_ERROR		BIT(14)
+#define IMGU_IRQCTRL_IRQ_SP1_ICACHE_MEM_ERROR	BIT(15)
+#define IMGU_IRQCTRL_IRQ_SP1_DMEM_ERROR		BIT(16)
+#define IMGU_IRQCTRL_IRQ_SP2_ICACHE_MEM_ERROR	BIT(17)
+#define IMGU_IRQCTRL_IRQ_SP2_DMEM_ERROR		BIT(18)
+#define IMGU_IRQCTRL_IRQ_ACCS_SCRATCH_MEM_ERROR	BIT(19)
+#define IMGU_IRQCTRL_IRQ_GP_TIMER(n)		BIT(20 + (n)) /* n=0..1 */
+#define IMGU_IRQCTRL_IRQ_DMA			BIT(22)
+#define IMGU_IRQCTRL_IRQ_SW_PIN(n)		BIT(23 + (n)) /* n=0..4 */
+#define IMGU_IRQCTRL_IRQ_ACC_SYS		BIT(28)
+#define IMGU_IRQCTRL_IRQ_OUT_FORM_IRQ_CTRL	BIT(29)
+#define IMGU_IRQCTRL_IRQ_SP1_IRQ_CTRL		BIT(30)
+#define IMGU_IRQCTRL_IRQ_SP2_IRQ_CTRL		BIT(31)
+#define IMGU_REG_IRQCTRL_EDGE(n)	(IMGU_REG_IRQCTRL_BASE(n) + 0x00)
+#define IMGU_REG_IRQCTRL_MASK(n)	(IMGU_REG_IRQCTRL_BASE(n) + 0x04)
+#define IMGU_REG_IRQCTRL_STATUS(n)	(IMGU_REG_IRQCTRL_BASE(n) + 0x08)
+#define IMGU_REG_IRQCTRL_CLEAR(n)	(IMGU_REG_IRQCTRL_BASE(n) + 0x0c)
+#define IMGU_REG_IRQCTRL_ENABLE(n)	(IMGU_REG_IRQCTRL_BASE(n) + 0x10)
+#define IMGU_REG_IRQCTRL_EDGE_NOT_PULSE(n) (IMGU_REG_IRQCTRL_BASE(n) + 0x14)
+#define IMGU_REG_IRQCTRL_STR_OUT_ENABLE(n) (IMGU_REG_IRQCTRL_BASE(n) + 0x18)
+
+#define IMGU_REG_GP_TIMER		(IMGU_REG_BASE + 0xa34)
+
+#define IMGU_REG_SP_DMEM_BASE(n)	(IMGU_REG_BASE + (n) * 0x4000 + 0x4000)
+#define IMGU_REG_ISP_DMEM_BASE		(IMGU_REG_BASE + 0xc000)
+
+#define IMGU_REG_GDC_BASE		(IMGU_REG_BASE + 0x18000)
+#define IMGU_REG_GDC_LUT_BASE		(IMGU_REG_GDC_BASE + 0x140)
+#define IMGU_GDC_LUT_MASK		((1 << 12) - 1) /* Range -1024..+1024 */
+
+#define IMGU_SCALER_PHASES			32
+#define IMGU_SCALER_COEFF_BITS			24
+#define IMGU_SCALER_PHASE_COUNTER_PREC_REF	6
+#define IMGU_SCALER_MAX_EXPONENT_SHIFT		3
+#define IMGU_SCALER_FILTER_TAPS			4
+#define IMGU_SCALER_TAPS_Y			IMGU_SCALER_FILTER_TAPS
+#define IMGU_SCALER_TAPS_UV			(IMGU_SCALER_FILTER_TAPS / 2)
+#define IMGU_SCALER_FIR_PHASES \
+		(IMGU_SCALER_PHASES << IMGU_SCALER_PHASE_COUNTER_PREC_REF)
+#define IMGU_OSYS_BLOCK_WIDTH			(2 * IPU3_UAPI_ISP_VEC_ELEMS)
+#define IMGU_OSYS_BLOCK_HEIGHT			32
+
+/******************* imgu_abi_acc_param *******************/
+
+#define IMGU_ABI_BNR_LUT_SIZE			32
+
+/* number of elements in gamma correction LUT */
+#define IMGU_ABI_GAMMA_CORR_LUT_ENTRIES		256
+
+#define IMGU_ABI_SHD_MAX_OPERATIONS \
+		(IMGU_ABI_SHD_MAX_PROCESS_LINES + IMGU_ABI_SHD_MAX_TRANSFERS)
+#define IMGU_ABI_SHD_MAX_PROCESS_LINES		31
+#define IMGU_ABI_SHD_MAX_TRANSFERS		31
+#define IMGU_ABI_SHD_MAX_CELLS_PER_SET		146
+/* largest grid is 73x56 */
+#define IMGU_ABI_SHD_MAX_CFG_SETS		(2 * 28)
+
+#define IMGU_ABI_DVS_STAT_L0_MD_ENTRIES		84
+#define IMGU_ABI_DVS_STAT_PARTS_IN_MD_ENTRY	10
+#define IMGU_ABI_DVS_STAT_L1_MD_ENTRIES		66
+#define IMGU_ABI_DVS_STAT_L2_MD_ENTRIES		45
+#define IMGU_ABI_DVS_STAT_MAX_OPERATIONS	100
+#define IMGU_ABI_DVS_STAT_MAX_PROCESS_LINES	52
+#define IMGU_ABI_DVS_STAT_MAX_TRANSFERS		52
+
+#define IMGU_ABI_YUVP2_YTM_LUT_ENTRIES		256
+#define IMGU_ABI_YUVP2_TCC_MACC_TABLE_ELEMENTS	16
+#define IMGU_ABI_YUVP2_TCC_INV_Y_LUT_ELEMENTS	14
+#define IMGU_ABI_YUVP2_TCC_GAIN_PCWL_LUT_ELEMENTS	258
+#define IMGU_ABI_YUVP2_TCC_R_SQR_LUT_ELEMENTS		24
+
+#define IMGU_ABI_DPC_COMMANDS_PER_TRANSFER	2
+#define IMGU_ABI_DPC_MAX_SUPPORTED_HEIGHT	3840
+#define IMGU_ABI_DPC_STRIPE_SIZE		50
+#define IMGU_ABI_DPC_MAX_OPERATIONS \
+	(IMGU_ABI_DPC_COMMANDS_PER_TRANSFER * IMGU_ABI_DPC_MAX_CFG_SETS)
+#define IMGU_ABI_DPC_MAX_PROCESS_LINES		IMGU_ABI_DPC_MAX_CFG_SETS
+#define IMGU_ABI_DPC_MAX_TRANSFERS		IMGU_ABI_DPC_MAX_CFG_SETS
+#define IMGU_ABI_DPC_MAX_DP_FIRST_LINES_PAIR	70
+#define IMGU_ABI_DPC_MAX_DP_PER_SET		192
+#define IMGU_ABI_DPC_MAX_CFG_SETS \
+	((IMGU_ABI_DPC_MAX_SUPPORTED_HEIGHT + IMGU_ABI_DPC_STRIPE_SIZE - 1) \
+	/ IMGU_ABI_DPC_STRIPE_SIZE)
+
+#define IMGU_ABI_BDS_SAMPLE_PATTERN_ARRAY_SIZE	8
+#define IMGU_ABI_BDS_PHASE_COEFFS_ARRAY_SIZE	32
+
+#define IMGU_ABI_ANR_LUT_SIZE			26
+#define IMGU_ABI_ANR_PYRAMID_SIZE		22
+
+#define IMGU_ABI_AWB_FR_MAX_TRANSFERS		30
+#define IMGU_ABI_AWB_FR_MAX_PROCESS_LINES	30
+#define IMGU_ABI_AWB_FR_MAX_OPERATIONS \
+	(IMGU_ABI_AWB_FR_MAX_TRANSFERS + IMGU_ABI_AWB_FR_MAX_PROCESS_LINES)
+
+#define IMGU_ABI_AE_WEIGHTS			96
+
+#define IMGU_ABI_AF_MAX_TRANSFERS		30
+#define IMGU_ABI_AF_MAX_PROCESS_LINES		30
+#define IMGU_ABI_AF_MAX_OPERATIONS \
+		(IMGU_ABI_AF_MAX_TRANSFERS + IMGU_ABI_AF_MAX_PROCESS_LINES)
+
+#define IMGU_ABI_AWB_MAX_PROCESS_LINES		68
+#define IMGU_ABI_AWB_MAX_TRANSFERS		68
+#define IMGU_ABI_AWB_MAX_OPERATIONS \
+		(IMGU_ABI_AWB_MAX_PROCESS_LINES + IMGU_ABI_AWB_MAX_TRANSFERS)
+
+#define IMGU_ABI_OSYS_PIN_VF			0
+#define IMGU_ABI_OSYS_PIN_OUT			1
+#define IMGU_ABI_OSYS_PINS			2
+
+enum imgu_abi_frame_format {
+	IMGU_ABI_FRAME_FORMAT_NV11,	/* 12 bit YUV 411, Y, UV plane */
+	IMGU_ABI_FRAME_FORMAT_NV12,	/* 12 bit YUV 420, Y, UV plane */
+	IMGU_ABI_FRAME_FORMAT_NV12_16,	/* 16 bit YUV 420, Y, UV plane */
+	IMGU_ABI_FRAME_FORMAT_NV12_TILEY,/* 12 bit YUV 420,Intel tiled format */
+	IMGU_ABI_FRAME_FORMAT_NV16,	/* 16 bit YUV 422, Y, UV plane */
+	IMGU_ABI_FRAME_FORMAT_NV21,	/* 12 bit YUV 420, Y, VU plane */
+	IMGU_ABI_FRAME_FORMAT_NV61,	/* 16 bit YUV 422, Y, VU plane */
+	IMGU_ABI_FRAME_FORMAT_YV12,	/* 12 bit YUV 420, Y, V, U plane */
+	IMGU_ABI_FRAME_FORMAT_YV16,	/* 16 bit YUV 422, Y, V, U plane */
+	IMGU_ABI_FRAME_FORMAT_YUV420,	/* 12 bit YUV 420, Y, U, V plane */
+	IMGU_ABI_FRAME_FORMAT_YUV420_16,/* yuv420, 16 bits per subpixel */
+	IMGU_ABI_FRAME_FORMAT_YUV422,	/* 16 bit YUV 422, Y, U, V plane */
+	IMGU_ABI_FRAME_FORMAT_YUV422_16,/* yuv422, 16 bits per subpixel */
+	IMGU_ABI_FRAME_FORMAT_UYVY,	/* 16 bit YUV 422, UYVY interleaved */
+	IMGU_ABI_FRAME_FORMAT_YUYV,	/* 16 bit YUV 422, YUYV interleaved */
+	IMGU_ABI_FRAME_FORMAT_YUV444,	/* 24 bit YUV 444, Y, U, V plane */
+	IMGU_ABI_FRAME_FORMAT_YUV_LINE,	/* Internal format, 2 y lines */
+					/* followed by a uv-interleaved line */
+	IMGU_ABI_FRAME_FORMAT_RAW,	/* RAW, 1 plane */
+	IMGU_ABI_FRAME_FORMAT_RGB565,	/* 16 bit RGB, 1 plane. Each 3 sub
+					 * pixels are packed into one 16 bit
+					 * value, 5 bits for R, 6 bits for G
+					 * and 5 bits for B.
+					 */
+	IMGU_ABI_FRAME_FORMAT_PLANAR_RGB888, /* 24 bit RGB, 3 planes */
+	IMGU_ABI_FRAME_FORMAT_RGBA888,	/* 32 bit RGBA, 1 plane, A=Alpha
+					 * (alpha is unused)
+					 */
+	IMGU_ABI_FRAME_FORMAT_QPLANE6,	/* Internal, for advanced ISP */
+	IMGU_ABI_FRAME_FORMAT_BINARY_8,	/* byte stream, used for jpeg. For
+					 * frames of this type, we set the
+					 * height to 1 and the width to the
+					 * number of allocated bytes.
+					 */
+	IMGU_ABI_FRAME_FORMAT_MIPI,	/* MIPI frame, 1 plane */
+	IMGU_ABI_FRAME_FORMAT_RAW_PACKED,	 /* RAW, 1 plane, packed */
+	IMGU_ABI_FRAME_FORMAT_CSI_MIPI_YUV420_8, /* 8 bit per Y/U/V. Y odd line
+						  * UYVY interleaved even line
+						  */
+	IMGU_ABI_FRAME_FORMAT_CSI_MIPI_LEGACY_YUV420_8, /* Legacy YUV420.
+							 * UY odd line;
+							 * VY even line
+							 */
+	IMGU_ABI_FRAME_FORMAT_CSI_MIPI_YUV420_10,/* 10 bit per Y/U/V. Y odd
+						  * line; UYVY interleaved
+						  * even line
+						  */
+	IMGU_ABI_FRAME_FORMAT_YCgCo444_16, /* Internal format for ISP2.7,
+					    * 16 bits per plane YUV 444,
+					    * Y, U, V plane
+					    */
+	IMGU_ABI_FRAME_FORMAT_NUM
+};
+
+enum imgu_abi_bayer_order {
+	IMGU_ABI_BAYER_ORDER_GRBG,
+	IMGU_ABI_BAYER_ORDER_RGGB,
+	IMGU_ABI_BAYER_ORDER_BGGR,
+	IMGU_ABI_BAYER_ORDER_GBRG
+};
+
+enum imgu_abi_osys_format {
+	IMGU_ABI_OSYS_FORMAT_YUV420,
+	IMGU_ABI_OSYS_FORMAT_YV12,
+	IMGU_ABI_OSYS_FORMAT_NV12,
+	IMGU_ABI_OSYS_FORMAT_NV21,
+	IMGU_ABI_OSYS_FORMAT_YUV_LINE,
+	IMGU_ABI_OSYS_FORMAT_YUY2,	/* = IMGU_ABI_OSYS_FORMAT_YUYV */
+	IMGU_ABI_OSYS_FORMAT_NV16,
+	IMGU_ABI_OSYS_FORMAT_RGBA,
+	IMGU_ABI_OSYS_FORMAT_BGRA
+};
+
+enum imgu_abi_osys_tiling {
+	IMGU_ABI_OSYS_TILING_NONE,
+	IMGU_ABI_OSYS_TILING_Y,
+	IMGU_ABI_OSYS_TILING_YF,
+};
+
+struct imgu_abi_shd_grid_config {
+	/* reg 0 */
+	u32 grid_width:8;
+	u32 grid_height:8;
+	u32 block_width:3;
+	u32 __reserved0:1;
+	u32 block_height:3;
+	u32 __reserved1:1;
+	u32 grid_height_per_slice:8;
+	/* reg 1 */
+	s32 x_start:13;
+	s32 __reserved2:3;
+	s32 y_start:13;
+	s32 __reserved3:3;
+} __packed;
+
+struct imgu_abi_shd_general_config {
+	u32 init_set_vrt_offst_ul:8;
+	u32 shd_enable:1;
+	/* aka 'gf' */
+	u32 gain_factor:2;
+	u32 __reserved:21;
+} __packed;
+
+struct imgu_abi_shd_black_level_config {
+	/* reg 0 */
+	s32 bl_r:12;
+	s32 __reserved0:4;
+	s32 bl_gr:12;
+	u32 __reserved1:1;
+	/* aka 'nf' */
+	u32 normalization_shift:3;
+	/* reg 1 */
+	s32 bl_gb:12;
+	s32 __reserved2:4;
+	s32 bl_b:12;
+	s32 __reserved3:4;
+} __packed;
+
+struct imgu_abi_shd_config_static {
+	/* B0: Fixed order: one transfer to GAC */
+	struct imgu_abi_shd_grid_config grid;
+	struct imgu_abi_shd_general_config general;
+	struct imgu_abi_shd_black_level_config black_level;
+} __packed;
+
+struct imgu_abi_shd_lut_elem {
+	u16 factors[2];
+} __packed;
+
+struct imgu_abi_shd_lut_set {
+	struct imgu_abi_shd_lut_elem elems[IMGU_ABI_SHD_MAX_CELLS_PER_SET]
+		IMGU_ABI_PAD;
+} __packed;
+
+struct imgu_abi_shd_lut {
+	struct imgu_abi_shd_lut_set sets[IMGU_ABI_SHD_MAX_CFG_SETS];
+} __packed;
+
+struct imgu_abi_shd_config {
+	struct imgu_abi_shd_config_static shd IMGU_ABI_PAD;
+	struct ipu3_uapi_shd_intra_frame_operations_data shd_ops IMGU_ABI_PAD;
+	struct imgu_abi_shd_lut shd_lut IMGU_ABI_PAD;
+} __packed;
+
+struct imgu_abi_dpc_param0 {
+	u32 enable:1;
+	u32 __reserved0:15;
+	u32 grad_threshold:13;
+	u32 __reserved1:3;
+} __packed;
+
+struct imgu_abi_dpc_num_of_dp {
+	u32 num_of_dp_gr:8;
+	u32 num_of_dp_bg:8;
+	u32 __reserved0:16;
+} __packed;
+
+struct imgu_abi_dpc_params {
+	struct imgu_abi_dpc_param0 enable_and_threshold;
+	struct imgu_abi_dpc_num_of_dp num_of_dp_set0;
+	struct imgu_abi_dpc_num_of_dp num_of_dp_set1;
+	struct imgu_abi_dpc_num_of_dp num_of_dp_first_line_pair;
+} __packed;
+
+/******************* Firmware ABI definitions *******************/
+
+/***** struct imgu_abi_sp_stage *****/
+
+#define IMGU_ABI_BINARY_MAX_OUTPUT_PORTS 2
+
+enum imgu_abi_queue_id {
+	IMGU_ABI_QUEUE_EVENT_ID = -1,
+	IMGU_ABI_QUEUE_A_ID = 0,
+	IMGU_ABI_QUEUE_B_ID,
+	IMGU_ABI_QUEUE_C_ID,
+	IMGU_ABI_QUEUE_D_ID,
+	IMGU_ABI_QUEUE_E_ID,
+	IMGU_ABI_QUEUE_F_ID,
+	IMGU_ABI_QUEUE_G_ID,
+	IMGU_ABI_QUEUE_H_ID,		/* input frame queue for skycam */
+	IMGU_ABI_QUEUE_NUM
+};
+
+enum imgu_abi_buffer_type {
+	IMGU_ABI_BUFFER_TYPE_INVALID = -1,
+	IMGU_ABI_BUFFER_TYPE_3A_STATISTICS = 0,
+	IMGU_ABI_BUFFER_TYPE_DIS_STATISTICS,
+	IMGU_ABI_BUFFER_TYPE_LACE_STATISTICS,
+	IMGU_ABI_BUFFER_TYPE_INPUT_FRAME,
+	IMGU_ABI_BUFFER_TYPE_OUTPUT_FRAME,
+	IMGU_ABI_BUFFER_TYPE_SEC_OUTPUT_FRAME,
+	IMGU_ABI_BUFFER_TYPE_VF_OUTPUT_FRAME,
+	IMGU_ABI_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME,
+	IMGU_ABI_BUFFER_TYPE_RAW_OUTPUT_FRAME,
+	IMGU_ABI_BUFFER_TYPE_CUSTOM_INPUT,
+	IMGU_ABI_BUFFER_TYPE_CUSTOM_OUTPUT,
+	IMGU_ABI_BUFFER_TYPE_METADATA,
+	IMGU_ABI_BUFFER_TYPE_PARAMETER_SET,
+	IMGU_ABI_BUFFER_TYPE_PER_FRAME_PARAMETER_SET,
+	IMGU_ABI_NUM_DYNAMIC_BUFFER_TYPE,
+	IMGU_ABI_NUM_BUFFER_TYPE
+};
+
+struct imgu_abi_crop_pos {
+	u16 x;
+	u16 y;
+} __packed;
+
+struct imgu_abi_sp_resolution {
+	u16 width;			/* Width of valid data in pixels */
+	u16 height;			/* Height of valid data in lines */
+} __packed;
+
+/*
+ * Frame info struct. This describes the contents of an image frame buffer.
+ */
+struct imgu_abi_frame_sp_info {
+	struct imgu_abi_sp_resolution res;
+	u16 padded_width;		/* stride of line in memory
+					 * (in pixels)
+					 */
+	u8 format;			/* format of the frame data */
+	u8 raw_bit_depth;		/* number of valid bits per pixel,
+					 * only valid for RAW bayer frames
+					 */
+	u8 raw_bayer_order;		/* bayer order, only valid
+					 * for RAW bayer frames
+					 */
+	u8 raw_type;		/* To choose the proper raw frame type. for
+				 * Legacy SKC pipes/Default is set to
+				 * IMGU_ABI_RAW_TYPE_BAYER. For RGB IR sensor -
+				 * driver should set it to:
+				 * IronGr case - IMGU_ABI_RAW_TYPE_IR_ON_GR
+				 * IronGb case - IMGU_ABI_RAW_TYPE_IR_ON_GB
+				 */
+#define IMGU_ABI_RAW_TYPE_BAYER		0
+#define IMGU_ABI_RAW_TYPE_IR_ON_GR	1
+#define IMGU_ABI_RAW_TYPE_IR_ON_GB	2
+	u8 padding[2];			/* Extend to 32 bit multiple */
+} __packed;
+
+struct imgu_abi_buffer_sp {
+	union {
+		imgu_addr_t xmem_addr;
+		enum imgu_abi_queue_id queue_id;
+	} buf_src;
+	enum imgu_abi_buffer_type buf_type;
+} __packed;
+
+struct imgu_abi_frame_sp_plane {
+	u32 offset;		/* offset in bytes to start of frame data */
+				/* offset is wrt data in imgu_abi_sp_sp_frame */
+} __packed;
+
+struct imgu_abi_frame_sp_rgb_planes {
+	struct imgu_abi_frame_sp_plane r;
+	struct imgu_abi_frame_sp_plane g;
+	struct imgu_abi_frame_sp_plane b;
+} __packed;
+
+struct imgu_abi_frame_sp_yuv_planes {
+	struct imgu_abi_frame_sp_plane y;
+	struct imgu_abi_frame_sp_plane u;
+	struct imgu_abi_frame_sp_plane v;
+} __packed;
+
+struct imgu_abi_frame_sp_nv_planes {
+	struct imgu_abi_frame_sp_plane y;
+	struct imgu_abi_frame_sp_plane uv;
+} __packed;
+
+struct imgu_abi_frame_sp_plane6 {
+	struct imgu_abi_frame_sp_plane r;
+	struct imgu_abi_frame_sp_plane r_at_b;
+	struct imgu_abi_frame_sp_plane gr;
+	struct imgu_abi_frame_sp_plane gb;
+	struct imgu_abi_frame_sp_plane b;
+	struct imgu_abi_frame_sp_plane b_at_r;
+} __packed;
+
+struct imgu_abi_frame_sp_binary_plane {
+	u32 size;
+	struct imgu_abi_frame_sp_plane data;
+} __packed;
+
+struct imgu_abi_frame_sp {
+	struct imgu_abi_frame_sp_info info;
+	struct imgu_abi_buffer_sp buf_attr;
+	union {
+		struct imgu_abi_frame_sp_plane raw;
+		struct imgu_abi_frame_sp_plane rgb;
+		struct imgu_abi_frame_sp_rgb_planes planar_rgb;
+		struct imgu_abi_frame_sp_plane yuyv;
+		struct imgu_abi_frame_sp_yuv_planes yuv;
+		struct imgu_abi_frame_sp_nv_planes nv;
+		struct imgu_abi_frame_sp_plane6 plane6;
+		struct imgu_abi_frame_sp_binary_plane binary;
+	} planes;
+} __packed;
+
+struct imgu_abi_resolution {
+	u32 width;
+	u32 height;
+} __packed;
+
+struct imgu_abi_frames_sp {
+	struct imgu_abi_frame_sp in;
+	struct imgu_abi_frame_sp out[IMGU_ABI_BINARY_MAX_OUTPUT_PORTS];
+	struct imgu_abi_resolution effective_in_res;
+	struct imgu_abi_frame_sp out_vf;
+	struct imgu_abi_frame_sp_info internal_frame_info;
+	struct imgu_abi_buffer_sp s3a_buf;
+	struct imgu_abi_buffer_sp dvs_buf;
+	struct imgu_abi_buffer_sp lace_buf;
+} __packed;
+
+struct imgu_abi_uds_info {
+	u16 curr_dx;
+	u16 curr_dy;
+	u16 xc;
+	u16 yc;
+} __packed;
+
+/* Information for a single pipeline stage */
+struct imgu_abi_sp_stage {
+	/* Multiple boolean flags can be stored in an integer */
+	u8 num;				/* Stage number */
+	u8 isp_online;
+	u8 isp_copy_vf;
+	u8 isp_copy_output;
+	u8 sp_enable_xnr;
+	u8 isp_deci_log_factor;
+	u8 isp_vf_downscale_bits;
+	u8 deinterleaved;
+	/*
+	 * NOTE: Programming the input circuit can only be done at the
+	 * start of a session. It is illegal to program it during execution
+	 * The input circuit defines the connectivity
+	 */
+	u8 program_input_circuit;
+	u8 func;
+#define IMGU_ABI_STAGE_FUNC_RAW_COPY	0
+#define IMGU_ABI_STAGE_FUNC_BIN_COPY	1
+#define IMGU_ABI_STAGE_FUNC_ISYS_COPY	2
+#define IMGU_ABI_STAGE_FUNC_NO_FUNC	3
+	u8 stage_type;			/* The type of the pipe-stage */
+#define IMGU_ABI_STAGE_TYPE_SP		0
+#define IMGU_ABI_STAGE_TYPE_ISP		1
+	u8 num_stripes;
+	u8 isp_pipe_version;
+	struct {
+		u8 vf_output;
+		u8 s3a;
+		u8 sdis;
+		u8 dvs_stats;
+		u8 lace_stats;
+	} enable;
+
+	struct imgu_abi_crop_pos sp_out_crop_pos;
+	u8 padding[2];
+	struct imgu_abi_frames_sp frames;
+	struct imgu_abi_resolution dvs_envelope;
+	struct imgu_abi_uds_info uds;
+	imgu_addr_t isp_stage_addr;
+	imgu_addr_t xmem_bin_addr;
+	imgu_addr_t xmem_map_addr;
+
+	u16 top_cropping;
+	u16 row_stripes_height;
+	u16 row_stripes_overlap_lines;
+	u8 if_config_index;	/* Which should be applied by this stage. */
+	u8 padding2;
+} __packed;
+
+/***** struct imgu_abi_isp_stage *****/
+
+#define IMGU_ABI_MAX_BINARY_NAME  64
+
+enum imgu_abi_memories {
+	IMGU_ABI_MEM_ISP_PMEM0 = 0,
+	IMGU_ABI_MEM_ISP_DMEM0,
+	IMGU_ABI_MEM_ISP_VMEM0,
+	IMGU_ABI_MEM_ISP_VAMEM0,
+	IMGU_ABI_MEM_ISP_VAMEM1,
+	IMGU_ABI_MEM_ISP_VAMEM2,
+	IMGU_ABI_MEM_ISP_HMEM0,
+	IMGU_ABI_MEM_SP0_DMEM0,
+	IMGU_ABI_MEM_SP1_DMEM0,
+	IMGU_ABI_MEM_DDR,
+	IMGU_ABI_NUM_MEMORIES
+};
+
+enum imgu_abi_param_class {
+	IMGU_ABI_PARAM_CLASS_PARAM,	/* Late binding parameters, like 3A */
+	IMGU_ABI_PARAM_CLASS_CONFIG,	/* Pipe config time parameters */
+	IMGU_ABI_PARAM_CLASS_STATE,	/* State parameters, eg. buffer index */
+	IMGU_ABI_PARAM_CLASS_NUM
+};
+
+struct imgu_abi_isp_param_memory_offsets {
+	u32 offsets[IMGU_ABI_PARAM_CLASS_NUM];	/* offset wrt hdr in bytes */
+} __packed;
+
+/*
+ * Blob descriptor.
+ * This structure describes an SP or ISP blob.
+ * It describes the test, data and bss sections as well as position in a
+ * firmware file.
+ * For convenience, it contains dynamic data after loading.
+ */
+struct imgu_abi_blob_info {
+	/* Static blob data */
+	u32 offset;			/* Blob offset in fw file */
+	struct imgu_abi_isp_param_memory_offsets memory_offsets;
+					/* offset wrt hdr in bytes */
+	u32 prog_name_offset;		/* offset wrt hdr in bytes */
+	u32 size;			/* Size of blob */
+	u32 padding_size;		/* total cummulative of bytes added
+					 * due to section alignment
+					 */
+	u32 icache_source;		/* Position of icache in blob */
+	u32 icache_size;		/* Size of icache section */
+	u32 icache_padding;	/* added due to icache section alignment */
+	u32 text_source;		/* Position of text in blob */
+	u32 text_size;			/* Size of text section */
+	u32 text_padding;	/* bytes added due to text section alignment */
+	u32 data_source;		/* Position of data in blob */
+	u32 data_target;		/* Start of data in SP dmem */
+	u32 data_size;			/* Size of text section */
+	u32 data_padding;	/* bytes added due to data section alignment */
+	u32 bss_target;		/* Start position of bss in SP dmem */
+	u32 bss_size;			/* Size of bss section
+					 * Dynamic data filled by loader
+					 */
+	const void *code __aligned(8);	/* Code section absolute pointer */
+					/* within fw, code = icache + text */
+	const void *data __aligned(8);	/* Data section absolute pointer */
+					/* within fw, data = data + bss */
+} __packed;
+
+struct imgu_abi_binary_pipeline_info {
+	u32 mode;
+	u32 isp_pipe_version;
+	u32 pipelining;
+	u32 c_subsampling;
+	u32 top_cropping;
+	u32 left_cropping;
+	u32 variable_resolution;
+} __packed;
+
+struct imgu_abi_binary_input_info {
+	u32 min_width;
+	u32 min_height;
+	u32 max_width;
+	u32 max_height;
+	u32 source;			/* memory, sensor, variable */
+#define IMGU_ABI_BINARY_INPUT_SOURCE_SENSOR	0
+#define IMGU_ABI_BINARY_INPUT_SOURCE_MEMORY	1
+#define IMGU_ABI_BINARY_INPUT_SOURCE_VARIABLE	2
+} __packed;
+
+struct imgu_abi_binary_output_info {
+	u32 min_width;
+	u32 min_height;
+	u32 max_width;
+	u32 max_height;
+	u32 num_chunks;
+	u32 variable_format;
+} __packed;
+
+struct imgu_abi_binary_internal_info {
+	u32 max_width;
+	u32 max_height;
+} __packed;
+
+struct imgu_abi_binary_bds_info {
+	u32 supported_bds_factors;
+/*
+ * enumeration of the bayer downscale factors. When a binary supports multiple
+ * factors, the OR of these defines is used to build the mask of supported
+ * factors. The BDS factor is used in pre-processor expressions so we cannot
+ * use an enum here.
+ */
+#define IMGU_ABI_BDS_FACTOR_1_00		BIT(0)
+#define IMGU_ABI_BDS_FACTOR_1_25		BIT(1)
+#define IMGU_ABI_BDS_FACTOR_1_50		BIT(2)
+#define IMGU_ABI_BDS_FACTOR_2_00		BIT(3)
+#define IMGU_ABI_BDS_FACTOR_2_25		BIT(4)
+#define IMGU_ABI_BDS_FACTOR_2_50		BIT(5)
+#define IMGU_ABI_BDS_FACTOR_3_00		BIT(6)
+#define IMGU_ABI_BDS_FACTOR_4_00		BIT(7)
+#define IMGU_ABI_BDS_FACTOR_4_50		BIT(8)
+#define IMGU_ABI_BDS_FACTOR_5_00		BIT(9)
+#define IMGU_ABI_BDS_FACTOR_6_00		BIT(10)
+#define IMGU_ABI_BDS_FACTOR_8_00		BIT(11)
+} __packed;
+
+struct imgu_abi_binary_dvs_info {
+	u32 max_envelope_width;
+	u32 max_envelope_height;
+} __packed;
+
+struct imgu_abi_binary_vf_dec_info {
+	u32 is_variable;
+	u32 max_log_downscale;
+} __packed;
+
+struct imgu_abi_binary_s3a_info {
+	u32 s3atbl_use_dmem;
+	u32 fixed_s3a_deci_log;
+} __packed;
+
+struct imgu_abi_binary_dpc_info {
+	u32 bnr_lite;			/* bnr lite enable flag */
+} __packed;
+
+struct imgu_abi_binary_iterator_info {
+	u32 num_stripes;
+	u32 row_stripes_height;
+	u32 row_stripes_overlap_lines;
+} __packed;
+
+struct imgu_abi_binary_address_info {
+	u32 isp_addresses;		/* Address in ISP dmem */
+	u32 main_entry;			/* Address of entry fct */
+	u32 in_frame;			/* Address in ISP dmem */
+	u32 out_frame;			/* Address in ISP dmem */
+	u32 in_data;			/* Address in ISP dmem */
+	u32 out_data;			/* Address in ISP dmem */
+	u32 sh_dma_cmd_ptr;		/* In ISP dmem */
+} __packed;
+
+struct imgu_abi_binary_uds_info {
+	u16 bpp;
+	u16 use_bci;
+	u16 use_str;
+	u16 woix;
+	u16 woiy;
+	u16 extra_out_vecs;
+	u16 vectors_per_line_in;
+	u16 vectors_per_line_out;
+	u16 vectors_c_per_line_in;
+	u16 vectors_c_per_line_out;
+	u16 vmem_gdc_in_block_height_y;
+	u16 vmem_gdc_in_block_height_c;
+} __packed;
+
+struct imgu_abi_binary_block_info {
+	u32 block_width;
+	u32 block_height;
+	u32 output_block_height;
+} __packed;
+
+struct imgu_abi_isp_data {
+	imgu_addr_t address;		/* ISP address */
+	u32 size;			/* Disabled if 0 */
+} __packed;
+
+struct imgu_abi_isp_param_segments {
+	struct imgu_abi_isp_data
+			params[IMGU_ABI_PARAM_CLASS_NUM][IMGU_ABI_NUM_MEMORIES];
+} __packed;
+
+struct imgu_abi_binary_info {
+	u32 id __aligned(8);		/* IMGU_ABI_BINARY_ID_* */
+	struct imgu_abi_binary_pipeline_info pipeline;
+	struct imgu_abi_binary_input_info input;
+	struct imgu_abi_binary_output_info output;
+	struct imgu_abi_binary_internal_info internal;
+	struct imgu_abi_binary_bds_info bds;
+	struct imgu_abi_binary_dvs_info dvs;
+	struct imgu_abi_binary_vf_dec_info vf_dec;
+	struct imgu_abi_binary_s3a_info s3a;
+	struct imgu_abi_binary_dpc_info dpc_bnr; /* DPC related binary info */
+	struct imgu_abi_binary_iterator_info iterator;
+	struct imgu_abi_binary_address_info addresses;
+	struct imgu_abi_binary_uds_info uds;
+	struct imgu_abi_binary_block_info block;
+	struct imgu_abi_isp_param_segments mem_initializers;
+	struct {
+		u8 input_feeder;
+		u8 output_system;
+		u8 obgrid;
+		u8 lin;
+		u8 dpc_acc;
+		u8 bds_acc;
+		u8 shd_acc;
+		u8 shd_ff;
+		u8 stats_3a_raw_buffer;
+		u8 acc_bayer_denoise;
+		u8 bnr_ff;
+		u8 awb_acc;
+		u8 awb_fr_acc;
+		u8 anr_acc;
+		u8 rgbpp_acc;
+		u8 rgbpp_ff;
+		u8 demosaic_acc;
+		u8 demosaic_ff;
+		u8 dvs_stats;
+		u8 lace_stats;
+		u8 yuvp1_b0_acc;
+		u8 yuvp1_c0_acc;
+		u8 yuvp2_acc;
+		u8 ae;
+		u8 af;
+		u8 dergb;
+		u8 rgb2yuv;
+		u8 high_quality;
+		u8 kerneltest;
+		u8 routing_shd_to_bnr;		/* connect SHD with BNR ACCs*/
+		u8 routing_bnr_to_anr;		/* connect BNR with ANR ACCs*/
+		u8 routing_anr_to_de;		/* connect ANR with DE ACCs */
+		u8 routing_rgb_to_yuvp1;	/* connect RGB with YUVP1 ACCs*/
+		u8 routing_yuvp1_to_yuvp2;    /* connect YUVP1 with YUVP2 ACCs*/
+		u8 luma_only;
+		u8 input_yuv;
+		u8 input_raw;
+		u8 reduced_pipe;
+		u8 vf_veceven;
+		u8 dis;
+		u8 dvs_envelope;
+		u8 uds;
+		u8 dvs_6axis;
+		u8 block_output;
+		u8 streaming_dma;
+		u8 ds;
+		u8 bayer_fir_6db;
+		u8 raw_binning;
+		u8 continuous;
+		u8 s3a;
+		u8 fpnr;
+		u8 sc;
+		u8 macc;
+		u8 output;
+		u8 ref_frame;
+		u8 tnr;
+		u8 xnr;
+		u8 params;
+		u8 ca_gdc;
+		u8 isp_addresses;
+		u8 in_frame;
+		u8 out_frame;
+		u8 high_speed;
+		u8 dpc;
+		u8 padding[2];
+		u8 rgbir;
+	} enable;
+	struct {
+		/* DMA channel ID: [0,...,IMGU_NUM_DMA_CHANNELS> */
+#define IMGU_NUM_DMA_CHANNELS		19
+		u8 ref_y_channel;
+		u8 ref_c_channel;
+		u8 tnr_channel;
+		u8 tnr_out_channel;
+		u8 dvs_coords_channel;
+		u8 output_channel;
+		u8 c_channel;
+		u8 vfout_channel;
+		u8 vfout_c_channel;
+		u8 vfdec_bits_per_pixel;
+		u8 claimed_by_isp;
+		u8 padding[2];
+	} dma;
+} __packed;
+
+struct imgu_abi_isp_stage {
+	struct imgu_abi_blob_info blob_info;
+	struct imgu_abi_binary_info binary_info;
+	char binary_name[IMGU_ABI_MAX_BINARY_NAME];
+	struct imgu_abi_isp_param_segments mem_initializers;
+} __packed;
+
+/***** struct imgu_abi_ddr_address_map and parameter set *****/
+
+#define IMGU_ABI_ISP_DDR_WORD_BITS	256
+#define IMGU_ABI_ISP_DDR_WORD_BYTES	(IMGU_ABI_ISP_DDR_WORD_BITS / 8)
+#define IMGU_ABI_MAX_STAGES		3
+
+/* xmem address map allocation */
+struct imgu_abi_ddr_address_map {
+	imgu_addr_t isp_mem_param[IMGU_ABI_MAX_STAGES][IMGU_ABI_NUM_MEMORIES];
+	imgu_addr_t obgrid_tbl[IPU3_UAPI_MAX_STRIPES];
+	imgu_addr_t acc_cluster_params_for_sp;
+	imgu_addr_t dvs_6axis_params_y;
+} __packed;
+
+struct imgu_abi_parameter_set_info {
+	/* Pointers to Parameters in ISP format IMPT */
+	struct imgu_abi_ddr_address_map mem_map;
+	/* Unique ID to track per-frame configurations */
+	u32 isp_parameters_id;
+	/* Output frame to which this config has to be applied (optional) */
+	imgu_addr_t output_frame_ptr;
+} __packed;
+
+/***** struct imgu_abi_sp_group *****/
+
+#define IMGU_ABI_MAX_IF_CONFIGS	3
+
+/* SP configuration information */
+struct imgu_abi_sp_config {
+	u8 no_isp_sync;		/* Signal host immediately after start */
+	u8 enable_raw_pool_locking;    /* Enable Raw Buffer Locking for HALv3 */
+	u8 lock_all;
+	u8 disable_cont_vf;
+	u8 disable_preview_on_capture;
+	u8 padding[3];
+} __packed;
+
+/* Information for a pipeline */
+struct imgu_abi_sp_pipeline {
+	u32 pipe_id;			/* the pipe ID */
+	u32 pipe_num;			/* the dynamic pipe number */
+	u32 thread_id;			/* the sp thread ID */
+	u32 pipe_config;		/* the pipe config */
+#define IMGU_ABI_PIPE_CONFIG_ACQUIRE_ISP	(1 << 31)
+	u32 pipe_qos_config;		/* Bitmap of multiple QOS extension fw
+					 * state, 0xffffffff indicates non
+					 * QOS pipe.
+					 */
+	u32 inout_port_config;
+#define IMGU_ABI_PORT_CONFIG_TYPE_INPUT_HOST		(1 << 0)
+#define IMGU_ABI_PORT_CONFIG_TYPE_INPUT_COPYSINK	(1 << 1)
+#define IMGU_ABI_PORT_CONFIG_TYPE_INPUT_TAGGERSINK	(1 << 2)
+#define IMGU_ABI_PORT_CONFIG_TYPE_OUTPUT_HOST		(1 << 4)
+#define IMGU_ABI_PORT_CONFIG_TYPE_OUTPUT_COPYSINK	(1 << 5)
+#define IMGU_ABI_PORT_CONFIG_TYPE_OUTPUT_TAGGERSINK	(1 << 6)
+	u32 required_bds_factor;
+	u32 dvs_frame_delay;
+	u32 num_stages;		/* the pipe config */
+	u32 running;			/* needed for pipe termination */
+	imgu_addr_t sp_stage_addr[IMGU_ABI_MAX_STAGES];
+	imgu_addr_t scaler_pp_lut;	/* Early bound LUT */
+	u32 stage;			/* stage ptr is only used on sp */
+	s32 num_execs;			/* number of times to run if this is
+					 * an acceleration pipe.
+					 */
+	union {
+		struct {
+			u32 bytes_available;
+		} bin;
+		struct {
+			u32 height;
+			u32 width;
+			u32 padded_width;
+			u32 max_input_width;
+			u32 raw_bit_depth;
+		} raw;
+	} copy;
+
+	/* Parameters passed to Shading Correction kernel. */
+	struct {
+		/* Origin X (bqs) of internal frame on shading table */
+		u32 internal_frame_origin_x_bqs_on_sctbl;
+		/* Origin Y (bqs) of internal frame on shading table */
+		u32 internal_frame_origin_y_bqs_on_sctbl;
+	} shading;
+} __packed;
+
+struct imgu_abi_sp_debug_command {
+	/*
+	 * The DMA software-mask,
+	 *      Bit 31...24: unused.
+	 *      Bit 23...16: unused.
+	 *      Bit 15...08: reading-request enabling bits for DMA channel 7..0
+	 *      Bit 07...00: writing-request enabling bits for DMA channel 7..0
+	 *
+	 * For example, "0...0 0...0 11111011 11111101" indicates that the
+	 * writing request through DMA Channel 1 and the reading request
+	 * through DMA channel 2 are both disabled. The others are enabled.
+	 */
+	u32 dma_sw_reg;
+} __packed;
+
+#define IMGU_ABI_MAX_SP_THREADS	4
+
+/*
+ * Group all host initialized SP variables into this struct.
+ * This is initialized every stage through dma.
+ * The stage part itself is transferred through imgu_abi_sp_stage.
+ */
+struct imgu_abi_sp_group {
+	struct imgu_abi_sp_config config;
+	struct imgu_abi_sp_pipeline pipe[IMGU_ABI_MAX_SP_THREADS];
+	struct imgu_abi_sp_debug_command debug;
+} __packed;
+
+/***** parameter and state class binary configurations *****/
+
+#define IMGU_ABI_FRAMES_REF		3
+#define IMGU_ABI_FRAMES_TNR		4
+#define IMGU_ABI_BUF_SETS_TNR		1
+
+struct imgu_abi_isp_iterator_config {
+	struct imgu_abi_frame_sp_info input_info;
+	struct imgu_abi_frame_sp_info internal_info;
+	struct imgu_abi_frame_sp_info output_info;
+	struct imgu_abi_frame_sp_info vf_info;
+	struct imgu_abi_sp_resolution dvs_envelope;
+} __packed;
+
+struct imgu_abi_dma_port_config {
+	u8 crop, elems;
+	u16 width;
+	u32 stride;
+} __packed;
+
+struct imgu_abi_isp_ref_config {
+	u32 width_a_over_b;
+	struct imgu_abi_dma_port_config port_b;
+	u32 ref_frame_addr_y[IMGU_ABI_FRAMES_REF];
+	u32 ref_frame_addr_c[IMGU_ABI_FRAMES_REF];
+	u32 dvs_frame_delay;
+} __packed;
+
+struct imgu_abi_isp_ref_dmem_state {
+	u32 ref_in_buf_idx;
+	u32 ref_out_buf_idx;
+} __packed;
+
+struct imgu_abi_isp_dvs_config {
+	u32 num_horizontal_blocks;
+	u32 num_vertical_blocks;
+} __packed;
+
+struct imgu_abi_isp_tnr3_config {
+	u32 width_a_over_b;
+	u32 frame_height;
+	struct imgu_abi_dma_port_config port_b;
+	u32 delay_frame;
+	u32 frame_addr[IMGU_ABI_FRAMES_TNR];
+} __packed;
+
+struct imgu_abi_isp_tnr3_dmem_state {
+	u32 in_bufidx;
+	u32 out_bufidx;
+	u32 total_frame_counter;
+	u32 buffer_frame_counter[IMGU_ABI_BUF_SETS_TNR];
+	u32 bypass_filter;
+} __packed;
+
+/***** DVS statistics metadata *****/
+
+#define IMGU_ABI_DVS_METADATA_L0_REGS		(84 * 10)
+#define IMGU_ABI_DVS_METADATA_L1_REGS		(66 * 10)
+#define IMGU_ABI_DVS_METADATA_L2_REGS		(45 * 10)
+
+struct imgu_abi_dvs_meta_data {
+	u32 dvs_prev_frame_fe_l0[IMGU_ABI_DVS_METADATA_L0_REGS]
+		__aligned(IMGU_ABI_ISP_DDR_WORD_BYTES);
+	u32 dvs_prev_frame_fe_l1[IMGU_ABI_DVS_METADATA_L1_REGS]
+		__aligned(IMGU_ABI_ISP_DDR_WORD_BYTES);
+	u32 dvs_prev_frame_fe_l2[IMGU_ABI_DVS_METADATA_L2_REGS]
+		__aligned(IMGU_ABI_ISP_DDR_WORD_BYTES);
+} __packed;
+
+/***** Queues *****/
+
+#define IMGU_ABI_EVENT_BUFFER_ENQUEUED(thread, queue)	\
+				(0 << 24 | (thread) << 16 | (queue) << 8)
+#define IMGU_ABI_EVENT_BUFFER_DEQUEUED(queue)	(1 << 24 | (queue) << 8)
+#define IMGU_ABI_EVENT_EVENT_DEQUEUED		(2 << 24)
+#define IMGU_ABI_EVENT_START_STREAM		(3 << 24)
+#define IMGU_ABI_EVENT_STOP_STREAM		(4 << 24)
+#define IMGU_ABI_EVENT_MIPI_BUFFERS_READY	(5 << 24)
+#define IMGU_ABI_EVENT_UNLOCK_RAW_BUFFER	(6 << 24)
+#define IMGU_ABI_EVENT_STAGE_ENABLE_DISABLE	(7 << 24)
+
+#define IMGU_ABI_HOST2SP_BUFQ_SIZE	3
+#define IMGU_ABI_SP2HOST_BUFQ_SIZE	(2 * IMGU_ABI_MAX_SP_THREADS)
+#define IMGU_ABI_HOST2SP_EVTQ_SIZE	(IMGU_ABI_QUEUE_NUM * \
+		IMGU_ABI_MAX_SP_THREADS * 2 + IMGU_ABI_MAX_SP_THREADS * 4)
+#define IMGU_ABI_SP2HOST_EVTQ_SIZE	(6 * IMGU_ABI_MAX_SP_THREADS)
+
+#define IMGU_ABI_EVTTYPE_EVENT_SHIFT	0
+#define IMGU_ABI_EVTTYPE_EVENT_MASK	(0xff << IMGU_ABI_EVTTYPE_EVENT_SHIFT)
+#define IMGU_ABI_EVTTYPE_PIPE_SHIFT	8
+#define IMGU_ABI_EVTTYPE_PIPE_MASK	(0xff << IMGU_ABI_EVTTYPE_PIPE_SHIFT)
+#define IMGU_ABI_EVTTYPE_PIPEID_SHIFT	16
+#define IMGU_ABI_EVTTYPE_PIPEID_MASK	(0xff << IMGU_ABI_EVTTYPE_PIPEID_SHIFT)
+#define IMGU_ABI_EVTTYPE_MODULEID_SHIFT	8
+#define IMGU_ABI_EVTTYPE_MODULEID_MASK (0xff << IMGU_ABI_EVTTYPE_MODULEID_SHIFT)
+#define IMGU_ABI_EVTTYPE_LINENO_SHIFT	16
+#define IMGU_ABI_EVTTYPE_LINENO_MASK   (0xffff << IMGU_ABI_EVTTYPE_LINENO_SHIFT)
+
+/* Output frame ready */
+#define IMGU_ABI_EVTTYPE_OUT_FRAME_DONE			0
+/* Second output frame ready */
+#define IMGU_ABI_EVTTYPE_2ND_OUT_FRAME_DONE		1
+/* Viewfinder Output frame ready */
+#define IMGU_ABI_EVTTYPE_VF_OUT_FRAME_DONE		2
+/* Second viewfinder Output frame ready */
+#define IMGU_ABI_EVTTYPE_2ND_VF_OUT_FRAME_DONE		3
+/* Indication that 3A statistics are available */
+#define IMGU_ABI_EVTTYPE_3A_STATS_DONE			4
+/* Indication that DIS statistics are available */
+#define IMGU_ABI_EVTTYPE_DIS_STATS_DONE			5
+/* Pipeline Done event, sent after last pipeline stage */
+#define IMGU_ABI_EVTTYPE_PIPELINE_DONE			6
+/* Frame tagged */
+#define IMGU_ABI_EVTTYPE_FRAME_TAGGED			7
+/* Input frame ready */
+#define IMGU_ABI_EVTTYPE_INPUT_FRAME_DONE		8
+/* Metadata ready */
+#define IMGU_ABI_EVTTYPE_METADATA_DONE			9
+/* Indication that LACE statistics are available */
+#define IMGU_ABI_EVTTYPE_LACE_STATS_DONE		10
+/* Extension stage executed */
+#define IMGU_ABI_EVTTYPE_ACC_STAGE_COMPLETE		11
+/* Timing measurement data */
+#define IMGU_ABI_EVTTYPE_TIMER				12
+/* End Of Frame event, sent when in buffered sensor mode */
+#define IMGU_ABI_EVTTYPE_PORT_EOF			13
+/* Performance warning encountered by FW */
+#define IMGU_ABI_EVTTYPE_FW_WARNING			14
+/* Assertion hit by FW */
+#define IMGU_ABI_EVTTYPE_FW_ASSERT			15
+
+struct imgu_abi_queue_info {
+	u8 size;		/* the maximum number of elements*/
+	u8 step;		/* number of bytes per element */
+	u8 start;		/* index of the oldest element */
+	u8 end;			/* index at which to write the new element */
+} __packed;
+
+struct imgu_abi_queues {
+	/*
+	 * Queues for the dynamic frame information,
+	 * i.e. the "in_frame" buffer, the "out_frame"
+	 * buffer and the "vf_out_frame" buffer.
+	 */
+	struct imgu_abi_queue_info host2sp_bufq_info
+			[IMGU_ABI_MAX_SP_THREADS][IMGU_ABI_QUEUE_NUM];
+	u32 host2sp_bufq[IMGU_ABI_MAX_SP_THREADS][IMGU_ABI_QUEUE_NUM]
+			[IMGU_ABI_HOST2SP_BUFQ_SIZE];
+	struct imgu_abi_queue_info sp2host_bufq_info[IMGU_ABI_QUEUE_NUM];
+	u32 sp2host_bufq[IMGU_ABI_QUEUE_NUM][IMGU_ABI_SP2HOST_BUFQ_SIZE];
+
+	/*
+	 * The queues for the events.
+	 */
+	struct imgu_abi_queue_info host2sp_evtq_info;
+	u32 host2sp_evtq[IMGU_ABI_HOST2SP_EVTQ_SIZE];
+	struct imgu_abi_queue_info sp2host_evtq_info;
+	u32 sp2host_evtq[IMGU_ABI_SP2HOST_EVTQ_SIZE];
+} __packed;
+
+/***** Buffer descriptor *****/
+
+struct imgu_abi_metadata_info {
+	struct imgu_abi_resolution resolution;	/* Resolution */
+	u32 stride;				/* Stride in bytes */
+	u32 size;				/* Total size in bytes */
+} __packed;
+
+struct imgu_abi_isp_3a_statistics {
+	union {
+		struct {
+			imgu_addr_t s3a_tbl;
+		} dmem;
+		struct {
+			imgu_addr_t s3a_tbl_hi;
+			imgu_addr_t s3a_tbl_lo;
+		} vmem;
+	} data;
+	struct {
+		imgu_addr_t rgby_tbl;
+	} data_hmem;
+	u32 exp_id;	/* exposure id, to match statistics to a frame, */
+	u32 isp_config_id;		/* Tracks per-frame configs */
+	imgu_addr_t data_ptr;		/* pointer to base of all data */
+	u32 size;			/* total size of all data */
+	u32 dmem_size;
+	u32 vmem_size;			/* both lo and hi have this size */
+	u32 hmem_size;
+} __packed;
+
+struct imgu_abi_isp_dvs_statistics {
+	imgu_addr_t hor_proj;
+	imgu_addr_t ver_proj;
+	u32 hor_size;
+	u32 ver_size;
+	u32 exp_id;
+	imgu_addr_t data_ptr;		/* base pointer containing all memory */
+	u32 size;			/* size of memory in data_ptr */
+} __packed;
+
+struct imgu_abi_metadata {
+	struct imgu_abi_metadata_info info;	/* Layout info */
+	imgu_addr_t address;		/* CSS virtual address */
+	u32 exp_id;			/* Exposure ID */
+} __packed;
+
+struct imgu_abi_time_meas {
+	u32 start_timer_value;		/* measured time in ticks */
+	u32 end_timer_value;		/* measured time in ticks */
+} __packed;
+
+struct imgu_abi_buffer {
+	union {
+		struct imgu_abi_isp_3a_statistics s3a;
+		struct imgu_abi_isp_dvs_statistics dis;
+		imgu_addr_t skc_dvs_statistics;
+		imgu_addr_t lace_stat;
+		struct imgu_abi_metadata metadata;
+		struct {
+			imgu_addr_t frame_data;
+			u32 flashed;
+			u32 exp_id;
+			u32 isp_parameters_id;   /* Tracks per-frame configs */
+			u32 padded_width;
+		} frame;
+		imgu_addr_t ddr_ptrs;
+	} payload;
+	/*
+	 * kernel_ptr is present for host administration purposes only.
+	 * type is uint64_t in order to be 64-bit host compatible.
+	 * uint64_t does not exist on SP/ISP.
+	 * Size of the struct is checked by sp.hive.c.
+	 */
+	u64 cookie_ptr __aligned(8);
+	u64 kernel_ptr;
+	struct imgu_abi_time_meas timing_data;
+	u32 isys_eof_clock_tick;
+} __packed;
+
+#define IMGU_ABI_NUM_CONTINUOUS_FRAMES		10
+#define IMGU_ABI_SP_COMM_COMMAND		0x00
+
+/*
+ * The host2sp_cmd_ready command is the only command written by the SP
+ * It acknowledges that is previous command has been received.
+ * (this does not mean that the command has been executed)
+ * It also indicates that a new command can be send (it is a queue
+ * with depth 1).
+ */
+#define IMGU_ABI_SP_COMM_COMMAND_READY		1
+/* Command written by the Host */
+#define IMGU_ABI_SP_COMM_COMMAND_DUMMY		2	/* No action */
+#define IMGU_ABI_SP_COMM_COMMAND_START_FLASH	3	/* Start the flash */
+#define IMGU_ABI_SP_COMM_COMMAND_TERMINATE	4	/* Terminate */
+
+/* n = 0..IMGU_ABI_NUM_CONTINUOUS_FRAMES-1 */
+#define IMGU_ABI_SP_COMM_OFFLINE_FRAME(n)	((n) * 4 + 0x04)
+#define IMGU_ABI_SP_COMM_OFFLINE_METADATA(n)	((n) * 4 + 0x2c)
+#define IMGU_ABI_SP_COMM_CONT_AVAIL_RAW_FRAMES	0x54
+#define IMGU_ABI_SP_COMM_CONT_EXTRA_RAW_FRAMES	0x58
+#define IMGU_ABI_SP_COMM_CONT_TARGET_RAW_FRAMES	0x5c
+/* n = 0..IPU3_CSS_PIPE_ID_NUM-1 */
+#define IMGU_ABI_SP_COMM_EVENT_IRQ_MASK(n)	((n) * 4 + 0x60)
+#define IMGU_ABI_SP_COMM_EVENT_IRQ_MASK_OR_SHIFT	0
+#define IMGU_ABI_SP_COMM_EVENT_IRQ_MASK_AND_SHIFT	16
+
+struct imgu_abi_bl_dma_cmd_entry {
+	u32 src_addr;			/* virtual DDR address */
+	u32 size;			/* number of bytes to transferred */
+	u32 dst_type;
+#define IMGU_ABI_BL_DMACMD_TYPE_SP_PMEM	1	/* sp_pmem */
+	u32 dst_addr;			/* hmm address of xMEM or MMIO */
+} __packed;
+
+struct imgu_abi_sp_init_dmem_cfg {
+	u32 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             */
+	u32 sp_id;			/* sp id */
+} __packed;
+
+/***** For parameter computation *****/
+
+#define IMGU_SCALER_ELEMS_PER_VEC		0x10
+#define IMGU_SCALER_FILTER_TAPS_Y		0x4
+#define IMGU_SCALER_OUT_BPP			0x8
+
+#define IMGU_HIVE_OF_SYS_SCALER_TO_FA_OFFSET	0xC
+#define IMGU_HIVE_OF_SYS_OF_TO_FA_OFFSET	0x8
+
+#define IMGU_SCALER_MS_TO_OUTFORMACC_SL_ADDR	0x400
+#define IMGU_SCALER_TO_OF_ACK_FA_ADDR \
+	(0xC00  + IMGU_HIVE_OF_SYS_SCALER_TO_FA_OFFSET)
+#define IMGU_OF_TO_ACK_FA_ADDR (0xC00 + IMGU_HIVE_OF_SYS_OF_TO_FA_OFFSET)
+#define IMGU_OUTFORMACC_MS_TO_SCALER_SL_ADDR 0
+#define IMGU_OSYS_PHASES			0x20
+#define IMGU_OSYS_FILTER_TAPS			0x4
+#define IMGU_SCALER_INTR_BPP			10
+
+#define IMGU_PS_SNR_PRESERVE_BITS		3
+#define IMGU_CNTX_BPP				11
+#define IMGU_SCALER_FILTER_TAPS_UV	(IMGU_SCALER_FILTER_TAPS_Y/2)
+
+#define IMGU_VMEM2_ELEMS_PER_VEC	(IMGU_SCALER_ELEMS_PER_VEC)
+#define IMGU_STRIDE_Y			(IMGU_SCALER_FILTER_TAPS_Y + 1)
+#define IMGU_MAX_FRAME_WIDTH		3840
+#define IMGU_VMEM3_ELEMS_PER_VEC	(IMGU_SCALER_ELEMS_PER_VEC)
+
+#define IMGU_VER_CNTX_WORDS		DIV_ROUND_UP((IMGU_SCALER_OUT_BPP + \
+	IMGU_PS_SNR_PRESERVE_BITS), IMGU_CNTX_BPP)	/* 1 */
+#define IMGU_MAX_INPUT_BLOCK_HEIGHT	64
+#define IMGU_HOR_CNTX_WORDS		DIV_ROUND_UP((IMGU_SCALER_INTR_BPP + \
+	IMGU_PS_SNR_PRESERVE_BITS), IMGU_CNTX_BPP)	/* 2 */
+#define IMGU_MAX_OUTPUT_BLOCK_WIDTH		128
+#define IMGU_CNTX_STRIDE_UV		(IMGU_SCALER_FILTER_TAPS_UV + 1)
+
+#define IMGU_OSYS_PHASE_COUNTER_PREC_REF	6
+#define IMGU_VMEM1_Y_SIZE \
+	(IMGU_OSYS_BLOCK_HEIGHT * IMGU_VMEM1_Y_STRIDE)
+#define IMGU_VMEM1_UV_SIZE			(IMGU_VMEM1_Y_SIZE / 4)
+#define IMGU_VMEM1_OUT_BUF_ADDR			(IMGU_VMEM1_INP_BUF_ADDR + \
+	(IMGU_OSYS_NUM_INPUT_BUFFERS * IMGU_VMEM1_BUF_SIZE))
+#define IMGU_OSYS_NUM_OUTPUT_BUFFERS		2
+
+/* transpose of input height */
+#define IMGU_VMEM2_VECS_PER_LINE \
+	(DIV_ROUND_UP(IMGU_OSYS_BLOCK_HEIGHT, IMGU_VMEM2_ELEMS_PER_VEC))
+/* size in words (vectors)  */
+#define IMGU_VMEM2_BUF_SIZE \
+	(IMGU_VMEM2_VECS_PER_LINE * IMGU_VMEM2_LINES_PER_BLOCK)
+#define IMGU_VMEM3_VER_Y_SIZE	\
+			((IMGU_STRIDE_Y * IMGU_MAX_FRAME_WIDTH \
+			 / IMGU_VMEM3_ELEMS_PER_VEC) * IMGU_VER_CNTX_WORDS)
+#define IMGU_VMEM3_HOR_Y_SIZE \
+	((IMGU_STRIDE_Y * IMGU_MAX_INPUT_BLOCK_HEIGHT \
+	 / IMGU_VMEM3_ELEMS_PER_VEC) * IMGU_HOR_CNTX_WORDS)
+#define IMGU_VMEM3_VER_Y_EXTRA \
+	((IMGU_STRIDE_Y * IMGU_MAX_OUTPUT_BLOCK_WIDTH \
+	 / IMGU_VMEM3_ELEMS_PER_VEC) * IMGU_VER_CNTX_WORDS)
+#define IMGU_VMEM3_VER_U_SIZE \
+	(((IMGU_CNTX_STRIDE_UV * IMGU_MAX_FRAME_WIDTH \
+	 / IMGU_VMEM3_ELEMS_PER_VEC) * IMGU_VER_CNTX_WORDS) / 2)
+#define IMGU_VMEM3_HOR_U_SIZE \
+	(((IMGU_STRIDE_Y * IMGU_MAX_INPUT_BLOCK_HEIGHT \
+	 / IMGU_VMEM3_ELEMS_PER_VEC) * IMGU_HOR_CNTX_WORDS) / 2)
+#define IMGU_VMEM3_VER_U_EXTRA \
+	(((IMGU_CNTX_STRIDE_UV * IMGU_MAX_OUTPUT_BLOCK_WIDTH \
+	 / IMGU_VMEM3_ELEMS_PER_VEC) * IMGU_VER_CNTX_WORDS) / 2)
+#define IMGU_VMEM3_VER_V_SIZE \
+	(((IMGU_CNTX_STRIDE_UV * IMGU_MAX_FRAME_WIDTH \
+	 / IMGU_VMEM3_ELEMS_PER_VEC) * IMGU_VER_CNTX_WORDS) / 2)
+
+#define IMGU_OSYS_DMA_CROP_W_LIMIT	64
+#define IMGU_OSYS_DMA_CROP_H_LIMIT	4
+
+#define IMGU_ISP_VEC_NELEMS		64
+#define IMGU_LUMA_TO_CHROMA_RATIO	2
+#define IMGU_OSYS_FIR_PHASES \
+	(IMGU_OSYS_PHASES << IMGU_OSYS_PHASE_COUNTER_PREC_REF)
+#define IMGU_OSYS_TAPS_UV		(IMGU_OSYS_FILTER_TAPS / 2)
+#define IMGU_INPUT_BLOCK_WIDTH			(128)
+#define IMGU_OSYS_TAPS_Y		(IMGU_OSYS_FILTER_TAPS)
+#define IMGU_FIFO_ADDR_SCALER_TO_FMT \
+	(IMGU_SCALER_MS_TO_OUTFORMACC_SL_ADDR >> 2)
+#define IMGU_FIFO_ADDR_SCALER_TO_SP	(IMGU_SCALER_TO_OF_ACK_FA_ADDR >> 2)
+#define IMGU_VMEM1_INP_BUF_ADDR		0
+#define IMGU_VMEM1_Y_STRIDE \
+	(IMGU_OSYS_BLOCK_WIDTH / IMGU_VMEM1_ELEMS_PER_VEC)
+#define IMGU_VMEM1_BUF_SIZE	(IMGU_VMEM1_V_OFFSET + IMGU_VMEM1_UV_SIZE)
+
+#define IMGU_VMEM1_U_OFFSET		(IMGU_VMEM1_Y_SIZE)
+#define IMGU_VMEM1_V_OFFSET	(IMGU_VMEM1_U_OFFSET + IMGU_VMEM1_UV_SIZE)
+#define IMGU_VMEM1_UV_STRIDE		(IMGU_VMEM1_Y_STRIDE / 2)
+#define IMGU_OSYS_NUM_INPUT_BUFFERS	2
+#define IMGU_VMEM1_INT_BUF_ADDR		(IMGU_VMEM1_OUT_BUF_ADDR + \
+	(IMGU_OSYS_NUM_OUTPUT_BUFFERS * IMGU_VMEM1_BUF_SIZE))
+
+#define IMGU_VMEM1_ELEMS_PER_VEC	(IMGU_HIVE_OF_SYS_OF_SYSTEM_NWAYS)
+#define IMGU_OSYS_NUM_INTERM_BUFFERS	2
+#define IMGU_VMEM2_BUF_Y_ADDR		0
+#define IMGU_VMEM2_BUF_Y_STRIDE		(IMGU_VMEM2_VECS_PER_LINE)
+#define IMGU_VMEM2_BUF_U_ADDR \
+	(IMGU_VMEM2_BUF_Y_ADDR + IMGU_VMEM2_BUF_SIZE)
+#define IMGU_VMEM2_BUF_V_ADDR \
+	(IMGU_VMEM2_BUF_U_ADDR + IMGU_VMEM2_BUF_SIZE/4)
+#define IMGU_VMEM2_BUF_UV_STRIDE	(IMGU_VMEM2_VECS_PER_LINE/2)
+/* 1.5 x depth of intermediate buffer */
+#define IMGU_VMEM2_LINES_PER_BLOCK	192
+#define IMGU_VMEM3_HOR_Y_ADDR \
+	(IMGU_VMEM3_VER_Y_ADDR + IMGU_VMEM3_VER_Y_SIZE)
+#define IMGU_VMEM3_HOR_U_ADDR \
+	(IMGU_VMEM3_VER_U_ADDR + IMGU_VMEM3_VER_U_SIZE)
+#define IMGU_VMEM3_HOR_V_ADDR \
+	(IMGU_VMEM3_VER_V_ADDR + IMGU_VMEM3_VER_V_SIZE)
+#define IMGU_VMEM3_VER_Y_ADDR		0
+#define IMGU_VMEM3_VER_U_ADDR \
+	(IMGU_VMEM3_VER_Y_ADDR + IMGU_VMEM3_VER_Y_SIZE + \
+	max(IMGU_VMEM3_HOR_Y_SIZE, IMGU_VMEM3_VER_Y_EXTRA))
+#define IMGU_VMEM3_VER_V_ADDR \
+	(IMGU_VMEM3_VER_U_ADDR + IMGU_VMEM3_VER_U_SIZE + \
+	max(IMGU_VMEM3_HOR_U_SIZE, IMGU_VMEM3_VER_U_EXTRA))
+#define IMGU_HIVE_OF_SYS_OF_SYSTEM_NWAYS	32
+#define IMGU_FIFO_ADDR_FMT_TO_SP	(IMGU_OF_TO_ACK_FA_ADDR >> 2)
+#define IMGU_FIFO_ADDR_FMT_TO_SCALER (IMGU_OUTFORMACC_MS_TO_SCALER_SL_ADDR >> 2)
+#define IMGU_VMEM1_HST_BUF_ADDR		(IMGU_VMEM1_INT_BUF_ADDR + \
+	(IMGU_OSYS_NUM_INTERM_BUFFERS * IMGU_VMEM1_BUF_SIZE))
+#define IMGU_VMEM1_HST_BUF_STRIDE	120
+#define IMGU_VMEM1_HST_BUF_NLINES	3
+
+#endif
diff --git a/drivers/media/pci/intel/ipu3/ipu3-css-fw.c b/drivers/media/pci/intel/ipu3/ipu3-css-fw.c
new file mode 100644
index 000000000000..a95ad225487b
--- /dev/null
+++ b/drivers/media/pci/intel/ipu3/ipu3-css-fw.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2017 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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/device.h>
+#include <linux/firmware.h>
+#include <linux/slab.h>
+
+#include "ipu3-css.h"
+#include "ipu3-css-fw.h"
+
+static void ipu3_css_fw_show_binary(struct device *dev,
+			struct imgu_fw_info *bi, const char *name)
+{
+	int i;
+
+	dev_dbg(dev, "found firmware binary type %i size %i name %s\n",
+		bi->type, bi->blob.size, name);
+	if (bi->type != IMGU_FW_ISP_FIRMWARE)
+		return;
+
+	dev_dbg(dev, "    id %i mode %i bds 0x%x veceven %i/%i out_pins %i\n",
+		bi->info.isp.sp.id, bi->info.isp.sp.pipeline.mode,
+		bi->info.isp.sp.bds.supported_bds_factors,
+		bi->info.isp.sp.enable.vf_veceven,
+		bi->info.isp.sp.vf_dec.is_variable,
+		bi->info.isp.num_output_pins);
+
+	dev_dbg(dev, "    input (%i,%i)-(%i,%i) formats %s%s%s\n",
+		bi->info.isp.sp.input.min_width,
+		bi->info.isp.sp.input.min_height,
+		bi->info.isp.sp.input.max_width,
+		bi->info.isp.sp.input.max_height,
+		bi->info.isp.sp.enable.input_yuv ? "yuv420 " : "",
+		bi->info.isp.sp.enable.input_feeder ||
+		bi->info.isp.sp.enable.input_raw ? "raw8 raw10 " : "",
+		bi->info.isp.sp.enable.input_raw ? "raw12" : "");
+
+	dev_dbg(dev, "    internal (%i,%i)\n",
+		bi->info.isp.sp.internal.max_width,
+		bi->info.isp.sp.internal.max_height);
+
+	dev_dbg(dev, "    output (%i,%i)-(%i,%i) formats",
+		bi->info.isp.sp.output.min_width,
+		bi->info.isp.sp.output.min_height,
+		bi->info.isp.sp.output.max_width,
+		bi->info.isp.sp.output.max_height);
+	for (i = 0; i < bi->info.isp.num_output_formats; i++)
+		dev_dbg(dev, " %i", bi->info.isp.output_formats[i]);
+	dev_dbg(dev, " vf");
+	for (i = 0; i < bi->info.isp.num_vf_formats; i++)
+		dev_dbg(dev, " %i", bi->info.isp.vf_formats[i]);
+	dev_dbg(dev, "\n");
+}
+
+const int ipu3_css_fw_obgrid_size(const struct imgu_fw_info *bi)
+{
+	unsigned int stripes = bi->info.isp.sp.iterator.num_stripes;
+	unsigned int width, height, obgrid_size;
+
+	width = ALIGN(DIV_ROUND_UP(bi->info.isp.sp.internal.max_width,
+		IMGU_OBGRID_TILE_SIZE * 2) + 1, IPU3_UAPI_ISP_VEC_ELEMS / 4);
+	height = DIV_ROUND_UP(bi->info.isp.sp.internal.max_height,
+		IMGU_OBGRID_TILE_SIZE * 2) + 1;
+	obgrid_size = PAGE_ALIGN(width * height *
+		sizeof(struct ipu3_uapi_obgrid_param)) * stripes;
+
+	return obgrid_size;
+}
+
+void *ipu3_css_fw_pipeline_params(struct ipu3_css *css,
+		enum imgu_abi_param_class c, enum imgu_abi_memories m,
+		struct imgu_fw_isp_parameter *par, size_t par_size,
+		void *binary_params)
+{
+	struct imgu_fw_info *bi = &css->fwp->binary_header[css->current_binary];
+
+	if (par->offset + par->size >
+	    bi->info.isp.sp.mem_initializers.params[c][m].size)
+		return NULL;
+
+	if (par->size != par_size)
+		pr_warn("parameter size doesn't match defined size\n");
+
+	if (par->size < par_size)
+		return NULL;
+
+	return binary_params + par->offset;
+}
+
+void ipu3_css_fw_cleanup(struct ipu3_css *css)
+{
+	if (css->binary) {
+		int i;
+
+		for (i = 0; i < css->fwp->file_header.binary_nr; i++)
+			ipu3_css_dma_free(css->dev, &css->binary[i]);
+		kfree(css->binary);
+	}
+	if (css->fw)
+		release_firmware(css->fw);
+
+	css->binary = NULL;
+	css->fw = NULL;
+}
+
+int ipu3_css_fw_init(struct ipu3_css *css)
+{
+	static const u32 BLOCK_MAX = 65536;
+	struct device *dev = css->dev;
+	int binary_nr = 0;
+	int i, j, r;
+
+	r = request_firmware(&css->fw, IMGU_FW_NAME, css->dev);
+	if (r)
+		return r;
+
+	/* Check and display fw header info */
+
+	css->fwp = (struct imgu_fw_header *)css->fw->data;
+	if (css->fw->size < sizeof(struct imgu_fw_header *) ||
+	    css->fwp->file_header.h_size != sizeof(struct imgu_fw_bi_file_h))
+		goto bad_fw;
+	if (sizeof(struct imgu_fw_bi_file_h) +
+	    css->fwp->file_header.binary_nr * sizeof(struct imgu_fw_info) >
+	    css->fw->size)
+		goto bad_fw;
+
+	dev_info(dev, "loaded firmware version %.64s, %u binaries, %zu bytes\n",
+		 css->fwp->file_header.version, css->fwp->file_header.binary_nr,
+		 css->fw->size);
+
+	/* Validate and display info on fw binaries */
+
+	binary_nr = css->fwp->file_header.binary_nr;
+
+	css->fw_bl = css->fw_sp[0] = css->fw_sp[1] = -1;
+	for (i = 0; i < binary_nr; i++) {
+		struct imgu_fw_info *bi = &css->fwp->binary_header[i];
+		const char *name = (void *)css->fwp + bi->blob.prog_name_offset;
+		size_t len;
+
+		if (bi->blob.prog_name_offset >= css->fw->size)
+			goto bad_fw;
+		len = strnlen(name, css->fw->size - bi->blob.prog_name_offset);
+		if (len + 1 > css->fw->size - bi->blob.prog_name_offset ||
+		    len + 1 >= IMGU_ABI_MAX_BINARY_NAME)
+			goto bad_fw;
+
+		if (bi->blob.size != bi->blob.text_size + bi->blob.icache_size
+		    + bi->blob.data_size + bi->blob.padding_size)
+			goto bad_fw;
+		if (bi->blob.offset + bi->blob.size > css->fw->size)
+			goto bad_fw;
+
+		if (bi->type == IMGU_FW_BOOTLOADER_FIRMWARE) {
+			css->fw_bl = i;
+			if (bi->info.bl.sw_state >= css->iomem_length ||
+			    bi->info.bl.num_dma_cmds >= css->iomem_length
+			    || bi->info.bl.dma_cmd_list >=
+			    css->iomem_length)
+				goto bad_fw;
+		}
+		if (bi->type == IMGU_FW_SP_FIRMWARE ||
+		    bi->type == IMGU_FW_SP1_FIRMWARE) {
+			css->fw_sp[bi->type == IMGU_FW_SP_FIRMWARE ? 0 : 1] = i;
+			if (bi->info.sp.per_frame_data >= css->iomem_length
+			    || bi->info.sp.init_dmem_data >=
+			    css->iomem_length
+			    || bi->info.sp.host_sp_queue >=
+			    css->iomem_length
+			    || bi->info.sp.isp_started >= css->iomem_length
+			    || bi->info.sp.sw_state >= css->iomem_length
+			    || bi->info.sp.host_sp_queues_initialized >=
+			    css->iomem_length
+			    || bi->info.sp.sleep_mode >= css->iomem_length
+			    || bi->info.sp.invalidate_tlb >=
+			    css->iomem_length
+			    || bi->info.sp.host_sp_com >= css->iomem_length
+			    || bi->info.sp.output + 12 >=
+			    css->iomem_length)
+				goto bad_fw;
+		}
+		if (bi->type != IMGU_FW_ISP_FIRMWARE)
+			continue;
+
+		if (bi->info.isp.sp.pipeline.mode >= IPU3_CSS_PIPE_ID_NUM)
+			goto bad_fw;
+
+		if (bi->info.isp.sp.iterator.num_stripes >
+		    IPU3_UAPI_MAX_STRIPES)
+			goto bad_fw;
+
+		if (bi->info.isp.num_output_formats > IMGU_ABI_FRAME_FORMAT_NUM
+		    || bi->info.isp.num_vf_formats > IMGU_ABI_FRAME_FORMAT_NUM)
+			goto bad_fw;
+
+		for (j = 0; j < bi->info.isp.num_output_formats; j++)
+			if (bi->info.isp.output_formats[j] < 0 ||
+			    bi->info.isp.output_formats[j] >=
+			    IMGU_ABI_FRAME_FORMAT_NUM)
+				goto bad_fw;
+		for (j = 0; j < bi->info.isp.num_vf_formats; j++)
+			if (bi->info.isp.vf_formats[j] < 0 ||
+			    bi->info.isp.vf_formats[j] >=
+			    IMGU_ABI_FRAME_FORMAT_NUM)
+				goto bad_fw;
+
+		if (bi->info.isp.sp.block.block_width <= 0 ||
+		    bi->info.isp.sp.block.block_width > BLOCK_MAX ||
+		    bi->info.isp.sp.block.output_block_height <= 0 ||
+		    bi->info.isp.sp.block.output_block_height > BLOCK_MAX)
+			goto bad_fw;
+
+		if (bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_PARAM]
+		    + sizeof(struct imgu_fw_param_memory_offsets)
+		    > css->fw->size ||
+		    bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_CONFIG]
+		    + sizeof(struct imgu_fw_config_memory_offsets)
+		    > css->fw->size ||
+		    bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_STATE]
+		    + sizeof(struct imgu_fw_state_memory_offsets)
+		    > css->fw->size)
+			goto bad_fw;
+
+		ipu3_css_fw_show_binary(dev, bi, name);
+	}
+
+	if (css->fw_bl == -1 || css->fw_sp[0] == -1 || css->fw_sp[1] == -1)
+		goto bad_fw;
+
+	/* Allocate and map fw binaries into IMGU */
+
+	css->binary = kcalloc(binary_nr, sizeof(*css->binary), GFP_KERNEL);
+	if (!css->binary) {
+		r = -ENOMEM;
+		goto error_out;
+	}
+
+	for (i = 0; i < css->fwp->file_header.binary_nr; i++) {
+		struct imgu_fw_info *bi = &css->fwp->binary_header[i];
+		void *blob = (void *)css->fwp + bi->blob.offset;
+		size_t size = bi->blob.size;
+
+		if (ipu3_css_dma_alloc(css->dev, &css->binary[i], size)) {
+			r = -ENOMEM;
+			goto error_out;
+		}
+		memcpy(css->binary[i].vaddr, blob, size);
+	}
+
+	return 0;
+
+bad_fw:
+	dev_err(dev, "invalid firmware binary, size %u\n", (int)css->fw->size);
+	r = -ENODEV;
+
+error_out:
+	ipu3_css_fw_cleanup(css);
+	return r;
+}
diff --git a/drivers/media/pci/intel/ipu3/ipu3-css-fw.h b/drivers/media/pci/intel/ipu3/ipu3-css-fw.h
new file mode 100644
index 000000000000..9b7f6d3b12bd
--- /dev/null
+++ b/drivers/media/pci/intel/ipu3/ipu3-css-fw.h
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2017 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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 __IPU3_CSS_FW_H
+#define __IPU3_CSS_FW_H
+
+/******************* Firmware file definitions *******************/
+
+#define IMGU_FW_NAME			"ipu3-fw.bin"
+
+typedef u32 imgu_fw_ptr;
+
+enum imgu_fw_type {
+	IMGU_FW_SP_FIRMWARE,	/* Firmware for the SP */
+	IMGU_FW_SP1_FIRMWARE,	/* Firmware for the SP1 */
+	IMGU_FW_ISP_FIRMWARE,	/* Firmware for the ISP */
+	IMGU_FW_BOOTLOADER_FIRMWARE,	/* Firmware for the BootLoader */
+	IMGU_FW_ACC_FIRMWARE	/* Firmware for accelerations */
+};
+
+enum imgu_fw_acc_type {
+	IMGU_FW_ACC_NONE,	/* Normal binary */
+	IMGU_FW_ACC_OUTPUT,	/* Accelerator stage on output frame */
+	IMGU_FW_ACC_VIEWFINDER,	/* Accelerator stage on viewfinder frame */
+	IMGU_FW_ACC_STANDALONE,	/* Stand-alone acceleration */
+};
+
+struct imgu_fw_isp_parameter {
+	u32 offset;		/* Offset in isp_<mem> config, params, etc. */
+	u32 size;		/* Disabled if 0 */
+};
+
+struct imgu_fw_param_memory_offsets {
+	struct {
+		struct imgu_fw_isp_parameter lin;	/* lin_vmem_params */
+		struct imgu_fw_isp_parameter tnr3;	/* tnr3_vmem_params */
+		struct imgu_fw_isp_parameter xnr3;	/* xnr3_vmem_params */
+	} vmem;
+	struct {
+		struct imgu_fw_isp_parameter tnr;
+		struct imgu_fw_isp_parameter tnr3;	/* tnr3_params */
+		struct imgu_fw_isp_parameter xnr3;	/* xnr3_params */
+		struct imgu_fw_isp_parameter plane_io_config;	/* 192 bytes */
+		struct imgu_fw_isp_parameter rgbir;	/* rgbir_params */
+	} dmem;
+};
+
+struct imgu_fw_config_memory_offsets {
+	struct {
+		struct imgu_fw_isp_parameter iterator;
+		struct imgu_fw_isp_parameter dvs;
+		struct imgu_fw_isp_parameter output;
+		struct imgu_fw_isp_parameter raw;
+		struct imgu_fw_isp_parameter input_yuv;
+		struct imgu_fw_isp_parameter tnr;
+		struct imgu_fw_isp_parameter tnr3;
+		struct imgu_fw_isp_parameter ref;
+	} dmem;
+};
+
+struct imgu_fw_state_memory_offsets {
+	struct {
+		struct imgu_fw_isp_parameter tnr;
+		struct imgu_fw_isp_parameter tnr3;
+		struct imgu_fw_isp_parameter ref;
+	} dmem;
+};
+
+union imgu_fw_all_memory_offsets {
+	struct {
+		u64 imgu_fw_mem_offsets[3]; /* params, config, state */
+	} offsets;
+	struct {
+		u64 ptr;
+	} array[IMGU_ABI_PARAM_CLASS_NUM];
+};
+
+struct imgu_fw_binary_xinfo {
+	/* Part that is of interest to the SP. */
+	struct imgu_abi_binary_info sp;
+
+	/* Rest of the binary info, only interesting to the host. */
+	enum imgu_fw_acc_type type;
+
+	u32 num_output_formats __aligned(8);
+	enum imgu_abi_frame_format output_formats[IMGU_ABI_FRAME_FORMAT_NUM];
+
+	/* number of supported vf formats */
+	u32 num_vf_formats __aligned(8);
+	/* types of supported vf formats */
+	enum imgu_abi_frame_format vf_formats[IMGU_ABI_FRAME_FORMAT_NUM];
+	u8 num_output_pins;
+	imgu_fw_ptr xmem_addr;
+
+	u64 imgu_fw_blob_descr_ptr __aligned(8);
+	u32 blob_index __aligned(8);
+	union imgu_fw_all_memory_offsets mem_offsets __aligned(8);
+	struct imgu_fw_binary_xinfo *next __aligned(8);
+};
+
+struct imgu_fw_sp_info {
+	u32 init_dmem_data;	/* data sect config, stored to dmem */
+	u32 per_frame_data;	/* Per frame data, stored to dmem */
+	u32 group;		/* Per pipeline data, loaded by dma */
+	u32 output;		/* SP output data, loaded by dmem */
+	u32 host_sp_queue;	/* Host <-> SP queues */
+	u32 host_sp_com;	/* Host <-> SP commands */
+	u32 isp_started;	/* P'ed from sensor thread, csim only */
+	u32 sw_state;		/* Polled from css */
+#define IMGU_ABI_SP_SWSTATE_TERMINATED	0
+#define IMGU_ABI_SP_SWSTATE_INITIALIZED	1
+#define IMGU_ABI_SP_SWSTATE_CONNECTED	2
+#define IMGU_ABI_SP_SWSTATE_RUNNING	3
+	u32 host_sp_queues_initialized;	/* Polled from the SP */
+	u32 sleep_mode;		/* different mode to halt SP */
+	u32 invalidate_tlb;	/* inform SP to invalidate mmu TLB */
+	u32 debug_buffer_ddr_address;	/* inform SP the addr of DDR debug
+					 * queue
+					 */
+	/* input system perf count array */
+	u32 perf_counter_input_system_error;
+	u32 threads_stack;	/* sp thread's stack pointers */
+	u32 threads_stack_size;	/* sp thread's stack sizes */
+	u32 curr_binary_id;	/* current binary id */
+	u32 raw_copy_line_count;	/* raw copy line counter */
+	u32 ddr_parameter_address;	/* acc param ddrptr, sp dmem */
+	u32 ddr_parameter_size;	/* acc param size, sp dmem */
+	/* Entry functions */
+	u32 sp_entry;		/* The SP entry function */
+	u32 tagger_frames_addr;	/* Base address of tagger state */
+};
+
+struct imgu_fw_bl_info {
+	u32 num_dma_cmds;	/* Number of cmds sent by CSS */
+	u32 dma_cmd_list;	/* Dma command list sent by CSS */
+	u32 sw_state;		/* Polled from css */
+#define IMGU_ABI_BL_SWSTATE_OK		0x100
+#define IMGU_ABI_BL_SWSTATE_BUSY	(IMGU_ABI_BL_SWSTATE_OK + 1)
+#define IMGU_ABI_BL_SWSTATE_ERR		(IMGU_ABI_BL_SWSTATE_OK + 2)
+	/* Entry functions */
+	u32 bl_entry;		/* The SP entry function */
+};
+
+struct imgu_fw_acc_info {
+	u32 per_frame_data;	/* Dummy for now */
+};
+
+union imgu_fw_union {
+	struct imgu_fw_binary_xinfo isp;	/* ISP info */
+	struct imgu_fw_sp_info sp;	/* SP info */
+	struct imgu_fw_sp_info sp1;	/* SP1 info */
+	struct imgu_fw_bl_info bl;	/* Bootloader info */
+	struct imgu_fw_acc_info acc;	/* Accelerator info */
+};
+
+struct imgu_fw_info {
+	size_t header_size;	/* size of fw header */
+	enum imgu_fw_type type __aligned(8);
+	union imgu_fw_union info;	/* Binary info */
+	struct imgu_abi_blob_info blob;	/* Blob info */
+	/* Dynamic part */
+	u64 next;
+
+	u32 loaded __aligned(8);	/* Firmware has been loaded */
+	const u64 isp_code __aligned(8);	/* ISP pointer to code */
+	/* Firmware handle between user space and kernel */
+	u32 handle __aligned(8);
+	/* Sections to copy from/to ISP */
+	struct imgu_abi_isp_param_segments mem_initializers;
+	/* Initializer for local ISP memories */
+};
+
+struct imgu_fw_bi_file_h {
+	char version[64];	/* branch tag + week day + time */
+	int binary_nr;		/* Number of binaries */
+	unsigned int h_size;	/* sizeof(struct imgu_fw_bi_file_h) */
+};
+
+struct imgu_fw_header {
+	struct imgu_fw_bi_file_h file_header;
+	struct imgu_fw_info binary_header[1];	/* binary_nr items */
+};
+
+/******************* Firmware functions *******************/
+
+int ipu3_css_fw_init(struct ipu3_css *css);
+void ipu3_css_fw_cleanup(struct ipu3_css *css);
+
+const int ipu3_css_fw_obgrid_size(const struct imgu_fw_info *bi);
+void *ipu3_css_fw_pipeline_params(struct ipu3_css *css,
+				  enum imgu_abi_param_class c,
+				  enum imgu_abi_memories m,
+				  struct imgu_fw_isp_parameter *par,
+				  size_t par_size, void *binary_params);
+#endif
diff --git a/drivers/media/pci/intel/ipu3/ipu3-css.h b/drivers/media/pci/intel/ipu3/ipu3-css.h
new file mode 100644
index 000000000000..79dbf0625740
--- /dev/null
+++ b/drivers/media/pci/intel/ipu3/ipu3-css.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2017 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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 __IPU3_CSS_H
+#define __IPU3_CSS_H
+
+#include "ipu3-abi.h"
+#include "ipu3-css-pool.h"
+
+/* 2 stages for split isp pipeline, 1 for scaling */
+#define IMGU_NUM_SP			2
+#define IMGU_MAX_PIPELINE_NUM		20
+
+/*
+ * The pipe id type, distinguishes the kind of pipes that
+ * can be run in parallel.
+ */
+enum ipu3_css_pipe_id {
+	IPU3_CSS_PIPE_ID_PREVIEW,
+	IPU3_CSS_PIPE_ID_COPY,
+	IPU3_CSS_PIPE_ID_VIDEO,
+	IPU3_CSS_PIPE_ID_CAPTURE,
+	IPU3_CSS_PIPE_ID_YUVPP,
+	IPU3_CSS_PIPE_ID_ACC,
+	IPU3_CSS_PIPE_ID_NUM
+};
+
+/* IPU3 Camera Sub System structure */
+struct ipu3_css {
+	struct device *dev;
+	void __iomem *base;
+	struct device *dma_dev;
+	const struct firmware *fw;
+	struct imgu_fw_header *fwp;
+	int iomem_length;
+	int fw_bl, fw_sp[IMGU_NUM_SP];	/* Indices of bl and SP binaries */
+	struct ipu3_css_map *binary;	/* fw binaries mapped to device */
+	int current_binary;	/* Currently selected binary or -1 */
+	bool streaming;		/* true when streaming is enabled */
+	long frame;	/* Latest frame not yet processed */
+	enum ipu3_css_pipe_id pipe_id;  /* CSS pipe ID. */
+};
+
+#endif
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v4 08/12] intel-ipu3: params: compute and program ccs
  2017-10-18  3:54 [PATCH v4 04/12] intel-ipu3: Add user space ABI definitions Yong Zhi
  2017-10-18  3:54 ` [PATCH v4 06/12] intel-ipu3: css: imgu dma buff pool Yong Zhi
  2017-10-18  3:54 ` [PATCH v4 07/12] intel-ipu3: css: firmware management Yong Zhi
@ 2017-10-18  3:54 ` Yong Zhi
  2017-10-18  3:54 ` [PATCH v4 09/12] intel-ipu3: css hardware setup Yong Zhi
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 19+ messages in thread
From: Yong Zhi @ 2017-10-18  3:54 UTC (permalink / raw)
  To: linux-media, sakari.ailus
  Cc: jian.xu.zheng, rajmohan.mani, tuukka.toivonen, jerry.w.hu,
	Yong Zhi, Chiranjeevi Rapolu

A collection of routines that are mainly responsible
to calculate the acc parameters.

Signed-off-by: Yong Zhi <yong.zhi@intel.com>
Signed-off-by: Chiranjeevi Rapolu <chiranjeevi.rapolu@intel.com>
---
 drivers/media/pci/intel/ipu3/ipu3-css-params.c | 3161 ++++++++++++++++++++++++
 drivers/media/pci/intel/ipu3/ipu3-css-params.h |  105 +
 drivers/media/pci/intel/ipu3/ipu3-css.h        |   79 +-
 3 files changed, 3344 insertions(+), 1 deletion(-)
 create mode 100644 drivers/media/pci/intel/ipu3/ipu3-css-params.c
 create mode 100644 drivers/media/pci/intel/ipu3/ipu3-css-params.h

diff --git a/drivers/media/pci/intel/ipu3/ipu3-css-params.c b/drivers/media/pci/intel/ipu3/ipu3-css-params.c
new file mode 100644
index 000000000000..ad95bce103a4
--- /dev/null
+++ b/drivers/media/pci/intel/ipu3/ipu3-css-params.c
@@ -0,0 +1,3161 @@
+/*
+ * Copyright (c) 2017 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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/device.h>
+#include <linux/dma-mapping.h>
+
+#include "ipu3-abi.h"
+#include "ipu3-css.h"
+#include "ipu3-css-fw.h"
+#include "ipu3-css-params.h"
+#include "ipu3-tables.h"
+
+static unsigned int ipu3_css_scaler_get_exp(unsigned int counter,
+					    unsigned int divider)
+{
+	int i = fls(divider) - fls(counter);
+
+	if (i <= 0)
+		return 0;
+
+	if (divider >> i < counter)
+		i = i - 1;
+
+	return i;
+}
+
+/* Set up the CSS scaler look up table */
+static void ipu3_css_scaler_setup_lut(unsigned int taps,
+				      unsigned int input_width,
+				      unsigned int output_width,
+				      int phase_step_correction,
+				      const int *coeffs,
+				      unsigned int coeffs_size,
+				      s8 coeff_lut[IMGU_SCALER_PHASES *
+						   IMGU_SCALER_FILTER_TAPS],
+				      struct ipu3_css_scaler_info *info)
+{
+	int tap;
+	int phase;
+	int exponent = ipu3_css_scaler_get_exp(output_width, input_width);
+	int mantissa = (1 << exponent) * output_width;
+	unsigned int phase_step = 0;
+	int phase_sum_left = 0;
+	int phase_sum_right = 0;
+
+	if (input_width == output_width) {
+		for (phase = 0; phase < IMGU_SCALER_PHASES; phase++) {
+			for (tap = 0; tap < taps; tap++) {
+				coeff_lut[phase * IMGU_SCALER_FILTER_TAPS + tap]
+					= 0;
+			}
+		}
+
+		info->phase_step = IMGU_SCALER_PHASES *
+			(1 << IMGU_SCALER_PHASE_COUNTER_PREC_REF);
+		info->exp_shift = 0;
+		info->pad_left = 0;
+		info->pad_right = 0;
+		info->phase_init = 0;
+		info->crop_left = 0;
+		info->crop_top = 0;
+		return;
+	}
+
+	for (phase = 0; phase < IMGU_SCALER_PHASES; phase++) {
+		for (tap = 0; tap < taps; tap++) {
+			/* flip table to for convolution reverse indexing */
+			s64 coeff =  coeffs[coeffs_size -
+						((tap * (coeffs_size / taps)) +
+						phase) - 1];
+			coeff *= mantissa;
+			do_div(coeff, input_width);
+
+			/* Add +"0.5" */
+			coeff += 1 << (IMGU_SCALER_COEFF_BITS - 1);
+			coeff >>= IMGU_SCALER_COEFF_BITS;
+
+			coeff_lut[phase * IMGU_SCALER_FILTER_TAPS + tap] =
+				coeff;
+		}
+	}
+
+	phase_step = IMGU_SCALER_PHASES *
+			(1 << IMGU_SCALER_PHASE_COUNTER_PREC_REF)
+			* output_width / input_width;
+	phase_step += phase_step_correction;
+	phase_sum_left = (taps / 2 * IMGU_SCALER_PHASES *
+			(1 << IMGU_SCALER_PHASE_COUNTER_PREC_REF))
+			- (1 << (IMGU_SCALER_PHASE_COUNTER_PREC_REF - 1));
+	phase_sum_right = (taps / 2 * IMGU_SCALER_PHASES *
+			(1 << IMGU_SCALER_PHASE_COUNTER_PREC_REF))
+			+ (1 << (IMGU_SCALER_PHASE_COUNTER_PREC_REF - 1));
+
+	info->exp_shift = IMGU_SCALER_MAX_EXPONENT_SHIFT - exponent;
+	info->pad_left = (phase_sum_left % phase_step == 0) ?
+		phase_sum_left / phase_step - 1 : phase_sum_left / phase_step;
+	info->pad_right = (phase_sum_right % phase_step == 0) ?
+		phase_sum_right / phase_step - 1 : phase_sum_right / phase_step;
+	info->phase_init = phase_sum_left - phase_step * info->pad_left;
+	info->phase_step = phase_step;
+	info->crop_left = taps - 1;
+	info->crop_top = taps - 1;
+}
+
+/*
+ * Calculates the exact output image width/height, based on phase_step setting
+ * (must be perfectly aligned with hardware).
+ */
+static unsigned int
+ipu3_css_scaler_calc_scaled_output(unsigned int input,
+				   struct ipu3_css_scaler_info *info)
+{
+	unsigned int arg1 = input * info->phase_step +
+		(1 - IMGU_SCALER_TAPS_Y / 2) *
+		IMGU_SCALER_FIR_PHASES - IMGU_SCALER_FIR_PHASES
+		/ (2 * IMGU_SCALER_PHASES);
+	unsigned int arg2 = ((IMGU_SCALER_TAPS_Y / 2) * IMGU_SCALER_FIR_PHASES
+		+ IMGU_SCALER_FIR_PHASES / (2 * IMGU_SCALER_PHASES))
+		* IMGU_SCALER_FIR_PHASES + info->phase_step / 2;
+
+	return ((arg1 + (arg2 - IMGU_SCALER_FIR_PHASES * info->phase_step)
+		/ IMGU_SCALER_FIR_PHASES) / (2 * IMGU_SCALER_FIR_PHASES)) * 2;
+}
+
+/*
+ * Calculate the output width and height, given the luma
+ * and chroma details of a scaler
+ */
+static int ipu3_css_scaler_calc(u32 input_width, u32 input_height,
+				u32 target_width, u32 target_height,
+				struct ipu3_uapi_osys_config *cfg,
+				struct ipu3_css_scaler_info *info_luma,
+				struct ipu3_css_scaler_info *info_chroma,
+				unsigned int *output_width,
+				unsigned int *output_height,
+				unsigned int *procmode)
+{
+	u32 out_width = target_width;
+	u32 out_height = target_height;
+	unsigned int height_alignment = 2;
+	int phase_step_correction = -1;
+
+	/*
+	 * Calculate scaled output width. If the horizontal and vertical scaling
+	 * factor is different, then choose the biggest and crop off excess
+	 * lines or columns after formatting.
+	 */
+	if (target_height * input_width > target_width * input_height)
+		target_width = DIV_ROUND_UP(target_height * input_width,
+					    input_height);
+
+	if (input_width == target_width)
+		*procmode = IPU3_UAPI_OSYS_PROCMODE_BYPASS;
+	else
+		*procmode = IPU3_UAPI_OSYS_PROCMODE_DOWNSCALE;
+
+	memset(&cfg->scaler_coeffs_chroma, 0,
+	       sizeof(cfg->scaler_coeffs_chroma));
+	memset(&cfg->scaler_coeffs_luma, 0, sizeof(*cfg->scaler_coeffs_luma));
+	do {
+		phase_step_correction++;
+
+		ipu3_css_scaler_setup_lut(IMGU_SCALER_TAPS_Y,
+					  input_width, target_width,
+					  phase_step_correction,
+					  ipu3_css_downscale_4taps,
+					  IMGU_SCALER_DOWNSCALE_4TAPS_LEN,
+					  cfg->scaler_coeffs_luma, info_luma);
+
+		ipu3_css_scaler_setup_lut(IMGU_SCALER_TAPS_UV,
+					  input_width, target_width,
+					  phase_step_correction,
+					  ipu3_css_downscale_2taps,
+					  IMGU_SCALER_DOWNSCALE_2TAPS_LEN,
+					  cfg->scaler_coeffs_chroma,
+					  info_chroma);
+
+		out_width = ipu3_css_scaler_calc_scaled_output(input_width,
+							       info_luma);
+		out_height = ipu3_css_scaler_calc_scaled_output(input_height,
+								info_luma);
+	} while ((out_width < target_width || out_height < target_height ||
+		 !IS_ALIGNED(out_height, height_alignment)) &&
+		 phase_step_correction <= 5);
+
+	*output_width = out_width;
+	*output_height = out_height;
+
+	return 0;
+}
+
+/********************** Osys routines for scaler****************************/
+
+static void ipu3_css_osys_set_format(enum imgu_abi_frame_format host_format,
+				     unsigned int *osys_format,
+				     unsigned int *osys_tiling)
+{
+	*osys_format = IMGU_ABI_OSYS_FORMAT_YUV420;
+	*osys_tiling = IMGU_ABI_OSYS_TILING_NONE;
+
+	switch (host_format) {
+	case IMGU_ABI_FRAME_FORMAT_YUV420:
+		*osys_format = IMGU_ABI_OSYS_FORMAT_YUV420;
+		break;
+	case IMGU_ABI_FRAME_FORMAT_YV12:
+		*osys_format = IMGU_ABI_OSYS_FORMAT_YV12;
+		break;
+	case IMGU_ABI_FRAME_FORMAT_NV12:
+		*osys_format = IMGU_ABI_OSYS_FORMAT_NV12;
+		break;
+	case IMGU_ABI_FRAME_FORMAT_NV16:
+		*osys_format = IMGU_ABI_OSYS_FORMAT_NV16;
+		break;
+	case IMGU_ABI_FRAME_FORMAT_NV21:
+		*osys_format = IMGU_ABI_OSYS_FORMAT_NV21;
+		break;
+	case IMGU_ABI_FRAME_FORMAT_NV12_TILEY:
+		*osys_format = IMGU_ABI_OSYS_FORMAT_NV12;
+		*osys_tiling = IMGU_ABI_OSYS_TILING_Y;
+		break;
+	default:
+		/* For now, assume use default values */
+		break;
+	}
+}
+
+/*
+ * Function calculates input frame stripe offset, based
+ * on output frame stripe offset and filter parameters.
+ */
+static int ipu3_css_osys_calc_stripe_offset(int stripe_offset_out,
+					    int fir_phases,
+					    int phase_init,
+					    int phase_step, int pad_left)
+{
+	int stripe_offset_inp;
+
+	stripe_offset_inp = stripe_offset_out * fir_phases -
+						pad_left * phase_step;
+	stripe_offset_inp = DIV_ROUND_UP(stripe_offset_inp - phase_init,
+					 phase_step);
+
+	return stripe_offset_inp;
+}
+
+/*
+ * Calculate input frame phase, given the output frame
+ * stripe offset and filter parameters
+ */
+static int ipu3_css_osys_calc_stripe_phase_init(int stripe_offset_out,
+						int fir_phases, int phase_init,
+						int phase_step, int pad_left)
+{
+	int stripe_phase_init_inp;
+	int stripe_offset_inp;
+
+	stripe_offset_inp = ipu3_css_osys_calc_stripe_offset(stripe_offset_out,
+							     fir_phases,
+							     phase_init,
+							     phase_step,
+							     pad_left);
+
+	stripe_phase_init_inp = phase_init +
+				((pad_left + stripe_offset_inp) * phase_step) -
+				stripe_offset_out * fir_phases;
+
+	return stripe_phase_init_inp;
+}
+
+/*
+ * This function calculates input frame stripe width,
+ * based on output frame stripe offset and filter parameters
+ */
+static int ipu3_css_osys_calc_inp_stripe_width(int stripe_width_out,
+					       int fir_phases, int phase_init,
+					       int phase_step, int fir_taps,
+					       int pad_left, int pad_right)
+{
+	int stripe_width_inp;
+
+	stripe_width_inp = (stripe_width_out + fir_taps - 1) * fir_phases;
+	stripe_width_inp = DIV_ROUND_UP(stripe_width_inp - phase_init,
+					phase_step);
+	stripe_width_inp = stripe_width_inp - pad_left - pad_right;
+
+	return stripe_width_inp;
+}
+
+/*
+ * This function calculates output frame stripe width, basedi
+ * on output frame stripe offset and filter parameters
+ */
+static int ipu3_css_osys_out_stripe_width(int stripe_width_inp, int fir_phases,
+					  int phase_init, int phase_step,
+					  int fir_taps, int pad_left,
+					  int pad_right, int column_offset)
+{
+	int stripe_width_out;
+
+	stripe_width_out = (pad_left + stripe_width_inp +
+			    pad_right - column_offset) * phase_step;
+	stripe_width_out = (stripe_width_out + phase_init) / fir_phases;
+	stripe_width_out -= fir_taps - 1;
+
+	return stripe_width_out;
+}
+
+/*
+ * frame_params - size IMGU_ABI_OSYS_PINS
+ * stripe_params - size IPU3_UAPI_MAX_STRIPES
+ */
+static int ipu3_css_osys_calc_frame_and_stripe_params(
+		struct ipu3_css *css, unsigned int stripes,
+		struct ipu3_uapi_osys_config *osys,
+		struct ipu3_css_scaler_info *scaler_luma,
+		struct ipu3_css_scaler_info *scaler_chroma,
+		struct ipu3_css_frame_params frame_params[],
+		struct ipu3_css_stripe_params stripe_params[])
+{
+	struct ipu3_css_reso reso;
+	int output_width;
+	int pin, s;
+	u32 input_width, input_height, target_width, target_height;
+	unsigned int procmode = 0;
+
+	input_width = css->rect[IPU3_CSS_RECT_GDC].width;
+	input_height = css->rect[IPU3_CSS_RECT_GDC].height;
+	target_width = css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
+	target_height = css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
+
+	/**** Frame params ****/
+
+	/* Input width for Output System is output width of DVS (with GDC) */
+	reso.input_width = css->rect[IPU3_CSS_RECT_GDC].width;
+
+	/* Input height for Output System is output height of DVS (with GDC) */
+	reso.input_height = css->rect[IPU3_CSS_RECT_GDC].height;
+
+	reso.input_format =
+		css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
+
+	reso.pin_width[IMGU_ABI_OSYS_PIN_OUT] =
+		css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
+	reso.pin_height[IMGU_ABI_OSYS_PIN_OUT] =
+		css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
+	reso.pin_stride[IMGU_ABI_OSYS_PIN_OUT] =
+		css->queue[IPU3_CSS_QUEUE_OUT].width_pad;
+	reso.pin_format[IMGU_ABI_OSYS_PIN_OUT] =
+		css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
+
+	reso.pin_width[IMGU_ABI_OSYS_PIN_VF] =
+		css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
+	reso.pin_height[IMGU_ABI_OSYS_PIN_VF] =
+		css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
+	reso.pin_stride[IMGU_ABI_OSYS_PIN_VF] =
+		css->queue[IPU3_CSS_QUEUE_VF].width_pad;
+	reso.pin_format[IMGU_ABI_OSYS_PIN_VF] =
+		css->queue[IPU3_CSS_QUEUE_VF].css_fmt->frame_format;
+
+	/* Configure the frame parameters for all output pins */
+
+	frame_params[IMGU_ABI_OSYS_PIN_OUT].width =
+		css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
+	frame_params[IMGU_ABI_OSYS_PIN_OUT].height =
+		css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
+	frame_params[IMGU_ABI_OSYS_PIN_VF].width =
+		css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
+	frame_params[IMGU_ABI_OSYS_PIN_VF].height =
+		css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
+	frame_params[IMGU_ABI_OSYS_PIN_VF].crop_top = 0;
+	frame_params[IMGU_ABI_OSYS_PIN_VF].crop_left = 0;
+
+	for (pin = 0; pin < IMGU_ABI_OSYS_PINS; pin++) {
+		int enable = 0;
+		int scaled = 0;
+		unsigned int format = 0;
+		unsigned int tiling = 0;
+
+		frame_params[pin].flip = 0;
+		frame_params[pin].mirror = 0;
+		frame_params[pin].reduce_range = 0;
+		if (reso.pin_width[pin] != 0 && reso.pin_height[pin] != 0) {
+			enable = 1;
+			if (pin == IMGU_ABI_OSYS_PIN_OUT) {
+				if (reso.input_width < reso.pin_width[pin] ||
+				    reso.input_height < reso.pin_height[pin])
+					return -EINVAL;
+				/*
+				 * When input and output resolution is
+				 * different instead of scaling, cropping
+				 * should happen. Determine the crop factor
+				 * to do the symmetric cropping
+				 */
+				frame_params[pin].crop_left = roundclosest_down(
+						(reso.input_width -
+						 reso.pin_width[pin]) / 2,
+						 IMGU_OSYS_DMA_CROP_W_LIMIT);
+				frame_params[pin].crop_top = roundclosest_down(
+						(reso.input_height -
+						 reso.pin_height[pin]) / 2,
+						 IMGU_OSYS_DMA_CROP_H_LIMIT);
+			} else {
+				if (reso.pin_width[pin] !=
+				    reso.input_width ||
+				    reso.pin_height[pin] != reso.input_height) {
+					/*
+					 * If resolution is different at input
+					 * and output of OSYS, scaling is
+					 * considered except when pin is MAIN.
+					 * Later it will be decide whether
+					 * scaler factor is 1 or other
+					 * and cropping has to be done or not.
+					 */
+					scaled = 1;
+				}
+			}
+			ipu3_css_osys_set_format(reso.pin_format[pin], &format,
+						 &tiling);
+		} else {
+			enable = 0;
+		}
+		frame_params[pin].enable = enable;
+		frame_params[pin].format = format;
+		frame_params[pin].tiling = tiling;
+		frame_params[pin].stride = reso.pin_stride[pin];
+		frame_params[pin].scaled = scaled;
+	}
+
+	if (ipu3_css_scaler_calc(input_width, input_height,
+				 target_width, target_height,
+				 osys, scaler_luma, scaler_chroma,
+				 &reso.pin_width[IMGU_ABI_OSYS_PIN_VF],
+				 &reso.pin_height[IMGU_ABI_OSYS_PIN_VF],
+				 &procmode))
+		return -EINVAL;
+
+	dev_dbg(css->dev, "osys scaler procmode is %u", procmode);
+	output_width = reso.pin_width[IMGU_ABI_OSYS_PIN_VF];
+
+	if (output_width < reso.input_width / 2) {
+		/* Scaling factor <= 0.5 */
+		reso.chunk_width = IMGU_OSYS_BLOCK_WIDTH;
+		reso.block_width = IMGU_OSYS_BLOCK_WIDTH;
+	} else { /* 0.5 <= Scaling factor <= 1.0 */
+		reso.chunk_width = IMGU_OSYS_BLOCK_WIDTH / 2;
+		reso.block_width = IMGU_OSYS_BLOCK_WIDTH;
+	}
+
+	if (output_width <= reso.input_width * 7 / 8) {
+		/* Scaling factor <= 0.875 */
+		reso.chunk_height = IMGU_OSYS_BLOCK_HEIGHT;
+		reso.block_height = IMGU_OSYS_BLOCK_HEIGHT;
+	} else { /* 1.0 <= Scaling factor <= 1.75 */
+		reso.chunk_height = IMGU_OSYS_BLOCK_HEIGHT / 2;
+		reso.block_height = IMGU_OSYS_BLOCK_HEIGHT;
+	}
+
+	/*
+	 * Calculate scaler configuration parameters based on input and output
+	 * resolution.
+	 */
+
+	if (frame_params[IMGU_ABI_OSYS_PIN_VF].enable) {
+		/*
+		 * When aspect ratio is different between target resolution and
+		 * required resolution, determine the crop factor to do
+		 * symmetric cropping
+		 */
+		u32 w = reso.pin_width[IMGU_ABI_OSYS_PIN_VF] -
+			frame_params[IMGU_ABI_OSYS_PIN_VF].width;
+		u32 h = reso.pin_height[IMGU_ABI_OSYS_PIN_VF] -
+			frame_params[IMGU_ABI_OSYS_PIN_VF].height;
+
+		frame_params[IMGU_ABI_OSYS_PIN_VF].crop_left =
+			roundclosest_down(w / 2, IMGU_OSYS_DMA_CROP_W_LIMIT);
+		frame_params[IMGU_ABI_OSYS_PIN_VF].crop_top =
+			roundclosest_down(h / 2, IMGU_OSYS_DMA_CROP_H_LIMIT);
+
+		if (reso.input_height % 4 || reso.input_width % 8) {
+			dev_err(css->dev, "OSYS input width is not multiple of 8 or\n");
+			dev_err(css->dev, "height is not multiple of 4\n");
+			return -EINVAL;
+		}
+	}
+
+	/* stripe parameters */
+
+	if (frame_params[IMGU_ABI_OSYS_PIN_VF].enable) {
+		output_width = reso.pin_width[IMGU_ABI_OSYS_PIN_VF];
+	} else {
+		/*
+		 * in case scaler output is not enabled
+		 * take output width as input width since
+		 * there is no scaling at main pin.
+		 * Due to the fact that main pin can be different
+		 * from input resolution to osys in the case of cropping,
+		 * main pin resolution is not taken.
+		 */
+		output_width = reso.input_width;
+	}
+
+	for (s = 0; s < stripes; s++) {
+		int stripe_offset_inp_y = 0;
+		int stripe_offset_inp_uv = 0;
+		int stripe_offset_out_y = 0;
+		int stripe_offset_out_uv = 0;
+		int stripe_phase_init_y = scaler_luma->phase_init;
+		int stripe_phase_init_uv = scaler_chroma->phase_init;
+		int stripe_offset_blk_y = 0;
+		int stripe_offset_blk_uv = 0;
+		int stripe_offset_col_y = 0;
+		int stripe_offset_col_uv = 0;
+		int stripe_pad_left_y = scaler_luma->pad_left;
+		int stripe_pad_left_uv = scaler_chroma->pad_left;
+		int stripe_pad_right_y = scaler_luma->pad_right;
+		int stripe_pad_right_uv = scaler_chroma->pad_right;
+		int stripe_crop_left_y = scaler_luma->crop_left;
+		int stripe_crop_left_uv = scaler_chroma->crop_left;
+		int stripe_input_width_y = reso.input_width;
+		int stripe_input_width_uv = 0;
+		int stripe_output_width_y = output_width;
+		int stripe_output_width_uv = 0;
+		int chunk_floor_y = 0;
+		int chunk_floor_uv = 0;
+		int chunk_ceil_uv = 0;
+
+		if (stripes > 1) {
+			if (s > 0) {
+				/* Calculate stripe offsets */
+				stripe_offset_out_y = output_width * s /
+					stripes;
+				stripe_offset_out_y =
+					rounddown(stripe_offset_out_y,
+						  IPU3_UAPI_ISP_VEC_ELEMS);
+				stripe_offset_out_uv = stripe_offset_out_y /
+						IMGU_LUMA_TO_CHROMA_RATIO;
+				stripe_offset_inp_y =
+					ipu3_css_osys_calc_stripe_offset(
+						stripe_offset_out_y,
+						IMGU_OSYS_FIR_PHASES,
+						scaler_luma->phase_init,
+						scaler_luma->phase_step,
+						scaler_luma->pad_left);
+				stripe_offset_inp_uv =
+					ipu3_css_osys_calc_stripe_offset(
+						stripe_offset_out_uv,
+						IMGU_OSYS_FIR_PHASES,
+						scaler_chroma->phase_init,
+						scaler_chroma->phase_step,
+						scaler_chroma->pad_left);
+
+				/* Calculate stripe phase init */
+				stripe_phase_init_y =
+					ipu3_css_osys_calc_stripe_phase_init(
+						stripe_offset_out_y,
+						IMGU_OSYS_FIR_PHASES,
+						scaler_luma->phase_init,
+						scaler_luma->phase_step,
+						scaler_luma->pad_left);
+				stripe_phase_init_uv =
+					ipu3_css_osys_calc_stripe_phase_init(
+						stripe_offset_out_uv,
+						IMGU_OSYS_FIR_PHASES,
+						scaler_chroma->phase_init,
+						scaler_chroma->phase_step,
+						scaler_chroma->pad_left);
+
+				/*
+				 * Chunk boundary corner case - luma and chroma
+				 * start from different input chunks.
+				 */
+				chunk_floor_y = rounddown(stripe_offset_inp_y,
+							  reso.chunk_width);
+				chunk_floor_uv =
+					rounddown(stripe_offset_inp_uv,
+						  reso.chunk_width /
+						  IMGU_LUMA_TO_CHROMA_RATIO);
+
+				if (chunk_floor_y != chunk_floor_uv *
+				    IMGU_LUMA_TO_CHROMA_RATIO) {
+					/*
+					 * Match starting luma/chroma chunks.
+					 * Decrease offset for UV and add output
+					 * cropping.
+					 */
+					stripe_offset_inp_uv -= 1;
+					stripe_crop_left_uv += 1;
+					stripe_phase_init_uv -=
+						scaler_luma->phase_step;
+					if (stripe_phase_init_uv < 0)
+						stripe_phase_init_uv =
+							stripe_phase_init_uv +
+							IMGU_OSYS_FIR_PHASES;
+				}
+				/*
+				 * FW workaround for a HW bug: if the first
+				 * chroma pixel is generated exactly at the end
+				 * of chunck scaler HW may not output the pixel
+				 * for downscale factors smaller than 1.5
+				 * (timing issue).
+				 */
+				chunk_ceil_uv =
+					roundup(stripe_offset_inp_uv,
+						reso.chunk_width /
+						IMGU_LUMA_TO_CHROMA_RATIO);
+
+				if (stripe_offset_inp_uv ==
+				    chunk_ceil_uv - IMGU_OSYS_TAPS_UV) {
+					/*
+					 * Decrease input offset and add
+					 * output cropping
+					 */
+					stripe_offset_inp_uv -= 1;
+					stripe_phase_init_uv -=
+						scaler_luma->phase_step;
+					if (stripe_phase_init_uv < 0) {
+						stripe_phase_init_uv +=
+							IMGU_OSYS_FIR_PHASES;
+						stripe_crop_left_uv += 1;
+					}
+				}
+
+				/*
+				 * Calculate block and column offsets for the
+				 * input stripe
+				 */
+				stripe_offset_blk_y =
+					rounddown(stripe_offset_inp_y,
+						  IMGU_INPUT_BLOCK_WIDTH);
+				stripe_offset_blk_uv =
+					rounddown(stripe_offset_inp_uv,
+						  IMGU_INPUT_BLOCK_WIDTH /
+						  IMGU_LUMA_TO_CHROMA_RATIO);
+				stripe_offset_col_y = stripe_offset_inp_y -
+							stripe_offset_blk_y;
+				stripe_offset_col_uv = stripe_offset_inp_uv -
+							stripe_offset_blk_uv;
+
+				/* Left padding is only for the first stripe */
+				stripe_pad_left_y = 0;
+				stripe_pad_left_uv = 0;
+			}
+
+			/* Right padding is only for the last stripe */
+			if (s < stripes - 1) {
+				int next_offset;
+
+				stripe_pad_right_y = 0;
+				stripe_pad_right_uv = 0;
+
+				next_offset = output_width * (s + 1) / stripes;
+				next_offset = rounddown(next_offset, 64);
+				stripe_output_width_y = next_offset -
+							stripe_offset_out_y;
+			} else {
+				stripe_output_width_y = output_width -
+							stripe_offset_out_y;
+			}
+
+			/* Calculate target output stripe width */
+			stripe_output_width_uv = stripe_output_width_y /
+						IMGU_LUMA_TO_CHROMA_RATIO;
+			/* Calculate input stripe width */
+			stripe_input_width_y =
+				ipu3_css_osys_calc_inp_stripe_width(
+						stripe_output_width_y,
+						IMGU_OSYS_FIR_PHASES,
+						stripe_phase_init_y,
+						scaler_luma->phase_step,
+						IMGU_OSYS_TAPS_Y,
+						stripe_pad_left_y,
+						stripe_pad_right_y) +
+							stripe_offset_col_y;
+
+			stripe_input_width_uv =
+				ipu3_css_osys_calc_inp_stripe_width(
+						stripe_output_width_uv,
+						IMGU_OSYS_FIR_PHASES,
+						stripe_phase_init_uv,
+						scaler_chroma->phase_step,
+						IMGU_OSYS_TAPS_UV,
+						stripe_pad_left_uv,
+						stripe_pad_right_uv) +
+							stripe_offset_col_uv;
+
+			stripe_input_width_uv = max(DIV_ROUND_UP(
+						    stripe_input_width_y,
+						    IMGU_LUMA_TO_CHROMA_RATIO),
+						    stripe_input_width_uv);
+
+			stripe_input_width_y = stripe_input_width_uv *
+						IMGU_LUMA_TO_CHROMA_RATIO;
+
+			if (s >= stripes - 1) {
+				stripe_input_width_y = reso.input_width -
+					stripe_offset_blk_y;
+				/*
+				 * The scaler requires that the last stripe
+				 * spans at least two input blocks.
+				 */
+			}
+
+			/*
+			 * Spec: input stripe width must be a multiple of 8.
+			 * Increase the input width and recalculate the output
+			 * width. This may produce an extra column of junk
+			 * blocks which will be overwritten by the
+			 * next stripe.
+			 */
+			stripe_input_width_y = ALIGN(stripe_input_width_y, 8);
+			stripe_output_width_y =
+				ipu3_css_osys_out_stripe_width(
+						stripe_input_width_y,
+						IMGU_OSYS_FIR_PHASES,
+						stripe_phase_init_y,
+						scaler_luma->phase_step,
+						IMGU_OSYS_TAPS_Y,
+						stripe_pad_left_y,
+						stripe_pad_right_y,
+						stripe_offset_col_y);
+
+			stripe_output_width_y =
+					rounddown(stripe_output_width_y,
+						  IMGU_LUMA_TO_CHROMA_RATIO);
+		}
+		/*
+		 * Following section executes and process parameters
+		 * for both cases - Striping or No Striping.
+		 */
+		{
+			unsigned int i;
+			int pin_scale = 0;
+			/*Input resolution */
+
+			stripe_params[s].input_width = stripe_input_width_y;
+			stripe_params[s].input_height = reso.input_height;
+
+			for (i = 0; i < IMGU_ABI_OSYS_PINS; i++) {
+				if (frame_params[i].scaled) {
+					/*
+					 * Output stripe resolution and offset
+					 * as produced by the scaler; actual
+					 * output resolution may be slightly
+					 * smaller.
+					 */
+					stripe_params[s].output_width[i] =
+						stripe_output_width_y;
+					stripe_params[s].output_height[i] =
+						reso.pin_height[i];
+					stripe_params[s].output_offset[i] =
+						stripe_offset_out_y;
+
+					pin_scale += frame_params[i].scaled;
+				} else {
+					/* Unscaled pin */
+					stripe_params[s].output_width[i] =
+						stripe_params[s].input_width;
+					stripe_params[s].output_height[i] =
+						stripe_params[s].input_height;
+					stripe_params[s].output_offset[i] =
+						stripe_offset_blk_y;
+				}
+			}
+
+			/* If no pin use scale, we use BYPASS mode */
+			stripe_params[s].processing_mode = procmode;
+			stripe_params[s].phase_step = scaler_luma->phase_step;
+			stripe_params[s].exp_shift = scaler_luma->exp_shift;
+			stripe_params[s].phase_init_left_y =
+				stripe_phase_init_y;
+			stripe_params[s].phase_init_left_uv =
+				stripe_phase_init_uv;
+			stripe_params[s].phase_init_top_y =
+				scaler_luma->phase_init;
+			stripe_params[s].phase_init_top_uv =
+				scaler_chroma->phase_init;
+			stripe_params[s].pad_left_y = stripe_pad_left_y;
+			stripe_params[s].pad_left_uv = stripe_pad_left_uv;
+			stripe_params[s].pad_right_y = stripe_pad_right_y;
+			stripe_params[s].pad_right_uv = stripe_pad_right_uv;
+			stripe_params[s].pad_top_y = scaler_luma->pad_left;
+			stripe_params[s].pad_top_uv = scaler_chroma->pad_left;
+			stripe_params[s].pad_bottom_y = scaler_luma->pad_right;
+			stripe_params[s].pad_bottom_uv =
+				scaler_chroma->pad_right;
+			stripe_params[s].crop_left_y = stripe_crop_left_y;
+			stripe_params[s].crop_top_y = scaler_luma->crop_top;
+			stripe_params[s].crop_left_uv = stripe_crop_left_uv;
+			stripe_params[s].crop_top_uv = scaler_chroma->crop_top;
+			stripe_params[s].start_column_y = stripe_offset_col_y;
+			stripe_params[s].start_column_uv = stripe_offset_col_uv;
+			stripe_params[s].chunk_width = reso.chunk_width;
+			stripe_params[s].chunk_height = reso.chunk_height;
+			stripe_params[s].block_width = reso.block_width;
+			stripe_params[s].block_height = reso.block_height;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * This function configures the Output System, given the number of
+ * stripes, scaler luma and chrome parameters
+ */
+static int ipu3_css_osys_calc(struct ipu3_css *css, unsigned int stripes,
+			      struct ipu3_uapi_osys_config *osys,
+			      struct ipu3_css_scaler_info *scaler_luma,
+			      struct ipu3_css_scaler_info *scaler_chroma,
+			      struct ipu3_uapi_stripes block_stripes
+						[IPU3_UAPI_MAX_STRIPES])
+{
+	struct ipu3_css_frame_params frame_params[IMGU_ABI_OSYS_PINS];
+	struct ipu3_css_stripe_params stripe_params[IPU3_UAPI_MAX_STRIPES];
+	int pin, s;
+	struct ipu3_uapi_osys_formatter_params *param;
+
+	memset(osys, 0, sizeof(*osys));
+
+	/* compute the frame and stripe params */
+	ipu3_css_osys_calc_frame_and_stripe_params(css, stripes, osys,
+						   scaler_luma, scaler_chroma,
+						   frame_params, stripe_params);
+
+	/**** osys parameters ****/
+
+	for (s = 0; s < stripes; s++) {
+		struct ipu3_uapi_osys_scaler_params *scaler =
+					&osys->scaler[s].param;
+		int fifo_addr_fmt = IMGU_FIFO_ADDR_SCALER_TO_FMT;
+		int fifo_addr_ack = IMGU_FIFO_ADDR_SCALER_TO_SP;
+
+		/* OUTPUT 0 / PIN 0 is only Scaler output */
+		scaler->inp_buf_y_st_addr = IMGU_VMEM1_INP_BUF_ADDR;
+
+		/*
+		 * = (IMGU_OSYS_BLOCK_WIDTH / IMGU_VMEM1_ELEMS_PER_VEC)
+		 * = (2 * IPU3_UAPI_ISP_VEC_ELEMS) /
+		 *   (IMGU_HIVE_OF_SYS_OF_SYSTEM_NWAYS)
+		 * = 2 * 64 / 32 = 4
+		 */
+		scaler->inp_buf_y_line_stride = IMGU_VMEM1_Y_STRIDE;
+		/*
+		 * = (IMGU_VMEM1_V_OFFSET + VMEM1_uv_size)
+		 * = (IMGU_VMEM1_U_OFFSET + VMEM1_uv_size) +
+		 *	(VMEM1_y_size / 4)
+		 * = (VMEM1_y_size) + (VMEM1_y_size / 4) +
+		 * (IMGU_OSYS_BLOCK_HEIGHT * IMGU_VMEM1_Y_STRIDE)/4
+		 * = (IMGU_OSYS_BLOCK_HEIGHT * IMGU_VMEM1_Y_STRIDE)
+		 */
+		scaler->inp_buf_y_buffer_stride = IMGU_VMEM1_BUF_SIZE;
+		scaler->inp_buf_u_st_addr = IMGU_VMEM1_INP_BUF_ADDR +
+						IMGU_VMEM1_U_OFFSET;
+		scaler->inp_buf_v_st_addr = IMGU_VMEM1_INP_BUF_ADDR +
+						IMGU_VMEM1_V_OFFSET;
+		scaler->inp_buf_uv_line_stride = IMGU_VMEM1_UV_STRIDE;
+		scaler->inp_buf_uv_buffer_stride = IMGU_VMEM1_BUF_SIZE;
+		scaler->inp_buf_chunk_width = stripe_params[s].chunk_width;
+		scaler->inp_buf_nr_buffers = IMGU_OSYS_NUM_INPUT_BUFFERS;
+
+		/* Output buffers */
+		scaler->out_buf_y_st_addr = IMGU_VMEM1_INT_BUF_ADDR;
+		scaler->out_buf_y_line_stride = stripe_params[s].block_width /
+		    IMGU_VMEM1_ELEMS_PER_VEC;
+		scaler->out_buf_y_buffer_stride = IMGU_VMEM1_BUF_SIZE;
+		scaler->out_buf_u_st_addr = IMGU_VMEM1_INT_BUF_ADDR +
+						IMGU_VMEM1_U_OFFSET;
+		scaler->out_buf_v_st_addr = IMGU_VMEM1_INT_BUF_ADDR +
+						IMGU_VMEM1_V_OFFSET;
+		scaler->out_buf_uv_line_stride = stripe_params[s].block_width /
+		    IMGU_VMEM1_ELEMS_PER_VEC / 2;
+		scaler->out_buf_uv_buffer_stride = IMGU_VMEM1_BUF_SIZE;
+		scaler->out_buf_nr_buffers = IMGU_OSYS_NUM_INTERM_BUFFERS;
+
+		/* Intermediate buffers */
+		scaler->int_buf_y_st_addr = IMGU_VMEM2_BUF_Y_ADDR;
+		scaler->int_buf_y_line_stride = IMGU_VMEM2_BUF_Y_STRIDE;
+		scaler->int_buf_u_st_addr = IMGU_VMEM2_BUF_U_ADDR;
+		scaler->int_buf_v_st_addr = IMGU_VMEM2_BUF_V_ADDR;
+		scaler->int_buf_uv_line_stride = IMGU_VMEM2_BUF_UV_STRIDE;
+		scaler->int_buf_height = IMGU_VMEM2_LINES_PER_BLOCK;
+		scaler->int_buf_chunk_width = stripe_params[s].chunk_height;
+		scaler->int_buf_chunk_height = stripe_params[s].block_width;
+
+		/* Context buffers */
+		scaler->ctx_buf_hor_y_st_addr = IMGU_VMEM3_HOR_Y_ADDR;
+		scaler->ctx_buf_hor_u_st_addr = IMGU_VMEM3_HOR_U_ADDR;
+		scaler->ctx_buf_hor_v_st_addr = IMGU_VMEM3_HOR_V_ADDR;
+		scaler->ctx_buf_ver_y_st_addr = IMGU_VMEM3_VER_Y_ADDR;
+		scaler->ctx_buf_ver_u_st_addr = IMGU_VMEM3_VER_U_ADDR;
+		scaler->ctx_buf_ver_v_st_addr = IMGU_VMEM3_VER_V_ADDR;
+
+		/* Addresses for release-input and process-output tokens */
+		scaler->release_inp_buf_addr = fifo_addr_ack;
+		scaler->release_inp_buf_en = 1;
+		scaler->release_out_buf_en = 1;
+		scaler->process_out_buf_addr = fifo_addr_fmt;
+
+		/* Settings dimensions, padding, cropping */
+		scaler->input_image_y_width = stripe_params[s].input_width;
+		scaler->input_image_y_height = stripe_params[s].input_height;
+		scaler->input_image_y_start_column =
+					stripe_params[s].start_column_y;
+		scaler->input_image_uv_start_column =
+					stripe_params[s].start_column_uv;
+		scaler->input_image_y_left_pad = stripe_params[s].pad_left_y;
+		scaler->input_image_uv_left_pad = stripe_params[s].pad_left_uv;
+		scaler->input_image_y_right_pad = stripe_params[s].pad_right_y;
+		scaler->input_image_uv_right_pad =
+					stripe_params[s].pad_right_uv;
+		scaler->input_image_y_top_pad = stripe_params[s].pad_top_y;
+		scaler->input_image_uv_top_pad = stripe_params[s].pad_top_uv;
+		scaler->input_image_y_bottom_pad =
+					stripe_params[s].pad_bottom_y;
+		scaler->input_image_uv_bottom_pad =
+					stripe_params[s].pad_bottom_uv;
+		scaler->processing_mode = stripe_params[s].processing_mode;
+		scaler->scaling_ratio = stripe_params[s].phase_step;
+		scaler->y_left_phase_init = stripe_params[s].phase_init_left_y;
+		scaler->uv_left_phase_init =
+					stripe_params[s].phase_init_left_uv;
+		scaler->y_top_phase_init = stripe_params[s].phase_init_top_y;
+		scaler->uv_top_phase_init = stripe_params[s].phase_init_top_uv;
+		scaler->coeffs_exp_shift = stripe_params[s].exp_shift;
+		scaler->out_y_left_crop = stripe_params[s].crop_left_y;
+		scaler->out_uv_left_crop = stripe_params[s].crop_left_uv;
+		scaler->out_y_top_crop = stripe_params[s].crop_top_y;
+		scaler->out_uv_top_crop = stripe_params[s].crop_top_uv;
+
+		for (pin = 0; pin < IMGU_ABI_OSYS_PINS; pin++) {
+			int in_fifo_addr;
+			int out_fifo_addr;
+			int block_width_vecs;
+			int input_width_s;
+			int input_width_vecs;
+			int input_buf_y_st_addr;
+			int input_buf_u_st_addr;
+			int input_buf_v_st_addr;
+			int input_buf_y_line_stride;
+			int input_buf_uv_line_stride;
+			int output_buf_y_line_stride;
+			int output_buf_uv_line_stride;
+			int output_buf_nr_y_lines;
+			int block_height;
+			int block_width;
+			struct ipu3_uapi_osys_frame_params *fr_pr;
+
+			fr_pr = &osys->frame[pin].param;
+
+			/* FRAME PARAMETERS */
+			fr_pr->enable = frame_params[pin].enable;
+			fr_pr->format = frame_params[pin].format;
+			fr_pr->mirror = frame_params[pin].mirror;
+			fr_pr->flip = frame_params[pin].flip;
+			fr_pr->tiling = frame_params[pin].tiling;
+			fr_pr->width = frame_params[pin].width;
+			fr_pr->height = frame_params[pin].height;
+			fr_pr->stride = frame_params[pin].stride;
+			fr_pr->scaled = frame_params[pin].scaled;
+
+			/* STRIPING PARAMETERS */
+			osys->stripe[s].crop_top[pin] =
+				frame_params[pin].crop_top;
+			osys->stripe[s].input_width =
+				stripe_params[s].input_width;
+			osys->stripe[s].input_height =
+				stripe_params[s].input_height;
+			osys->stripe[s].block_height =
+				stripe_params[s].block_height;
+			osys->stripe[s].block_width =
+				stripe_params[s].block_width;
+			osys->stripe[s].output_width[pin] =
+				stripe_params[s].output_width[pin];
+			osys->stripe[s].output_height[pin] =
+				stripe_params[s].output_height[pin];
+
+			if (s == 0) {
+				/* Only first stripe should do left cropping */
+				osys->stripe[s].crop_left[pin] =
+					frame_params[pin].crop_left;
+				osys->stripe[s].output_offset[pin] =
+					stripe_params[s].output_offset[pin];
+			} else {
+				/* stripe offset for other strips should be
+				 * adjusted according to the cropping done
+				 * at the first strip
+				 */
+				osys->stripe[s].crop_left[pin] = 0;
+				osys->stripe[s].output_offset[pin] =
+					(stripe_params[s].output_offset[pin] -
+					osys->stripe[0].crop_left[pin]);
+			}
+
+			if (!frame_params[pin].enable)
+				continue;
+
+			/* FORMATTER: CONFIGURATION */
+
+			/* Get the dimensions of the input blocks of the
+			 * formatter, which is the same as the output
+			 * blocks of the scaler.
+			 */
+			if (frame_params[pin].scaled) {
+				block_height = stripe_params[s].block_height;
+				block_width = stripe_params[s].block_width;
+			} else {
+				block_height = IMGU_OSYS_BLOCK_HEIGHT;
+				block_width = IMGU_OSYS_BLOCK_WIDTH;
+			}
+			block_width_vecs =
+					block_width / IMGU_VMEM1_ELEMS_PER_VEC;
+			/* The input/output line stride depends on the
+			 * block size.
+			 */
+			input_buf_y_line_stride = block_width_vecs;
+			input_buf_uv_line_stride = block_width_vecs / 2;
+			output_buf_y_line_stride = block_width_vecs;
+			output_buf_uv_line_stride = block_width_vecs / 2;
+			output_buf_nr_y_lines = block_height;
+			if (frame_params[pin].format ==
+				IMGU_ABI_OSYS_FORMAT_NV12 ||
+				frame_params[pin].format ==
+				IMGU_ABI_OSYS_FORMAT_NV21)
+				output_buf_uv_line_stride =
+					output_buf_y_line_stride;
+
+			/* Tiled outputs use a different output buffer
+			 * configuration. The input (= scaler output) block
+			 * width translates to a tile height, and the block
+			 * height to the tile width. The default block size of
+			 * 128x32 maps exactly onto a 4kB tile (512x8) for Y.
+			 * For UV, the tile width is always half.
+			 */
+			if (frame_params[pin].tiling) {
+				output_buf_nr_y_lines = 8;
+				output_buf_y_line_stride = 512 /
+					IMGU_VMEM1_ELEMS_PER_VEC;
+				output_buf_uv_line_stride = 256 /
+					IMGU_VMEM1_ELEMS_PER_VEC;
+			}
+
+			/* Store the output buffer line stride. Will be
+			 * used to compute buffer offsets in boundary
+			 * conditions when output blocks are partially
+			 * outside the image.
+			 */
+			osys->stripe[s].buf_stride[pin] =
+				output_buf_y_line_stride *
+				IMGU_HIVE_OF_SYS_OF_SYSTEM_NWAYS;
+			if (frame_params[pin].scaled) {
+				/* the input buffs are the intermediate
+				 * buffers (scalers' output)
+				 */
+				input_buf_y_st_addr = IMGU_VMEM1_INT_BUF_ADDR;
+				input_buf_u_st_addr = IMGU_VMEM1_INT_BUF_ADDR +
+							IMGU_VMEM1_U_OFFSET;
+				input_buf_v_st_addr = IMGU_VMEM1_INT_BUF_ADDR +
+							IMGU_VMEM1_V_OFFSET;
+			} else {
+				/* the input bufferss are the buffers
+				 * filled by the SP
+				 */
+				input_buf_y_st_addr = IMGU_VMEM1_INP_BUF_ADDR;
+				input_buf_u_st_addr = IMGU_VMEM1_INP_BUF_ADDR +
+							IMGU_VMEM1_U_OFFSET;
+				input_buf_v_st_addr = IMGU_VMEM1_INP_BUF_ADDR +
+							IMGU_VMEM1_V_OFFSET;
+			}
+
+			/* The formatter input width must be rounded to
+			 * the block width. Otherwise the formatter will
+			 * not recognize the end of the line, resulting
+			 * in incorrect tiling (system may hang!) and
+			 * possibly other problems.
+			 */
+			input_width_s = roundup(
+					stripe_params[s].output_width[pin],
+					block_width);
+			input_width_vecs = input_width_s /
+					IMGU_VMEM1_ELEMS_PER_VEC;
+			out_fifo_addr = IMGU_FIFO_ADDR_FMT_TO_SP;
+			/* Process-output tokens must be sent to the SP.
+			 * When scaling, the release-input tokens can be
+			 * sent directly to the scaler, otherwise the
+			 * formatter should send them to the SP.
+			 */
+			if (frame_params[pin].scaled)
+				in_fifo_addr = IMGU_FIFO_ADDR_FMT_TO_SCALER;
+			else
+				in_fifo_addr = IMGU_FIFO_ADDR_FMT_TO_SP;
+
+			/* FORMATTER */
+			param = &osys->formatter[s][pin].param;
+
+			param->format = frame_params[pin].format;
+			param->flip = frame_params[pin].flip;
+			param->mirror = frame_params[pin].mirror;
+			param->tiling = frame_params[pin].tiling;
+			param->reduce_range =
+				frame_params[pin].reduce_range;
+			param->alpha_blending = 0;
+			param->release_inp_addr = in_fifo_addr;
+			param->release_inp_en = 1;
+			param->process_out_buf_addr = out_fifo_addr;
+			param->image_width_vecs = input_width_vecs;
+			param->image_height_lines =
+				stripe_params[s].output_height[pin];
+			param->inp_buff_y_st_addr = input_buf_y_st_addr;
+			param->inp_buff_y_line_stride =
+				input_buf_y_line_stride;
+			param->inp_buff_y_buffer_stride =
+				IMGU_VMEM1_BUF_SIZE;
+			param->int_buff_u_st_addr = input_buf_u_st_addr;
+			param->int_buff_v_st_addr = input_buf_v_st_addr;
+			param->inp_buff_uv_line_stride =
+				input_buf_uv_line_stride;
+			param->inp_buff_uv_buffer_stride = IMGU_VMEM1_BUF_SIZE;
+			param->out_buff_level = 0;
+			param->out_buff_nr_y_lines =
+				output_buf_nr_y_lines;
+			param->out_buff_u_st_offset = IMGU_VMEM1_U_OFFSET;
+			param->out_buff_v_st_offset = IMGU_VMEM1_V_OFFSET;
+			param->out_buff_y_line_stride =
+				output_buf_y_line_stride;
+			param->out_buff_uv_line_stride =
+				output_buf_uv_line_stride;
+			param->hist_buff_st_addr = IMGU_VMEM1_HST_BUF_ADDR;
+			param->hist_buff_line_stride =
+				IMGU_VMEM1_HST_BUF_STRIDE;
+			param->hist_buff_nr_lines = IMGU_VMEM1_HST_BUF_NLINES;
+		}
+	}
+
+	block_stripes[0].offset = 0;
+	if (stripes <= 1) {
+		block_stripes[0].width = stripe_params[0].input_width;
+		block_stripes[0].height = stripe_params[0].input_height;
+	} else {
+		struct imgu_fw_info *bi =
+				&css->fwp->binary_header[css->current_binary];
+		unsigned int sp_block_width =
+				bi->info.isp.sp.block.block_width *
+					IPU3_UAPI_ISP_VEC_ELEMS;
+
+		block_stripes[0].width =
+			roundup(stripe_params[0].input_width, sp_block_width);
+		block_stripes[1].offset =
+			rounddown(css->rect[IPU3_CSS_RECT_GDC].width
+			- stripe_params[1].input_width, sp_block_width);
+		block_stripes[1].width =
+			roundup(css->rect[IPU3_CSS_RECT_GDC].width
+			- block_stripes[1].offset, sp_block_width);
+		block_stripes[0].height = css->rect[IPU3_CSS_RECT_GDC].height;
+		block_stripes[1].height = block_stripes[0].height;
+	}
+
+	return 0;
+}
+
+/*********************** Mostly 3A operations ******************************/
+
+/*
+ * This function creates a "TO-DO list" (operations) for the sp code.
+ *
+ * There are 2 types of operations:
+ * 1. Transfer: Issue DMA transfer request for copying grid cells from DDR to
+ *    accelerator space (NOTE that this space is limited) associated data:
+ *    DDR address + accelerator's config set index(acc's address).
+ *
+ * 2. Issue "Process Lines Command" to shd accelerator
+ *    associated data: #lines + which config set to use (actually, accelerator
+ *    will use x AND (x+1)%num_of_sets - NOTE that this implies the restriction
+ *    of not touching config sets x & (x+1)%num_of_sets when process_lines(x)
+ *    is active).
+ *
+ * Basically there are 2 types of operations "chunks":
+ * 1. "initial chunk": Initially, we do as much transfers as we can (and need)
+ *    [0 - max sets(3) ] followed by 1 or 2 "process lines" operations.
+ *
+ * 2. "regular chunk" - 1 transfer followed by 1 process line operation.
+ *    (in some cases we might need additional transfer ate the last chunk).
+ *
+ * for some case:
+ * --> init
+ *	tr (0)
+ *	tr (1)
+ *	tr (2)
+ *	pl (0)
+ *	pl (1)
+ * --> ack (0)
+ *	tr (3)
+ *	pl (2)
+ * --> ack (1)
+ *	pl (3)
+ * --> ack (2)
+ *	do nothing
+ * --> ack (3)
+ *	do nothing
+ */
+
+static int
+ipu3_css_shd_ops_calc(struct ipu3_uapi_shd_intra_frame_operations_data *ops,
+		      const struct ipu3_uapi_shd_grid_config *grid,
+		      unsigned int image_height)
+{
+	unsigned int block_height = 1 << grid->block_height_log2;
+	unsigned int grid_height_per_slice = grid->grid_height_per_slice;
+	unsigned int set_height = grid_height_per_slice * block_height;
+
+	/* We currently support only abs(y_start) > grid_height_per_slice */
+	unsigned int positive_y_start = (unsigned int)-grid->y_start;
+	unsigned int first_process_lines =
+		set_height - (positive_y_start % set_height);
+	unsigned int last_set_height;
+	unsigned int num_of_sets;
+
+	struct ipu3_uapi_acc_operation *p_op;
+	struct ipu3_uapi_acc_process_lines_cmd_data *p_pl;
+	struct ipu3_uapi_shd_transfer_luts_set_data *p_tr;
+
+	unsigned int op_idx;
+	unsigned int pl_idx;
+	unsigned int tr_idx;
+	unsigned char tr_set_num;
+	unsigned char pl_cfg_set;
+
+	/*
+	 * When the number of lines for the last process lines command
+	 * is equal to a set height, we need another line of grid cell -
+	 * additional transfer is required.
+	 */
+	unsigned char last_tr = 0;
+
+	/* Add "process lines" command to the list of operations */
+	bool add_pl;
+	/* Add DMA xfer (config set) command to the list of ops */
+	bool add_tr;
+
+	/*
+	 * Available partial grid (the part that fits into #IMGU_SHD_SETS sets)
+	 * doesn't cover whole frame - need to process in chunks
+	 */
+	if (image_height > first_process_lines) {
+		last_set_height =
+			(image_height - first_process_lines) % set_height;
+		num_of_sets = last_set_height > 0 ?
+			(image_height - first_process_lines) / set_height + 2 :
+			(image_height - first_process_lines) / set_height + 1;
+		last_tr = (set_height - last_set_height <= block_height ||
+			   last_set_height == 0) ? 1 : 0;
+	} else { /* partial grid covers whole frame */
+		last_set_height = 0;
+		num_of_sets = 1;
+		first_process_lines = image_height;
+		last_tr = set_height - image_height <= block_height ? 1 : 0;
+	}
+
+	/* Init operations lists and counters */
+	p_op = ops->operation_list;
+	op_idx = 0;
+	p_pl = ops->process_lines_data;
+	pl_idx = 0;
+	p_tr = ops->transfer_data;
+	tr_idx = 0;
+
+	memset(ops, 0, sizeof(*ops));
+
+	/* Cyclic counters that holds config set number [0,IMGU_SHD_SETS) */
+	tr_set_num = 0;
+	pl_cfg_set = 0;
+
+	/*
+	 * Always start with a transfer - process lines command must be
+	 * initiated only after appropriate config sets are in place
+	 * (2 configuration sets per process line command, except for last one).
+	 */
+	add_pl = false;
+	add_tr = true;
+
+	while (add_pl || add_tr) {
+		/* Transfer ops */
+		if (add_tr) {
+			if (op_idx >= IPU3_UAPI_SHD_MAX_OPERATIONS ||
+			    tr_idx >= IPU3_UAPI_SHD_MAX_TRANSFERS)
+				return -EINVAL;
+			p_op[op_idx].op_type =
+				IMGU_ABI_ACC_OPTYPE_TRANSFER_DATA;
+			p_op[op_idx].op_indicator = IMGU_ABI_ACC_OP_IDLE;
+			op_idx++;
+			p_tr[tr_idx].set_number = tr_set_num;
+			tr_idx++;
+			tr_set_num = (tr_set_num + 1) % IMGU_SHD_SETS;
+		}
+
+		/* Process-lines ops */
+		if (add_pl) {
+			if (op_idx >= IPU3_UAPI_SHD_MAX_OPERATIONS ||
+			    pl_idx >= IPU3_UAPI_SHD_MAX_PROCESS_LINES)
+				return -EINVAL;
+			p_op[op_idx].op_type =
+				IMGU_ABI_ACC_OPTYPE_PROCESS_LINES;
+
+			/*
+			 * In case we have 2 process lines commands -
+			 * don't stop after the first one
+			 */
+			if (pl_idx == 0 && num_of_sets != 1)
+				p_op[op_idx].op_indicator =
+					IMGU_ABI_ACC_OP_IDLE;
+			/*
+			 * Initiate last process lines command -
+			 * end of operation list.
+			 */
+			else if (pl_idx == num_of_sets - 1)
+				p_op[op_idx].op_indicator =
+					IMGU_ABI_ACC_OP_END_OF_OPS;
+			/*
+			 * Intermediate process line command - end of operation
+			 * "chunk" (meaning few "transfers" followed by few
+			 * "process lines" commands).
+			 */
+			else
+				p_op[op_idx].op_indicator =
+					IMGU_ABI_ACC_OP_END_OF_ACK;
+
+			op_idx++;
+
+			/* first process line operation */
+			if (pl_idx == 0)
+				p_pl[pl_idx].lines = first_process_lines;
+			/* Last process line operation */
+			else if (pl_idx == num_of_sets - 1 &&
+				 last_set_height > 0)
+				p_pl[pl_idx].lines = last_set_height;
+			else	/* "regular" process lines operation */
+				p_pl[pl_idx].lines = set_height;
+
+			p_pl[pl_idx].cfg_set = pl_cfg_set;
+			pl_idx++;
+			pl_cfg_set = (pl_cfg_set + 1) % IMGU_SHD_SETS;
+		}
+
+		/*
+		 * Initially, we always transfer
+		 * min(IMGU_SHD_SETS, num_of_sets) - after that we fill in the
+		 * corresponding process lines commands.
+		 */
+		if (tr_idx == IMGU_SHD_SETS ||
+		    tr_idx == num_of_sets + last_tr) {
+			add_tr = false;
+			add_pl = true;
+		}
+
+		/*
+		 * We have finished the "initial" operations chunk -
+		 * be ready to get more chunks.
+		 */
+		if (pl_idx == 2) {
+			add_tr = true;
+			add_pl = true;
+		}
+
+		/* Stop conditions for each operation type */
+		if (tr_idx == num_of_sets + last_tr)
+			add_tr = false;
+		if (pl_idx == num_of_sets)
+			add_pl = false;
+	}
+
+	return 0;
+}
+
+/* Common for AF, AWB and AWB FR */
+struct process_lines {
+	unsigned short process_lines;
+	unsigned short first_pl; /* first process lines */
+	unsigned short last_pl_in_grid;
+	unsigned int pl_after_grid;
+	unsigned short num_of_pl;
+	unsigned short max_op; /* max operation */
+	unsigned short max_tr; /* max transaction */
+};
+
+static int
+ipu3_css_acc_process_lines(const struct process_lines *pl,
+			   const unsigned short num_of_sets,
+			   struct ipu3_uapi_acc_operation *p_op,
+			   struct ipu3_uapi_acc_process_lines_cmd_data *p_pl,
+			   struct ipu3_uapi_acc_transfer_op_data *p_tr)
+{
+	unsigned short process_lines = pl->process_lines;
+	unsigned short first_process_lines = pl->first_pl;
+	unsigned short last_process_lines_in_grid = pl->last_pl_in_grid;
+	unsigned int process_lines_after_grid = pl->pl_after_grid;
+	unsigned short num_of_process_lines = pl->num_of_pl;
+	unsigned short op_idx = 0, pl_idx = 0, tr_idx = 0;
+	unsigned char tr_set_num = 0, pl_cfg_set = 0;
+
+	while (tr_idx < num_of_sets || pl_idx < num_of_process_lines) {
+		/* read-meta-data */
+		if (pl_idx >= 2 || (num_of_sets == 1 && pl_idx == 1)) {
+			if (op_idx >= pl->max_op || tr_idx >= pl->max_tr)
+				return -EINVAL;
+
+			p_op[op_idx].op_type =
+				IMGU_ABI_ACC_OPTYPE_TRANSFER_DATA;
+
+			if (tr_idx == num_of_sets - 1)
+				/* the last operation is always a tr */
+				p_op[op_idx].op_indicator =
+					IMGU_ABI_ACC_OP_END_OF_OPS;
+			else if (tr_idx == num_of_sets - 2)
+				if (process_lines_after_grid == 0)
+					/*
+					 * no additional pl op left -
+					 * this op is left as lats of cycle
+					 */
+					p_op[op_idx].op_indicator =
+						IMGU_ABI_ACC_OP_END_OF_ACK;
+				else
+					/*
+					 * we still have to process-lines after
+					 * the grid so have one more pl op
+					 */
+					p_op[op_idx].op_indicator =
+						IMGU_ABI_ACC_OP_IDLE;
+			else
+				/* default - usually there's a pl after a tr */
+				p_op[op_idx].op_indicator =
+					IMGU_ABI_ACC_OP_IDLE;
+
+			op_idx++;
+			if (p_tr) {
+				p_tr[tr_idx].set_number = tr_set_num;
+				tr_set_num = 1 - tr_set_num;
+			}
+			tr_idx++;
+		}
+
+		/* process_lines */
+		if (pl_idx < num_of_process_lines) {
+			if (op_idx >= pl->max_op || pl_idx >= pl->max_tr)
+				return -EINVAL;
+
+			p_op[op_idx].op_type =
+				IMGU_ABI_ACC_OPTYPE_PROCESS_LINES;
+			if (pl_idx == 0)
+				if (num_of_process_lines == 1)
+					/* only one pl op */
+					p_op[op_idx].op_indicator =
+						IMGU_ABI_ACC_OP_END_OF_ACK;
+				else
+					/* on init - do two pl ops */
+					p_op[op_idx].op_indicator =
+						IMGU_ABI_ACC_OP_IDLE;
+			else
+				/* usually pl is the end of the ack cycle */
+				p_op[op_idx].op_indicator =
+					IMGU_ABI_ACC_OP_END_OF_ACK;
+
+			op_idx++;
+
+			if (pl_idx == 0)
+				/* first */
+				p_pl[pl_idx].lines = first_process_lines;
+			else if (pl_idx == num_of_sets - 1)
+				/* last in grid */
+				p_pl[pl_idx].lines = last_process_lines_in_grid;
+			else if (pl_idx == num_of_process_lines - 1)
+				/* after the grid */
+				p_pl[pl_idx].lines = process_lines_after_grid;
+			else
+				/* inside the grid */
+				p_pl[pl_idx].lines = process_lines;
+
+			if (p_tr) {
+				p_pl[pl_idx].cfg_set = pl_cfg_set;
+				pl_cfg_set = 1 - pl_cfg_set;
+			}
+			pl_idx++;
+		} /* if (pl_idx<num_of_sets-2) */
+	} /* while ( op_idx < 2*num_of_sets ) */
+
+	return 0;
+}
+
+/* for n sets of meta-data, the flow is:
+ * --> init
+ *  process-lines  (0)
+ *  process-lines  (1)	 eoc
+ *  --> ack (0)
+ *  read-meta-data (0)
+ *  process-lines  (2)	 eoc
+ *  --> ack (1)
+ *  read-meta-data (1)
+ *  process-lines  (3)	 eoc
+ *  ...
+ *
+ *  --> ack (n-3)
+ *  read-meta-data (n-3)
+ *  process-lines  (n-1) eoc
+ *  --> ack (n-2)
+ *  read-meta-data (n-2) eoc
+ *  --> ack (n-1)
+ *  read-meta-data (n-1) eof
+ *
+ * for 2 sets we get:
+ * --> init
+ * pl (0)
+ * pl (1) eoc
+ * --> ack (0)
+ * pl (2) - rest of image, if applicable)
+ * rmd (0) eoc
+ * --> ack (1)
+ * rmd (1) eof
+ * --> (ack (2))
+ * do nothing
+ *
+ * for only one set:
+ *
+ * --> init
+ * pl(0)   eoc
+ * --> ack (0)
+ * rmd (0) eof
+ *
+ * grid smaller than image case
+ * for example 128x128 grid (block size 8x8, 16x16 num of blocks)
+ * start at (0,0)
+ * 1st set holds 160 cells - 10 blocks vertical, 16 horizontal
+ * => 1st process lines = 80
+ * we're left with 128-80=48 lines (6 blocks vertical)
+ * => 2nd process lines = 48
+ * last process lines to cover the image - image_height - 128
+ *
+ * --> init
+ * pl (0) first
+ * pl (1) last-in-grid
+ * --> ack (0)
+ * rmd (0)
+ * pl (2) after-grid
+ * --> ack (1)
+ * rmd (1) eof
+ * --> ack (2)
+ * do nothing
+ */
+static int ipu3_css_af_ops_calc(struct ipu3_css *css,
+				struct ipu3_uapi_af_config *af_config)
+{
+	const unsigned char grid_height_per_slice =
+		af_config->stripes[0].grid_cfg.height_per_slice;
+	struct ipu3_uapi_af_intra_frame_operations_data *to =
+		&af_config->operations_data;
+	unsigned int image_height = css->rect[IPU3_CSS_RECT_BDS].height;
+	unsigned short block_height =
+		1 << af_config->config.grid_cfg.block_height_log2;
+	unsigned short grid_height = af_config->config.grid_cfg.height;
+	unsigned short y_start = af_config->config.grid_cfg.y_start
+		& IPU3_UAPI_GRID_START_MASK;
+	unsigned short grid_last_line = y_start + grid_height * block_height;
+	unsigned short num_of_sets;
+
+	struct ipu3_uapi_acc_operation *p_op;
+	struct ipu3_uapi_acc_process_lines_cmd_data *p_pl;
+	struct imgu_fw_info *bi = &css->fwp->binary_header[css->current_binary];
+	struct process_lines pl = {
+		.max_op = IPU3_UAPI_AF_MAX_OPERATIONS,
+		.max_tr = IPU3_UAPI_AF_MAX_TRANSFERS,
+	};
+
+	if (grid_height_per_slice == 0)
+		return -EINVAL;
+
+	num_of_sets = grid_height / grid_height_per_slice;
+	if (num_of_sets * grid_height_per_slice < grid_height)
+		num_of_sets++;
+
+	if (bi->info.isp.sp.enable.af && grid_last_line > image_height)
+		return -EINVAL;
+
+	pl.process_lines = grid_height_per_slice * block_height;
+
+	/* account for two line delay inside the FF */
+	pl.first_pl = pl.process_lines + y_start + 2;
+	pl.last_pl_in_grid = (grid_last_line - pl.first_pl) -
+		((num_of_sets - 2) * pl.process_lines) + 4;
+	pl.pl_after_grid = image_height - grid_last_line - 4;
+
+	pl.num_of_pl = num_of_sets;
+	if (pl.pl_after_grid > 0)
+		pl.num_of_pl++;
+
+	p_op = to->ops;
+	p_pl = to->process_lines_data;
+
+	return ipu3_css_acc_process_lines(&pl, num_of_sets, p_op, p_pl, NULL);
+}
+
+/*
+ * for n sets of meta-data, the flow is:
+ *
+ * --> init
+ *          process-lines  (0)
+ *          process-lines  (1)   eoc
+ * --> ack (0)
+ *          read-meta-data (0)
+ *          process-lines  (2)   eoc
+ * --> ack (1)
+ *          read-meta-data (1)
+ *          process-lines  (3)   eoc
+ * ...
+ *
+ * --> ack (n-3)
+ *          read-meta-data (n-3)
+ *          process-lines  (n-1) eoc
+ * --> ack (n-2)
+ *          read-meta-data (n-2) eoc
+ * --> ack (n-1)
+ *          read-meta-data (n-1) eof
+ *
+ * for 2 sets we get:
+ *
+ * --> init
+ *          pl (0)
+ *          pl (1) eoc
+ * --> ack (0)
+ *          (pl (2) - rest of image, if applicable)
+ *          rmd (0) eoc
+ * --> ack (1)
+ *          rmd (1) eof
+ * --> (ack (2))
+ *          do nothing
+ *
+ * for only one set:
+ *
+ * --> init
+ *          pl(0)   eoc
+ * --> ack (0)
+ *          rmd (0) eof
+ *
+ * grid smaller than image case
+ * for example 128x128 grid (block size 8x8, 16x16 num of blocks)
+ * start at (0,0)
+ * 1st set holds 160 cells - 10 blocks vertical, 16 horizontal
+ * => 1st process lines = 80
+ * we're left with 128-80=48 lines (6 blocks vertical)
+ * => 2nd process lines = 48
+ * last process lines to cover the image - image_height - 128
+ *
+ * --> init
+ *          pl (0) first
+ *          pl (1) last-in-grid
+ * --> ack (0)
+ *          rmd (0)
+ *          pl (2) after-grid
+ * --> ack (1)
+ *          rmd (1) eof
+ * --> ack (2)
+ *          do nothing
+ */
+static int ipu3_css_awb_fr_ops_calc(struct ipu3_css *css,
+				    struct ipu3_uapi_awb_fr_config
+				    *awb_fr_config)
+{
+	const unsigned char grid_height_per_slice =
+		awb_fr_config->stripes[0].grid_cfg.height_per_slice;
+	struct ipu3_uapi_awb_fr_intra_frame_operations_data *to =
+		&awb_fr_config->operations_data;
+	unsigned int image_height =
+			css->rect[IPU3_CSS_RECT_BDS].height;
+	unsigned short block_height =
+		1 << awb_fr_config->config.grid_cfg.block_height_log2;
+	unsigned short grid_height = awb_fr_config->config.grid_cfg.height;
+	unsigned short y_start = awb_fr_config->config.grid_cfg.y_start &
+				IPU3_UAPI_GRID_START_MASK;
+	unsigned short grid_last_line = y_start + grid_height * block_height;
+	unsigned short num_of_sets = 0;
+
+	struct ipu3_uapi_acc_operation *p_op = to->ops;
+	struct ipu3_uapi_acc_process_lines_cmd_data *p_pl;
+	struct imgu_fw_info *bi = &css->fwp->binary_header[css->current_binary];
+	struct process_lines pl = {
+		.max_op = IPU3_UAPI_AWB_FR_MAX_OPERATIONS,
+		.max_tr = IPU3_UAPI_AWB_FR_MAX_PROCESS_LINES,
+	};
+
+	if (grid_height_per_slice == 0)
+		return -EINVAL;
+
+	num_of_sets = grid_height / grid_height_per_slice;
+	if (num_of_sets * grid_height_per_slice < grid_height)
+		num_of_sets++;
+
+	if (bi->info.isp.sp.enable.awb_fr_acc && grid_last_line > image_height)
+		return -EINVAL;
+
+	pl.process_lines = grid_height_per_slice * block_height;
+
+	/* account for two line delay inside the FF */
+	pl.first_pl = pl.process_lines + y_start;
+	pl.last_pl_in_grid = (grid_last_line - pl.first_pl) -
+	    ((num_of_sets - 2) * pl.process_lines);
+	pl.pl_after_grid = image_height - grid_last_line;
+
+	pl.num_of_pl = num_of_sets;
+	if (pl.pl_after_grid > 0)
+		pl.num_of_pl++;
+
+	p_pl = to->process_lines_data;
+
+	return ipu3_css_acc_process_lines(&pl, num_of_sets, p_op, p_pl, NULL);
+}
+
+/* for n sets of meta-data, the flow is:
+ *
+ * --> init
+ * process-lines  (0)
+ * process-lines  (1)   eoc
+ * --> ack (0)
+ * read-meta-data (0)
+ * process-lines  (2)   eoc
+ * --> ack (1)
+ * read-meta-data (1)
+ * process-lines  (3)   eoc
+ * ...
+ *
+ * --> ack (n-3)
+ * read-meta-data (n-3)
+ * process-lines  (n-1) eoc
+ * --> ack (n-2)
+ * read-meta-data (n-2) eoc
+ * --> ack (n-1)
+ * read-meta-data (n-1) eof
+ *
+ * for 2 sets we get:
+ * --> init
+ * pl (0)
+ * pl (1) eoc
+ * --> ack (0)
+ * (pl (2) - rest of image, if applicable)
+ * rmd (0) eoc
+ * --> ack (1)
+ * rmd (1) eof
+ * --> (ack (2))
+ *  do nothing
+ *
+ * for only one set:
+ *
+ * --> init
+ * pl(0)   eoc
+ * --> ack (0)
+ * rmd (0) eof
+ *
+ * grid smaller than image case
+ * for example 128x128 grid (block size 8x8, 16x16 num of blocks)
+ * start at (0,0)
+ * 1st set holds 160 cells - 10 blocks vertical, 16 horizontal
+ * => 1st process lines = 80
+ * we're left with 128-80=48 lines (6 blocks vertical)
+ * => 2nd process lines = 48
+ * last process lines to cover the image - image_height - 128
+ *
+ * --> init
+ * pl (0) first
+ * pl (1) last-in-grid
+ * --> ack (0)
+ * rmd (0)
+ * pl (2) after-grid
+ * --> ack (1)
+ * rmd (1) eof
+ * --> ack (2)
+ * do nothing
+ */
+static int ipu3_css_awb_ops_calc(struct ipu3_css *css,
+				 struct ipu3_uapi_awb_config *awb_config)
+{
+	struct ipu3_uapi_awb_intra_frame_operations_data *to =
+		&awb_config->operations_data;
+	const unsigned char grid_height_per_slice =
+		awb_config->stripes[0].grid.height_per_slice;
+	unsigned int image_height = css->rect[IPU3_CSS_RECT_BDS].height;
+	unsigned short block_height =
+		1 << awb_config->config.grid.block_height_log2;
+	unsigned short grid_height = awb_config->config.grid.height;
+	unsigned short y_start = awb_config->config.grid.y_start;
+
+	unsigned short grid_last_line = y_start + grid_height * block_height;
+	unsigned short num_of_sets = 0;
+
+	struct ipu3_uapi_acc_operation *p_op;
+	struct ipu3_uapi_acc_process_lines_cmd_data *p_pl;
+	struct ipu3_uapi_acc_transfer_op_data *p_tr;
+	struct imgu_fw_info *bi = &css->fwp->binary_header[css->current_binary];
+	struct process_lines pl = {
+		.max_op = IPU3_UAPI_AWB_MAX_OPERATIONS,
+		.max_tr = IPU3_UAPI_AWB_MAX_TRANSFERS,
+	};
+
+	/* avoid division by 0 */
+	if (grid_height_per_slice == 0)
+		return -EINVAL;
+
+	num_of_sets = grid_height / grid_height_per_slice;
+
+	if (num_of_sets * grid_height_per_slice < grid_height)
+		num_of_sets++;
+
+	if (bi->info.isp.sp.enable.awb_acc && grid_last_line > image_height)
+		return -EINVAL;
+
+	pl.process_lines = grid_height_per_slice * block_height;
+	pl.first_pl = pl.process_lines + y_start;
+	pl.last_pl_in_grid = (grid_last_line - pl.first_pl) -
+		((num_of_sets - 2) * pl.process_lines);
+	pl.pl_after_grid = image_height - grid_last_line;
+
+	pl.num_of_pl = num_of_sets;
+	if (pl.pl_after_grid > 0)
+		pl.num_of_pl++;
+
+	p_op = to->ops;
+	p_pl = to->process_lines_data;
+	p_tr = to->transfer_data;
+
+	return ipu3_css_acc_process_lines(&pl, num_of_sets, p_op, p_pl, p_tr);
+}
+
+static u16 ipu3_css_grid_end(u16 start, u8 width, u8 block_width_log2)
+{
+	return (start & IPU3_UAPI_GRID_START_MASK) +
+		(width << block_width_log2) - 1;
+}
+
+static void ipu3_css_grid_end_calc(struct ipu3_uapi_grid_config *grid_cfg)
+{
+	grid_cfg->x_end = ipu3_css_grid_end(grid_cfg->x_start, grid_cfg->width,
+					    grid_cfg->block_width_log2);
+	grid_cfg->y_end = ipu3_css_grid_end(grid_cfg->y_start, grid_cfg->height,
+					    grid_cfg->block_height_log2);
+}
+
+/****************** config computation *****************************/
+
+static int ipu3_css_cfg_acc_stripe(
+		struct ipu3_css *css, struct ipu3_uapi_acc_param *acc)
+{
+	const struct imgu_fw_info *bi =
+		&css->fwp->binary_header[css->current_binary];
+	const unsigned int stripes = bi->info.isp.sp.iterator.num_stripes;
+	struct ipu3_css_scaler_info scaler_luma;
+	struct ipu3_css_scaler_info scaler_chroma;
+	unsigned int bds_ds;
+	int s, f;
+
+	memset(acc, 0, sizeof(*acc));
+
+	/* acc_param: osys_config */
+
+	if (ipu3_css_osys_calc(css, stripes, &acc->osys,
+			       &scaler_luma, &scaler_chroma,
+			       acc->stripe.block_stripes))
+		return -EINVAL;
+
+	/* acc_param: stripe data */
+
+	/*
+	 * for the striped case the approach is as follows:
+	 * 1. down-scaled stripes are calculated - with 128 overlap
+	 *    (this is the main limiter therefore it's first)
+	 * 2. input stripes are derived by up-scaling the down-scaled stripes
+	 *    (there are no alignment requirements on input stripes)
+	 * 3. output stripes are derived from down-scaled stripes too
+	 */
+
+	f = IPU3_UAPI_ISP_VEC_ELEMS * 2;
+
+	acc->stripe.num_of_stripes = stripes;
+	acc->stripe.input_frame.width =
+		css->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.width;
+	acc->stripe.input_frame.height =
+		css->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.height;
+	acc->stripe.input_frame.bayer_order =
+		css->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order;
+
+	for (s = 0; s < stripes; s++)
+		acc->stripe.bds_out_stripes[s].height =
+					css->rect[IPU3_CSS_RECT_BDS].height;
+	acc->stripe.bds_out_stripes[0].offset = 0;
+	if (stripes <= 1) {
+		acc->stripe.bds_out_stripes[0].width =
+			ALIGN(css->rect[IPU3_CSS_RECT_BDS].width, f);
+	} else {
+		/* Image processing is divided into two stripes */
+		acc->stripe.bds_out_stripes[0].width =
+			acc->stripe.bds_out_stripes[1].width =
+			(css->rect[IPU3_CSS_RECT_BDS].width / 2 & ~(f - 1)) + f;
+		/* Sum of width of the two stripes should not be smaller
+		 * than output width and must be even times of overlapping
+		 * unit f.
+		 */
+		if ((css->rect[IPU3_CSS_RECT_BDS].width / f & 1) !=
+		    !!(css->rect[IPU3_CSS_RECT_BDS].width & (f - 1)))
+			acc->stripe.bds_out_stripes[0].width += f;
+		if ((css->rect[IPU3_CSS_RECT_BDS].width / f & 1) &&
+		    (css->rect[IPU3_CSS_RECT_BDS].width & (f - 1))) {
+			acc->stripe.bds_out_stripes[0].width += f;
+			acc->stripe.bds_out_stripes[1].width += f;
+		}
+		/* Overlap between stripes is IPU3_UAPI_ISP_VEC_ELEMS * 4 */
+		acc->stripe.bds_out_stripes[1].offset =
+		    acc->stripe.bds_out_stripes[0].width - 2 * f;
+	}
+
+	acc->stripe.effective_stripes[0].height =
+				css->rect[IPU3_CSS_RECT_EFFECTIVE].height;
+	acc->stripe.effective_stripes[0].offset = 0;
+	acc->stripe.bds_out_stripes_no_overlap[0].height =
+				css->rect[IPU3_CSS_RECT_BDS].height;
+	acc->stripe.bds_out_stripes_no_overlap[0].offset = 0;
+	acc->stripe.output_stripes[0].height =
+	    css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
+	acc->stripe.output_stripes[0].offset = 0;
+	if (stripes <= 1) {
+		acc->stripe.down_scaled_stripes[0].width =
+				css->rect[IPU3_CSS_RECT_BDS].width;
+		acc->stripe.down_scaled_stripes[0].height =
+				css->rect[IPU3_CSS_RECT_BDS].height;
+		acc->stripe.down_scaled_stripes[0].offset = 0;
+
+		acc->stripe.effective_stripes[0].width =
+				css->rect[IPU3_CSS_RECT_EFFECTIVE].width;
+		acc->stripe.bds_out_stripes_no_overlap[0].width =
+			ALIGN(css->rect[IPU3_CSS_RECT_BDS].width, f);
+
+		acc->stripe.output_stripes[0].width =
+			css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
+	} else { /* Two stripes */
+		bds_ds = css->rect[IPU3_CSS_RECT_EFFECTIVE].width *
+				IMGU_BDS_GRANULARITY /
+				css->rect[IPU3_CSS_RECT_BDS].width;
+
+		acc->stripe.down_scaled_stripes[0] =
+			acc->stripe.bds_out_stripes[0];
+		acc->stripe.down_scaled_stripes[1] =
+			acc->stripe.bds_out_stripes[1];
+		if (!IS_ALIGNED(css->rect[IPU3_CSS_RECT_BDS].width, f))
+			acc->stripe.down_scaled_stripes[1].width +=
+				(css->rect[IPU3_CSS_RECT_BDS].width
+				& (f - 1)) - f;
+
+		acc->stripe.effective_stripes[0].width = bds_ds *
+			acc->stripe.down_scaled_stripes[0].width /
+			IMGU_BDS_GRANULARITY;
+		acc->stripe.effective_stripes[1].width = bds_ds *
+			acc->stripe.down_scaled_stripes[1].width  /
+			IMGU_BDS_GRANULARITY;
+		acc->stripe.effective_stripes[1].height =
+			css->rect[IPU3_CSS_RECT_EFFECTIVE].height;
+		acc->stripe.effective_stripes[1].offset = bds_ds *
+			acc->stripe.down_scaled_stripes[1].offset /
+			IMGU_BDS_GRANULARITY;
+
+		acc->stripe.bds_out_stripes_no_overlap[0].width =
+		acc->stripe.bds_out_stripes_no_overlap[1].offset =
+			ALIGN(css->rect[IPU3_CSS_RECT_BDS].width, 2 * f) / 2;
+		acc->stripe.bds_out_stripes_no_overlap[1].width =
+			DIV_ROUND_UP(css->rect[IPU3_CSS_RECT_BDS].width, f)
+			/ 2 * f;
+		acc->stripe.bds_out_stripes_no_overlap[1].height =
+			css->rect[IPU3_CSS_RECT_BDS].height;
+
+		acc->stripe.output_stripes[0].width =
+			acc->stripe.down_scaled_stripes[0].width - f;
+		acc->stripe.output_stripes[1].width =
+			acc->stripe.down_scaled_stripes[1].width - f;
+		acc->stripe.output_stripes[1].height =
+			css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
+		acc->stripe.output_stripes[1].offset =
+			acc->stripe.output_stripes[0].width;
+	}
+
+	acc->stripe.output_system_in_frame_width =
+		css->rect[IPU3_CSS_RECT_GDC].width;
+	acc->stripe.output_system_in_frame_height =
+		css->rect[IPU3_CSS_RECT_GDC].height;
+
+	acc->stripe.effective_frame_width =
+				css->rect[IPU3_CSS_RECT_EFFECTIVE].width;
+	acc->stripe.bds_frame_width = css->rect[IPU3_CSS_RECT_BDS].width;
+	acc->stripe.out_frame_width =
+		css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
+	acc->stripe.out_frame_height =
+		css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
+	acc->stripe.gdc_in_buffer_width =
+		css->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperline /
+		css->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperpixel;
+	acc->stripe.gdc_in_buffer_height =
+		css->aux_frames[IPU3_CSS_AUX_FRAME_REF].height;
+	acc->stripe.gdc_in_buffer_offset_x = IMGU_GDC_BUF_X;
+	acc->stripe.gdc_in_buffer_offset_y = IMGU_GDC_BUF_Y;
+	acc->stripe.display_frame_width =
+		css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
+	acc->stripe.display_frame_height =
+		css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
+	acc->stripe.bds_aligned_frame_width =
+		roundup(css->rect[IPU3_CSS_RECT_BDS].width,
+			2 * IPU3_UAPI_ISP_VEC_ELEMS);
+
+	if (stripes > 1)
+		acc->stripe.half_overlap_vectors =
+			IMGU_STRIPE_FIXED_HALF_OVERLAP;
+	else
+		acc->stripe.half_overlap_vectors = 0;
+
+	return 0;
+}
+
+static void acc_dvs_per_stripe_grd(struct ipu3_uapi_acc_param *acc,
+				   const unsigned int stripes,
+				   const unsigned int i)
+{
+	unsigned int s, bin = i + 1;
+
+	acc->dvs_stat.stripe.stripe_cfg[0].grd_config[i].grid_width =
+		DIV_ROUND_UP(acc->dvs_stat.cfg.grd_config[i].grid_width, 2);
+
+	acc->dvs_stat.stripe.stripe_cfg[1].grd_config[i].grid_width =
+		acc->dvs_stat.cfg.grd_config[i].grid_width -
+		acc->dvs_stat.stripe.stripe_cfg[0].grd_config[i].grid_width;
+
+	acc->dvs_stat.stripe.stripe_cfg[1].grd_config[i].x_start +=
+		acc->dvs_stat.stripe.stripe_cfg[0].grd_config[i].grid_width *
+		acc->dvs_stat.cfg.grd_config[i].block_width -
+		(acc->stripe.down_scaled_stripes[1].offset >> bin);
+
+	for (s = 0; s < stripes; s++) {
+		acc->dvs_stat.stripe.stripe_cfg[s].grd_config[i].x_end =
+		acc->dvs_stat.stripe.stripe_cfg[s].grd_config[i].x_start +
+		acc->dvs_stat.stripe.stripe_cfg[s].grd_config[i].grid_width *
+		acc->dvs_stat.cfg.grd_config[i].block_width - 1;
+	}
+}
+
+static int ipu3_css_cfg_acc_dvs(struct ipu3_css *css,
+				struct ipu3_uapi_acc_param *acc)
+{
+	const struct imgu_fw_info *bi =
+		&css->fwp->binary_header[css->current_binary];
+	const unsigned int stripes = bi->info.isp.sp.iterator.num_stripes;
+	const int pipe = 0;
+	unsigned int i;
+
+	/* acc_param: dvs_stat_config */
+
+	acc->dvs_stat.cfg.gbl_cfg.kappa = IMGU_DVSSTAT_DEFAULT_KAPPA;
+	acc->dvs_stat.cfg.gbl_cfg.match_shift = 0;
+	acc->dvs_stat.cfg.gbl_cfg.ybin_mode = 0;
+
+	/*
+	 * Find some default block parameters for each of the three levels.
+	 * HW restrictions (for each level):
+	 * - block_w, block_h = 16 ... 254 / 128 / 64 and even
+	 * - hor_blocks <= 12 / 11 / 9
+	 * - hor_blocks * ver_blocks <= 84 / 66 / 45
+	 * - sum of horizontal blocks from each stripe equals total hor blocks
+	 */
+	for (i = 0; i < IPU3_UAPI_DVS_STAT_LEVELS; i++) {
+		static const unsigned int max_block_size[] = { 254, 128, 64 };
+		static const unsigned int max_hor_blocks[] = { 12, 11, 9 };
+		static const unsigned int max_tot_blocks[] = { 84, 66, 45 };
+		const struct v4l2_pix_format_mplane *pixm =
+				&css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix;
+
+		unsigned int bin = i + 1;
+		unsigned int frame_w = (pixm->width >> bin) -
+					2 * IMGU_DVSSTAT_DEFAULT_START;
+		unsigned int frame_h = (pixm->height >> bin) -
+					2 * IMGU_DVSSTAT_DEFAULT_START;
+		unsigned int block_w = ALIGN(max_block_size[i] / 2, 2);
+		unsigned int block_h = block_w;
+		unsigned int hor_blocks =
+			clamp_t(unsigned int, frame_w / block_w, 1,
+				max_hor_blocks[i]);
+		unsigned int ver_blocks =
+				max_t(unsigned int, frame_h / block_h, 1);
+
+		if (hor_blocks * ver_blocks > max_tot_blocks[i])
+			ver_blocks = max_tot_blocks[i] / hor_blocks;
+		if (ver_blocks <= 0)
+			return -EINVAL;
+
+		acc->dvs_stat.cfg.grd_config[i].grid_width = hor_blocks;
+		acc->dvs_stat.cfg.grd_config[i].grid_height = ver_blocks;
+		acc->dvs_stat.cfg.grd_config[i].block_width = block_w;
+		acc->dvs_stat.cfg.grd_config[i].block_height = block_h;
+		acc->dvs_stat.cfg.grd_config[i].x_start =
+			IMGU_DVSSTAT_DEFAULT_START;
+		acc->dvs_stat.cfg.grd_config[i].y_start =
+			IMGU_DVSSTAT_DEFAULT_START;
+		acc->dvs_stat.cfg.grd_config[i].enable = 1;
+		acc->dvs_stat.cfg.grd_config[i].x_end =
+			acc->dvs_stat.cfg.grd_config[i].x_start +
+			hor_blocks * block_w - 1;
+		acc->dvs_stat.cfg.grd_config[i].y_end =
+			acc->dvs_stat.cfg.grd_config[i].y_start +
+			ver_blocks * block_h - 1;
+
+		acc->dvs_stat.cfg.fe_roi_cfg[i].x_start =
+			IMGU_DVSSTAT_FE_ROI_START;
+		acc->dvs_stat.cfg.fe_roi_cfg[i].y_start =
+			IMGU_DVSSTAT_FE_ROI_START;
+		acc->dvs_stat.cfg.fe_roi_cfg[i].x_end =
+			acc->dvs_stat.cfg.grd_config[i].block_width -
+			IMGU_DVSSTAT_FE_ROI_END_MARGIN;
+		acc->dvs_stat.cfg.fe_roi_cfg[i].y_end =
+			acc->dvs_stat.cfg.grd_config[i].block_height -
+			IMGU_DVSSTAT_FE_ROI_END_MARGIN;
+	}
+
+	for (i = 0; i < stripes; i++)
+		acc->dvs_stat.stripe.stripe_cfg[i] = acc->dvs_stat.cfg;
+
+	if (stripes > 1) {
+		for (i = 0; i < IPU3_UAPI_DVS_STAT_LEVELS; i++)
+			acc_dvs_per_stripe_grd(acc, stripes, i);
+	}
+
+	for (i = 0; i < stripes; i++)
+		acc->dvs_stat.meta_data[i].p_meta_data =
+		    css->dvs_meta_data[pipe][i].daddr;
+
+	/* FIXME: calculate operations data here if DVS is enabled */
+
+	/* Disable DVS statistics */
+	acc->dvs_stat.operations_data.process_lines_data[0].lines =
+				css->rect[IPU3_CSS_RECT_BDS].height;
+	acc->dvs_stat.operations_data.process_lines_data[0].cfg_set = 0;
+	acc->dvs_stat.operations_data.ops[0].op_type =
+		IMGU_ABI_ACC_OPTYPE_PROCESS_LINES;
+	acc->dvs_stat.operations_data.ops[0].op_indicator =
+		IMGU_ABI_ACC_OP_NO_OPS;
+	for (i = 0; i < IPU3_UAPI_DVS_STAT_LEVELS; i++)
+		acc->dvs_stat.cfg.grd_config[i].enable = 0;
+
+	return 0;
+}
+
+static void acc_bds_per_stripe_data(struct ipu3_css *css,
+				    struct ipu3_uapi_acc_param *acc,
+				    const int i)
+{
+	acc->bds.per_stripe.aligned_data[i].data.crop.hor_crop_en = 0;
+	acc->bds.per_stripe.aligned_data[i].data.crop.hor_crop_start = 0;
+	acc->bds.per_stripe.aligned_data[i].data.crop.hor_crop_end = 0;
+	acc->bds.per_stripe.aligned_data[i].data.hor_ctrl0 =
+		acc->bds.hor.hor_ctrl0;
+	acc->bds.per_stripe.aligned_data[i].data.hor_ctrl0.out_frame_width =
+		acc->stripe.down_scaled_stripes[i].width;
+	acc->bds.per_stripe.aligned_data[i].data.ver_ctrl1.out_frame_width =
+		acc->stripe.down_scaled_stripes[i].width;
+	acc->bds.per_stripe.aligned_data[i].data.ver_ctrl1.out_frame_height =
+		css->rect[IPU3_CSS_RECT_BDS].height;
+}
+
+/*
+ * Configure `acc' parameters. `acc_old' contains the old values (or is NULL)
+ * and `acc_user' contains new prospective values. `use' contains flags
+ * telling which fields to take from the old values (or generate if it is NULL)
+ * and which to take from the new user values.
+ */
+int ipu3_css_cfg_acc(struct ipu3_css *css, struct ipu3_uapi_flags *use,
+		     struct ipu3_uapi_acc_param *acc,
+		     struct ipu3_uapi_acc_param *acc_old,
+		     struct ipu3_uapi_acc_param *acc_user)
+{
+	const struct imgu_fw_info *bi =
+		&css->fwp->binary_header[css->current_binary];
+	const unsigned int stripes = bi->info.isp.sp.iterator.num_stripes;
+	unsigned int tnr_frame_width;
+	const struct ipu3_css_bds_config *cfg_bds;
+	const struct v4l2_pix_format_mplane *pixm = NULL;
+	unsigned int bds_ds;
+	unsigned int ofs_x, ofs_y;
+	u8 b_w_log2; /* block width log2 */
+	int min_overlap;
+	int i, s, width, ret;
+	struct ipu3_uapi_input_feeder_data *feeder_data;
+
+	/* update stripe using chroma and luma */
+
+	ret = ipu3_css_cfg_acc_stripe(css, acc);
+	if (ret)
+		return ret;
+
+	tnr_frame_width = acc->stripe.bds_aligned_frame_width;
+	pixm = &css->queue[IPU3_CSS_QUEUE_IN].fmt.mpix;
+	/* acc_param: input_feeder_config */
+
+	ofs_x = ((pixm->width -
+		  css->rect[IPU3_CSS_RECT_EFFECTIVE].width) >> 1) & ~1;
+	ofs_x += css->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order ==
+		IMGU_ABI_BAYER_ORDER_RGGB ||
+		css->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order ==
+		IMGU_ABI_BAYER_ORDER_GBRG ? 1 : 0;
+	ofs_y = ((pixm->height -
+		  css->rect[IPU3_CSS_RECT_EFFECTIVE].height) >> 1) & ~1;
+	ofs_y += css->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order ==
+		IMGU_ABI_BAYER_ORDER_BGGR ||
+		css->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order ==
+		IMGU_ABI_BAYER_ORDER_GBRG ? 1 : 0;
+	acc->input_feeder.data.row_stride = pixm->plane_fmt[0].bytesperline;
+	acc->input_feeder.data.start_row_address =
+		ofs_x / IMGU_PIXELS_PER_WORD * IMGU_BYTES_PER_WORD +
+		ofs_y * acc->input_feeder.data.row_stride;
+	acc->input_feeder.data.start_pixel = ofs_x % IMGU_PIXELS_PER_WORD;
+
+	acc->input_feeder.data_per_stripe.input_feeder_data[0].data =
+		acc->input_feeder.data;
+
+	ofs_x += acc->stripe.effective_stripes[1].offset;
+
+	feeder_data =
+		&acc->input_feeder.data_per_stripe.input_feeder_data[1].data;
+	feeder_data->row_stride = acc->input_feeder.data.row_stride;
+	feeder_data->start_row_address =
+		ofs_x / IMGU_PIXELS_PER_WORD * IMGU_BYTES_PER_WORD +
+		ofs_y * acc->input_feeder.data.row_stride;
+	feeder_data->start_pixel = ofs_x % IMGU_PIXELS_PER_WORD;
+
+	/* acc_param: bnr_static_config */
+
+	/*
+	 * originate from user or be the original default values if user has
+	 * never set them before, when user gives a new set of parameters,
+	 * for each chunk in the parameter structure there is a flag use->xxx
+	 * whether to use the user-provided parameter or not. If not, the
+	 * parameter remains unchanged in the driver:
+	 * it's value is taken from acc_old.
+	 */
+	if (use && use->acc_bnr) {
+		/* Take values from user */
+		acc->bnr = acc_user->bnr;
+	} else if (acc_old) {
+		/* Use old value */
+		acc->bnr = acc_old->bnr;
+	} else {
+		/* Calculate from scratch */
+		acc->bnr = ipu3_css_bnr_defaults;
+	}
+
+	acc->bnr.column_size = tnr_frame_width;
+	acc->bnr.opt_center_sqr.x_sqr_reset = sqr(acc->bnr.opt_center.x_reset);
+	acc->bnr.opt_center_sqr.y_sqr_reset = sqr(acc->bnr.opt_center.y_reset);
+
+	/* acc_param: bnr_static_config_green_disparity */
+
+	if (use && use->acc_green_disparity) {
+		/* Take values from user */
+		acc->green_disparity = acc_user->green_disparity;
+	} else if (acc_old) {
+		/* Use old value */
+		acc->green_disparity = acc_old->green_disparity;
+	} else {
+		/* Calculate from scratch */
+		memset(&acc->green_disparity, 0, sizeof(acc->green_disparity));
+	}
+
+	/* acc_param: dm_config */
+
+	if (use && use->acc_dm) {
+		/* Take values from user */
+		acc->dm = acc_user->dm;
+	} else if (acc_old) {
+		/* Use old value */
+		acc->dm = acc_old->dm;
+	} else {
+		/* Calculate from scratch */
+		acc->dm = ipu3_css_dm_defaults;
+	}
+
+	acc->dm.frame_width = tnr_frame_width;
+
+	/* acc_param: ccm_mat_config */
+
+	if (use && use->acc_ccm) {
+		/* Take values from user */
+		acc->ccm = acc_user->ccm;
+	} else if (acc_old) {
+		/* Use old value */
+		acc->ccm = acc_old->ccm;
+	} else {
+		/* Calculate from scratch */
+		acc->ccm = ipu3_css_ccm_defaults;
+	}
+
+	/* acc_param: gamma_config */
+
+	if (use && use->acc_gamma) {
+		/* Take values from user */
+		acc->gamma = acc_user->gamma;
+	} else if (acc_old) {
+		/* Use old value */
+		acc->gamma = acc_old->gamma;
+	} else {
+		/* Calculate from scratch */
+		acc->gamma.gc_ctrl.enable = 1;
+		acc->gamma.gc_lut = ipu3_css_gamma_lut;
+	}
+
+	/* acc_param: csc_mat_config */
+
+	if (use && use->acc_csc) {
+		/* Take values from user */
+		acc->csc = acc_user->csc;
+	} else if (acc_old) {
+		/* Use old value */
+		acc->csc = acc_old->csc;
+	} else {
+		/* Calculate from scratch */
+		acc->csc = ipu3_css_csc_defaults;
+	}
+
+	/* acc_param: cds_params */
+
+	if (use && use->acc_cds) {
+		/* Take values from user */
+		acc->cds = acc_user->cds;
+	} else if (acc_old) {
+		/* Use old value */
+		acc->cds = acc_old->cds;
+	} else {
+		/* Calculate from scratch */
+		acc->cds = ipu3_css_cds_defaults;
+	}
+
+	/* acc_param: shd_config */
+
+	if (use && use->acc_shd) {
+		/* Take values from user */
+		acc->shd.shd = acc_user->shd.shd;
+		acc->shd.shd_lut = acc_user->shd.shd_lut;
+	} else if (acc_old) {
+		/* Use old value */
+		acc->shd.shd = acc_old->shd.shd;
+		acc->shd.shd_lut = acc_old->shd.shd_lut;
+	} else {
+		/* Calculate from scratch */
+		acc->shd.shd = ipu3_css_shd_defaults;
+		memset(&acc->shd.shd_lut, 0, sizeof(acc->shd.shd_lut));
+	}
+
+	if (acc->shd.shd.grid.width <= 0)
+		return -EINVAL;
+
+	acc->shd.shd.grid.grid_height_per_slice =
+		IPU3_UAPI_SHD_MAX_CELLS_PER_SET / acc->shd.shd.grid.width;
+
+	if (acc->shd.shd.grid.grid_height_per_slice <= 0)
+		return -EINVAL;
+
+	acc->shd.shd.general.init_set_vrt_offst_ul =
+				(-acc->shd.shd.grid.y_start >>
+				acc->shd.shd.grid.block_height_log2) %
+				acc->shd.shd.grid.grid_height_per_slice;
+
+	if (ipu3_css_shd_ops_calc(&acc->shd.shd_ops, &acc->shd.shd.grid,
+				  css->rect[IPU3_CSS_RECT_BDS].height))
+		return -EINVAL;
+
+	/* acc_param: dvs_stat_config */
+	ret = ipu3_css_cfg_acc_dvs(css, acc);
+	if (ret)
+		return ret;
+
+	/* acc_param: lace_stat_config */
+	/* acc_param: yuvp1_iefd_config */
+
+	if (use && use->acc_iefd) {
+		/* Take values from user */
+		acc->iefd = acc_user->iefd;
+	} else if (acc_old) {
+		/* Use old value */
+		acc->iefd = acc_old->iefd;
+	} else {
+		/* Calculate from scratch */
+		acc->iefd = ipu3_css_iefd_defaults;
+	}
+
+	/* acc_param: yuvp1_yds_config yds_c0 */
+
+	if (use && use->acc_yds_c0) {
+		/* Take values from user */
+		acc->yds_c0 = acc_user->yds_c0;
+	} else if (acc_old) {
+		/* Use old value */
+		acc->yds_c0 = acc_old->yds_c0;
+	} else {
+		/* Calculate from scratch */
+		acc->yds_c0 = ipu3_css_yds_defaults;
+	}
+
+	/* acc_param: yuvp1_chnr_config chnr_c0 */
+
+	if (use && use->acc_chnr_c0) {
+		/* Take values from user */
+		acc->chnr_c0 = acc_user->chnr_c0;
+	} else if (acc_old) {
+		/* Use old value */
+		acc->chnr_c0 = acc_old->chnr_c0;
+	} else {
+		/* Calculate from scratch */
+		acc->chnr_c0 = ipu3_css_chnr_defaults;
+	}
+
+	/* acc_param: yuvp1_y_ee_nr_config */
+
+	if (use && use->acc_y_ee_nr) {
+		/* Take values from user */
+		acc->y_ee_nr = acc_user->y_ee_nr;
+	} else if (acc_old) {
+		/* Use old value */
+		acc->y_ee_nr = acc_old->y_ee_nr;
+	} else {
+		/* Calculate from scratch */
+		acc->y_ee_nr = ipu3_css_y_ee_nr_defaults;
+	}
+
+	/* acc_param: yuvp1_yds_config yds */
+
+	if (use && use->acc_yds) {
+		/* Take values from user */
+		acc->yds = acc_user->yds;
+	} else if (acc_old) {
+		/* Use old value */
+		acc->yds = acc_old->yds;
+	} else {
+		/* Calculate from scratch */
+		acc->yds = ipu3_css_yds_defaults;
+	}
+
+	/* acc_param: yuvp1_chnr_config chnr */
+
+	if (use && use->acc_chnr) {
+		/* Take values from user */
+		acc->chnr = acc_user->chnr;
+	} else if (acc_old) {
+		/* Use old value */
+		acc->chnr = acc_old->chnr;
+	} else {
+		/* Calculate from scratch */
+		acc->chnr = ipu3_css_chnr_defaults;
+	}
+
+	/* acc_param: yuvp2_y_tm_lut_static_config */
+
+	for (i = 0; i < IPU3_UAPI_YUVP2_YTM_LUT_ENTRIES; i++)
+		acc->ytm.entries[i] = i * 32;
+	acc->ytm.enable = 0;	/* Always disabled on IPU3 */
+
+	/* acc_param: yuvp1_yds_config yds2 */
+
+	if (use && use->acc_yds2) {
+		/* Take values from user */
+		acc->yds2 = acc_user->yds2;
+	} else if (acc_old) {
+		/* Use old value */
+		acc->yds2 = acc_old->yds2;
+	} else {
+		/* Calculate from scratch */
+		acc->yds2 = ipu3_css_yds_defaults;
+	}
+
+	/* acc_param: yuvp2_tcc_static_config */
+
+	if (use && use->acc_tcc) {
+		/* Take values from user */
+		acc->tcc = acc_user->tcc;
+	} else if (acc_old) {
+		/* Use old value */
+		acc->tcc = acc_old->tcc;
+	} else {
+		/* Calculate from scratch */
+		memset(&acc->tcc, 0, sizeof(acc->tcc));
+
+		acc->tcc.gen_control.en = 1;
+		acc->tcc.gen_control.blend_shift = 3;
+		acc->tcc.gen_control.gain_according_to_y_only = 1;
+		acc->tcc.gen_control.gamma = 8;
+		acc->tcc.gen_control.delta = 0;
+
+		for (i = 0; i < IPU3_UAPI_YUVP2_TCC_MACC_TABLE_ELEMENTS; i++) {
+			acc->tcc.macc_table.entries[i].a = 1024;
+			acc->tcc.macc_table.entries[i].b = 0;
+			acc->tcc.macc_table.entries[i].c = 0;
+			acc->tcc.macc_table.entries[i].d = 1024;
+		}
+
+		acc->tcc.inv_y_lut.entries[6] = 1023;
+		for (i = 7; i < IPU3_UAPI_YUVP2_TCC_INV_Y_LUT_ELEMENTS; i++)
+			acc->tcc.inv_y_lut.entries[i] = 1024 >> (i - 6);
+
+		acc->tcc.gain_pcwl = ipu3_css_tcc_gain_pcwl_lut;
+		acc->tcc.r_sqr_lut = ipu3_css_tcc_r_sqr_lut;
+	}
+
+	/* acc_param: dpc_config */
+
+	if (use && use->acc_dpc)
+		return -EINVAL;	/* Not supported yet */
+
+	/* Just disable by default */
+	memset(&acc->dpc, 0, sizeof(acc->dpc));
+
+	/* acc_param: bds_config */
+
+	bds_ds = (css->rect[IPU3_CSS_RECT_EFFECTIVE].height *
+		  IMGU_BDS_GRANULARITY) / css->rect[IPU3_CSS_RECT_BDS].height;
+	if (bds_ds < IMGU_BDS_MIN_SF_INV ||
+	    bds_ds - IMGU_BDS_MIN_SF_INV >= ARRAY_SIZE(ipu3_css_bds_configs))
+		return -EINVAL;
+
+	cfg_bds = &ipu3_css_bds_configs[bds_ds - IMGU_BDS_MIN_SF_INV];
+	acc->bds.hor.hor_ctrl1.hor_crop_en = 0;
+	acc->bds.hor.hor_ctrl1.hor_crop_start = 0;
+	acc->bds.hor.hor_ctrl1.hor_crop_end = 0;
+	acc->bds.hor.hor_ctrl0.sample_patrn_length =
+		cfg_bds->sample_patrn_length;
+	acc->bds.hor.hor_ctrl0.hor_ds_en = cfg_bds->hor_ds_en;
+	acc->bds.hor.hor_ctrl0.min_clip_val = IMGU_BDS_MIN_CLIP_VAL;
+	acc->bds.hor.hor_ctrl0.max_clip_val = IMGU_BDS_MAX_CLIP_VAL;
+	acc->bds.hor.hor_ctrl0.out_frame_width =
+					css->rect[IPU3_CSS_RECT_BDS].width;
+	acc->bds.hor.hor_ptrn_arr = cfg_bds->ptrn_arr;
+	acc->bds.hor.hor_phase_arr = cfg_bds->hor_phase_arr;
+	acc->bds.hor.hor_ctrl2.input_frame_height =
+				css->rect[IPU3_CSS_RECT_EFFECTIVE].height;
+	acc->bds.ver.ver_ctrl0.min_clip_val = IMGU_BDS_MIN_CLIP_VAL;
+	acc->bds.ver.ver_ctrl0.max_clip_val = IMGU_BDS_MAX_CLIP_VAL;
+	acc->bds.ver.ver_ctrl0.sample_patrn_length =
+	    cfg_bds->sample_patrn_length;
+	acc->bds.ver.ver_ctrl0.ver_ds_en = cfg_bds->ver_ds_en;
+	acc->bds.ver.ver_ptrn_arr = cfg_bds->ptrn_arr;
+	acc->bds.ver.ver_phase_arr = cfg_bds->ver_phase_arr;
+	acc->bds.ver.ver_ctrl1.out_frame_width =
+					css->rect[IPU3_CSS_RECT_BDS].width;
+	acc->bds.ver.ver_ctrl1.out_frame_height =
+					css->rect[IPU3_CSS_RECT_BDS].height;
+	for (s = 0; s < stripes; s++)
+		acc_bds_per_stripe_data(css, acc, s);
+
+	acc->bds.enabled = cfg_bds->hor_ds_en || cfg_bds->ver_ds_en;
+
+	/* acc_param: anr_config */
+
+	if (use && use->acc_anr) {
+		/* Take values from user */
+		acc->anr = acc_user->anr;
+	} else if (acc_old) {
+		/* Use old value */
+		acc->anr = acc_old->anr;
+	} else {
+		/* Calculate from scratch */
+		acc->anr = ipu3_css_anr_defaults;
+	}
+
+	/* Always enabled */
+	acc->anr.search.enable = 1;
+	acc->anr.transform.enable = 1;
+	acc->anr.tile2strm.enable = 1;
+	acc->anr.tile2strm.frame_width = ALIGN(
+				css->rect[IPU3_CSS_RECT_BDS].width,
+				IMGU_ISP_VMEM_ALIGN);
+	acc->anr.search.frame_width = acc->anr.tile2strm.frame_width;
+	acc->anr.stitch.frame_width = acc->anr.tile2strm.frame_width;
+
+	acc->anr.tile2strm.frame_height =
+				css->rect[IPU3_CSS_RECT_BDS].height;
+	acc->anr.search.frame_height = acc->anr.tile2strm.frame_height;
+	acc->anr.stitch.frame_height = acc->anr.tile2strm.frame_height;
+
+	width = ALIGN(css->rect[IPU3_CSS_RECT_BDS].width,
+		      IMGU_ISP_VMEM_ALIGN);
+	if (acc->anr.transform.xreset > IPU3_UAPI_ANR_MAX_XRESET - width)
+		acc->anr.transform.xreset = IPU3_UAPI_ANR_MAX_XRESET - width;
+
+	/* acc_param: awb_fr_config */
+
+	if (use && use->acc_awb_fr) {
+		/* Take values from user */
+		acc->awb_fr.config = acc_user->awb_fr.config;
+	} else if (acc_old) {
+		/* Use old value */
+		acc->awb_fr.config = acc_old->awb_fr.config;
+	} else {
+		/* Set from scratch */
+		acc->awb_fr.config = ipu3_css_awb_fr_defaults;
+	}
+
+	ipu3_css_grid_end_calc(&acc->awb_fr.config.grid_cfg);
+
+	if (acc->awb_fr.config.grid_cfg.width <= 0)
+		return -EINVAL;
+
+	acc->awb_fr.config.grid_cfg.height_per_slice =
+		IPU3_ABI_AWB_FR_MAX_CELLS_PER_SET /
+		acc->awb_fr.config.grid_cfg.width;
+
+	min_overlap = 10;
+
+	for (s = 0; s < stripes; s++)
+		acc->awb_fr.stripes[s] = acc->awb_fr.config;
+
+	if (acc->awb_fr.config.grid_cfg.x_start >=
+	    acc->stripe.down_scaled_stripes[1].offset + min_overlap) {
+		/* Enable only for rightmost stripe, disable left */
+		acc->awb_fr.stripes[0].grid_cfg.y_start &=
+		    ~IPU3_UAPI_GRID_Y_START_EN;
+	} else if (acc->awb_fr.config.grid_cfg.x_end <=
+		   acc->stripe.bds_out_stripes[0].width - min_overlap) {
+		/* Enable only for leftmost stripe, disable right */
+		acc->awb_fr.stripes[1].grid_cfg.y_start &=
+			~IPU3_UAPI_GRID_Y_START_EN;
+	} else {
+		/* Enable for both stripes */
+		u16 end; /* width for grid end */
+
+		acc->awb_fr.stripes[0].grid_cfg.width =
+			(acc->stripe.bds_out_stripes[0].width - min_overlap
+			- acc->awb_fr.config.grid_cfg.x_start + 1) >>
+			acc->awb_fr.config.grid_cfg.block_width_log2;
+		acc->awb_fr.stripes[1].grid_cfg.width =
+			acc->awb_fr.config.grid_cfg.width -
+			acc->awb_fr.stripes[0].grid_cfg.width;
+
+		b_w_log2 = acc->awb_fr.stripes[0].grid_cfg.block_width_log2;
+		end = ipu3_css_grid_end(acc->awb_fr.stripes[0].grid_cfg.x_start,
+					acc->awb_fr.stripes[0].grid_cfg.width,
+					b_w_log2);
+		acc->awb_fr.stripes[0].grid_cfg.x_end = end;
+
+		acc->awb_fr.stripes[1].grid_cfg.x_start =
+			(acc->awb_fr.stripes[0].grid_cfg.x_end + 1 -
+			acc->stripe.down_scaled_stripes[1].offset) &
+			IPU3_UAPI_GRID_START_MASK;
+		b_w_log2 = acc->awb_fr.stripes[1].grid_cfg.block_width_log2;
+		end = ipu3_css_grid_end(acc->awb_fr.stripes[1].grid_cfg.x_start,
+					acc->awb_fr.stripes[1].grid_cfg.width,
+					b_w_log2);
+		acc->awb_fr.stripes[1].grid_cfg.x_end = end;
+
+		/*
+		 * To reduce complexity of debubbling and loading
+		 * statistics fix grid_height_per_slice to 1 for both
+		 * stripes.
+		 */
+		for (s = 0; s < stripes; s++)
+			acc->awb_fr.stripes[s].grid_cfg.height_per_slice = 1;
+	}
+
+	if (ipu3_css_awb_fr_ops_calc(css, &acc->awb_fr))
+		return -EINVAL;
+
+	/* acc_param: ae_config */
+
+	if (use && use->acc_ae) {
+		/* Take values from user */
+		acc->ae.grid_cfg = acc_user->ae.grid_cfg;
+		acc->ae.ae_ccm = acc_user->ae.ae_ccm;
+		for (i = 0; i < IPU3_UAPI_AE_WEIGHTS; i++)
+			acc->ae.weights[i] = acc_user->ae.weights[i];
+	} else if (acc_old) {
+		/* Use old value */
+		acc->ae.grid_cfg = acc_old->ae.grid_cfg;
+		acc->ae.ae_ccm = acc_old->ae.ae_ccm;
+		for (i = 0; i < IPU3_UAPI_AE_WEIGHTS; i++)
+			acc->ae.weights[i] = acc_old->ae.weights[i];
+	} else {
+		/* Set from scratch */
+		static const struct ipu3_uapi_ae_weight_elem
+			weight_def = { 1, 1, 1, 1, 1, 1, 1, 1 };
+
+		acc->ae.grid_cfg = ipu3_css_ae_grid_defaults;
+		acc->ae.ae_ccm = ipu3_css_ae_ccm_defaults;
+		for (i = 0; i < IPU3_UAPI_AE_WEIGHTS; i++)
+			acc->ae.weights[i] = weight_def;
+	}
+
+	b_w_log2 = acc->ae.grid_cfg.block_width_log2;
+	acc->ae.grid_cfg.x_end = ipu3_css_grid_end(acc->ae.grid_cfg.x_start,
+						   acc->ae.grid_cfg.width,
+						   b_w_log2);
+	b_w_log2 = acc->ae.grid_cfg.block_height_log2;
+	acc->ae.grid_cfg.y_end = ipu3_css_grid_end(acc->ae.grid_cfg.y_start,
+						   acc->ae.grid_cfg.height,
+						   b_w_log2);
+
+	for (s = 0; s < stripes; s++)
+		acc->ae.stripes[s].grid = acc->ae.grid_cfg;
+
+	if (acc->ae.grid_cfg.x_start >=
+	    acc->stripe.down_scaled_stripes[1].offset) {
+		/* Enable only for rightmost stripe, disable left */
+		acc->ae.stripes[0].grid.ae_en = 0;
+	} else if (acc->ae.grid_cfg.x_end <=
+		   acc->stripe.bds_out_stripes[0].width) {
+		/* Enable only for leftmost stripe, disable right */
+		acc->ae.stripes[1].grid.ae_en = 0;
+	} else {
+		/* Enable for both stripes */
+		u8 b_w_log2;
+
+		acc->ae.stripes[0].grid.width =
+			(acc->stripe.bds_out_stripes[0].width -
+			acc->ae.grid_cfg.x_start + 1) >>
+			acc->ae.grid_cfg.block_width_log2;
+
+		acc->ae.stripes[1].grid.width =
+			acc->ae.grid_cfg.width - acc->ae.stripes[0].grid.width;
+
+		b_w_log2 = acc->ae.stripes[0].grid.block_width_log2;
+		acc->ae.stripes[0].grid.x_end = ipu3_css_grid_end(
+					acc->ae.stripes[0].grid.x_start,
+					acc->ae.stripes[0].grid.width,
+					b_w_log2);
+
+		acc->ae.stripes[1].grid.x_start =
+			(acc->ae.stripes[0].grid.x_end + 1 -
+			acc->stripe.down_scaled_stripes[1].offset) &
+			IPU3_UAPI_GRID_START_MASK;
+		b_w_log2 = acc->ae.stripes[1].grid.block_width_log2;
+		acc->ae.stripes[1].grid.x_end =
+			ipu3_css_grid_end(acc->ae.stripes[1].grid.x_start,
+					  acc->ae.stripes[1].grid.width,
+					  b_w_log2);
+	}
+
+	/* acc_param: af_config */
+
+	if (use && use->acc_af) {
+		/* Take values from user */
+		acc->af.config = acc_user->af.config;
+	} else if (acc_old) {
+		/* Use old value */
+		acc->af.config = acc_old->af.config;
+	} else {
+		/* Set from scratch */
+		acc->af.config = ipu3_css_af_defaults;
+	}
+
+	ipu3_css_grid_end_calc(&acc->af.config.grid_cfg);
+
+	if (acc->af.config.grid_cfg.width <= 0)
+		return -EINVAL;
+
+	acc->af.config.grid_cfg.height_per_slice =
+		IPU3_ABI_AF_MAX_CELLS_PER_SET / acc->af.config.grid_cfg.width;
+
+	min_overlap = 10;
+	acc->af.config.frame_size.width =
+		ALIGN(css->rect[IPU3_CSS_RECT_BDS].width, IMGU_ISP_VMEM_ALIGN);
+	acc->af.config.frame_size.height =
+		css->rect[IPU3_CSS_RECT_BDS].height;
+
+	if (acc->stripe.bds_out_stripes[0].width <= min_overlap)
+		return -EINVAL;
+
+	for (s = 0; s < stripes; s++) {
+		acc->af.stripes[s].grid_cfg = acc->af.config.grid_cfg;
+		acc->af.stripes[s].frame_size.height =
+				css->rect[IPU3_CSS_RECT_BDS].height;
+		acc->af.stripes[s].frame_size.width =
+			acc->stripe.bds_out_stripes[s].width;
+	}
+
+	if (acc->af.config.grid_cfg.x_start >=
+	    acc->stripe.down_scaled_stripes[1].offset + min_overlap) {
+		/* Enable only for rightmost stripe, disable left */
+		acc->af.stripes[0].grid_cfg.y_start &=
+			~IPU3_UAPI_GRID_Y_START_EN;
+	} else if (acc->af.config.grid_cfg.x_end <=
+		   acc->stripe.bds_out_stripes[0].width - min_overlap) {
+		/* Enable only for leftmost stripe, disable right */
+		acc->af.stripes[1].grid_cfg.y_start &=
+			~IPU3_UAPI_GRID_Y_START_EN;
+	} else {
+		/* Enable for both stripes */
+
+		acc->af.stripes[0].grid_cfg.width =
+			(acc->stripe.bds_out_stripes[0].width - min_overlap
+			- acc->af.config.grid_cfg.x_start + 1) >>
+			acc->af.config.grid_cfg.block_width_log2;
+		acc->af.stripes[1].grid_cfg.width =
+			acc->af.config.grid_cfg.width -
+			acc->af.stripes[0].grid_cfg.width;
+
+		b_w_log2 = acc->af.stripes[0].grid_cfg.block_width_log2;
+		acc->af.stripes[0].grid_cfg.x_end =
+			ipu3_css_grid_end(acc->af.stripes[0].grid_cfg.x_start,
+					  acc->af.stripes[0].grid_cfg.width,
+					  b_w_log2);
+
+		acc->af.stripes[1].grid_cfg.x_start =
+			(acc->af.stripes[0].grid_cfg.x_end + 1 -
+			acc->stripe.down_scaled_stripes[1].offset) &
+			IPU3_UAPI_GRID_START_MASK;
+
+		b_w_log2 = acc->af.stripes[1].grid_cfg.block_width_log2;
+		acc->af.stripes[1].grid_cfg.x_end =
+			ipu3_css_grid_end(acc->af.stripes[1].grid_cfg.x_start,
+					  acc->af.stripes[1].grid_cfg.width,
+					  b_w_log2);
+
+		/*
+		 * To reduce complexity of debubbling and loading statistics
+		 * fix grid_height_per_slice to 1 for both stripes
+		 */
+		for (s = 0; s < stripes; s++)
+			acc->af.stripes[s].grid_cfg.height_per_slice = 1;
+	}
+
+	if (ipu3_css_af_ops_calc(css, &acc->af))
+		return -EINVAL;
+
+	/* acc_param: awb_config */
+
+	if (use && use->acc_awb) {
+		/* Take values from user */
+		acc->awb.config = acc_user->awb.config;
+	} else if (acc_old) {
+		/* Use old value */
+		acc->awb.config = acc_old->awb.config;
+	} else {
+		/* Set from scratch */
+		acc->awb.config = ipu3_css_awb_defaults;
+	}
+
+	if (acc->awb.config.grid.width <= 0)
+		return -EINVAL;
+
+	acc->awb.config.grid.height_per_slice =
+		IPU3_ABI_AWB_MAX_CELLS_PER_SET / acc->awb.config.grid.width,
+	ipu3_css_grid_end_calc(&acc->awb.config.grid);
+
+	for (s = 0; s < stripes; s++)
+		acc->awb.stripes[s] = acc->awb.config;
+
+	if (acc->awb.config.grid.x_start >=
+	    acc->stripe.down_scaled_stripes[1].offset + min_overlap) {
+		/* Enable only for rightmost stripe, disable left */
+		acc->awb.stripes[0].rgbs_thr_b &= ~IPU3_UAPI_AWB_RGBS_THR_B_EN;
+	} else if (acc->awb.config.grid.x_end <=
+		   acc->stripe.bds_out_stripes[0].width - min_overlap) {
+		/* Enable only for leftmost stripe, disable right */
+		acc->awb.stripes[1].rgbs_thr_b &= ~IPU3_UAPI_AWB_RGBS_THR_B_EN;
+	} else {
+		/* Enable for both stripes */
+
+		acc->awb.stripes[0].grid.width =
+			(acc->stripe.bds_out_stripes[0].width -
+			acc->awb.config.grid.x_start + 1) >>
+			acc->awb.config.grid.block_width_log2;
+		acc->awb.stripes[1].grid.width = acc->awb.config.grid.width -
+				acc->awb.stripes[0].grid.width;
+
+		b_w_log2 = acc->awb.stripes[0].grid.block_width_log2;
+		acc->awb.stripes[0].grid.x_end =
+			ipu3_css_grid_end(acc->awb.stripes[0].grid.x_start,
+					  acc->awb.stripes[0].grid.width,
+					  b_w_log2);
+
+		acc->awb.stripes[1].grid.x_start =
+			(acc->awb.stripes[0].grid.x_end + 1 -
+			acc->stripe.down_scaled_stripes[1].offset) &
+			IPU3_UAPI_GRID_START_MASK;
+
+		b_w_log2 = acc->awb.stripes[1].grid.block_width_log2;
+		acc->awb.stripes[1].grid.x_end =
+			ipu3_css_grid_end(acc->awb.stripes[1].grid.x_start,
+					  acc->awb.stripes[1].grid.width,
+					  b_w_log2);
+
+		/*
+		 * To reduce complexity of debubbling and loading statistics
+		 * fix grid_height_per_slice to 1 for both stripes
+		 */
+		for (s = 0; s < stripes; s++)
+			acc->awb.stripes[s].grid.height_per_slice = 1;
+	}
+
+	if (ipu3_css_awb_ops_calc(css, &acc->awb))
+		return -EINVAL;
+
+	return 0;
+}
+
+/*
+ * Fill the indicated structure in `new_binary_params' from the possible
+ * sources based on `use_user' flag: if the flag is false, copy from
+ * `old_binary_params', or if the flag is true, copy from `user_setting'
+ * and return NULL (or error pointer on error).
+ * If the flag is false and `old_binary_params' is NULL, return pointer
+ * to the structure inside `new_binary_params'. In that case the caller
+ * should calculate and fill the structure from scratch.
+ */
+static void *ipu3_css_cfg_copy(struct ipu3_css *css, bool use_user,
+			       void *user_setting, void *old_binary_params,
+			       void *new_binary_params,
+			       enum imgu_abi_memories m,
+			       struct imgu_fw_isp_parameter *par,
+			       size_t par_size)
+{
+	const enum imgu_abi_param_class c = IMGU_ABI_PARAM_CLASS_PARAM;
+	void *new_setting, *old_setting;
+
+	new_setting = ipu3_css_fw_pipeline_params(css, c, m, par, par_size,
+						  new_binary_params);
+	if (!new_setting)
+		return ERR_PTR(-EPROTO);	/* Corrupted firmware */
+
+	if (use_user) {
+		/* Take new user parameters */
+		memcpy(new_setting, user_setting, par_size);
+	} else if (old_binary_params) {
+		/* Take previous value */
+		old_setting = ipu3_css_fw_pipeline_params(css, c, m, par,
+							  par_size,
+							  old_binary_params);
+		if (!old_setting)
+			return ERR_PTR(-EPROTO);
+		memcpy(new_setting, old_setting, par_size);
+	} else {
+		return new_setting;	/* Need to calculate */
+	}
+
+	return NULL;		/* Copied from other value */
+}
+
+/*
+ * Configure VMEM0 parameters (late binding parameters).
+ */
+int ipu3_css_cfg_vmem0(struct ipu3_css *css, struct ipu3_uapi_flags *use,
+		       void *vmem0, void *vmem0_old,
+		       struct ipu3_uapi_params *user)
+{
+	const struct imgu_fw_info *bi =
+		&css->fwp->binary_header[css->current_binary];
+	struct imgu_fw_param_memory_offsets *pofs = (void *)css->fwp +
+		bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_PARAM];
+	struct ipu3_uapi_isp_lin_vmem_params *lin_vmem;
+	struct ipu3_uapi_isp_tnr3_vmem_params *tnr_vmem;
+	struct ipu3_uapi_isp_xnr3_vmem_params *xnr_vmem;
+	const enum imgu_abi_param_class c = IMGU_ABI_PARAM_CLASS_PARAM;
+	const enum imgu_abi_memories m = IMGU_ABI_MEM_ISP_VMEM0;
+	int i;
+
+	/* Configure VMEM0 */
+
+	memset(vmem0, 0, bi->info.isp.sp.mem_initializers.params[c][m].size);
+
+	/* Configure Linearization VMEM0 parameters */
+
+	lin_vmem = ipu3_css_cfg_copy(css, use && use->lin_vmem_params,
+				     &user->lin_vmem_params, vmem0_old, vmem0,
+				     m, &pofs->vmem.lin, sizeof(*lin_vmem));
+	if (!IS_ERR_OR_NULL(lin_vmem)) {
+		/* Generate parameter from scratch */
+		for (i = 0; i < IPU3_UAPI_LIN_LUT_SIZE; i++) {
+			lin_vmem->lin_lutlow_gr[i] = 32 * i;
+			lin_vmem->lin_lutlow_r[i] = 32 * i;
+			lin_vmem->lin_lutlow_b[i] = 32 * i;
+			lin_vmem->lin_lutlow_gb[i] = 32 * i;
+
+			lin_vmem->lin_lutdif_gr[i] = 32;
+			lin_vmem->lin_lutdif_r[i] = 32;
+			lin_vmem->lin_lutdif_b[i] = 32;
+			lin_vmem->lin_lutdif_gb[i] = 32;
+		}
+	}
+
+	/* Configure TNR3 VMEM parameters */
+	if (css->pipe_id == IPU3_CSS_PIPE_ID_VIDEO) {
+		tnr_vmem = ipu3_css_cfg_copy(css, use && use->tnr3_vmem_params,
+					     &user->tnr3_vmem_params,
+					     vmem0_old, vmem0, m,
+					     &pofs->vmem.tnr3,
+					     sizeof(*tnr_vmem));
+		if (!IS_ERR_OR_NULL(tnr_vmem)) {
+			/* Generate parameter from scratch */
+			for (i = 0; i < IPU3_UAPI_ISP_TNR3_VMEM_LEN; i++)
+				tnr_vmem->sigma[i] = 256;
+		}
+	}
+	i = IPU3_UAPI_ISP_TNR3_VMEM_LEN;
+
+	/* Configure XNR3 VMEM parameters */
+
+	xnr_vmem = ipu3_css_cfg_copy(css, use && use->xnr3_vmem_params,
+				     &user->xnr3_vmem_params, vmem0_old, vmem0,
+				     m, &pofs->vmem.xnr3, sizeof(*xnr_vmem));
+	if (!IS_ERR_OR_NULL(xnr_vmem)) {
+		xnr_vmem->x[i] = ipu3_css_xnr3_vmem_defaults.x
+			[i % IMGU_XNR3_VMEM_LUT_LEN];
+		xnr_vmem->a[i] = ipu3_css_xnr3_vmem_defaults.a
+			[i % IMGU_XNR3_VMEM_LUT_LEN];
+		xnr_vmem->b[i] = ipu3_css_xnr3_vmem_defaults.b
+			[i % IMGU_XNR3_VMEM_LUT_LEN];
+		xnr_vmem->c[i] = ipu3_css_xnr3_vmem_defaults.c
+			[i % IMGU_XNR3_VMEM_LUT_LEN];
+	}
+
+	return IS_ERR(lin_vmem) || IS_ERR(tnr_vmem) || IS_ERR(xnr_vmem) ?
+	    -EPROTO : 0;
+}
+
+/*
+ * Configure DMEM0 parameters (late binding parameters).
+ */
+int ipu3_css_cfg_dmem0(struct ipu3_css *css, struct ipu3_uapi_flags *use,
+		       void *dmem0, void *dmem0_old,
+		       struct ipu3_uapi_params *user)
+{
+	const struct imgu_fw_info *bi =
+		&css->fwp->binary_header[css->current_binary];
+	struct imgu_fw_param_memory_offsets *pofs = (void *)css->fwp +
+		bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_PARAM];
+
+	struct ipu3_uapi_isp_tnr3_params *tnr_dmem = NULL;
+	struct ipu3_uapi_isp_xnr3_params *xnr_dmem;
+
+	const enum imgu_abi_param_class c = IMGU_ABI_PARAM_CLASS_PARAM;
+	const enum imgu_abi_memories m = IMGU_ABI_MEM_ISP_DMEM0;
+
+	/* Configure DMEM0 */
+
+	memset(dmem0, 0, bi->info.isp.sp.mem_initializers.params[c][m].size);
+
+	/* Configure TNR3 DMEM0 parameters */
+	if (css->pipe_id == IPU3_CSS_PIPE_ID_VIDEO) {
+		tnr_dmem = ipu3_css_cfg_copy(css, use && use->tnr3_dmem_params,
+					     &user->tnr3_dmem_params, dmem0_old,
+					     dmem0, m, &pofs->dmem.tnr3,
+					     sizeof(*tnr_dmem));
+		if (!IS_ERR_OR_NULL(tnr_dmem)) {
+			/* Generate parameter from scratch */
+			tnr_dmem->knee_y1 = 768;
+			tnr_dmem->knee_y2 = 1280;
+		}
+	}
+
+	/* Configure XNR3 DMEM0 parameters */
+
+	xnr_dmem = ipu3_css_cfg_copy(css, use && use->xnr3_dmem_params,
+				     &user->xnr3_dmem_params, dmem0_old, dmem0,
+				     m, &pofs->dmem.xnr3, sizeof(*xnr_dmem));
+	if (!IS_ERR_OR_NULL(xnr_dmem)) {
+		/* Generate parameter from scratch */
+		xnr_dmem->alpha.y0 = 2047;
+		xnr_dmem->alpha.u0 = 2047;
+		xnr_dmem->alpha.v0 = 2047;
+	}
+
+	return IS_ERR(tnr_dmem) || IS_ERR(xnr_dmem) ? -EPROTO : 0;
+}
+
+/* Generate unity morphing table without morphing effect */
+void ipu3_css_cfg_gdc_table(struct ipu3_uapi_gdc_warp_param *gdc,
+			    int frame_in_x, int frame_in_y,
+			    int frame_out_x, int frame_out_y)
+{
+	static const unsigned int S = IPU3_UAPI_GDC_FRAC_BITS;
+	static const unsigned int XMEM_ALIGN = 4;
+	const unsigned int XMEM_ALIGN_MASK = ~(XMEM_ALIGN - 1);
+	static const unsigned int BCI_ENV = 4;
+	static const unsigned int BYP = 2;	/* Bytes per pixel */
+	const unsigned int OFFSET_X = 2 * IMGU_DVS_BLOCK_W + 1;
+	const unsigned int OFFSET_Y = IMGU_DVS_BLOCK_H + 1;
+
+	struct ipu3_uapi_gdc_warp_param gdc_luma, gdc_chroma;
+
+	unsigned int blocks_x = ALIGN(DIV_ROUND_UP(frame_out_x,
+						   IMGU_DVS_BLOCK_W), 2);
+	unsigned int blocks_y = DIV_ROUND_UP(frame_out_y, IMGU_DVS_BLOCK_H);
+	unsigned int y0, x0, x1, x, y;
+
+	/* Global luma settings */
+	gdc_luma.origin_x = 0;
+	gdc_luma.origin_y = 0;
+	gdc_luma.p0_x = (OFFSET_X - (OFFSET_X & XMEM_ALIGN_MASK)) << S;
+	gdc_luma.p0_y = 0;
+	gdc_luma.p1_x = gdc_luma.p0_x + (IMGU_DVS_BLOCK_W << S);
+	gdc_luma.p1_y = gdc_luma.p0_y;
+	gdc_luma.p2_x = gdc_luma.p0_x;
+	gdc_luma.p2_y = gdc_luma.p0_y + (IMGU_DVS_BLOCK_H << S);
+	gdc_luma.p3_x = gdc_luma.p1_x;
+	gdc_luma.p3_y = gdc_luma.p2_y;
+
+	gdc_luma.in_block_width = IMGU_DVS_BLOCK_W +
+				  (OFFSET_X - (OFFSET_X & XMEM_ALIGN_MASK)) +
+				  BCI_ENV;
+	gdc_luma.in_block_width_a = DIV_ROUND_UP(gdc_luma.in_block_width,
+						 IPU3_UAPI_ISP_VEC_ELEMS);
+	gdc_luma.in_block_width_b = DIV_ROUND_UP(gdc_luma.in_block_width,
+						 IMGU_ABI_ISP_DDR_WORD_BYTES /
+						 BYP);
+	gdc_luma.in_block_height = IMGU_DVS_BLOCK_H + BCI_ENV;
+	gdc_luma.padding = 0;
+
+	/* Global chroma settings */
+	gdc_chroma.origin_x = 0;
+	gdc_chroma.origin_y = 0;
+	gdc_chroma.p0_x = 0;
+	gdc_chroma.p0_y = 0;
+	gdc_chroma.p1_x = gdc_chroma.p0_x + (IMGU_DVS_BLOCK_W << S);
+	gdc_chroma.p1_y = gdc_chroma.p0_y;
+	gdc_chroma.p2_x = gdc_chroma.p0_x;
+	gdc_chroma.p2_y = gdc_chroma.p0_y + (IMGU_DVS_BLOCK_H / 2 << S);
+	gdc_chroma.p3_x = gdc_chroma.p1_x;
+	gdc_chroma.p3_y = gdc_chroma.p2_y;
+
+	gdc_chroma.in_block_width = IMGU_DVS_BLOCK_W + BCI_ENV;
+	gdc_chroma.in_block_width_a = DIV_ROUND_UP(gdc_chroma.in_block_width,
+						   IPU3_UAPI_ISP_VEC_ELEMS);
+	gdc_chroma.in_block_width_b = DIV_ROUND_UP(gdc_chroma.in_block_width,
+						   IMGU_ABI_ISP_DDR_WORD_BYTES /
+						   BYP);
+	gdc_chroma.in_block_height = IMGU_DVS_BLOCK_H / 2 + BCI_ENV;
+	gdc_chroma.padding = 0;
+
+	/* Calculate block offsets for luma and chroma */
+	for (y0 = 0; y0 < blocks_y; y0++) {
+		for (x0 = 0; x0 < blocks_x / 2; x0++) {
+			for (x1 = 0; x1 < 2; x1++) {
+				/* Luma blocks */
+				x = (x0 * 2 + x1) * IMGU_DVS_BLOCK_W + OFFSET_X;
+				x &= XMEM_ALIGN_MASK;
+				y = y0 * IMGU_DVS_BLOCK_H + OFFSET_Y;
+				*gdc = gdc_luma;
+				gdc->in_addr_offset =
+					(y * frame_in_x + x) * BYP;
+				gdc++;
+			}
+
+			/* Chroma block */
+			x = x0 * IMGU_DVS_BLOCK_W + OFFSET_X / 2;
+			x &= XMEM_ALIGN_MASK;
+			y = y0 * (IMGU_DVS_BLOCK_H / 2) + OFFSET_Y / 2;
+			*gdc = gdc_chroma;
+			gdc->in_addr_offset = (y * frame_in_x + x) * BYP;
+			gdc++;
+		}
+	}
+}
diff --git a/drivers/media/pci/intel/ipu3/ipu3-css-params.h b/drivers/media/pci/intel/ipu3/ipu3-css-params.h
new file mode 100644
index 000000000000..7cbb7b79c24f
--- /dev/null
+++ b/drivers/media/pci/intel/ipu3/ipu3-css-params.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2017 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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.
+ *
+ */
+
+struct ipu3_css_frame_params {
+	/* Output pins */
+	unsigned int enable;
+	unsigned int format;
+	unsigned int flip;
+	unsigned int mirror;
+	unsigned int tiling;
+	unsigned int reduce_range;
+	unsigned int width;
+	unsigned int height;
+	unsigned int stride;
+	unsigned int scaled;
+	unsigned int crop_left;
+	unsigned int crop_top;
+};
+
+struct ipu3_css_stripe_params {
+	unsigned int processing_mode;
+	unsigned int phase_step;
+	unsigned int exp_shift;
+	unsigned int phase_init_left_y;
+	unsigned int phase_init_left_uv;
+	unsigned int phase_init_top_y;
+	unsigned int phase_init_top_uv;
+	unsigned int pad_left_y;
+	unsigned int pad_left_uv;
+	unsigned int pad_right_y;
+	unsigned int pad_right_uv;
+	unsigned int pad_top_y;
+	unsigned int pad_top_uv;
+	unsigned int pad_bottom_y;
+	unsigned int pad_bottom_uv;
+	unsigned int crop_left_y;
+	unsigned int crop_top_y;
+	unsigned int crop_left_uv;
+	unsigned int crop_top_uv;
+	unsigned int start_column_y;
+	unsigned int start_column_uv;
+	unsigned int chunk_width;
+	unsigned int chunk_height;
+	unsigned int block_width;
+	unsigned int block_height;
+	unsigned int input_width;
+	unsigned int input_height;
+	int output_width[IMGU_ABI_OSYS_PINS];
+	int output_height[IMGU_ABI_OSYS_PINS];
+	int output_offset[IMGU_ABI_OSYS_PINS];
+};
+
+struct ipu3_css_reso {
+	unsigned int input_width;
+	unsigned int input_height;
+	enum imgu_abi_frame_format input_format;
+	unsigned int pin_width[IMGU_ABI_OSYS_PINS];
+	unsigned int pin_height[IMGU_ABI_OSYS_PINS];
+	unsigned int pin_stride[IMGU_ABI_OSYS_PINS];
+	enum imgu_abi_frame_format pin_format[IMGU_ABI_OSYS_PINS];
+	int chunk_width;
+	int chunk_height;
+	int block_height;
+	int block_width;
+};
+
+struct ipu3_css_scaler_info {
+	unsigned int phase_step;	/* Same for luma/chroma */
+	int exp_shift;
+
+	unsigned int phase_init;	/* luma/chroma dependent */
+	int pad_left;
+	int pad_right;
+	int crop_left;
+	int crop_top;
+};
+
+int ipu3_css_cfg_acc(struct ipu3_css *css, struct ipu3_uapi_flags *use,
+			struct ipu3_uapi_acc_param *acc,
+			struct ipu3_uapi_acc_param *acc_old,
+			struct ipu3_uapi_acc_param *acc_user);
+
+int ipu3_css_cfg_vmem0(struct ipu3_css *css, struct ipu3_uapi_flags *use,
+			void *vmem0, void *vmem0_old,
+			struct ipu3_uapi_params *user);
+
+
+int ipu3_css_cfg_dmem0(struct ipu3_css *css, struct ipu3_uapi_flags *use,
+			void *dmem0, void *dmem0_old,
+			struct ipu3_uapi_params *user);
+
+void ipu3_css_cfg_gdc_table(struct ipu3_uapi_gdc_warp_param *gdc,
+				int frame_in_x, int frame_in_y,
+				int frame_out_x, int frame_out_y);
diff --git a/drivers/media/pci/intel/ipu3/ipu3-css.h b/drivers/media/pci/intel/ipu3/ipu3-css.h
index 79dbf0625740..92ae102cf480 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-css.h
+++ b/drivers/media/pci/intel/ipu3/ipu3-css.h
@@ -14,6 +14,8 @@
 #ifndef __IPU3_CSS_H
 #define __IPU3_CSS_H
 
+#include <linux/videodev2.h>
+#include <linux/types.h>
 #include "ipu3-abi.h"
 #include "ipu3-css-pool.h"
 
@@ -21,6 +23,25 @@
 #define IMGU_NUM_SP			2
 #define IMGU_MAX_PIPELINE_NUM		20
 
+/* For DVS etc., format FRAME_FMT_YUV420_16 */
+#define IPU3_CSS_AUX_FRAME_REF		0
+/* For temporal noise reduction DVS etc., format FRAME_FMT_YUV_LINE */
+#define IPU3_CSS_AUX_FRAME_TNR		1
+#define IPU3_CSS_AUX_FRAME_TYPES	2	/* REF and TNR */
+#define IPU3_CSS_AUX_FRAMES		2	/* 2 for REF and 2 for TNR */
+
+#define IPU3_CSS_QUEUE_IN		0
+#define IPU3_CSS_QUEUE_PARAMS		1
+#define IPU3_CSS_QUEUE_OUT		2
+#define IPU3_CSS_QUEUE_VF		3
+#define IPU3_CSS_QUEUE_STAT_3A		4
+#define IPU3_CSS_QUEUE_STAT_DVS		5
+#define IPU3_CSS_QUEUE_STAT_LACE	6
+#define IPU3_CSS_QUEUES			7
+
+#define IA_CSS_BINARY_MODE_PRIMARY	2
+#define IA_CSS_BINARY_MODE_VIDEO	3
+
 /*
  * The pipe id type, distinguishes the kind of pipes that
  * can be run in parallel.
@@ -35,11 +56,41 @@ enum ipu3_css_pipe_id {
 	IPU3_CSS_PIPE_ID_NUM
 };
 
+struct ipu3_css_format {
+	u32 pixelformat;
+	enum v4l2_colorspace colorspace;
+	enum imgu_abi_frame_format frame_format;
+	enum imgu_abi_bayer_order bayer_order;
+	enum imgu_abi_osys_format osys_format;
+	enum imgu_abi_osys_tiling osys_tiling;
+	u32 bytesperpixel_num;	/* Bytes per pixel in first plane * 50 */
+	u8 bit_depth;		/* Effective bits per pixel */
+	u8 chroma_decim;	/* Chroma plane decimation, 0=no chroma plane */
+	u8 width_align;		/* Alignment requirement for width_pad */
+	u8 flags;
+#define IPU3_CSS_QUEUE_TO_FLAGS(q)	(1 << (q))
+#define IPU3_CSS_FORMAT_FL_IN		\
+			IPU3_CSS_QUEUE_TO_FLAGS(IPU3_CSS_QUEUE_IN)
+#define IPU3_CSS_FORMAT_FL_OUT		\
+			IPU3_CSS_QUEUE_TO_FLAGS(IPU3_CSS_QUEUE_OUT)
+#define IPU3_CSS_FORMAT_FL_VF		\
+			IPU3_CSS_QUEUE_TO_FLAGS(IPU3_CSS_QUEUE_VF)
+};
+
+struct ipu3_css_queue {
+	union {
+		struct v4l2_pix_format_mplane mpix;
+		struct v4l2_meta_format	meta;
+	} fmt;
+	const struct ipu3_css_format *css_fmt;
+	unsigned int width_pad;	/* bytesperline / byp */
+	struct list_head bufs;
+};
+
 /* IPU3 Camera Sub System structure */
 struct ipu3_css {
 	struct device *dev;
 	void __iomem *base;
-	struct device *dma_dev;
 	const struct firmware *fw;
 	struct imgu_fw_header *fwp;
 	int iomem_length;
@@ -49,6 +100,32 @@ struct ipu3_css {
 	bool streaming;		/* true when streaming is enabled */
 	long frame;	/* Latest frame not yet processed */
 	enum ipu3_css_pipe_id pipe_id;  /* CSS pipe ID. */
+
+	/* Data structures shared with IMGU and driver, always allocated */
+	struct ipu3_css_map xmem_sp_stage_ptrs[IPU3_CSS_PIPE_ID_NUM]
+					    [IMGU_ABI_MAX_STAGES];
+	struct ipu3_css_map xmem_isp_stage_ptrs[IPU3_CSS_PIPE_ID_NUM]
+					    [IMGU_ABI_MAX_STAGES];
+	struct ipu3_css_map sp_ddr_ptrs;
+	struct ipu3_css_map xmem_sp_group_ptrs;
+	struct ipu3_css_map dvs_meta_data[IMGU_MAX_PIPELINE_NUM]
+					[IPU3_UAPI_MAX_STRIPES];
+
+	/* Data structures shared with IMGU and driver, binary specific */
+	/* PARAM_CLASS_CONFIG and PARAM_CLASS_STATE parameters */
+	struct ipu3_css_map binary_params_cs[IMGU_ABI_PARAM_CLASS_NUM - 1]
+					    [IMGU_ABI_NUM_MEMORIES];
+
+	struct {
+		struct ipu3_css_map mem[IPU3_CSS_AUX_FRAMES];
+		unsigned int width;
+		unsigned int height;
+		unsigned int bytesperline;
+		unsigned int bytesperpixel;
+	} aux_frames[IPU3_CSS_AUX_FRAME_TYPES];
+
+	struct ipu3_css_queue queue[IPU3_CSS_QUEUES];
+	struct v4l2_rect rect[IPU3_CSS_RECTS];
 };
 
 #endif
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v4 09/12] intel-ipu3: css hardware setup
  2017-10-18  3:54 [PATCH v4 04/12] intel-ipu3: Add user space ABI definitions Yong Zhi
                   ` (2 preceding siblings ...)
  2017-10-18  3:54 ` [PATCH v4 08/12] intel-ipu3: params: compute and program ccs Yong Zhi
@ 2017-10-18  3:54 ` Yong Zhi
  2017-10-18  3:54 ` [PATCH v4 10/12] intel-ipu3: css pipeline Yong Zhi
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 19+ messages in thread
From: Yong Zhi @ 2017-10-18  3:54 UTC (permalink / raw)
  To: linux-media, sakari.ailus
  Cc: jian.xu.zheng, rajmohan.mani, tuukka.toivonen, jerry.w.hu,
	Yong Zhi, Tomasz Figa

The driver code that handles hw programming for
clock, irq and power etc.

Signed-off-by: Yong Zhi <yong.zhi@intel.com>
Signed-off-by: Tomasz Figa <tfiga@chromium.org>
---
 drivers/media/pci/intel/ipu3/ipu3-css.c | 519 ++++++++++++++++++++++++++++++++
 drivers/media/pci/intel/ipu3/ipu3-css.h |   5 +
 2 files changed, 524 insertions(+)
 create mode 100644 drivers/media/pci/intel/ipu3/ipu3-css.c

diff --git a/drivers/media/pci/intel/ipu3/ipu3-css.c b/drivers/media/pci/intel/ipu3/ipu3-css.c
new file mode 100644
index 000000000000..6e615bf9378a
--- /dev/null
+++ b/drivers/media/pci/intel/ipu3/ipu3-css.c
@@ -0,0 +1,519 @@
+/*
+ * Copyright (c) 2017 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/iopoll.h>
+#include "ipu3-css.h"
+#include "ipu3-css-fw.h"
+#include "ipu3-tables.h"
+
+/* IRQ configuration */
+#define IMGU_IRQCTRL_IRQ_MASK	(IMGU_IRQCTRL_IRQ_SP1 | \
+				 IMGU_IRQCTRL_IRQ_SP2 | \
+				 IMGU_IRQCTRL_IRQ_SW_PIN(0) | \
+				 IMGU_IRQCTRL_IRQ_SW_PIN(1))
+
+/******************* css hw *******************/
+
+/* in the style of writesl() defined in include/asm-generic/io.h */
+static inline void writes(const void *mem, ssize_t count, void __iomem *addr)
+{
+	if (count) {
+		const u32 *buf = mem;
+
+		do {
+			writel(*buf++, addr);
+			addr += 4;
+		} while (count--);
+	}
+}
+
+/* Wait until register `reg', masked with `mask', becomes `cmp' */
+static int ipu3_hw_wait(void __iomem *base, int reg, u32 mask, u32 cmp)
+{
+	u32 val;
+
+	return readl_poll_timeout(base + reg, val, (val & mask) == cmp,
+				  1000, 100 * 1000);
+}
+
+/* Initialize the IPU3 CSS hardware and associated h/w blocks */
+
+int ipu3_css_set_powerup(struct device *dev, void __iomem *base)
+{
+	static const unsigned int freq = 450;
+	u32 pm_ctrl, state, val;
+
+	dev_dbg(dev, "power up.\n");
+	/* Clear the CSS busy signal */
+	readl(base + IMGU_REG_GP_BUSY);
+	writel(0, base + IMGU_REG_GP_BUSY);
+
+	/* Wait for idle signal */
+	if (ipu3_hw_wait(base, IMGU_REG_STATE, IMGU_STATE_IDLE_STS,
+			 IMGU_STATE_IDLE_STS)) {
+		dev_err(dev, "failed to set CSS idle\n");
+		goto fail;
+	}
+
+	/* Reset the css */
+	writel(readl(base + IMGU_REG_PM_CTRL) | IMGU_PM_CTRL_FORCE_RESET,
+	       base + IMGU_REG_PM_CTRL);
+
+	usleep_range(200, 300);
+
+	/** Prepare CSS */
+
+	pm_ctrl = readl(base + IMGU_REG_PM_CTRL);
+	state = readl(base + IMGU_REG_STATE);
+
+	dev_dbg(dev, "CSS pm_ctrl 0x%x state 0x%x (power %s)\n",
+		pm_ctrl, state, state & IMGU_STATE_POWER_DOWN ? "down" : "up");
+
+	/* Power up CSS using wrapper */
+	if (state & IMGU_STATE_POWER_DOWN) {
+		writel(IMGU_PM_CTRL_RACE_TO_HALT | IMGU_PM_CTRL_START,
+		       base + IMGU_REG_PM_CTRL);
+		if (ipu3_hw_wait(base, IMGU_REG_PM_CTRL,
+				 IMGU_PM_CTRL_START, 0)) {
+			dev_err(dev, "failed to power up CSS\n");
+			goto fail;
+		}
+		usleep_range(2000, 3000);
+	} else {
+		writel(IMGU_PM_CTRL_RACE_TO_HALT, base + IMGU_REG_PM_CTRL);
+	}
+
+	/* Set the busy bit */
+	writel(readl(base + IMGU_REG_GP_BUSY) | 1, base + IMGU_REG_GP_BUSY);
+
+	/* Set CSS clock frequency */
+	pm_ctrl = readl(base + IMGU_REG_PM_CTRL);
+	val = pm_ctrl & ~(IMGU_PM_CTRL_CSS_PWRDN | IMGU_PM_CTRL_RST_AT_EOF);
+	writel(val, base + IMGU_REG_PM_CTRL);
+	writel(0, base + IMGU_REG_GP_BUSY);
+	if (ipu3_hw_wait(base, IMGU_REG_STATE,
+			 IMGU_STATE_PWRDNM_FSM_MASK, 0)) {
+		dev_err(dev, "failed to pwrdn CSS\n");
+		goto fail;
+	}
+	val = (freq / IMGU_SYSTEM_REQ_FREQ_DIVIDER) & IMGU_SYSTEM_REQ_FREQ_MASK;
+	writel(val, base + IMGU_REG_SYSTEM_REQ);
+	writel(1, base + IMGU_REG_GP_BUSY);
+	writel(readl(base + IMGU_REG_PM_CTRL) | IMGU_PM_CTRL_FORCE_HALT,
+	       base + IMGU_REG_PM_CTRL);
+	if (ipu3_hw_wait(base, IMGU_REG_STATE, IMGU_STATE_HALT_STS,
+			 IMGU_STATE_HALT_STS)) {
+		dev_err(dev, "failed to halt CSS\n");
+		goto fail;
+	}
+
+	writel(readl(base + IMGU_REG_PM_CTRL) | IMGU_PM_CTRL_START,
+	       base + IMGU_REG_PM_CTRL);
+	if (ipu3_hw_wait(base, IMGU_REG_PM_CTRL, IMGU_PM_CTRL_START, 0)) {
+		dev_err(dev, "failed to start CSS\n");
+		goto fail;
+	}
+	writel(readl(base + IMGU_REG_PM_CTRL) | IMGU_PM_CTRL_FORCE_UNHALT,
+	       base + IMGU_REG_PM_CTRL);
+
+	val = readl(base + IMGU_REG_PM_CTRL);	/* get pm_ctrl */
+	val &= ~(IMGU_PM_CTRL_CSS_PWRDN | IMGU_PM_CTRL_RST_AT_EOF);
+	val |= pm_ctrl & (IMGU_PM_CTRL_CSS_PWRDN | IMGU_PM_CTRL_RST_AT_EOF);
+	writel(val, base + IMGU_REG_PM_CTRL);
+
+	return 0;
+
+fail:
+	ipu3_css_set_powerdown(dev, base);
+	return -EIO;
+}
+
+int ipu3_css_set_powerdown(struct device *dev, void __iomem *base)
+{
+	dev_dbg(dev, "power down.\n");
+
+	/* wait for cio idle signal */
+	if (ipu3_hw_wait(base, IMGU_REG_CIO_GATE_BURST_STATE,
+			 IMGU_CIO_GATE_BURST_MASK, 0))
+		dev_warn(dev, "wait cio gate idle timeout");
+
+	/* wait for css idle signal */
+	if (ipu3_hw_wait(base, IMGU_REG_STATE, IMGU_STATE_IDLE_STS,
+			 IMGU_STATE_IDLE_STS))
+		dev_warn(dev, "wait css idle timeout\n");
+
+	/* do halt-halted handshake with css */
+	writel(1, base + IMGU_REG_GP_HALT);
+	if (ipu3_hw_wait(base, IMGU_REG_STATE, IMGU_STATE_HALT_STS,
+			 IMGU_STATE_HALT_STS))
+		dev_warn(dev, "failed to halt css");
+
+	/* de-assert the busy bit */
+	writel(0, base + IMGU_REG_GP_BUSY);
+
+	return 0;
+}
+
+static int ipu3_css_hw_init(struct ipu3_css *css)
+{
+	/* For checking that streaming monitor statuses are valid */
+	static const struct {
+		u32 reg;
+		u32 mask;
+		const char *name;
+	} stream_monitors[] = {
+		{
+			IMGU_REG_GP_SP1_STRMON_STAT,
+			IMGU_GP_STRMON_STAT_ISP_PORT_SP12ISP,
+			"ISP0 to SP0"
+		}, {
+			IMGU_REG_GP_ISP_STRMON_STAT,
+			IMGU_GP_STRMON_STAT_SP1_PORT_ISP2SP1,
+			"SP0 to ISP0"
+		}, {
+			IMGU_REG_GP_MOD_STRMON_STAT,
+			IMGU_GP_STRMON_STAT_MOD_PORT_ISP2DMA,
+			"ISP0 to DMA0"
+		}, {
+			IMGU_REG_GP_ISP_STRMON_STAT,
+			IMGU_GP_STRMON_STAT_ISP_PORT_DMA2ISP,
+			"DMA0 to ISP0"
+		}, {
+			IMGU_REG_GP_MOD_STRMON_STAT,
+			IMGU_GP_STRMON_STAT_MOD_PORT_CELLS2GDC,
+			"ISP0 to GDC0"
+		}, {
+			IMGU_REG_GP_MOD_STRMON_STAT,
+			IMGU_GP_STRMON_STAT_MOD_PORT_GDC2CELLS,
+			"GDC0 to ISP0"
+		}, {
+			IMGU_REG_GP_MOD_STRMON_STAT,
+			IMGU_GP_STRMON_STAT_MOD_PORT_SP12DMA,
+			"SP0 to DMA0"
+		}, {
+			IMGU_REG_GP_SP1_STRMON_STAT,
+			IMGU_GP_STRMON_STAT_SP1_PORT_DMA2SP1,
+			"DMA0 to SP0"
+		}, {
+			IMGU_REG_GP_MOD_STRMON_STAT,
+			IMGU_GP_STRMON_STAT_MOD_PORT_CELLS2GDC,
+			"SP0 to GDC0"
+		}, {
+			IMGU_REG_GP_MOD_STRMON_STAT,
+			IMGU_GP_STRMON_STAT_MOD_PORT_GDC2CELLS,
+			"GDC0 to SP0"
+		},
+	};
+
+	struct device *dev = css->dev;
+	void __iomem *const base = css->base;
+	u32 val, i;
+
+	/* Set up interrupts */
+
+	/*
+	 * Enable IRQ on the SP which signals that SP goes to idle
+	 * (aka ready state) and set trigger to pulse
+	 */
+	val = readl(base + IMGU_REG_SP_CTRL(0)) | IMGU_CTRL_IRQ_READY;
+	writel(val, base + IMGU_REG_SP_CTRL(0));
+	writel(val | IMGU_CTRL_IRQ_CLEAR, base + IMGU_REG_SP_CTRL(0));
+
+	/* Enable IRQs from the IMGU wrapper */
+	writel(IMGU_REG_INT_CSS_IRQ, base + IMGU_REG_INT_ENABLE);
+	/* Clear */
+	writel(IMGU_REG_INT_CSS_IRQ, base + IMGU_REG_INT_STATUS);
+
+	/* Enable IRQs from main IRQ controller */
+	writel(~0, base + IMGU_REG_IRQCTRL_EDGE_NOT_PULSE(IMGU_IRQCTRL_MAIN));
+	writel(0, base + IMGU_REG_IRQCTRL_MASK(IMGU_IRQCTRL_MAIN));
+	writel(IMGU_IRQCTRL_IRQ_MASK,
+	       base + IMGU_REG_IRQCTRL_EDGE(IMGU_IRQCTRL_MAIN));
+	writel(IMGU_IRQCTRL_IRQ_MASK,
+	       base + IMGU_REG_IRQCTRL_ENABLE(IMGU_IRQCTRL_MAIN));
+	writel(IMGU_IRQCTRL_IRQ_MASK,
+	       base + IMGU_REG_IRQCTRL_CLEAR(IMGU_IRQCTRL_MAIN));
+	writel(IMGU_IRQCTRL_IRQ_MASK,
+	       base + IMGU_REG_IRQCTRL_MASK(IMGU_IRQCTRL_MAIN));
+	/* Wait for write complete */
+	readl(base + IMGU_REG_IRQCTRL_ENABLE(IMGU_IRQCTRL_MAIN));
+
+	/* Enable IRQs from SP0 and SP1 controllers */
+	for (i = IMGU_IRQCTRL_SP0; i <= IMGU_IRQCTRL_SP1; i++) {
+		writel(~0, base + IMGU_REG_IRQCTRL_EDGE_NOT_PULSE(i));
+		writel(0, base + IMGU_REG_IRQCTRL_MASK(i));
+		writel(IMGU_IRQCTRL_IRQ_MASK, base + IMGU_REG_IRQCTRL_EDGE(i));
+		writel(IMGU_IRQCTRL_IRQ_MASK,
+		       base + IMGU_REG_IRQCTRL_ENABLE(i));
+		writel(IMGU_IRQCTRL_IRQ_MASK, base + IMGU_REG_IRQCTRL_CLEAR(i));
+		writel(IMGU_IRQCTRL_IRQ_MASK, base + IMGU_REG_IRQCTRL_MASK(i));
+		/* Wait for write complete */
+		readl(base + IMGU_REG_IRQCTRL_ENABLE(i));
+	}
+
+	/* Set instruction cache address and inv bit for ISP, SP, and SP1 */
+	for (i = 0; i < IMGU_NUM_SP; i++) {
+		struct imgu_fw_info *bi =
+			&css->fwp->binary_header[css->fw_sp[i]];
+
+		writel(css->binary[css->fw_sp[i]].daddr,
+		       base + IMGU_REG_SP_ICACHE_ADDR(bi->type));
+		writel(readl(base + IMGU_REG_SP_CTRL(bi->type)) |
+		       IMGU_CTRL_ICACHE_INV,
+		       base + IMGU_REG_SP_CTRL(bi->type));
+	}
+	writel(css->binary[css->fw_bl].daddr, base + IMGU_REG_ISP_ICACHE_ADDR);
+	writel(readl(base + IMGU_REG_ISP_CTRL) | IMGU_CTRL_ICACHE_INV,
+	       base + IMGU_REG_ISP_CTRL);
+
+	/* Check that IMGU hardware is ready */
+
+	if (!(readl(base + IMGU_REG_SP_CTRL(0)) & IMGU_CTRL_IDLE)) {
+		dev_err(dev, "SP is not idle\n");
+		return -EIO;
+	}
+	if (!(readl(base + IMGU_REG_ISP_CTRL) & IMGU_CTRL_IDLE)) {
+		dev_err(dev, "ISP is not idle\n");
+		return -EIO;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(stream_monitors); i++) {
+		val = readl(base + stream_monitors[i].reg);
+		if (val & stream_monitors[i].mask) {
+			dev_err(dev, "error: Stream monitor %s is valid\n",
+				stream_monitors[i].name);
+			return -EIO;
+		}
+	}
+
+	/* Initialize GDC with default values */
+
+	for (i = 0; i < ARRAY_SIZE(ipu3_css_gdc_lut[0]); i++) {
+		u32 val0 = ipu3_css_gdc_lut[0][i] & IMGU_GDC_LUT_MASK;
+		u32 val1 = ipu3_css_gdc_lut[1][i] & IMGU_GDC_LUT_MASK;
+		u32 val2 = ipu3_css_gdc_lut[2][i] & IMGU_GDC_LUT_MASK;
+		u32 val3 = ipu3_css_gdc_lut[3][i] & IMGU_GDC_LUT_MASK;
+
+		writel(val0 | (val1 << 16),
+		       base + IMGU_REG_GDC_LUT_BASE + i * 8);
+		writel(val2 | (val3 << 16),
+		       base + IMGU_REG_GDC_LUT_BASE + i * 8 + 4);
+	};
+
+	return 0;
+}
+
+/* Boot the given IPU3 CSS SP */
+static int ipu3_css_hw_start_sp(struct ipu3_css *css, int sp)
+{
+	void __iomem *const base = css->base;
+	struct imgu_fw_info *bi = &css->fwp->binary_header[css->fw_sp[sp]];
+	struct imgu_abi_sp_init_dmem_cfg dmem_cfg = {
+		.ddr_data_addr = css->binary[css->fw_sp[sp]].daddr
+			+ bi->blob.data_source,
+		.dmem_data_addr = bi->blob.data_target,
+		.dmem_bss_addr = bi->blob.bss_target,
+		.data_size = bi->blob.data_size,
+		.bss_size = bi->blob.bss_size,
+		.sp_id = sp,
+	};
+
+	writes(&dmem_cfg, sizeof(dmem_cfg) / 4, base +
+		IMGU_REG_SP_DMEM_BASE(sp) + bi->info.sp.init_dmem_data);
+
+	writel(bi->info.sp.sp_entry, base + IMGU_REG_SP_START_ADDR(sp));
+
+	writel(readl(base + IMGU_REG_SP_CTRL(sp))
+		| IMGU_CTRL_START | IMGU_CTRL_RUN, base + IMGU_REG_SP_CTRL(sp));
+
+	if (ipu3_hw_wait(css->base, IMGU_REG_SP_DMEM_BASE(sp)
+			 + bi->info.sp.sw_state,
+			 ~0, IMGU_ABI_SP_SWSTATE_INITIALIZED))
+		return -EIO;
+
+	return 0;
+}
+
+/* Start the IPU3 CSS ImgU (Imaging Unit) and all the SPs */
+static int ipu3_css_hw_start(struct ipu3_css *css)
+{
+	static const u32 event_mask =
+		((1 << IMGU_ABI_EVTTYPE_OUT_FRAME_DONE) |
+		(1 << IMGU_ABI_EVTTYPE_2ND_OUT_FRAME_DONE) |
+		(1 << IMGU_ABI_EVTTYPE_VF_OUT_FRAME_DONE) |
+		(1 << IMGU_ABI_EVTTYPE_2ND_VF_OUT_FRAME_DONE) |
+		(1 << IMGU_ABI_EVTTYPE_3A_STATS_DONE) |
+		(1 << IMGU_ABI_EVTTYPE_DIS_STATS_DONE) |
+		(1 << IMGU_ABI_EVTTYPE_PIPELINE_DONE) |
+		(1 << IMGU_ABI_EVTTYPE_FRAME_TAGGED) |
+		(1 << IMGU_ABI_EVTTYPE_INPUT_FRAME_DONE) |
+		(1 << IMGU_ABI_EVTTYPE_METADATA_DONE) |
+		(1 << IMGU_ABI_EVTTYPE_LACE_STATS_DONE) |
+		(1 << IMGU_ABI_EVTTYPE_ACC_STAGE_COMPLETE))
+		<< IMGU_ABI_SP_COMM_EVENT_IRQ_MASK_OR_SHIFT;
+
+	void __iomem *const base = css->base;
+	struct imgu_fw_info *bi, *bl = &css->fwp->binary_header[css->fw_bl];
+	unsigned int i;
+
+	writel(IMGU_TLB_INVALIDATE, base + IMGU_REG_TLB_INVALIDATE);
+
+	/* Start bootloader */
+
+	writel(IMGU_ABI_BL_SWSTATE_BUSY,
+	       base + IMGU_REG_ISP_DMEM_BASE + bl->info.bl.sw_state);
+	writel(IMGU_NUM_SP,
+	       base + IMGU_REG_ISP_DMEM_BASE + bl->info.bl.num_dma_cmds);
+
+	for (i = 0; i < IMGU_NUM_SP; i++) {
+		int j = IMGU_NUM_SP - i - 1;	/* load sp1 first, then sp0 */
+		struct imgu_fw_info *sp =
+			&css->fwp->binary_header[css->fw_sp[j]];
+		struct imgu_abi_bl_dma_cmd_entry dma_cmd = {
+			.src_addr = css->binary[css->fw_sp[j]].daddr
+				+ sp->blob.text_source,
+			.size = sp->blob.text_size,
+			.dst_type = IMGU_ABI_BL_DMACMD_TYPE_SP_PMEM,
+			.dst_addr = IMGU_SP_PMEM_BASE(j),
+		};
+
+		writes(&dma_cmd, sizeof(dma_cmd) / 4,
+		       base + IMGU_REG_ISP_DMEM_BASE + i * sizeof(dma_cmd) +
+		       bl->info.bl.dma_cmd_list);
+	}
+
+	writel(bl->info.bl.bl_entry, base + IMGU_REG_ISP_START_ADDR);
+
+	writel(readl(base + IMGU_REG_ISP_CTRL)
+		| IMGU_CTRL_START | IMGU_CTRL_RUN, base + IMGU_REG_ISP_CTRL);
+	if (ipu3_hw_wait(css->base, IMGU_REG_ISP_DMEM_BASE
+			 + bl->info.bl.sw_state, ~0,
+			 IMGU_ABI_BL_SWSTATE_OK)) {
+		dev_err(css->dev, "failed to start bootloader\n");
+		return -EIO;
+	}
+
+	/* Start ISP */
+
+	memset(css->xmem_sp_group_ptrs.vaddr, 0,
+	       sizeof(struct imgu_abi_sp_group));
+
+	bi = &css->fwp->binary_header[css->fw_sp[0]];
+
+	writel(css->xmem_sp_group_ptrs.daddr,
+	       base + IMGU_REG_SP_DMEM_BASE(0) + bi->info.sp.per_frame_data);
+
+	writel(IMGU_ABI_SP_SWSTATE_TERMINATED,
+	       base + IMGU_REG_SP_DMEM_BASE(0) + bi->info.sp.sw_state);
+	writel(1, base + IMGU_REG_SP_DMEM_BASE(0) + bi->info.sp.invalidate_tlb);
+
+	if (ipu3_css_hw_start_sp(css, 0))
+		return -EIO;
+
+	writel(0, base + IMGU_REG_SP_DMEM_BASE(0) + bi->info.sp.isp_started);
+	writel(0, base + IMGU_REG_SP_DMEM_BASE(0) +
+		bi->info.sp.host_sp_queues_initialized);
+	writel(0, base + IMGU_REG_SP_DMEM_BASE(0) + bi->info.sp.sleep_mode);
+	writel(0, base + IMGU_REG_SP_DMEM_BASE(0) + bi->info.sp.invalidate_tlb);
+	writel(IMGU_ABI_SP_COMM_COMMAND_READY, base + IMGU_REG_SP_DMEM_BASE(0)
+		+ bi->info.sp.host_sp_com + IMGU_ABI_SP_COMM_COMMAND);
+
+	/* Enable all events for all queues */
+
+	for (i = 0; i < IPU3_CSS_PIPE_ID_NUM; i++)
+		writel(event_mask, base + IMGU_REG_SP_DMEM_BASE(0)
+			+ bi->info.sp.host_sp_com
+			+ IMGU_ABI_SP_COMM_EVENT_IRQ_MASK(i));
+	writel(1, base + IMGU_REG_SP_DMEM_BASE(0) +
+		bi->info.sp.host_sp_queues_initialized);
+
+	/* Start SP1 */
+
+	bi = &css->fwp->binary_header[css->fw_sp[1]];
+
+	writel(IMGU_ABI_SP_SWSTATE_TERMINATED,
+	       base + IMGU_REG_SP_DMEM_BASE(1) + bi->info.sp.sw_state);
+
+	if (ipu3_css_hw_start_sp(css, 1))
+		return -EIO;
+
+	writel(IMGU_ABI_SP_COMM_COMMAND_READY, base + IMGU_REG_SP_DMEM_BASE(1)
+		+ bi->info.sp.host_sp_com + IMGU_ABI_SP_COMM_COMMAND);
+
+	return 0;
+}
+
+static void ipu3_css_hw_cleanup(struct ipu3_css *css)
+{
+	void __iomem *const base = css->base;
+
+	/** Reset CSS **/
+
+	/* Clear the CSS busy signal */
+	readl(base + IMGU_REG_GP_BUSY);
+	writel(0, base + IMGU_REG_GP_BUSY);
+
+	/* Wait for idle signal */
+	if (ipu3_hw_wait(css->base, IMGU_REG_STATE, IMGU_STATE_IDLE_STS,
+			 IMGU_STATE_IDLE_STS))
+		dev_err(css->dev, "failed to shut down hw cleanly\n");
+
+	/* Reset the css */
+	writel(readl(base + IMGU_REG_PM_CTRL) | IMGU_PM_CTRL_FORCE_RESET,
+	       base + IMGU_REG_PM_CTRL);
+
+	usleep_range(200, 300);
+}
+
+
+void ipu3_css_irq_ack(struct ipu3_css *css)
+{
+	static const int NUM_SWIRQS = 3;
+	struct imgu_fw_info *bi = &css->fwp->binary_header[css->fw_sp[0]];
+	void __iomem *const base = css->base;
+	u32 irq_status[IMGU_IRQCTRL_NUM];
+	int i;
+
+	u32 imgu_status = readl(base + IMGU_REG_INT_STATUS);
+
+	writel(imgu_status, base + IMGU_REG_INT_STATUS);
+	for (i = 0; i < IMGU_IRQCTRL_NUM; i++)
+		irq_status[i] = readl(base + IMGU_REG_IRQCTRL_STATUS(i));
+
+	for (i = 0; i < NUM_SWIRQS; i++) {
+		if (irq_status[IMGU_IRQCTRL_SP0] & IMGU_IRQCTRL_IRQ_SW_PIN(i)) {
+			/* SP SW interrupt */
+			u32 cnt = readl(base + IMGU_REG_SP_DMEM_BASE(0) +
+					bi->info.sp.output);
+			u32 val = readl(base + IMGU_REG_SP_DMEM_BASE(0) +
+					bi->info.sp.output + 4 + 4 * i);
+
+			dev_dbg(css->dev, "%s: swirq %i cnt %i val 0x%x\n",
+				 __func__, i, cnt, val);
+		}
+	}
+
+	for (i = IMGU_IRQCTRL_NUM - 1; i >= 0; i--)
+		if (irq_status[i]) {
+			writel(irq_status[i], base + IMGU_REG_IRQCTRL_CLEAR(i));
+			/* Wait for write to complete */
+			readl(base + IMGU_REG_IRQCTRL_ENABLE(i));
+		}
+
+	dev_dbg(css->dev, "%s: imgu 0x%x main 0x%x sp0 0x%x sp1 0x%x\n",
+		__func__,
+		imgu_status, irq_status[IMGU_IRQCTRL_MAIN],
+		irq_status[IMGU_IRQCTRL_SP0], irq_status[IMGU_IRQCTRL_SP1]);
+}
diff --git a/drivers/media/pci/intel/ipu3/ipu3-css.h b/drivers/media/pci/intel/ipu3/ipu3-css.h
index 92ae102cf480..5b8e92d47f5d 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-css.h
+++ b/drivers/media/pci/intel/ipu3/ipu3-css.h
@@ -128,4 +128,9 @@ struct ipu3_css {
 	struct v4l2_rect rect[IPU3_CSS_RECTS];
 };
 
+/******************* css hw *******************/
+int ipu3_css_set_powerup(struct device *dev, void __iomem *base);
+int ipu3_css_set_powerdown(struct device *dev, void __iomem *base);
+void ipu3_css_irq_ack(struct ipu3_css *css);
+
 #endif
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v4 10/12] intel-ipu3: css pipeline
  2017-10-18  3:54 [PATCH v4 04/12] intel-ipu3: Add user space ABI definitions Yong Zhi
                   ` (3 preceding siblings ...)
  2017-10-18  3:54 ` [PATCH v4 09/12] intel-ipu3: css hardware setup Yong Zhi
@ 2017-10-18  3:54 ` Yong Zhi
  2017-11-01 18:57   ` Sakari Ailus
  2017-10-18  3:54 ` [PATCH v4 11/12] intel-ipu3: Add imgu v4l2 driver Yong Zhi
  2017-10-20  9:30 ` [PATCH v4 04/12] intel-ipu3: Add user space ABI definitions Sakari Ailus
  6 siblings, 1 reply; 19+ messages in thread
From: Yong Zhi @ 2017-10-18  3:54 UTC (permalink / raw)
  To: linux-media, sakari.ailus
  Cc: jian.xu.zheng, rajmohan.mani, tuukka.toivonen, jerry.w.hu, Yong Zhi

Add css pipeline and v4l code.

Signed-off-by: Yong Zhi <yong.zhi@intel.com>
---
 drivers/media/pci/intel/ipu3/ipu3-css.c | 1761 ++++++++++++++++++++++++++++++-
 drivers/media/pci/intel/ipu3/ipu3-css.h |   89 ++
 2 files changed, 1849 insertions(+), 1 deletion(-)

diff --git a/drivers/media/pci/intel/ipu3/ipu3-css.c b/drivers/media/pci/intel/ipu3/ipu3-css.c
index 6e615bf9378a..11f7ad3514c3 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-css.c
+++ b/drivers/media/pci/intel/ipu3/ipu3-css.c
@@ -13,9 +13,16 @@
 
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
+#include <linux/firmware.h>
+#include <linux/gcd.h>
 #include <linux/iopoll.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/swab.h>
+
 #include "ipu3-css.h"
 #include "ipu3-css-fw.h"
+#include "ipu3-css-params.h"
 #include "ipu3-tables.h"
 
 /* IRQ configuration */
@@ -24,6 +31,159 @@
 				 IMGU_IRQCTRL_IRQ_SW_PIN(0) | \
 				 IMGU_IRQCTRL_IRQ_SW_PIN(1))
 
+#define IPU3_CSS_FORMAT_BPP_DEN	50	/* Denominator */
+
+/* Some sane limits for resolutions */
+#define IPU3_CSS_MIN_RES	32
+#define IPU3_CSS_MAX_H		3136
+#define IPU3_CSS_MAX_W		4224
+
+/* filter size from graph settings is fixed as 4 */
+#define FILTER_SIZE             4
+#define MIN_ENVELOPE            8
+
+/* Formats supported by IPU3 Camera Sub System */
+static const struct ipu3_css_format ipu3_css_formats[] = {
+	{
+		.pixelformat = V4L2_PIX_FMT_NV12,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.frame_format = IMGU_ABI_FRAME_FORMAT_NV12,
+		.osys_format = IMGU_ABI_OSYS_FORMAT_NV12,
+		.osys_tiling = IMGU_ABI_OSYS_TILING_NONE,
+		.bytesperpixel_num = 1 * IPU3_CSS_FORMAT_BPP_DEN,
+		.chroma_decim = 4,
+		.width_align = IPU3_UAPI_ISP_VEC_ELEMS,
+		.flags = IPU3_CSS_FORMAT_FL_OUT | IPU3_CSS_FORMAT_FL_VF,
+	}, {
+		/* Each 32 bytes contains 25 10-bit pixels */
+		.pixelformat = V4L2_PIX_FMT_IPU3_SBGGR10,
+		.colorspace = V4L2_COLORSPACE_RAW,
+		.frame_format = IMGU_ABI_FRAME_FORMAT_RAW_PACKED,
+		.bayer_order = IMGU_ABI_BAYER_ORDER_BGGR,
+		.bit_depth = 10,
+		.bytesperpixel_num = 64,
+		.width_align = 2 * IPU3_UAPI_ISP_VEC_ELEMS,
+		.flags = IPU3_CSS_FORMAT_FL_IN,
+	}, {
+		.pixelformat = V4L2_PIX_FMT_IPU3_SGBRG10,
+		.colorspace = V4L2_COLORSPACE_RAW,
+		.frame_format = IMGU_ABI_FRAME_FORMAT_RAW_PACKED,
+		.bayer_order = IMGU_ABI_BAYER_ORDER_GBRG,
+		.bit_depth = 10,
+		.bytesperpixel_num = 64,
+		.width_align = 2 * IPU3_UAPI_ISP_VEC_ELEMS,
+		.flags = IPU3_CSS_FORMAT_FL_IN,
+	}, {
+		.pixelformat = V4L2_PIX_FMT_IPU3_SGRBG10,
+		.colorspace = V4L2_COLORSPACE_RAW,
+		.frame_format = IMGU_ABI_FRAME_FORMAT_RAW_PACKED,
+		.bayer_order = IMGU_ABI_BAYER_ORDER_GRBG,
+		.bit_depth = 10,
+		.bytesperpixel_num = 64,
+		.width_align = 2 * IPU3_UAPI_ISP_VEC_ELEMS,
+		.flags = IPU3_CSS_FORMAT_FL_IN,
+	}, {
+		.pixelformat = V4L2_PIX_FMT_IPU3_SRGGB10,
+		.colorspace = V4L2_COLORSPACE_RAW,
+		.frame_format = IMGU_ABI_FRAME_FORMAT_RAW_PACKED,
+		.bayer_order = IMGU_ABI_BAYER_ORDER_RGGB,
+		.bit_depth = 10,
+		.bytesperpixel_num = 64,
+		.width_align = 2 * IPU3_UAPI_ISP_VEC_ELEMS,
+		.flags = IPU3_CSS_FORMAT_FL_IN,
+	},
+};
+
+static const struct {
+	enum imgu_abi_queue_id qid;
+	size_t ptr_ofs;
+} ipu3_css_queues[IPU3_CSS_QUEUES] = {
+	[IPU3_CSS_QUEUE_IN] = {
+		IMGU_ABI_QUEUE_C_ID,
+		offsetof(struct imgu_abi_buffer, payload.frame.frame_data)
+	},
+	[IPU3_CSS_QUEUE_OUT] = {
+		IMGU_ABI_QUEUE_D_ID,
+		offsetof(struct imgu_abi_buffer, payload.frame.frame_data)
+	},
+	[IPU3_CSS_QUEUE_VF] = {
+		IMGU_ABI_QUEUE_E_ID,
+		offsetof(struct imgu_abi_buffer, payload.frame.frame_data)
+	},
+	[IPU3_CSS_QUEUE_STAT_3A] = {
+		IMGU_ABI_QUEUE_F_ID,
+		offsetof(struct imgu_abi_buffer, payload.s3a.data_ptr)
+	},
+	[IPU3_CSS_QUEUE_STAT_DVS] = {
+		IMGU_ABI_QUEUE_G_ID,
+		offsetof(struct imgu_abi_buffer, payload.skc_dvs_statistics)
+	}
+};
+
+/* Initialize queue based on given format, adjust format as needed */
+static int ipu3_css_queue_init(struct ipu3_css_queue *queue,
+			       struct v4l2_pix_format_mplane *fmt, u32 flags)
+{
+	struct v4l2_pix_format_mplane *const f = &queue->fmt.mpix;
+	unsigned int i;
+	u32 sizeimage;
+
+	INIT_LIST_HEAD(&queue->bufs);
+
+	queue->css_fmt = NULL;	/* Disable */
+	if (!fmt)
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(ipu3_css_formats); i++) {
+		if (!(ipu3_css_formats[i].flags & flags))
+			continue;
+		queue->css_fmt = &ipu3_css_formats[i];
+		if (ipu3_css_formats[i].pixelformat == fmt->pixelformat)
+			break;
+	}
+	if (!queue->css_fmt)
+		return -EINVAL;	/* Could not find any suitable format */
+
+	queue->fmt.mpix = *fmt;
+
+	f->width = ALIGN(clamp_t(u32, f->width,
+				 IPU3_CSS_MIN_RES, IPU3_CSS_MAX_W), 2);
+	f->height = ALIGN(clamp_t(u32, f->height,
+				  IPU3_CSS_MIN_RES, IPU3_CSS_MAX_H), 2);
+	queue->width_pad = ALIGN(f->width, queue->css_fmt->width_align);
+	if (queue->css_fmt->frame_format != IMGU_ABI_FRAME_FORMAT_RAW_PACKED)
+		f->plane_fmt[0].bytesperline = DIV_ROUND_UP(queue->width_pad *
+					queue->css_fmt->bytesperpixel_num,
+					IPU3_CSS_FORMAT_BPP_DEN);
+	else
+		/* For packed raw, alignment for bpl is by 50 to the width */
+		f->plane_fmt[0].bytesperline =
+				DIV_ROUND_UP(f->width,
+					     IPU3_CSS_FORMAT_BPP_DEN) *
+					     queue->css_fmt->bytesperpixel_num;
+
+	sizeimage = f->height * f->plane_fmt[0].bytesperline;
+	if (queue->css_fmt->chroma_decim)
+		sizeimage += 2 * sizeimage / queue->css_fmt->chroma_decim;
+
+	f->plane_fmt[0].sizeimage = sizeimage;
+	f->field = V4L2_FIELD_NONE;
+	f->num_planes = 1;
+	f->colorspace = queue->css_fmt->colorspace;
+	f->flags = 0;
+	f->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+	f->quantization = V4L2_QUANTIZATION_DEFAULT;
+	f->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+	memset(f->reserved, 0, sizeof(f->reserved));
+
+	return 0;
+}
+
+static bool ipu3_css_queue_enabled(struct ipu3_css_queue *q)
+{
+	return !!q->css_fmt;
+}
+
 /******************* css hw *******************/
 
 /* in the style of writesl() defined in include/asm-generic/io.h */
@@ -477,6 +637,1605 @@ static void ipu3_css_hw_cleanup(struct ipu3_css *css)
 	usleep_range(200, 300);
 }
 
+static void ipu3_css_pipeline_cleanup(struct ipu3_css *css)
+{
+	struct imgu_fw_info *bi = &css->fwp->binary_header[css->current_binary];
+	int pipe = 0;
+	int i;
+
+	if (css->current_binary < 0)
+		return;
+
+	ipu3_css_pool_cleanup(css->dev, &css->pool.parameter_set_info);
+	ipu3_css_pool_cleanup(css->dev, &css->pool.acc);
+	ipu3_css_pool_cleanup(css->dev, &css->pool.gdc);
+	ipu3_css_pool_cleanup(css->dev, &css->pool.obgrid);
+	for (i = 0; i < IMGU_ABI_NUM_MEMORIES; i++)
+		ipu3_css_pool_cleanup(css->dev,
+				      &css->pool.binary_params_p[i]);
+
+	for (i = 0; i < bi->info.isp.sp.iterator.num_stripes; i++)
+		ipu3_css_dma_free(css->dev, &css->dvs_meta_data[pipe][i]);
+}
+
+/*
+ * This function initializes various stages of the
+ * IPU3 CSS ISP pipeline
+ */
+static int ipu3_css_pipeline_init(struct ipu3_css *css)
+{
+	static const unsigned int PIPE_ID = IPU3_CSS_PIPE_ID_VIDEO;
+	static const int BYPC = 2;	/* Bytes per component */
+	static const struct imgu_abi_buffer_sp buffer_sp_init = {
+		.buf_src = {.queue_id = IMGU_ABI_QUEUE_EVENT_ID},
+		.buf_type = IMGU_ABI_BUFFER_TYPE_INVALID,
+	};
+
+	struct imgu_abi_isp_iterator_config *cfg_iter;
+	struct imgu_abi_isp_ref_config *cfg_ref;
+	struct imgu_abi_isp_dvs_config *cfg_dvs;
+	struct imgu_abi_isp_tnr3_config *cfg_tnr;
+	struct imgu_abi_isp_ref_dmem_state *cfg_ref_state;
+	struct imgu_abi_isp_tnr3_dmem_state *cfg_tnr_state;
+
+	const int pipe = 0, stage = 0, thread = 0;
+	unsigned int i, j;
+
+	const struct imgu_fw_info *bi =
+	    &css->fwp->binary_header[css->current_binary];
+	const unsigned int stripes = bi->info.isp.sp.iterator.num_stripes;
+
+	struct imgu_fw_config_memory_offsets *cofs = (void *)css->fwp +
+	    bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_CONFIG];
+	struct imgu_fw_state_memory_offsets *sofs = (void *)css->fwp +
+	    bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_STATE];
+
+	struct imgu_abi_isp_stage *isp_stage;
+	struct imgu_abi_sp_stage *sp_stage;
+	struct imgu_abi_sp_group *sp_group;
+
+	const unsigned int bds_width_pad =
+				ALIGN(css->rect[IPU3_CSS_RECT_BDS].width,
+				      2 * IPU3_UAPI_ISP_VEC_ELEMS);
+
+	const enum imgu_abi_memories m0 = IMGU_ABI_MEM_ISP_DMEM0;
+	enum imgu_abi_param_class cfg = IMGU_ABI_PARAM_CLASS_CONFIG;
+	void *vaddr = css->binary_params_cs[cfg - 1][m0].vaddr;
+
+	if (css->current_binary == -1)
+		return -EAGAIN;
+
+	/* Configure iterator */
+
+	cfg_iter = ipu3_css_fw_pipeline_params(css, cfg, m0,
+					       &cofs->dmem.iterator,
+					       sizeof(*cfg_iter), vaddr);
+	if (!cfg_iter)
+		goto bad_firmware;
+
+	cfg_iter->input_info.res.width =
+	    css->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.width;
+	cfg_iter->input_info.res.height =
+	    css->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.height;
+	cfg_iter->input_info.padded_width =
+	    css->queue[IPU3_CSS_QUEUE_IN].width_pad;
+	cfg_iter->input_info.format =
+	    css->queue[IPU3_CSS_QUEUE_IN].css_fmt->frame_format;
+	cfg_iter->input_info.raw_bit_depth =
+	    css->queue[IPU3_CSS_QUEUE_IN].css_fmt->bit_depth;
+	cfg_iter->input_info.raw_bayer_order =
+	    css->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order;
+	cfg_iter->input_info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
+
+	cfg_iter->internal_info.res.width =
+			css->rect[IPU3_CSS_RECT_BDS].width;
+	cfg_iter->internal_info.res.height =
+			css->rect[IPU3_CSS_RECT_BDS].height;
+	cfg_iter->internal_info.padded_width = bds_width_pad;
+	cfg_iter->internal_info.format =
+	    css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
+	cfg_iter->internal_info.raw_bit_depth =
+	    css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bit_depth;
+	cfg_iter->internal_info.raw_bayer_order =
+	    css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bayer_order;
+	cfg_iter->internal_info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
+
+	cfg_iter->output_info.res.width =
+	    css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
+	cfg_iter->output_info.res.height =
+	    css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
+	cfg_iter->output_info.padded_width =
+	    css->queue[IPU3_CSS_QUEUE_OUT].width_pad;
+	cfg_iter->output_info.format =
+	    css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
+	cfg_iter->output_info.raw_bit_depth =
+	    css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bit_depth;
+	cfg_iter->output_info.raw_bayer_order =
+	    css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bayer_order;
+	cfg_iter->output_info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
+
+	cfg_iter->vf_info.res.width =
+	    css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
+	cfg_iter->vf_info.res.height =
+	    css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
+	cfg_iter->vf_info.padded_width =
+	    css->queue[IPU3_CSS_QUEUE_VF].width_pad;
+	cfg_iter->vf_info.format =
+	    css->queue[IPU3_CSS_QUEUE_VF].css_fmt->frame_format;
+	cfg_iter->vf_info.raw_bit_depth =
+	    css->queue[IPU3_CSS_QUEUE_VF].css_fmt->bit_depth;
+	cfg_iter->vf_info.raw_bayer_order =
+	    css->queue[IPU3_CSS_QUEUE_VF].css_fmt->bayer_order;
+	cfg_iter->vf_info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
+
+	cfg_iter->dvs_envelope.width = css->rect[IPU3_CSS_RECT_ENVELOPE].width;
+	cfg_iter->dvs_envelope.height =
+		css->rect[IPU3_CSS_RECT_ENVELOPE].height;
+
+	/* Configure reference (delay) frames */
+
+	cfg_ref = ipu3_css_fw_pipeline_params(css, cfg, m0, &cofs->dmem.ref,
+					      sizeof(*cfg_ref), vaddr);
+	if (!cfg_ref)
+		goto bad_firmware;
+
+	cfg_ref->port_b.crop = 0;
+	cfg_ref->port_b.elems = IMGU_ABI_ISP_DDR_WORD_BYTES / BYPC;
+	cfg_ref->port_b.width  = css->aux_frames[IPU3_CSS_AUX_FRAME_REF].width;
+	cfg_ref->port_b.stride =
+	    css->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperline;
+	cfg_ref->width_a_over_b =
+	    IPU3_UAPI_ISP_VEC_ELEMS / cfg_ref->port_b.elems;
+	cfg_ref->dvs_frame_delay = IPU3_CSS_AUX_FRAMES - 1;
+	for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++) {
+		cfg_ref->ref_frame_addr_y[i] =
+		    css->aux_frames[IPU3_CSS_AUX_FRAME_REF].mem[i].daddr;
+		cfg_ref->ref_frame_addr_c[i] =
+		    css->aux_frames[IPU3_CSS_AUX_FRAME_REF].mem[i].daddr +
+		    css->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperline *
+		    css->aux_frames[IPU3_CSS_AUX_FRAME_REF].height;
+	}
+	for (; i < IMGU_ABI_FRAMES_REF; i++) {
+		cfg_ref->ref_frame_addr_y[i] = 0;
+		cfg_ref->ref_frame_addr_c[i] = 0;
+	}
+
+	/* Configure DVS (digital video stabilization) */
+
+	cfg_dvs = ipu3_css_fw_pipeline_params(css, cfg, m0,
+					      &cofs->dmem.dvs, sizeof(*cfg_dvs),
+					      vaddr);
+	if (!cfg_dvs)
+		goto bad_firmware;
+
+	cfg_dvs->num_horizontal_blocks =
+	    ALIGN(DIV_ROUND_UP(css->rect[IPU3_CSS_RECT_GDC].width,
+			       IMGU_DVS_BLOCK_W), 2);
+	cfg_dvs->num_vertical_blocks =
+	    DIV_ROUND_UP(css->rect[IPU3_CSS_RECT_GDC].height,
+			 IMGU_DVS_BLOCK_H);
+
+	if (cfg_dvs->num_horizontal_blocks * cfg_dvs->num_vertical_blocks < 0)
+		return -EPROTO;
+
+	/* Configure TNR (temporal noise reduction) */
+
+	if (css->pipe_id == IPU3_CSS_PIPE_ID_VIDEO) {
+		cfg_tnr = ipu3_css_fw_pipeline_params(css, cfg, m0,
+						      &cofs->dmem.tnr3,
+						      sizeof(*cfg_tnr),
+						      vaddr);
+		if (!cfg_tnr)
+			goto bad_firmware;
+
+		cfg_tnr->port_b.crop = 0;
+		cfg_tnr->port_b.elems = IMGU_ABI_ISP_DDR_WORD_BYTES;
+		cfg_tnr->port_b.width =
+		    css->aux_frames[IPU3_CSS_AUX_FRAME_TNR].width;
+		cfg_tnr->port_b.stride =
+		    css->aux_frames[IPU3_CSS_AUX_FRAME_TNR].bytesperline;
+		cfg_tnr->width_a_over_b =
+		    IPU3_UAPI_ISP_VEC_ELEMS / cfg_tnr->port_b.elems;
+		cfg_tnr->frame_height =
+		    css->aux_frames[IPU3_CSS_AUX_FRAME_TNR].height;
+		cfg_tnr->delay_frame = IPU3_CSS_AUX_FRAMES - 1;
+		for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
+			cfg_tnr->frame_addr[i] =
+			    css->aux_frames[IPU3_CSS_AUX_FRAME_TNR]
+			    .mem[i].daddr;
+		for (; i < IMGU_ABI_FRAMES_TNR; i++)
+			cfg_tnr->frame_addr[i] = 0;
+	}
+
+	/* Configure ref dmem state parameters */
+
+	cfg = IMGU_ABI_PARAM_CLASS_STATE;
+	vaddr = css->binary_params_cs[cfg - 1][m0].vaddr;
+
+	cfg_ref_state = ipu3_css_fw_pipeline_params(css, cfg, m0,
+						    &sofs->dmem.ref,
+						    sizeof(*cfg_ref_state),
+						    vaddr);
+	if (!cfg_ref_state)
+		goto bad_firmware;
+
+	cfg_ref_state->ref_in_buf_idx = 0;
+	cfg_ref_state->ref_out_buf_idx = 1;
+
+	/* Configure tnr dmem state parameters */
+	if (css->pipe_id == IPU3_CSS_PIPE_ID_VIDEO) {
+		cfg_tnr_state =
+			ipu3_css_fw_pipeline_params(css, cfg, m0,
+						    &sofs->dmem.tnr3,
+						    sizeof(*cfg_tnr_state),
+						    vaddr);
+		if (!cfg_tnr_state)
+			goto bad_firmware;
+
+		cfg_tnr_state->in_bufidx = 0;
+		cfg_tnr_state->out_bufidx = 1;
+		cfg_tnr_state->bypass_filter = 0;
+		cfg_tnr_state->total_frame_counter = 0;
+		for (i = 0; i < IMGU_ABI_BUF_SETS_TNR; i++)
+			cfg_tnr_state->buffer_frame_counter[i] = 0;
+	}
+
+	/* Configure ISP stage */
+
+	isp_stage = css->xmem_isp_stage_ptrs[pipe][stage].vaddr;
+	memset(isp_stage, 0, sizeof(*isp_stage));
+	isp_stage->blob_info = bi->blob;
+	isp_stage->binary_info = bi->info.isp.sp;
+	strcpy(isp_stage->binary_name,
+	       (char *)css->fwp + bi->blob.prog_name_offset);
+	isp_stage->mem_initializers = bi->info.isp.sp.mem_initializers;
+	for (i = IMGU_ABI_PARAM_CLASS_CONFIG; i < IMGU_ABI_PARAM_CLASS_NUM; i++)
+		for (j = 0; j < IMGU_ABI_NUM_MEMORIES; j++)
+			isp_stage->mem_initializers.params[i][j].address =
+			    css->binary_params_cs[i - 1][j].daddr;
+
+	/* Configure SP stage */
+
+	sp_stage = css->xmem_sp_stage_ptrs[pipe][stage].vaddr;
+	memset(sp_stage, 0, sizeof(*sp_stage));
+
+	sp_stage->frames.in.buf_attr = buffer_sp_init;
+	for (i = 0; i < IMGU_ABI_BINARY_MAX_OUTPUT_PORTS; i++)
+		sp_stage->frames.out[i].buf_attr = buffer_sp_init;
+	sp_stage->frames.out_vf.buf_attr = buffer_sp_init;
+	sp_stage->frames.s3a_buf = buffer_sp_init;
+	sp_stage->frames.dvs_buf = buffer_sp_init;
+	sp_stage->frames.lace_buf = buffer_sp_init;
+
+	sp_stage->stage_type = IMGU_ABI_STAGE_TYPE_ISP;
+	sp_stage->num = stage;
+	sp_stage->isp_online = 0;
+	sp_stage->isp_copy_vf = 0;
+	sp_stage->isp_copy_output = 0;
+
+	/* Enable VF output only when VF or PV queue requested by user */
+
+	sp_stage->enable.vf_output =
+		(css->vf_output_en != IPU3_NODE_VF_DISABLED);
+
+	sp_stage->frames.effective_in_res.width =
+		css->rect[IPU3_CSS_RECT_EFFECTIVE].width;
+	sp_stage->frames.effective_in_res.height =
+		css->rect[IPU3_CSS_RECT_EFFECTIVE].height;
+	sp_stage->frames.in.info.res.width =
+	    css->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.width;
+	sp_stage->frames.in.info.res.height =
+	    css->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.height;
+	sp_stage->frames.in.info.padded_width =
+	    css->queue[IPU3_CSS_QUEUE_IN].width_pad;
+	sp_stage->frames.in.info.format =
+	    css->queue[IPU3_CSS_QUEUE_IN].css_fmt->frame_format;
+	sp_stage->frames.in.info.raw_bit_depth =
+	    css->queue[IPU3_CSS_QUEUE_IN].css_fmt->bit_depth;
+	sp_stage->frames.in.info.raw_bayer_order =
+	    css->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order;
+	sp_stage->frames.in.info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
+	sp_stage->frames.in.buf_attr.buf_src.queue_id = IMGU_ABI_QUEUE_C_ID;
+	sp_stage->frames.in.buf_attr.buf_type =
+	    IMGU_ABI_BUFFER_TYPE_INPUT_FRAME;
+
+	sp_stage->frames.out[0].info.res.width =
+	    css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
+	sp_stage->frames.out[0].info.res.height =
+	    css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
+	sp_stage->frames.out[0].info.padded_width =
+	    css->queue[IPU3_CSS_QUEUE_OUT].width_pad;
+	sp_stage->frames.out[0].info.format =
+	    css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
+	sp_stage->frames.out[0].info.raw_bit_depth =
+	    css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bit_depth;
+	sp_stage->frames.out[0].info.raw_bayer_order =
+	    css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bayer_order;
+	sp_stage->frames.out[0].info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
+	sp_stage->frames.out[0].planes.nv.uv.offset =
+	    css->queue[IPU3_CSS_QUEUE_OUT].width_pad *
+	    css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
+	sp_stage->frames.out[0].buf_attr.buf_src.queue_id = IMGU_ABI_QUEUE_D_ID;
+	sp_stage->frames.out[0].buf_attr.buf_type =
+	    IMGU_ABI_BUFFER_TYPE_OUTPUT_FRAME;
+
+	sp_stage->frames.out[1].buf_attr.buf_src.queue_id =
+	    IMGU_ABI_QUEUE_EVENT_ID;
+
+	sp_stage->frames.internal_frame_info.res.width =
+					css->rect[IPU3_CSS_RECT_BDS].width;
+	sp_stage->frames.internal_frame_info.res.height =
+					css->rect[IPU3_CSS_RECT_BDS].height;
+	sp_stage->frames.internal_frame_info.padded_width = bds_width_pad;
+
+	sp_stage->frames.internal_frame_info.format =
+	    css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
+	sp_stage->frames.internal_frame_info.raw_bit_depth =
+	    css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bit_depth;
+	sp_stage->frames.internal_frame_info.raw_bayer_order =
+	    css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bayer_order;
+	sp_stage->frames.internal_frame_info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
+
+	sp_stage->frames.out_vf.info.res.width =
+	    css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
+	sp_stage->frames.out_vf.info.res.height =
+	    css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
+	sp_stage->frames.out_vf.info.padded_width =
+	    css->queue[IPU3_CSS_QUEUE_VF].width_pad;
+	sp_stage->frames.out_vf.info.format =
+	    css->queue[IPU3_CSS_QUEUE_VF].css_fmt->frame_format;
+	sp_stage->frames.out_vf.info.raw_bit_depth =
+	    css->queue[IPU3_CSS_QUEUE_VF].css_fmt->bit_depth;
+	sp_stage->frames.out_vf.info.raw_bayer_order =
+	    css->queue[IPU3_CSS_QUEUE_VF].css_fmt->bayer_order;
+	sp_stage->frames.out_vf.info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
+	sp_stage->frames.out_vf.planes.yuv.u.offset =
+	    css->queue[IPU3_CSS_QUEUE_VF].width_pad *
+	    css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
+	sp_stage->frames.out_vf.planes.yuv.v.offset =
+	    css->queue[IPU3_CSS_QUEUE_VF].width_pad *
+	    css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height * 5 / 4;
+	sp_stage->frames.out_vf.buf_attr.buf_src.queue_id = IMGU_ABI_QUEUE_E_ID;
+	sp_stage->frames.out_vf.buf_attr.buf_type =
+	    IMGU_ABI_BUFFER_TYPE_VF_OUTPUT_FRAME;
+
+	sp_stage->frames.s3a_buf.buf_src.queue_id = IMGU_ABI_QUEUE_F_ID;
+	sp_stage->frames.s3a_buf.buf_type = IMGU_ABI_BUFFER_TYPE_3A_STATISTICS;
+
+	sp_stage->frames.dvs_buf.buf_src.queue_id = IMGU_ABI_QUEUE_G_ID;
+	sp_stage->frames.dvs_buf.buf_type = IMGU_ABI_BUFFER_TYPE_DIS_STATISTICS;
+
+	sp_stage->dvs_envelope.width = css->rect[IPU3_CSS_RECT_ENVELOPE].width;
+	sp_stage->dvs_envelope.height =
+		css->rect[IPU3_CSS_RECT_ENVELOPE].height;
+
+	sp_stage->isp_pipe_version =
+				bi->info.isp.sp.pipeline.isp_pipe_version;
+	sp_stage->isp_deci_log_factor = clamp(
+		max(fls(css->rect[IPU3_CSS_RECT_BDS].width /
+					IMGU_MAX_BQ_GRID_WIDTH),
+		    fls(css->rect[IPU3_CSS_RECT_BDS].height /
+					IMGU_MAX_BQ_GRID_HEIGHT)) - 1, 3, 5);
+	sp_stage->isp_vf_downscale_bits = 0;
+	sp_stage->if_config_index = 255;
+	sp_stage->sp_enable_xnr = 0;
+	sp_stage->num_stripes = stripes;
+	sp_stage->enable.s3a = 1;
+	sp_stage->enable.dvs_stats = 1;
+
+	sp_stage->xmem_bin_addr = css->binary[css->current_binary].daddr;
+	sp_stage->xmem_map_addr = css->sp_ddr_ptrs.daddr;
+	sp_stage->isp_stage_addr = css->xmem_isp_stage_ptrs[pipe][stage].daddr;
+
+	/* Configure SP group */
+
+	sp_group = css->xmem_sp_group_ptrs.vaddr;
+	memset(sp_group, 0, sizeof(*sp_group));
+
+	sp_group->pipe[thread].num_stages = 1;
+	sp_group->pipe[thread].pipe_id = PIPE_ID;
+	sp_group->pipe[thread].thread_id = thread;
+	sp_group->pipe[thread].pipe_num = pipe;
+	sp_group->pipe[thread].num_execs = -1;
+	sp_group->pipe[thread].pipe_qos_config = -1;
+	sp_group->pipe[thread].required_bds_factor = 0;
+	sp_group->pipe[thread].dvs_frame_delay = IPU3_CSS_AUX_FRAMES - 1;
+	sp_group->pipe[thread].inout_port_config =
+	    IMGU_ABI_PORT_CONFIG_TYPE_INPUT_HOST |
+	    IMGU_ABI_PORT_CONFIG_TYPE_OUTPUT_HOST;
+	sp_group->pipe[thread].scaler_pp_lut = 0;
+	sp_group->pipe[thread].shading.internal_frame_origin_x_bqs_on_sctbl = 0;
+	sp_group->pipe[thread].shading.internal_frame_origin_y_bqs_on_sctbl = 0;
+	sp_group->pipe[thread].sp_stage_addr[stage] =
+	    css->xmem_sp_stage_ptrs[pipe][stage].daddr;
+	sp_group->pipe[thread].pipe_config =
+	    bi->info.isp.sp.enable.params ? (1 << thread) : 0;
+	sp_group->pipe[thread].pipe_config |= IMGU_ABI_PIPE_CONFIG_ACQUIRE_ISP;
+
+	/* Allocate dvs statistics metadata */
+
+	for (i = 0; i < stripes; i++)
+		if (ipu3_css_dma_alloc(css->dev, &css->dvs_meta_data[pipe][i],
+				       sizeof(struct imgu_abi_dvs_meta_data)))
+			goto out_of_memory;
+
+	/* Initialize parameter pools */
+
+	if (ipu3_css_pool_init(css->dev, &css->pool.parameter_set_info,
+			       sizeof(struct imgu_abi_parameter_set_info)) ||
+	    ipu3_css_pool_init(css->dev, &css->pool.acc,
+			       sizeof(struct ipu3_uapi_acc_param)) ||
+	    ipu3_css_pool_init(css->dev, &css->pool.gdc,
+			       sizeof(struct ipu3_uapi_gdc_warp_param) *
+			       3 * cfg_dvs->num_horizontal_blocks / 2 *
+			       cfg_dvs->num_vertical_blocks) ||
+	    ipu3_css_pool_init(css->dev, &css->pool.obgrid,
+			       ipu3_css_fw_obgrid_size(
+			       &css->fwp->binary_header[css->current_binary])))
+		goto out_of_memory;
+
+	for (i = 0; i < IMGU_ABI_NUM_MEMORIES; i++)
+		if (ipu3_css_pool_init(css->dev, &css->pool.binary_params_p[i],
+				       bi->info.isp.sp.mem_initializers.params
+				       [IMGU_ABI_PARAM_CLASS_PARAM][i].size))
+			goto out_of_memory;
+
+	return 0;
+
+bad_firmware:
+	ipu3_css_pipeline_cleanup(css);
+	return -EPROTO;
+
+out_of_memory:
+	ipu3_css_pipeline_cleanup(css);
+	return -ENOMEM;
+}
+
+static u8 ipu3_css_queue_pos(struct ipu3_css *css, int queue, int thread)
+{
+	static const unsigned int sp;
+	void __iomem *const base = css->base;
+	struct imgu_fw_info *bi = &css->fwp->binary_header[css->fw_sp[sp]];
+	struct imgu_abi_queues __iomem *q = base + IMGU_REG_SP_DMEM_BASE(sp) +
+	    bi->info.sp.host_sp_queue;
+
+	return queue >= 0 ? readb(&q->host2sp_bufq_info[thread][queue].end) :
+	    readb(&q->host2sp_evtq_info.end);
+}
+
+/* Sent data to sp using given buffer queue, or if queue < 0, event queue. */
+static int ipu3_css_queue_data(struct ipu3_css *css,
+			       int queue, int thread, u32 data)
+{
+	static const unsigned int sp;
+	void __iomem *const base = css->base;
+	struct imgu_fw_info *bi = &css->fwp->binary_header[css->fw_sp[sp]];
+	struct imgu_abi_queues __iomem *q = base + IMGU_REG_SP_DMEM_BASE(sp) +
+	    bi->info.sp.host_sp_queue;
+	u8 size, start, end, end2;
+
+	if (queue >= 0) {
+		size = readb(&q->host2sp_bufq_info[thread][queue].size);
+		start = readb(&q->host2sp_bufq_info[thread][queue].start);
+		end = readb(&q->host2sp_bufq_info[thread][queue].end);
+	} else {
+		size = readb(&q->host2sp_evtq_info.size);
+		start = readb(&q->host2sp_evtq_info.start);
+		end = readb(&q->host2sp_evtq_info.end);
+	}
+
+	if (size == 0)
+		return -EIO;
+
+	end2 = (end + 1) % size;
+	if (end2 == start)
+		return -EBUSY;	/* Queue full */
+
+	if (queue >= 0) {
+		writel(data, &q->host2sp_bufq[thread][queue][end]);
+		writeb(end2, &q->host2sp_bufq_info[thread][queue].end);
+	} else {
+		writel(data, &q->host2sp_evtq[end]);
+		writeb(end2, &q->host2sp_evtq_info.end);
+	}
+
+	return 0;
+}
+
+/* Receive data using given buffer queue, or if queue < 0, event queue. */
+static int ipu3_css_dequeue_data(struct ipu3_css *css, int queue, u32 *data)
+{
+	static const unsigned int sp;
+	void __iomem *const base = css->base;
+	struct imgu_fw_info *bi = &css->fwp->binary_header[css->fw_sp[sp]];
+	struct imgu_abi_queues __iomem *q = base + IMGU_REG_SP_DMEM_BASE(sp) +
+	    bi->info.sp.host_sp_queue;
+	u8 size, start, end, start2;
+
+	if (queue >= 0) {
+		size = readb(&q->sp2host_bufq_info[queue].size);
+		start = readb(&q->sp2host_bufq_info[queue].start);
+		end = readb(&q->sp2host_bufq_info[queue].end);
+	} else {
+		size = readb(&q->sp2host_evtq_info.size);
+		start = readb(&q->sp2host_evtq_info.start);
+		end = readb(&q->sp2host_evtq_info.end);
+	}
+
+	if (size == 0)
+		return -EIO;
+
+	if (end == start)
+		return -EBUSY;	/* Queue empty */
+
+	start2 = (start + 1) % size;
+
+	if (queue >= 0) {
+		*data = readl(&q->sp2host_bufq[queue][start]);
+		writeb(start2, &q->sp2host_bufq_info[queue].start);
+	} else {
+		int r;
+
+		*data = readl(&q->sp2host_evtq[start]);
+		writeb(start2, &q->sp2host_evtq_info.start);
+
+		/* Acknowledge events dequeued from event queue */
+		r = ipu3_css_queue_data(css, queue, 0,
+					IMGU_ABI_EVENT_EVENT_DEQUEUED);
+		if (r < 0)
+			return r;
+	}
+
+	return 0;
+}
+
+/* Free binary-specific resources */
+static void ipu3_css_binary_cleanup(struct ipu3_css *css)
+{
+	unsigned int i, j;
+
+	for (j = 0; j < IMGU_ABI_PARAM_CLASS_NUM - 1; j++)
+		for (i = 0; i < IMGU_ABI_NUM_MEMORIES; i++)
+			ipu3_css_dma_free(css->dev,
+					  &css->binary_params_cs[j][i]);
+
+	j = IPU3_CSS_AUX_FRAME_REF;
+	for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
+		ipu3_css_dma_free(css->dev,
+				  &css->aux_frames[j].mem[i]);
+
+	j = IPU3_CSS_AUX_FRAME_TNR;
+	for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
+		ipu3_css_dma_free(css->dev,
+				  &css->aux_frames[j].mem[i]);
+}
+
+/* allocate binary-specific resources */
+static int ipu3_css_binary_setup(struct ipu3_css *css)
+{
+	struct imgu_fw_info *bi = &css->fwp->binary_header[css->current_binary];
+	int i, j, sz;
+	static const int BYPC = 2;	/* Bytes per component */
+	unsigned int w, h;
+
+	/* Allocate parameter memory blocks for this binary */
+	if (css->current_binary < 0)
+		return -EINVAL;
+
+	for (j = IMGU_ABI_PARAM_CLASS_CONFIG; j < IMGU_ABI_PARAM_CLASS_NUM; j++)
+		for (i = 0; i < IMGU_ABI_NUM_MEMORIES; i++) {
+			sz = bi->info.isp.sp.mem_initializers.params[j][i].size;
+			if (ipu3_css_dma_alloc(css->dev,
+					       &css->binary_params_cs[j - 1][i],
+					       sz))
+				goto out_of_memory;
+		}
+
+	/* Allocate internal frame buffers */
+
+	/* Reference frames for DVS, FRAME_FORMAT_YUV420_16 */
+	css->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperpixel = BYPC;
+	css->aux_frames[IPU3_CSS_AUX_FRAME_REF].width =
+	    css->rect[IPU3_CSS_RECT_BDS].width;
+	css->aux_frames[IPU3_CSS_AUX_FRAME_REF].height =
+				ALIGN(css->rect[IPU3_CSS_RECT_BDS].height,
+				      IMGU_DVS_BLOCK_H) + 2 * IMGU_GDC_BUF_Y;
+	h = css->aux_frames[IPU3_CSS_AUX_FRAME_REF].height;
+	w = ALIGN(css->rect[IPU3_CSS_RECT_BDS].width,
+		  2 * IPU3_UAPI_ISP_VEC_ELEMS) + 2 * IMGU_GDC_BUF_X;
+	css->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperline =
+		css->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperpixel * w;
+	sz = w * h * BYPC + (w / 2) * (h / 2) * BYPC * 2;
+	for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
+		if (ipu3_css_dma_alloc(css->dev,
+				       &css->aux_frames
+					[IPU3_CSS_AUX_FRAME_REF].mem[i], sz))
+			goto out_of_memory;
+
+	/* TNR frames for temporal noise reduction, FRAME_FORMAT_YUV_LINE */
+	css->aux_frames[IPU3_CSS_AUX_FRAME_TNR].bytesperpixel = 1;
+	css->aux_frames[IPU3_CSS_AUX_FRAME_TNR].width =
+			roundup(css->rect[IPU3_CSS_RECT_GDC].width,
+				bi->info.isp.sp.block.block_width *
+				IPU3_UAPI_ISP_VEC_ELEMS);
+	css->aux_frames[IPU3_CSS_AUX_FRAME_TNR].height =
+			roundup(css->rect[IPU3_CSS_RECT_GDC].height,
+				bi->info.isp.sp.block.output_block_height);
+
+	w = css->aux_frames[IPU3_CSS_AUX_FRAME_TNR].width;
+	css->aux_frames[IPU3_CSS_AUX_FRAME_TNR].bytesperline = w;
+	h = css->aux_frames[IPU3_CSS_AUX_FRAME_TNR].height;
+	sz = w * ALIGN(h * 3 / 2 + 3, 2);	/* +3 for vf_pp prefetch */
+
+	for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
+		if (ipu3_css_dma_alloc(css->dev,
+				       &css->aux_frames
+					[IPU3_CSS_AUX_FRAME_TNR].mem[i], sz))
+			goto out_of_memory;
+
+	return 0;
+
+out_of_memory:
+	ipu3_css_binary_cleanup(css);
+	return -ENOMEM;
+}
+
+int ipu3_css_start_streaming(struct ipu3_css *css)
+{
+	u32 data;
+	int r;
+
+	if (css->streaming)
+		return -EPROTO;
+
+	r = ipu3_css_binary_setup(css);
+	if (r < 0)
+		return r;
+
+	r = ipu3_css_hw_init(css);
+	if (r < 0)
+		return r;
+
+	r = ipu3_css_hw_start(css);
+	if (r < 0)
+		goto fail;
+
+	r = ipu3_css_pipeline_init(css);
+	if (r < 0)
+		goto fail;
+
+	css->streaming = true;
+	css->frame = 0;
+
+	/* Initialize parameters to default */
+	r = ipu3_css_set_parameters(css, NULL, NULL, 0, NULL, 0);
+	if (r < 0)
+		goto fail;
+
+	while (!(r = ipu3_css_dequeue_data(css, IMGU_ABI_QUEUE_A_ID, &data)))
+		;
+	if (r != -EBUSY)
+		goto fail;
+
+	while (!(r = ipu3_css_dequeue_data(css, IMGU_ABI_QUEUE_B_ID, &data)))
+		;
+	if (r != -EBUSY)
+		goto fail;
+
+	r = ipu3_css_queue_data(css, IMGU_ABI_QUEUE_EVENT_ID, 0,
+				IMGU_ABI_EVENT_START_STREAM);
+	if (r < 0)
+		goto fail;
+
+	return 0;
+
+fail:
+	css->streaming = false;
+	ipu3_css_hw_cleanup(css);
+	ipu3_css_pipeline_cleanup(css);
+	ipu3_css_binary_cleanup(css);
+
+	return r;
+}
+
+void ipu3_css_stop_streaming(struct ipu3_css *css)
+{
+	struct ipu3_css_buffer *b, *b0;
+	int q, r;
+
+	r = ipu3_css_queue_data(css, IMGU_ABI_QUEUE_EVENT_ID, 0,
+				IMGU_ABI_EVENT_STOP_STREAM);
+
+	if (r < 0)
+		dev_warn(css->dev, "failed on stop stream event\n");
+
+	if (!css->streaming)
+		return;
+
+	ipu3_css_hw_cleanup(css);
+
+	ipu3_css_pipeline_cleanup(css);
+
+	for (q = 0; q < IPU3_CSS_QUEUES; q++)
+		list_for_each_entry_safe(b, b0, &css->queue[q].bufs, list) {
+			b->state = IPU3_CSS_BUFFER_FAILED;
+			list_del(&b->list);
+		}
+
+	ipu3_css_binary_cleanup(css);
+
+	css->streaming = false;
+}
+
+bool ipu3_css_queue_empty(struct ipu3_css *css)
+{
+	int q;
+
+	for (q = 0; q < IPU3_CSS_QUEUES; q++)
+		if (!list_empty(&css->queue[q].bufs))
+			return false;
+	return true;
+}
+
+bool ipu3_css_is_streaming(struct ipu3_css *css)
+{
+	return css->streaming;
+}
+
+void ipu3_css_cleanup(struct ipu3_css *css)
+{
+	int p, q, i;
+
+	ipu3_css_stop_streaming(css);
+	ipu3_css_binary_cleanup(css);
+
+	for (q = 0; q < IPU3_CSS_QUEUES; q++)
+		for (i = 0; i < ARRAY_SIZE(css->abi_buffers[q]); i++)
+			ipu3_css_dma_free(css->dev, &css->abi_buffers[q][i]);
+
+	for (p = 0; p < IPU3_CSS_PIPE_ID_NUM; p++)
+		for (i = 0; i < IMGU_ABI_MAX_STAGES; i++) {
+			ipu3_css_dma_free(css->dev,
+					  &css->xmem_sp_stage_ptrs[p][i]);
+			ipu3_css_dma_free(css->dev,
+					  &css->xmem_isp_stage_ptrs[p][i]);
+		}
+
+	ipu3_css_dma_free(css->dev, &css->sp_ddr_ptrs);
+	ipu3_css_dma_free(css->dev, &css->xmem_sp_group_ptrs);
+
+	ipu3_css_fw_cleanup(css);
+}
+
+int ipu3_css_init(struct device *dev, struct ipu3_css *css,
+		  void __iomem *base, int length)
+{
+	int r, p, q, i;
+	struct imgu_abi_sp_stage *sp_stage;
+	/* Initialize main data structure */
+
+	css->dev = dev;
+	css->base = base;
+	css->iomem_length = length;
+	css->current_binary = -1;
+	css->pipe_id = IPU3_CSS_PIPE_ID_NUM;
+
+	for (q = 0; q < IPU3_CSS_QUEUES; q++) {
+		r = ipu3_css_queue_init(&css->queue[q], NULL, 0);
+		if (r)
+			return r;
+	}
+
+	r = ipu3_css_fw_init(css);
+	if (r)
+		return r;
+
+	/* Allocate and map common structures with imgu hardware */
+
+	for (p = 0; p < IPU3_CSS_PIPE_ID_NUM; p++)
+		for (i = 0; i < IMGU_ABI_MAX_STAGES; i++) {
+			if (ipu3_css_dma_alloc(dev,
+					       &css->xmem_sp_stage_ptrs[p][i],
+					       sizeof(*sp_stage)))
+				goto error_no_memory;
+			if (ipu3_css_dma_alloc(dev,
+					       &css->xmem_isp_stage_ptrs[p][i],
+					       sizeof(*sp_stage)))
+				goto error_no_memory;
+		}
+
+	if (ipu3_css_dma_alloc(dev, &css->sp_ddr_ptrs,
+			       ALIGN(sizeof(struct imgu_abi_ddr_address_map),
+				     IMGU_ABI_ISP_DDR_WORD_BYTES)))
+		goto error_no_memory;
+
+	if (ipu3_css_dma_alloc(dev, &css->xmem_sp_group_ptrs,
+			       sizeof(struct imgu_abi_sp_group)))
+		goto error_no_memory;
+
+	for (q = 0; q < IPU3_CSS_QUEUES; q++)
+		for (i = 0; i < ARRAY_SIZE(css->abi_buffers[q]); i++)
+			if (ipu3_css_dma_alloc(dev, &css->abi_buffers[q][i],
+					       sizeof(struct imgu_abi_buffer)))
+				goto error_no_memory;
+
+	return 0;
+
+error_no_memory:
+	ipu3_css_cleanup(css);
+
+	return -ENOMEM;
+}
+
+static u32 ipu3_css_adjust(u32 res, u32 align)
+{
+	if (res < IPU3_CSS_MIN_RES)
+		res = IPU3_CSS_MIN_RES;
+	res = roundclosest(res, align);
+
+	return res;
+}
+
+/* Select a binary matching the required resolutions and formats */
+static int ipu3_css_find_binary(struct ipu3_css *css,
+				struct ipu3_css_queue queue[IPU3_CSS_QUEUES],
+				struct v4l2_rect rects[IPU3_CSS_RECTS])
+{
+	const int binary_nr = css->fwp->file_header.binary_nr;
+	unsigned int binary_mode = (css->pipe_id == IPU3_CSS_PIPE_ID_CAPTURE) ?
+		IA_CSS_BINARY_MODE_PRIMARY : IA_CSS_BINARY_MODE_VIDEO;
+	const char *name;
+
+	const struct v4l2_pix_format_mplane *in =
+			&queue[IPU3_CSS_QUEUE_IN].fmt.mpix;
+	const struct v4l2_pix_format_mplane *out =
+			&queue[IPU3_CSS_QUEUE_OUT].fmt.mpix;
+	const struct v4l2_pix_format_mplane *vf =
+			&queue[IPU3_CSS_QUEUE_VF].fmt.mpix;
+
+	int i, j;
+	u32 stripe_w = 0;
+	u32 stripe_h = 0;
+
+	if (!ipu3_css_queue_enabled(&queue[IPU3_CSS_QUEUE_IN]))
+		return -EINVAL;
+
+	/* Find out the strip size boundary */
+	for (i = 0; i < binary_nr; i++) {
+		struct imgu_fw_info *bi = &css->fwp->binary_header[i];
+
+		u32 max_width = bi->info.isp.sp.output.max_width;
+		u32 max_height = bi->info.isp.sp.output.max_height;
+
+		if (bi->info.isp.sp.iterator.num_stripes <= 1) {
+			stripe_w = stripe_w ?
+				min(stripe_w, max_width) : max_width;
+			stripe_h = stripe_h ?
+				min(stripe_h, max_height) : max_height;
+		}
+	}
+
+	for (i = 0; i < binary_nr; i++) {
+		struct imgu_fw_info *bi = &css->fwp->binary_header[i];
+		enum imgu_abi_frame_format q_fmt;
+
+		name = (void *)css->fwp + bi->blob.prog_name_offset;
+
+		/* Check that binary supports memory-to-memory processing */
+		if (bi->info.isp.sp.input.source !=
+		    IMGU_ABI_BINARY_INPUT_SOURCE_MEMORY)
+			continue;
+
+		/* Check that binary supports raw10 input */
+		if (!bi->info.isp.sp.enable.input_feeder &&
+		    !bi->info.isp.sp.enable.input_raw)
+			continue;
+
+		/* Check binary mode */
+		if (bi->info.isp.sp.pipeline.mode != binary_mode)
+			continue;
+
+		/* Since input is RGGB bayer, need to process colors */
+		if (bi->info.isp.sp.enable.luma_only)
+			continue;
+
+		if (in->width < bi->info.isp.sp.input.min_width ||
+		    in->width > bi->info.isp.sp.input.max_width ||
+		    in->height < bi->info.isp.sp.input.min_height ||
+		    in->height > bi->info.isp.sp.input.max_height)
+			continue;
+
+		if (ipu3_css_queue_enabled(&queue[IPU3_CSS_QUEUE_OUT])) {
+			if (bi->info.isp.num_output_pins <= 0)
+				continue;
+
+			q_fmt = queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
+
+			for (j = 0; j < bi->info.isp.num_output_formats; j++)
+				if (bi->info.isp.output_formats[j] == q_fmt)
+					break;
+			if (j >= bi->info.isp.num_output_formats)
+				continue;
+
+			if (out->width < bi->info.isp.sp.output.min_width ||
+			    out->width > bi->info.isp.sp.output.max_width ||
+			    out->height < bi->info.isp.sp.output.min_height ||
+			    out->height > bi->info.isp.sp.output.max_height)
+				continue;
+
+			if (out->width > bi->info.isp.sp.internal.max_width ||
+			    out->height > bi->info.isp.sp.internal.max_height)
+				continue;
+		}
+
+		if (ipu3_css_queue_enabled(&queue[IPU3_CSS_QUEUE_VF])) {
+			if (bi->info.isp.num_output_pins <= 1)
+				continue;
+			q_fmt = queue[IPU3_CSS_QUEUE_VF].css_fmt->frame_format;
+			for (j = 0; j < bi->info.isp.num_output_formats; j++)
+				if (bi->info.isp.output_formats[j] == q_fmt)
+					break;
+			if (j >= bi->info.isp.num_output_formats)
+				continue;
+
+			if (vf->width < bi->info.isp.sp.output.min_width ||
+			    vf->width > bi->info.isp.sp.output.max_width ||
+			    vf->height < bi->info.isp.sp.output.min_height ||
+			    vf->height > bi->info.isp.sp.output.max_height)
+				continue;
+		}
+
+		/* All checks passed, select the binary */
+		dev_dbg(css->dev, "using binary %s\n", name);
+		return i;
+	}
+
+	/* Can not find suitable binary for these parameters */
+	return -EINVAL;
+}
+
+/*
+ * Check that there is a binary matching requirements. Parameters may be
+ * NULL indicating disabled input/output. Return negative if given
+ * parameters can not be supported or on error, zero or positive indicating
+ * found binary number. May modify the given parameters if not exact match
+ * is found.
+ */
+int ipu3_css_fmt_try(struct ipu3_css *css,
+		     struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES],
+		     struct v4l2_rect *rects[IPU3_CSS_RECTS])
+{
+	static const u32 EFF_ALIGN_W = 2;
+	static const u32 BDS_ALIGN_W = 4;
+	static const u32 OUT_ALIGN_W = 8;
+	static const u32 OUT_ALIGN_H = 4;
+	static const u32 VF_ALIGN_W  = 2;
+	static const char *qnames[IPU3_CSS_QUEUES] = {
+		[IPU3_CSS_QUEUE_IN] = "in",
+		[IPU3_CSS_QUEUE_PARAMS]    = "params",
+		[IPU3_CSS_QUEUE_OUT] = "out",
+		[IPU3_CSS_QUEUE_VF] = "vf",
+		[IPU3_CSS_QUEUE_STAT_3A]   = "3a",
+		[IPU3_CSS_QUEUE_STAT_DVS]  = "dvs",
+		[IPU3_CSS_QUEUE_STAT_LACE] = "lace",
+	};
+	static const char *rnames[IPU3_CSS_RECTS] = {
+		[IPU3_CSS_RECT_EFFECTIVE] = "effective resolution",
+		[IPU3_CSS_RECT_BDS]       = "bayer-domain scaled resolution",
+		[IPU3_CSS_RECT_ENVELOPE]  = "DVS envelope size",
+		[IPU3_CSS_RECT_GDC]  = "GDC output res",
+	};
+	struct v4l2_rect r[IPU3_CSS_RECTS] = { };
+	struct v4l2_rect *const eff = &r[IPU3_CSS_RECT_EFFECTIVE];
+	struct v4l2_rect *const bds = &r[IPU3_CSS_RECT_BDS];
+	struct v4l2_rect *const env = &r[IPU3_CSS_RECT_ENVELOPE];
+	struct v4l2_rect *const gdc = &r[IPU3_CSS_RECT_GDC];
+	struct ipu3_css_queue q[IPU3_CSS_QUEUES];
+	struct v4l2_pix_format_mplane *const in =
+			&q[IPU3_CSS_QUEUE_IN].fmt.mpix;
+	struct v4l2_pix_format_mplane *const out =
+			&q[IPU3_CSS_QUEUE_OUT].fmt.mpix;
+	struct v4l2_pix_format_mplane *const vf =
+			&q[IPU3_CSS_QUEUE_VF].fmt.mpix;
+	int binary, i, s;
+
+	/* Decide which pipe to use */
+	if (css->vf_output_en == IPU3_NODE_PV_ENABLED)
+		css->pipe_id = IPU3_CSS_PIPE_ID_CAPTURE;
+	else if (css->vf_output_en == IPU3_NODE_VF_ENABLED)
+		css->pipe_id = IPU3_CSS_PIPE_ID_VIDEO;
+
+	/* Adjust all formats, get statistics buffer sizes and formats */
+	for (i = 0; i < IPU3_CSS_QUEUES; i++) {
+		if (fmts[i])
+			dev_dbg(css->dev, "%s %s: (%i,%i) fmt 0x%x\n", __func__,
+				qnames[i], fmts[i]->width, fmts[i]->height,
+				fmts[i]->pixelformat);
+		else
+			dev_dbg(css->dev, "%s %s: (not set)\n", __func__,
+				qnames[i]);
+		if (ipu3_css_queue_init(&q[i], fmts[i],
+					IPU3_CSS_QUEUE_TO_FLAGS(i))) {
+			dev_notice(css->dev, "can not initialize queue %s\n",
+				   qnames[i]);
+			return -EINVAL;
+		}
+	}
+	for (i = 0; i < IPU3_CSS_RECTS; i++) {
+		if (rects[i]) {
+			dev_dbg(css->dev, "%s %s: (%i,%i)\n", __func__,
+				rnames[i], rects[i]->width, rects[i]->height);
+			r[i].width  = rects[i]->width;
+			r[i].height = rects[i]->height;
+		} else {
+			dev_dbg(css->dev, "%s %s: (not set)\n", __func__,
+				rnames[i]);
+		}
+		/* For now, force known good resolutions */
+		r[i].left = 0;
+		r[i].top  = 0;
+	}
+
+	/* Always require one input and vf only if out is also enabled */
+	if (!ipu3_css_queue_enabled(&q[IPU3_CSS_QUEUE_IN]) ||
+	    (ipu3_css_queue_enabled(&q[IPU3_CSS_QUEUE_VF]) &&
+	    !ipu3_css_queue_enabled(&q[IPU3_CSS_QUEUE_OUT]))) {
+		dev_dbg(css->dev, "required queues are disabled\n");
+		return -EINVAL;
+	}
+
+	if (!ipu3_css_queue_enabled(&q[IPU3_CSS_QUEUE_OUT])) {
+		out->width = in->width;
+		out->height = in->height;
+	}
+	if (eff->width <= 0 || eff->height <= 0) {
+		eff->width = in->width;
+		eff->height = in->height;
+	}
+	if (bds->width <= 0 || bds->height <= 0) {
+		bds->width = out->width;
+		bds->height = out->height;
+	}
+	if (gdc->width <= 0 || gdc->height <= 0) {
+		gdc->width = out->width;
+		gdc->height = out->height;
+	}
+
+	in->width   = ipu3_css_adjust(in->width, 1);
+	in->height  = ipu3_css_adjust(in->height, 1);
+	eff->width  = ipu3_css_adjust(eff->width, EFF_ALIGN_W);
+	eff->height = ipu3_css_adjust(eff->height, 1);
+	bds->width  = ipu3_css_adjust(bds->width, BDS_ALIGN_W);
+	bds->height = ipu3_css_adjust(bds->height, 1);
+	gdc->width  = ipu3_css_adjust(gdc->width, OUT_ALIGN_W);
+	gdc->height = ipu3_css_adjust(gdc->height, OUT_ALIGN_H);
+	out->width  = ipu3_css_adjust(out->width, OUT_ALIGN_W);
+	out->height = ipu3_css_adjust(out->height, OUT_ALIGN_H);
+	vf->width   = ipu3_css_adjust(vf->width, VF_ALIGN_W);
+	vf->height  = ipu3_css_adjust(vf->height, 1);
+
+	s = (bds->width - gdc->width) / 2 - FILTER_SIZE;
+	env->width = s < MIN_ENVELOPE ? MIN_ENVELOPE : s;
+	s = (bds->height - gdc->height) / 2 - FILTER_SIZE;
+	env->height = s < MIN_ENVELOPE ? MIN_ENVELOPE : s;
+
+	binary = ipu3_css_find_binary(css, q, r);
+	if (binary < 0) {
+		dev_err(css->dev, "failed to find suitable binary\n");
+		return -EINVAL;
+	}
+
+	/* Final adjustment and set back the queried formats */
+	for (i = 0; i < IPU3_CSS_QUEUES; i++) {
+		if (fmts[i]) {
+			if (ipu3_css_queue_init(&q[i], &q[i].fmt.mpix,
+						IPU3_CSS_QUEUE_TO_FLAGS(i))) {
+				dev_err(css->dev,
+					"final resolution adjustment failed\n");
+				return -EINVAL;
+			}
+			*fmts[i] = q[i].fmt.mpix;
+		}
+	}
+
+	for (i = 0; i < IPU3_CSS_RECTS; i++)
+		if (rects[i])
+			*rects[i] = r[i];
+
+	dev_dbg(css->dev,
+		"in(%u,%u) if(%u,%u) ds(%u,%u) gdc(%u,%u) out(%u,%u) vf(%u,%u)",
+		 in->width, in->height, eff->width, eff->height,
+		 bds->width, bds->height, gdc->width, gdc->height,
+		 out->width, out->height, vf->width, vf->height);
+
+	return binary;
+}
+
+int ipu3_css_fmt_set(struct ipu3_css *css,
+		     struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES],
+		     struct v4l2_rect *rects[IPU3_CSS_RECTS])
+{
+	struct v4l2_rect rect_data[IPU3_CSS_RECTS];
+	struct v4l2_rect *all_rects[IPU3_CSS_RECTS];
+	int i, r;
+
+	for (i = 0; i < IPU3_CSS_RECTS; i++) {
+		if (rects[i])
+			rect_data[i] = *rects[i];
+		else
+			memset(&rect_data[i], 0, sizeof(rect_data[i]));
+		all_rects[i] = &rect_data[i];
+	}
+	r = ipu3_css_fmt_try(css, fmts, all_rects);
+	if (r < 0)
+		return r;
+	css->current_binary = r;
+
+	for (i = 0; i < IPU3_CSS_QUEUES; i++)
+		if (ipu3_css_queue_init(&css->queue[i], fmts[i],
+					IPU3_CSS_QUEUE_TO_FLAGS(i)))
+			return -EINVAL;
+	for (i = 0; i < IPU3_CSS_RECTS; i++) {
+		css->rect[i] = rect_data[i];
+		if (rects[i])
+			*rects[i] = rect_data[i];
+	}
+
+	return 0;
+}
+
+int ipu3_css_meta_fmt_set(struct v4l2_meta_format *fmt)
+{
+	switch (fmt->dataformat) {
+	case V4L2_META_FMT_IPU3_PARAMS:
+		fmt->buffersize = sizeof(struct ipu3_uapi_params);
+		break;
+	case V4L2_META_FMT_IPU3_STAT_3A:
+		fmt->buffersize = sizeof(struct ipu3_uapi_stats_3a);
+		break;
+	case V4L2_META_FMT_IPU3_STAT_DVS:
+		fmt->buffersize = sizeof(struct ipu3_uapi_stats_dvs);
+		break;
+	case V4L2_META_FMT_IPU3_STAT_LACE:
+		fmt->buffersize = sizeof(struct ipu3_uapi_stats_lace);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * Queue given buffer to CSS. ipu3_css_buf_prepare() must have been first
+ * called for the buffer. May be called from interrupt context.
+ * Returns 0 on success, -EBUSY if the buffer queue is full, or some other
+ * code on error conditions.
+ */
+int ipu3_css_buf_queue(struct ipu3_css *css, struct ipu3_css_buffer *b)
+{
+	static const int thread;
+	struct imgu_abi_buffer *abi_buf;
+	struct imgu_addr_t *buf_addr;
+	u32 data;
+	int r;
+
+	if (!css->streaming)
+		return -EPROTO;	/* CSS or buffer in wrong state */
+
+	if (b->queue >= IPU3_CSS_QUEUES || !ipu3_css_queues[b->queue].qid)
+		return -EINVAL;
+
+	b->queue_pos = ipu3_css_queue_pos(
+				css, ipu3_css_queues[b->queue].qid, thread);
+
+	if (b->queue_pos >= ARRAY_SIZE(css->abi_buffers[b->queue]))
+		return -EIO;
+	abi_buf = css->abi_buffers[b->queue][b->queue_pos].vaddr;
+
+	/* Fill struct abi_buffer for firmware */
+	memset(abi_buf, 0, sizeof(*abi_buf));
+
+	buf_addr = (void *)abi_buf + ipu3_css_queues[b->queue].ptr_ofs;
+	*(imgu_addr_t *)buf_addr = b->daddr;
+
+	if (b->queue == IPU3_CSS_QUEUE_STAT_3A)
+		abi_buf->payload.s3a.data.dmem.s3a_tbl = b->daddr;
+
+	if (b->queue == IPU3_CSS_QUEUE_OUT)
+		abi_buf->payload.frame.padded_width =
+			css->queue[IPU3_CSS_QUEUE_OUT].width_pad;
+
+	if (b->queue == IPU3_CSS_QUEUE_VF)
+		abi_buf->payload.frame.padded_width =
+			css->queue[IPU3_CSS_QUEUE_VF].width_pad;
+
+	list_add_tail(&b->list, &css->queue[b->queue].bufs);
+	b->state = IPU3_CSS_BUFFER_QUEUED;
+
+	data = css->abi_buffers[b->queue][b->queue_pos].daddr;
+	r = ipu3_css_queue_data(css, ipu3_css_queues[b->queue].qid,
+				thread, data);
+	if (r < 0)
+		goto queueing_failed;
+
+	data = IMGU_ABI_EVENT_BUFFER_ENQUEUED(thread,
+					      ipu3_css_queues[b->queue].qid);
+	r = ipu3_css_queue_data(css, IMGU_ABI_QUEUE_EVENT_ID,
+				0, data);
+	if (r < 0)
+		goto queueing_failed;
+
+	dev_dbg(css->dev, "queued buffer %p to css queue %i\n", b, b->queue);
+
+	return 0;
+
+queueing_failed:
+	b->state = (r == -EBUSY || r == -EAGAIN) ?
+		IPU3_CSS_BUFFER_NEW : IPU3_CSS_BUFFER_FAILED;
+	list_del(&b->list);
+
+	return r;
+}
+
+/*
+ * Get next ready CSS buffer. Returns -EAGAIN in which case the function
+ * should be called again, or -EBUSY which means that there are no more
+ * buffers available. May be called from interrupt context.
+ */
+struct ipu3_css_buffer *ipu3_css_buf_dequeue(struct ipu3_css *css)
+{
+	static const int thread;
+	static const unsigned char evtype_to_queue[] = {
+		[IMGU_ABI_EVTTYPE_INPUT_FRAME_DONE] = IPU3_CSS_QUEUE_IN,
+		[IMGU_ABI_EVTTYPE_OUT_FRAME_DONE] = IPU3_CSS_QUEUE_OUT,
+		[IMGU_ABI_EVTTYPE_VF_OUT_FRAME_DONE] = IPU3_CSS_QUEUE_VF,
+		[IMGU_ABI_EVTTYPE_3A_STATS_DONE] = IPU3_CSS_QUEUE_STAT_3A,
+		[IMGU_ABI_EVTTYPE_DIS_STATS_DONE] = IPU3_CSS_QUEUE_STAT_DVS,
+		[IMGU_ABI_EVTTYPE_LACE_STATS_DONE] = IPU3_CSS_QUEUE_STAT_LACE,
+	};
+	struct ipu3_css_buffer *b = ERR_PTR(-EAGAIN);
+	u32 event, daddr;
+	int evtype, pipe, pipeid, queue, qid, r;
+
+	if (!css->streaming)
+		return ERR_PTR(-EPROTO);
+
+	r = ipu3_css_dequeue_data(css, IMGU_ABI_QUEUE_EVENT_ID, &event);
+	if (r < 0)
+		return ERR_PTR(r);
+
+	evtype = (event & IMGU_ABI_EVTTYPE_EVENT_MASK) >>
+	    IMGU_ABI_EVTTYPE_EVENT_SHIFT;
+
+	switch (evtype) {
+	case IMGU_ABI_EVTTYPE_OUT_FRAME_DONE:
+	case IMGU_ABI_EVTTYPE_VF_OUT_FRAME_DONE:
+	case IMGU_ABI_EVTTYPE_3A_STATS_DONE:
+	case IMGU_ABI_EVTTYPE_DIS_STATS_DONE:
+	case IMGU_ABI_EVTTYPE_INPUT_FRAME_DONE:
+	case IMGU_ABI_EVTTYPE_LACE_STATS_DONE:
+		pipe = (event & IMGU_ABI_EVTTYPE_PIPE_MASK) >>
+		    IMGU_ABI_EVTTYPE_PIPE_SHIFT;
+		pipeid = (event & IMGU_ABI_EVTTYPE_PIPEID_MASK) >>
+		    IMGU_ABI_EVTTYPE_PIPEID_SHIFT;
+		queue = evtype_to_queue[evtype];
+		qid = ipu3_css_queues[queue].qid;
+
+		if (qid >= IMGU_ABI_QUEUE_NUM) {
+			dev_err(css->dev, "Invalid qid: %i\n", qid);
+			return ERR_PTR(-EIO);
+		}
+
+		dev_dbg(css->dev,
+			"event: buffer done 0x%x queue %i pipe %i pipeid %i\n",
+			event, queue, pipe, pipeid);
+
+		r = ipu3_css_dequeue_data(css, qid, &daddr);
+		if (r < 0) {
+			dev_err(css->dev, "failed to dequeue buffer\n");
+			/* Force real error, not -EBUSY */
+			return ERR_PTR(-EIO);
+		}
+
+		r = ipu3_css_queue_data(css, IMGU_ABI_QUEUE_EVENT_ID, thread,
+					IMGU_ABI_EVENT_BUFFER_DEQUEUED(qid));
+		if (r < 0) {
+			dev_err(css->dev, "failed to queue event\n");
+			return ERR_PTR(-EIO);
+		}
+
+		if (list_empty(&css->queue[queue].bufs)) {
+			dev_err(css->dev, "event on empty queue\n");
+			return ERR_PTR(-EIO);
+		}
+		b = list_first_entry(&css->queue[queue].bufs,
+				     struct ipu3_css_buffer, list);
+		if (queue != b->queue ||
+		    daddr != css->abi_buffers[b->queue][b->queue_pos].daddr) {
+			dev_err(css->dev, "dequeued bad buffer 0x%x\n", daddr);
+			return ERR_PTR(-EIO);
+		}
+		b->state = IPU3_CSS_BUFFER_DONE;
+		list_del(&b->list);
+		break;
+	case IMGU_ABI_EVTTYPE_PIPELINE_DONE:
+		dev_dbg(css->dev, "event: pipeline done 0x%x for frame %ld\n",
+			event, css->frame);
+
+		if (css->frame == LONG_MAX)
+			css->frame = 0;
+		else
+			css->frame++;
+		break;
+	case IMGU_ABI_EVTTYPE_TIMER:
+		r = ipu3_css_dequeue_data(css, IMGU_ABI_QUEUE_EVENT_ID, &event);
+		if (r < 0)
+			return ERR_PTR(r);
+
+		if ((event & IMGU_ABI_EVTTYPE_EVENT_MASK) >>
+		    IMGU_ABI_EVTTYPE_EVENT_SHIFT == IMGU_ABI_EVTTYPE_TIMER)
+			dev_dbg(css->dev, "event: timer\n");
+		else
+			dev_warn(css->dev, "half of timer event missing\n");
+		break;
+	case IMGU_ABI_EVTTYPE_FW_WARNING:
+		dev_warn(css->dev, "event: firmware warning 0x%x\n", event);
+		break;
+	case IMGU_ABI_EVTTYPE_FW_ASSERT:
+		dev_err(css->dev,
+			"event: firmware assert 0x%x module_id %i line_no %i\n",
+			event,
+			(event & IMGU_ABI_EVTTYPE_MODULEID_MASK) >>
+			IMGU_ABI_EVTTYPE_MODULEID_SHIFT,
+			swab16((event & IMGU_ABI_EVTTYPE_LINENO_MASK) >>
+			       IMGU_ABI_EVTTYPE_LINENO_SHIFT));
+		break;
+	default:
+		dev_warn(css->dev, "received unknown event 0x%x\n", event);
+	}
+
+	return b;
+}
+
+/*
+ * Get a new set of parameters from pool and initialize them based on
+ * the parameters params, gdc, and obgrid. Any of these may be NULL,
+ * in which case the previously set parameters are used.
+ * If parameters haven't been set previously, initialize from scratch.
+ *
+ * Return index to css->parameter_set_info which has the newly created
+ * parameters or negative value on error.
+ */
+int ipu3_css_set_parameters(struct ipu3_css *css,
+			    struct ipu3_uapi_params *set_params,
+			    struct ipu3_uapi_gdc_warp_param *set_gdc,
+			    unsigned int gdc_bytes,
+			    struct ipu3_uapi_obgrid_param *set_obgrid,
+			    unsigned int obgrid_bytes)
+{
+	static const unsigned int queue_id = IMGU_ABI_QUEUE_A_ID;
+	const int stage = 0, thread = 0;
+	const struct imgu_fw_info *bi;
+	int obgrid_size;
+	unsigned int stripes;
+	struct ipu3_uapi_flags *use = set_params ? &set_params->use : NULL;
+
+	/* Destination buffers which are filled here */
+	struct imgu_abi_parameter_set_info *param_set;
+	struct ipu3_uapi_acc_param *acc = NULL;
+	struct ipu3_uapi_gdc_warp_param *gdc = NULL;
+	struct ipu3_uapi_obgrid_param *obgrid = NULL;
+	const struct ipu3_css_map *map;
+	void *vmem0 = NULL;
+	void *dmem0 = NULL;
+
+	enum imgu_abi_memories m;
+	int r = -EBUSY;
+	int s;
+
+	if (!css->streaming)
+		return -EPROTO;
+
+	bi = &css->fwp->binary_header[css->current_binary];
+	obgrid_size = ipu3_css_fw_obgrid_size(bi);
+	stripes = bi->info.isp.sp.iterator.num_stripes ? : 1;
+
+	/*
+	 * Check that we can get a new parameter_set_info from the pool.
+	 * If this succeeds, then all of the other pool_get() calls below
+	 * should also succeed.
+	 */
+	if (ipu3_css_pool_get(&css->pool.parameter_set_info, css->frame) < 0)
+		goto fail_no_put;
+	param_set = ipu3_css_pool_last(&css->pool.parameter_set_info, 0)->vaddr;
+
+	/* Get a new acc only if new parameters given, or none yet */
+	if (set_params || !ipu3_css_pool_last(&css->pool.acc, 0)->vaddr) {
+		if (ipu3_css_pool_get(&css->pool.acc, css->frame) < 0)
+			goto fail;
+		acc = ipu3_css_pool_last(&css->pool.acc, 0)->vaddr;
+	}
+
+	/* Get new VMEM0 only if needed, or none yet */
+	m = IMGU_ABI_MEM_ISP_VMEM0;
+	if (!ipu3_css_pool_last(&css->pool.binary_params_p[m], 0)->vaddr ||
+	    (set_params && (set_params->use.lin_vmem_params ||
+			    set_params->use.tnr3_vmem_params ||
+			    set_params->use.xnr3_vmem_params))) {
+		if (ipu3_css_pool_get(&css->pool.binary_params_p[m],
+				      css->frame) < 0)
+			goto fail;
+		vmem0 = ipu3_css_pool_last(&css->pool.binary_params_p[m], 0)
+		    ->vaddr;
+	}
+
+	/* Get new DMEM0 only if needed, or none yet */
+	m = IMGU_ABI_MEM_ISP_DMEM0;
+	if (!ipu3_css_pool_last(&css->pool.binary_params_p[m], 0)->vaddr ||
+	    (set_params && (set_params->use.tnr3_dmem_params ||
+			    set_params->use.xnr3_dmem_params))) {
+		if (ipu3_css_pool_get(&css->pool.binary_params_p[m],
+				      css->frame) < 0)
+			goto fail;
+		dmem0 = ipu3_css_pool_last(&css->pool.binary_params_p[m], 0)
+		    ->vaddr;
+	}
+
+	/* Configure acc parameter cluster */
+	if (acc) {
+		map = ipu3_css_pool_last(&css->pool.acc, 1);
+		r = ipu3_css_cfg_acc(css, use, acc, map->vaddr, set_params ?
+				     &set_params->acc_param : NULL);
+		if (r < 0)
+			goto fail;
+	}
+
+	/* Configure late binding parameters */
+	if (vmem0) {
+		m = IMGU_ABI_MEM_ISP_VMEM0;
+		map = ipu3_css_pool_last(&css->pool.binary_params_p[m], 1);
+		r = ipu3_css_cfg_vmem0(css, use, vmem0, map->vaddr, set_params);
+		if (r < 0)
+			goto fail;
+	}
+
+	if (dmem0) {
+		m = IMGU_ABI_MEM_ISP_DMEM0;
+		map = ipu3_css_pool_last(&css->pool.binary_params_p[m], 1);
+		r = ipu3_css_cfg_dmem0(css, use, dmem0, map->vaddr, set_params);
+		if (r < 0)
+			goto fail;
+	}
+
+	/* Get a new gdc only if a new gdc is given, or none yet */
+	if (bi->info.isp.sp.enable.dvs_6axis) {
+		unsigned int a = IPU3_CSS_AUX_FRAME_REF;
+		unsigned int g = IPU3_CSS_RECT_GDC;
+
+		map = ipu3_css_pool_last(&css->pool.gdc, 0);
+
+		if (set_params && !set_params->use.gdc)
+			set_gdc = NULL;
+		if (set_gdc || !map->vaddr) {
+			if (ipu3_css_pool_get(&css->pool.gdc, css->frame) < 0)
+
+				goto fail;
+			map = ipu3_css_pool_last(&css->pool.gdc, 0);
+			gdc =  map->vaddr;
+			ipu3_css_cfg_gdc_table(gdc,
+					       css->aux_frames[a].bytesperline /
+					       css->aux_frames[a].bytesperpixel,
+					       css->aux_frames[a].height,
+					       css->rect[g].width,
+					       css->rect[g].height);
+		}
+	}
+
+	/* Get a new obgrid only if a new obgrid is given, or none yet */
+	if (set_params && !set_params->use.obgrid)
+		set_obgrid = NULL;
+	if (set_obgrid && obgrid_bytes < obgrid_size / stripes)
+		goto fail;
+	if (set_obgrid || (set_params && set_params->use.obgrid_param) ||
+	    !ipu3_css_pool_last(&css->pool.obgrid, 0)->vaddr) {
+		if (ipu3_css_pool_get(&css->pool.obgrid, css->frame) < 0)
+			goto fail;
+		map = ipu3_css_pool_last(&css->pool.obgrid, 0);
+		obgrid = map->vaddr;
+
+		/* Configure optical black level grid (obgrid) */
+		if (set_obgrid) {
+			for (s = 0; s < stripes; s++)
+				memcpy((void *)obgrid +
+					(obgrid_size / stripes) * s, set_obgrid,
+					obgrid_size / stripes);
+
+		} else if (set_params && set_params->use.obgrid_param) {
+			for (s = 0; s < obgrid_size / sizeof(*obgrid); s++)
+				obgrid[s] = set_params->obgrid_param;
+		} else {
+			memset(obgrid, 0, obgrid_size);
+		}
+	}
+
+	/* Configure parameter set info, queued to `queue_id' */
+
+	memset(param_set, 0, sizeof(*param_set));
+
+	param_set->mem_map.acc_cluster_params_for_sp =
+	    ipu3_css_pool_last(&css->pool.acc, 0)->daddr;
+
+	param_set->mem_map.dvs_6axis_params_y =
+	    ipu3_css_pool_last(&css->pool.gdc, 0)->daddr;
+
+	for (s = 0; s < stripes; s++)
+		param_set->mem_map.obgrid_tbl[s] =
+		    ipu3_css_pool_last(&css->pool.obgrid, 0)->daddr +
+		    (obgrid_size / stripes) * s;
+
+	for (m = 0; m < IMGU_ABI_NUM_MEMORIES; m++)
+		param_set->mem_map.isp_mem_param[stage][m] =
+		    ipu3_css_pool_last(&css->pool.binary_params_p[m], 0)
+		    ->daddr;
+
+	/* Then queue the new parameter buffer */
+	map = ipu3_css_pool_last(&css->pool.parameter_set_info, 0);
+	r = ipu3_css_queue_data(css, queue_id, thread, map->daddr);
+	if (r < 0)
+		goto fail;
+
+	r = ipu3_css_queue_data(css, IMGU_ABI_QUEUE_EVENT_ID, 0,
+				IMGU_ABI_EVENT_BUFFER_ENQUEUED(thread,
+							       queue_id));
+	if (r < 0)
+		goto fail_no_put;
+
+	/* Finally dequeue all old parameter buffers */
+
+	do {
+		u32 daddr;
+
+		r = ipu3_css_dequeue_data(css, queue_id, &daddr);
+		if (r == -EBUSY)
+			break;
+		if (r)
+			goto fail_no_put;
+		r = ipu3_css_queue_data(css, IMGU_ABI_QUEUE_EVENT_ID, thread,
+					IMGU_ABI_EVENT_BUFFER_DEQUEUED
+					(queue_id));
+		if (r < 0) {
+			dev_err(css->dev, "failed to queue parameter event\n");
+			goto fail_no_put;
+		}
+	} while (1);
+
+	return 0;
+
+fail:
+	/*
+	 * A failure, most likely the parameter queue was full.
+	 * Return error but continue streaming. User can try submitting new
+	 * parameters again later.
+	 */
+
+	ipu3_css_pool_put(&css->pool.parameter_set_info);
+	if (acc)
+		ipu3_css_pool_put(&css->pool.acc);
+	if (gdc)
+		ipu3_css_pool_put(&css->pool.gdc);
+	if (obgrid)
+		ipu3_css_pool_put(&css->pool.obgrid);
+	if (vmem0)
+		ipu3_css_pool_put(
+			&css->pool.binary_params_p[IMGU_ABI_MEM_ISP_VMEM0]);
+	if (dmem0)
+		ipu3_css_pool_put(
+			&css->pool.binary_params_p[IMGU_ABI_MEM_ISP_DMEM0]);
+
+fail_no_put:
+	return r;
+}
 
 void ipu3_css_irq_ack(struct ipu3_css *css)
 {
@@ -501,7 +2260,7 @@ void ipu3_css_irq_ack(struct ipu3_css *css)
 					bi->info.sp.output + 4 + 4 * i);
 
 			dev_dbg(css->dev, "%s: swirq %i cnt %i val 0x%x\n",
-				 __func__, i, cnt, val);
+				__func__, i, cnt, val);
 		}
 	}
 
diff --git a/drivers/media/pci/intel/ipu3/ipu3-css.h b/drivers/media/pci/intel/ipu3/ipu3-css.h
index 5b8e92d47f5d..43627df9910d 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-css.h
+++ b/drivers/media/pci/intel/ipu3/ipu3-css.h
@@ -16,6 +16,8 @@
 
 #include <linux/videodev2.h>
 #include <linux/types.h>
+#include <media/v4l2-ctrls.h>
+#include <media/videobuf2-core.h>
 #include "ipu3-abi.h"
 #include "ipu3-css-pool.h"
 
@@ -39,6 +41,12 @@
 #define IPU3_CSS_QUEUE_STAT_LACE	6
 #define IPU3_CSS_QUEUES			7
 
+#define IPU3_CSS_RECT_EFFECTIVE		0       /* Effective resolution */
+#define IPU3_CSS_RECT_BDS		1       /* Resolution after BDS */
+#define IPU3_CSS_RECT_ENVELOPE		2       /* DVS envelope size */
+#define IPU3_CSS_RECT_GDC		3       /* gdc output res */
+#define IPU3_CSS_RECTS			4       /* number of rects */
+
 #define IA_CSS_BINARY_MODE_PRIMARY	2
 #define IA_CSS_BINARY_MODE_VIDEO	3
 
@@ -56,6 +64,33 @@ enum ipu3_css_pipe_id {
 	IPU3_CSS_PIPE_ID_NUM
 };
 
+struct ipu3_css_resolution {
+	u32 w;
+	u32 h;
+};
+
+enum ipu3_css_vf_status {
+	IPU3_NODE_VF_ENABLED,
+	IPU3_NODE_PV_ENABLED,
+	IPU3_NODE_VF_DISABLED
+};
+
+enum ipu3_css_buffer_state {
+	IPU3_CSS_BUFFER_NEW,	/* Not yet queued */
+	IPU3_CSS_BUFFER_QUEUED,	/* Queued, waiting to be filled */
+	IPU3_CSS_BUFFER_DONE,	/* Finished processing, removed from queue */
+	IPU3_CSS_BUFFER_FAILED,	/* Was not processed, removed from queue */
+};
+
+struct ipu3_css_buffer {
+	/* Private fields: user doesn't touch */
+	dma_addr_t daddr;
+	unsigned int queue;
+	enum ipu3_css_buffer_state state;
+	struct list_head list;
+	u8 queue_pos;
+};
+
 struct ipu3_css_format {
 	u32 pixelformat;
 	enum v4l2_colorspace colorspace;
@@ -126,11 +161,65 @@ struct ipu3_css {
 
 	struct ipu3_css_queue queue[IPU3_CSS_QUEUES];
 	struct v4l2_rect rect[IPU3_CSS_RECTS];
+	struct ipu3_css_map abi_buffers[IPU3_CSS_QUEUES]
+				    [IMGU_ABI_HOST2SP_BUFQ_SIZE];
+
+	struct {
+		struct ipu3_css_pool parameter_set_info;
+		struct ipu3_css_pool acc;
+		struct ipu3_css_pool gdc;
+		struct ipu3_css_pool obgrid;
+		/* PARAM_CLASS_PARAM parameters for binding while streaming */
+		struct ipu3_css_pool binary_params_p[IMGU_ABI_NUM_MEMORIES];
+	} pool;
+
+	enum ipu3_css_vf_status vf_output_en;
 };
 
+/******************* css v4l *******************/
+int ipu3_css_init(struct device *dev, struct ipu3_css *css,
+		  void __iomem *base, int length);
+void ipu3_css_cleanup(struct ipu3_css *css);
+int ipu3_css_fmt_try(struct ipu3_css *css,
+		     struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES],
+		     struct v4l2_rect *rects[IPU3_CSS_RECTS]);
+int ipu3_css_fmt_set(struct ipu3_css *css,
+		     struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES],
+		     struct v4l2_rect *rects[IPU3_CSS_RECTS]);
+int ipu3_css_meta_fmt_set(struct v4l2_meta_format *fmt);
+int ipu3_css_buf_queue(struct ipu3_css *css, struct ipu3_css_buffer *b);
+struct ipu3_css_buffer *ipu3_css_buf_dequeue(struct ipu3_css *css);
+int ipu3_css_start_streaming(struct ipu3_css *css);
+void ipu3_css_stop_streaming(struct ipu3_css *css);
+bool ipu3_css_queue_empty(struct ipu3_css *css);
+bool ipu3_css_is_streaming(struct ipu3_css *css);
+
 /******************* css hw *******************/
 int ipu3_css_set_powerup(struct device *dev, void __iomem *base);
 int ipu3_css_set_powerdown(struct device *dev, void __iomem *base);
 void ipu3_css_irq_ack(struct ipu3_css *css);
 
+/******************* set parameters ************/
+int ipu3_css_set_parameters(struct ipu3_css *css,
+		struct ipu3_uapi_params *set_params,
+		struct ipu3_uapi_gdc_warp_param *set_gdc,
+		unsigned int gdc_bytes,
+		struct ipu3_uapi_obgrid_param *set_obgrid,
+		unsigned int obgrid_bytes);
+
+/******************* css misc *******************/
+static inline enum ipu3_css_buffer_state
+ipu3_css_buf_state(struct ipu3_css_buffer *b)
+{
+	return b->state;
+}
+
+/* Initialize given buffer. May be called several times. */
+static inline void ipu3_css_buf_init(struct ipu3_css_buffer *b,
+				     unsigned int queue, dma_addr_t daddr)
+{
+	b->state = IPU3_CSS_BUFFER_NEW;
+	b->queue = queue;
+	b->daddr = daddr;
+}
 #endif
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v4 11/12] intel-ipu3: Add imgu v4l2 driver
  2017-10-18  3:54 [PATCH v4 04/12] intel-ipu3: Add user space ABI definitions Yong Zhi
                   ` (4 preceding siblings ...)
  2017-10-18  3:54 ` [PATCH v4 10/12] intel-ipu3: css pipeline Yong Zhi
@ 2017-10-18  3:54 ` Yong Zhi
  2017-10-20 11:29   ` Sakari Ailus
  2017-10-20  9:30 ` [PATCH v4 04/12] intel-ipu3: Add user space ABI definitions Sakari Ailus
  6 siblings, 1 reply; 19+ messages in thread
From: Yong Zhi @ 2017-10-18  3:54 UTC (permalink / raw)
  To: linux-media, sakari.ailus
  Cc: jian.xu.zheng, rajmohan.mani, tuukka.toivonen, jerry.w.hu,
	Yong Zhi, Ramya Vijaykumar

ipu3 imgu video device based on v4l2, vb2 and
media controller framework.

Signed-off-by: Yong Zhi <yong.zhi@intel.com>
Signed-off-by: Ramya Vijaykumar <ramya.vijaykumar@intel.com>
---
 drivers/media/pci/intel/ipu3/ipu3-v4l2.c | 1150 ++++++++++++++++++++++++++++++
 1 file changed, 1150 insertions(+)
 create mode 100644 drivers/media/pci/intel/ipu3/ipu3-v4l2.c

diff --git a/drivers/media/pci/intel/ipu3/ipu3-v4l2.c b/drivers/media/pci/intel/ipu3/ipu3-v4l2.c
new file mode 100644
index 000000000000..4618880b8675
--- /dev/null
+++ b/drivers/media/pci/intel/ipu3/ipu3-v4l2.c
@@ -0,0 +1,1150 @@
+/*
+ * Copyright (c) 2017 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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/module.h>
+#include <linux/pm_runtime.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-dma-sg.h>
+
+#include "ipu3.h"
+#include "ipu3-dmamap.h"
+
+/******************** v4l2_subdev_ops ********************/
+
+static int ipu3_subdev_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct ipu3_mem2mem2_device *m2m2 =
+		container_of(sd, struct ipu3_mem2mem2_device, subdev);
+	int r = 0;
+
+	if (m2m2->ops && m2m2->ops->s_stream)
+		r = m2m2->ops->s_stream(m2m2, enable);
+
+	if (!r)
+		m2m2->streaming = enable;
+
+	return r;
+}
+
+static int ipu3_subdev_get_fmt(struct v4l2_subdev *sd,
+			       struct v4l2_subdev_pad_config *cfg,
+			       struct v4l2_subdev_format *fmt)
+{
+	struct ipu3_mem2mem2_device *m2m2 =
+		container_of(sd, struct ipu3_mem2mem2_device, subdev);
+	struct v4l2_mbus_framefmt *mf;
+	u32 pad = fmt->pad;
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		fmt->format = m2m2->nodes[pad].pad_fmt;
+	} else {
+		mf = v4l2_subdev_get_try_format(sd, cfg, pad);
+		fmt->format = *mf;
+	}
+
+	return 0;
+}
+
+static int ipu3_subdev_set_fmt(struct v4l2_subdev *sd,
+			       struct v4l2_subdev_pad_config *cfg,
+			       struct v4l2_subdev_format *fmt)
+{
+	struct ipu3_mem2mem2_device *m2m2 =
+		container_of(sd, struct ipu3_mem2mem2_device, subdev);
+	struct v4l2_mbus_framefmt *mf;
+	u32 pad = fmt->pad;
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
+		mf = v4l2_subdev_get_try_format(sd, cfg, pad);
+	else
+		mf = &m2m2->nodes[pad].pad_fmt;
+
+	/* Clamp the w and h based on the hardware capabilities */
+	if (m2m2->subdev_pads[pad].flags & MEDIA_PAD_FL_SOURCE) {
+		fmt->format.width = clamp(fmt->format.width,
+					  IPU3_OUTPUT_MIN_WIDTH,
+					  IPU3_OUTPUT_MAX_WIDTH);
+		fmt->format.height = clamp(fmt->format.height,
+					   IPU3_OUTPUT_MIN_HEIGHT,
+					   IPU3_OUTPUT_MAX_HEIGHT);
+	} else {
+		fmt->format.width = clamp(fmt->format.width,
+					  IPU3_INPUT_MIN_WIDTH,
+					  IPU3_INPUT_MAX_WIDTH);
+		fmt->format.height = clamp(fmt->format.height,
+					   IPU3_INPUT_MIN_HEIGHT,
+					   IPU3_INPUT_MAX_HEIGHT);
+	}
+
+	*mf = fmt->format;
+
+	return 0;
+}
+
+/******************** media_entity_operations ********************/
+
+static int ipu3_link_setup(struct media_entity *entity,
+			   const struct media_pad *local,
+			   const struct media_pad *remote, u32 flags)
+{
+	struct ipu3_mem2mem2_device *m2m2 =
+	    container_of(entity, struct ipu3_mem2mem2_device, subdev.entity);
+	u32 pad = local->index;
+
+	WARN_ON(pad >= m2m2->num_nodes);
+
+	m2m2->nodes[pad].enabled = !!(flags & MEDIA_LNK_FL_ENABLED);
+
+	return 0;
+}
+
+/******************** vb2_ops ********************/
+
+static int ipu3_vb2_buf_init(struct vb2_buffer *vb)
+{
+	struct sg_table *sg = vb2_dma_sg_plane_desc(vb, 0);
+	struct ipu3_mem2mem2_device *m2m2 = vb2_get_drv_priv(vb->vb2_queue);
+	struct imgu_device *imgu =
+		container_of(m2m2, struct imgu_device, mem2mem2);
+	struct imgu_buffer *buf = container_of(vb,
+		struct imgu_buffer, m2m2_buf.vbb.vb2_buf);
+	struct imgu_video_device *node =
+		container_of(vb->vb2_queue, struct imgu_video_device, vbq);
+	int queue = imgu_node_to_queue(node - m2m2->nodes);
+
+	if (queue == IPU3_CSS_QUEUE_PARAMS)
+		return 0;
+
+	return ipu3_dmamap_map_sg(imgu, sg->sgl, sg->nents,
+				  vb->vb2_queue->dma_dir, &buf->map);
+}
+
+/* Called when each buffer is freed */
+static void ipu3_vb2_buf_cleanup(struct vb2_buffer *vb)
+{
+	struct ipu3_mem2mem2_device *m2m2 = vb2_get_drv_priv(vb->vb2_queue);
+	struct imgu_device *imgu =
+		container_of(m2m2, struct imgu_device, mem2mem2);
+	struct imgu_buffer *buf = container_of(vb,
+		struct imgu_buffer, m2m2_buf.vbb.vb2_buf);
+	struct imgu_video_device *node =
+		container_of(vb->vb2_queue, struct imgu_video_device, vbq);
+	int queue = imgu_node_to_queue(node - m2m2->nodes);
+
+	if (queue == IPU3_CSS_QUEUE_PARAMS)
+		return;
+
+	ipu3_dmamap_unmap(imgu, &buf->map);
+}
+
+/* Transfer buffer ownership to me */
+static void ipu3_vb2_buf_queue(struct vb2_buffer *vb)
+{
+	struct ipu3_mem2mem2_device *m2m2 = vb2_get_drv_priv(vb->vb2_queue);
+	struct imgu_device *imgu =
+		container_of(m2m2, struct imgu_device, mem2mem2);
+	struct imgu_video_device *node =
+		container_of(vb->vb2_queue, struct imgu_video_device, vbq);
+	int queue;
+
+	queue = imgu_node_to_queue(node - m2m2->nodes);
+
+	if (queue < 0) {
+		dev_err(&imgu->pci_dev->dev, "Invalid imgu node.\n");
+		return;
+	}
+
+	if (queue == IPU3_CSS_QUEUE_PARAMS) {
+		unsigned long need_bytes = sizeof(struct ipu3_uapi_params);
+		unsigned long payload = vb2_get_plane_payload(vb, 0);
+		struct vb2_v4l2_buffer *buf =
+			container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
+		int r = -EINVAL;
+
+		if (payload == 0) {
+			payload = need_bytes;
+			vb2_set_plane_payload(vb, 0, payload);
+		}
+		if (payload >= need_bytes)
+			r = ipu3_css_set_parameters(&imgu->css,
+						    vb2_plane_vaddr(vb, 0),
+						    NULL, 0, NULL, 0);
+		buf->flags = V4L2_BUF_FLAG_DONE;
+		vb2_buffer_done(vb, r == 0 ? VB2_BUF_STATE_DONE
+					   : VB2_BUF_STATE_ERROR);
+
+	} else {
+		struct imgu_buffer *buf = container_of(vb,
+				struct imgu_buffer, m2m2_buf.vbb.vb2_buf);
+
+		mutex_lock(&imgu->lock);
+		ipu3_css_buf_init(&buf->css_buf, queue, buf->map.daddr);
+		list_add_tail(&buf->m2m2_buf.list,
+			      &m2m2->nodes[node - m2m2->nodes].buffers);
+		mutex_unlock(&imgu->lock);
+
+		if (imgu->mem2mem2.streaming)
+			imgu_queue_buffers(imgu, false);
+	}
+}
+
+static int ipu3_vb2_queue_setup(struct vb2_queue *vq,
+				unsigned int *num_buffers,
+				unsigned int *num_planes,
+				unsigned int sizes[],
+				struct device *alloc_devs[])
+{
+	struct ipu3_mem2mem2_device *m2m2 = vb2_get_drv_priv(vq);
+	struct imgu_video_device *node =
+		container_of(vq, struct imgu_video_device, vbq);
+	const struct v4l2_format *fmt = &node->vdev_fmt;
+
+	*num_planes = 1;
+	*num_buffers = clamp_val(*num_buffers, 1, VB2_MAX_FRAME);
+
+	alloc_devs[0] = m2m2->vb2_alloc_dev;
+
+	if (vq->type == V4L2_BUF_TYPE_META_CAPTURE ||
+	    vq->type == V4L2_BUF_TYPE_META_OUTPUT) {
+		sizes[0] = fmt->fmt.meta.buffersize;
+	} else {
+		sizes[0] = fmt->fmt.pix_mp.plane_fmt[0].sizeimage;
+	}
+
+	/* Initialize buffer queue */
+	INIT_LIST_HEAD(&node->buffers);
+
+	return 0;
+}
+
+/* Check if all enabled video nodes are streaming, exception ignored */
+static bool ipu3_all_nodes_streaming(struct ipu3_mem2mem2_device *m2m2,
+				     struct imgu_video_device *except)
+{
+	int i;
+
+	for (i = 0; i < m2m2->num_nodes; i++) {
+		struct imgu_video_device *node = &m2m2->nodes[i];
+
+		if (node == except)
+			continue;
+		if (node->enabled && !vb2_start_streaming_called(&node->vbq))
+			return false;
+	}
+
+	return true;
+}
+
+static void ipu3_return_all_buffers(struct ipu3_mem2mem2_device *m2m2,
+				    struct imgu_video_device *node,
+				    enum vb2_buffer_state state)
+{
+	struct imgu_device *imgu =
+			container_of(m2m2, struct imgu_device, mem2mem2);
+	struct ipu3_mem2mem2_buffer *b, *b0;
+
+	/* Return all buffers */
+	mutex_lock(&imgu->lock);
+	list_for_each_entry_safe(b, b0, &node->buffers, list) {
+		list_del(&b->list);
+		vb2_buffer_done(&b->vbb.vb2_buf, state);
+	}
+	mutex_unlock(&imgu->lock);
+}
+
+static int ipu3_vb2_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+	struct ipu3_mem2mem2_device *m2m2 = vb2_get_drv_priv(vq);
+	struct imgu_video_device *node =
+		container_of(vq, struct imgu_video_device, vbq);
+	int r;
+
+	if (m2m2->streaming) {
+		r = -EBUSY;
+		goto fail_return_bufs;
+	}
+
+	if (!node->enabled) {
+		r = -EINVAL;
+		goto fail_return_bufs;
+	}
+
+	r = media_pipeline_start(&node->vdev.entity, &m2m2->pipeline);
+	if (r < 0)
+		goto fail_return_bufs;
+
+	if (!ipu3_all_nodes_streaming(m2m2, node))
+		return 0;
+
+	/* Start streaming of the whole pipeline now */
+
+	r = v4l2_subdev_call(&m2m2->subdev, video, s_stream, 1);
+	if (r < 0)
+		goto fail_stop_pipeline;
+
+	return 0;
+
+fail_stop_pipeline:
+	media_pipeline_stop(&node->vdev.entity);
+fail_return_bufs:
+	ipu3_return_all_buffers(m2m2, node, VB2_BUF_STATE_QUEUED);
+
+	return r;
+}
+
+static void ipu3_vb2_stop_streaming(struct vb2_queue *vq)
+{
+	struct ipu3_mem2mem2_device *m2m2 = vb2_get_drv_priv(vq);
+	struct imgu_video_device *node =
+		container_of(vq, struct imgu_video_device, vbq);
+	int r;
+
+	WARN_ON(!node->enabled);
+
+	/* Was this the first node with streaming disabled? */
+	if (ipu3_all_nodes_streaming(m2m2, node)) {
+		/* Yes, really stop streaming now */
+		r = v4l2_subdev_call(&m2m2->subdev, video, s_stream, 0);
+		if (r)
+			dev_err(m2m2->dev, "failed to stop streaming\n");
+	}
+
+	ipu3_return_all_buffers(m2m2, node, VB2_BUF_STATE_ERROR);
+	media_pipeline_stop(&node->vdev.entity);
+}
+
+/******************** v4l2_ioctl_ops ********************/
+
+#define M2M_CAPTURE	0
+#define M2M_OUTPUT	1
+
+struct ipu3_fmt {
+	u32	fourcc;
+	u16	types; /* M2M_CAPTURE or M2M_OUTPUT not both */
+};
+
+/* format descriptions for capture and preview */
+static const struct ipu3_fmt formats[] = {
+	{
+		.fourcc	= V4L2_PIX_FMT_NV12,
+		/* Capture format */
+		.types	= M2M_CAPTURE,
+	}, {
+		.fourcc	= V4L2_PIX_FMT_IPU3_SBGGR10,
+		/* Output format */
+		.types	= M2M_OUTPUT,
+	}, {
+		.fourcc	= V4L2_PIX_FMT_IPU3_SGBRG10,
+		.types	= M2M_OUTPUT,
+	}, {
+		.fourcc	= V4L2_PIX_FMT_IPU3_SGRBG10,
+		.types	= M2M_OUTPUT,
+	}, {
+		.fourcc	= V4L2_PIX_FMT_IPU3_SRGGB10,
+		.types	= M2M_OUTPUT,
+	},
+};
+
+/* Find the first matched format, return default if not found */
+static const struct ipu3_fmt *find_format(struct v4l2_format *f, u32 type)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(formats); i++) {
+		if (formats[i].fourcc == f->fmt.pix_mp.pixelformat &&
+		    formats[i].types == type)
+			return &formats[i];
+	}
+
+	return type == M2M_CAPTURE ? &formats[0] :
+			&formats[ARRAY_SIZE(formats) - 1];
+}
+
+static int ipu3_videoc_querycap(struct file *file, void *fh,
+				struct v4l2_capability *cap)
+{
+	struct ipu3_mem2mem2_device *m2m2 = video_drvdata(file);
+	struct imgu_video_device *node = file_to_intel_ipu3_node(file);
+
+	strlcpy(cap->driver, m2m2->name, sizeof(cap->driver));
+	strlcpy(cap->card, m2m2->model, sizeof(cap->card));
+	snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", node->name);
+
+	return 0;
+}
+
+static int enum_fmts(struct v4l2_fmtdesc *f, u32 type)
+{
+	unsigned int i, j;
+
+	for (i = j = 0; i < ARRAY_SIZE(formats); ++i) {
+		if (formats[i].types == type) {
+			if (j == f->index)
+				break;
+			++j;
+		}
+	}
+
+	if (i < ARRAY_SIZE(formats)) {
+		f->pixelformat = formats[i].fourcc;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+				   struct v4l2_fmtdesc *f)
+{
+	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		return -EINVAL;
+
+	return enum_fmts(f, M2M_CAPTURE);
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
+				   struct v4l2_fmtdesc *f)
+{
+	if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		return -EINVAL;
+
+	return enum_fmts(f, M2M_OUTPUT);
+}
+
+/* Propagate forward always the format from the CIO2 subdev */
+static int ipu3_videoc_g_fmt(struct file *file, void *fh,
+			     struct v4l2_format *f)
+{
+	struct imgu_video_device *node = file_to_intel_ipu3_node(file);
+
+	f->fmt = node->vdev_fmt.fmt;
+
+	return 0;
+}
+
+/*
+ * Set input/output format. Unless it is just a try, this also resets
+ * selections (ie. effective and BDS resolutions) to defaults.
+ */
+static int mem2mem2_fmt(struct ipu3_mem2mem2_device *m2m2_dev,
+			int node, struct v4l2_format *f, bool try)
+{
+	struct imgu_device *imgu =
+		container_of(m2m2_dev, struct imgu_device, mem2mem2);
+	struct v4l2_pix_format_mplane try_fmts[IPU3_CSS_QUEUES];
+	struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES] = { NULL };
+	struct v4l2_rect *rects[IPU3_CSS_RECTS] = { NULL };
+	unsigned int i;
+	int css_q, r;
+	struct v4l2_mbus_framefmt pad_fmt;
+
+	if (m2m2_dev->nodes[IMGU_NODE_PV].enabled &&
+	    m2m2_dev->nodes[IMGU_NODE_VF].enabled) {
+		dev_err(&imgu->pci_dev->dev,
+			"Postview and vf are not supported simultaneously\n");
+		return -EINVAL;
+	}
+	/*
+	 * Tell css that the vf q is used for PV
+	 */
+	if (m2m2_dev->nodes[IMGU_NODE_PV].enabled)
+		imgu->css.vf_output_en = IPU3_NODE_PV_ENABLED;
+	else
+		imgu->css.vf_output_en = IPU3_NODE_VF_ENABLED;
+
+	for (i = 0; i < IPU3_CSS_QUEUES; i++) {
+		int inode = imgu_map_node(imgu, i);
+
+		if (inode < 0)
+			return -EINVAL;
+
+		/* Skip the meta node */
+		if (inode == IMGU_NODE_STAT_3A || inode == IMGU_NODE_STAT_DVS ||
+		    inode == IMGU_NODE_STAT_LACE || inode == IMGU_NODE_PARAMS)
+			continue;
+
+		if (try) {
+			try_fmts[i] =
+				m2m2_dev->nodes[inode].vdev_fmt.fmt.pix_mp;
+			fmts[i] = &try_fmts[i];
+		} else {
+			fmts[i] = &m2m2_dev->nodes[inode].vdev_fmt.fmt.pix_mp;
+		}
+
+		/* CSS expects some format on OUT queue */
+		if (i != IPU3_CSS_QUEUE_OUT &&
+		    !m2m2_dev->nodes[inode].enabled && inode != node)
+			fmts[i] = NULL;
+	}
+
+	if (!try) {
+		/* eff and bds res got by m2m2_s_sel */
+		rects[IPU3_CSS_RECT_EFFECTIVE] = &imgu->rect.eff;
+		rects[IPU3_CSS_RECT_BDS] = &imgu->rect.bds;
+		rects[IPU3_CSS_RECT_GDC] = &imgu->rect.gdc;
+
+		/* suppose that pad fmt was set by subdev s_fmt before */
+		pad_fmt = m2m2_dev->nodes[IMGU_NODE_IN].pad_fmt;
+		rects[IPU3_CSS_RECT_GDC]->width = pad_fmt.width;
+		rects[IPU3_CSS_RECT_GDC]->height = pad_fmt.height;
+	}
+
+	/*
+	 * ipu3_mem2mem2 doesn't set the node to the value given by user
+	 * before we return success from this function, so set it here.
+	 */
+	css_q = imgu_node_to_queue(node);
+	if (fmts[css_q])
+		*fmts[css_q] = f->fmt.pix_mp;
+
+	if (try)
+		r = ipu3_css_fmt_try(&imgu->css, fmts, rects);
+	else
+		r = ipu3_css_fmt_set(&imgu->css, fmts, rects);
+
+	/* r is the binary number in the firmware blob */
+	if (r < 0)
+		return r;
+
+	if (try)
+		f->fmt.pix_mp = *fmts[css_q];
+	else
+		f->fmt = m2m2_dev->nodes[node].vdev_fmt.fmt;
+
+	return 0;
+}
+
+static int mem2mem2_s_selection(struct ipu3_mem2mem2_device *m2m2_dev,
+				int node, struct v4l2_selection *s)
+{
+	struct imgu_device *const imgu =
+		container_of(m2m2_dev, struct imgu_device, mem2mem2);
+	struct v4l2_rect *rect = NULL;
+
+	if (node != IPU3_CSS_QUEUE_IN)
+		return -ENOIOCTLCMD;
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_CROP:
+		rect = &imgu->rect.eff;
+		break;
+	case V4L2_SEL_TGT_COMPOSE:
+		rect = &imgu->rect.bds;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*rect = s->r;
+
+	return 0;
+}
+
+static int mem2mem2_g_selection(struct ipu3_mem2mem2_device *m2m2_dev,
+				int node, struct v4l2_selection *s)
+{
+	struct imgu_device *const imgu =
+		container_of(m2m2_dev, struct imgu_device, mem2mem2);
+
+	if (node != IPU3_CSS_QUEUE_IN)
+		return -ENOIOCTLCMD;
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_CROP:
+		s->r = imgu->rect.eff;
+		break;
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		break;
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+		break;
+	case V4L2_SEL_TGT_COMPOSE_PADDED:
+		break;
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+		break;
+	case V4L2_SEL_TGT_COMPOSE:
+		s->r = imgu->rect.bds;
+		break;
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ipu3_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
+{
+	struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
+	const struct ipu3_fmt *fmt;
+
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		fmt = find_format(f, M2M_CAPTURE);
+	else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+		fmt = find_format(f, M2M_OUTPUT);
+	else
+		return -EINVAL;
+
+	pixm->pixelformat = fmt->fourcc;
+
+	memset(pixm->plane_fmt[0].reserved, 0,
+	       sizeof(pixm->plane_fmt[0].reserved));
+
+	return 0;
+}
+
+static int ipu3_videoc_try_fmt(struct file *file, void *fh,
+			       struct v4l2_format *f)
+{
+	struct ipu3_mem2mem2_device *m2m2 = video_drvdata(file);
+	struct imgu_video_device *node = file_to_intel_ipu3_node(file);
+	int r;
+
+	r = ipu3_try_fmt(file, fh, f);
+	if (r)
+		return r;
+
+	return mem2mem2_fmt(m2m2, node - m2m2->nodes, f, true);
+}
+
+static int ipu3_videoc_s_fmt(struct file *file, void *fh,
+			     struct v4l2_format *f)
+{
+	struct ipu3_mem2mem2_device *m2m2 = video_drvdata(file);
+	struct imgu_video_device *node = file_to_intel_ipu3_node(file);
+	int r;
+
+	r = ipu3_try_fmt(file, fh, f);
+	if (r)
+		return r;
+
+	return mem2mem2_fmt(m2m2, node - m2m2->nodes, f, false);
+}
+
+static int ipu3_videoc_s_selection(struct file *file, void *fh,
+				   struct v4l2_selection *s)
+{
+	struct ipu3_mem2mem2_device *m2m2 = video_drvdata(file);
+	struct imgu_video_device *node = file_to_intel_ipu3_node(file);
+
+	if (!m2m2->ops)
+		return -ENOIOCTLCMD;
+
+	if (s->type != node->vdev_fmt.type)
+		return -EINVAL;
+
+	return mem2mem2_s_selection(m2m2, node - m2m2->nodes, s);
+}
+
+static int ipu3_videoc_g_selection(struct file *file, void *fh,
+				   struct v4l2_selection *s)
+{
+	struct ipu3_mem2mem2_device *m2m2 = video_drvdata(file);
+	struct imgu_video_device *node = file_to_intel_ipu3_node(file);
+
+	if (!m2m2->ops)
+		return -ENOIOCTLCMD;
+
+	if (s->type != node->vdev_fmt.type)
+		return -EINVAL;
+
+	return mem2mem2_g_selection(m2m2, node - m2m2->nodes, s);
+}
+
+static int ipu3_vidioc_enum_input(struct file *file, void *fh,
+				  struct v4l2_input *input)
+{
+	if (input->index > 0)
+		return -EINVAL;
+	strlcpy(input->name, "camera", sizeof(input->name));
+	input->type = V4L2_INPUT_TYPE_CAMERA;
+
+	return 0;
+}
+
+static int ipu3_vidioc_g_input(struct file *file, void *fh, unsigned int *input)
+{
+	*input = 0;
+
+	return 0;
+}
+
+static int ipu3_vidioc_s_input(struct file *file, void *fh,
+			       unsigned int input)
+{
+	return input == 0 ? 0 : -EINVAL;
+}
+
+static int ipu3_vidioc_enum_output(struct file *file, void *fh,
+				   struct v4l2_output *output)
+{
+	if (output->index > 0)
+		return -EINVAL;
+	strlcpy(output->name, "camera", sizeof(output->name));
+	output->type = V4L2_INPUT_TYPE_CAMERA;
+
+	return 0;
+}
+
+static int ipu3_vidioc_g_output(struct file *file, void *fh,
+				unsigned int *output)
+{
+	*output = 0;
+
+	return 0;
+}
+
+static int ipu3_vidioc_s_output(struct file *file, void *fh,
+				unsigned int output)
+{
+	return output == 0 ? 0 : -EINVAL;
+}
+
+static int ipu3_meta_enum_format(struct file *file, void *fh,
+				 struct v4l2_fmtdesc *f)
+{
+	struct imgu_video_device *node = file_to_intel_ipu3_node(file);
+
+	/* Each node is dedicated to only one meta format */
+	if (f->index > 0 || f->type != node->vbq.type)
+		return -EINVAL;
+
+	f->pixelformat = node->vdev_fmt.fmt.meta.dataformat;
+
+	return 0;
+}
+
+static int ipu3_videoc_g_meta_fmt(struct file *file, void *fh,
+				  struct v4l2_format *f)
+{
+	struct imgu_video_device *node = file_to_intel_ipu3_node(file);
+
+	if (f->type != node->vbq.type)
+		return -EINVAL;
+
+	f->fmt = node->vdev_fmt.fmt;
+
+	return 0;
+}
+
+/******************** function pointers ********************/
+
+static const struct v4l2_subdev_video_ops ipu3_subdev_video_ops = {
+	.s_stream = ipu3_subdev_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops ipu3_subdev_pad_ops = {
+	.link_validate = v4l2_subdev_link_validate_default,
+	.get_fmt = ipu3_subdev_get_fmt,
+	.set_fmt = ipu3_subdev_set_fmt,
+};
+
+static const struct v4l2_subdev_ops ipu3_subdev_ops = {
+	.video = &ipu3_subdev_video_ops,
+	.pad = &ipu3_subdev_pad_ops,
+};
+
+static const struct media_entity_operations ipu3_media_ops = {
+	.link_setup = ipu3_link_setup,
+	.link_validate = v4l2_subdev_link_validate,
+};
+
+/****************** vb2_ops of the Q ********************/
+
+static const struct vb2_ops ipu3_vb2_ops = {
+	.buf_init = ipu3_vb2_buf_init,
+	.buf_cleanup = ipu3_vb2_buf_cleanup,
+	.buf_queue = ipu3_vb2_buf_queue,
+	.queue_setup = ipu3_vb2_queue_setup,
+	.start_streaming = ipu3_vb2_start_streaming,
+	.stop_streaming = ipu3_vb2_stop_streaming,
+	.wait_prepare = vb2_ops_wait_prepare,
+	.wait_finish = vb2_ops_wait_finish,
+};
+
+/****************** v4l2_file_operations *****************/
+
+static const struct v4l2_file_operations ipu3_v4l2_fops = {
+	.unlocked_ioctl = video_ioctl2,
+	.open = v4l2_fh_open,
+	.release = vb2_fop_release,
+	.poll = vb2_fop_poll,
+	.mmap = vb2_fop_mmap,
+};
+
+/******************** v4l2_ioctl_ops ********************/
+
+static const struct v4l2_ioctl_ops ipu3_v4l2_ioctl_ops = {
+	.vidioc_querycap = ipu3_videoc_querycap,
+
+	.vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap_mplane = ipu3_videoc_g_fmt,
+	.vidioc_s_fmt_vid_cap_mplane = ipu3_videoc_s_fmt,
+	.vidioc_try_fmt_vid_cap_mplane = ipu3_videoc_try_fmt,
+
+	.vidioc_s_selection = ipu3_videoc_s_selection,
+	.vidioc_g_selection = ipu3_videoc_g_selection,
+
+	.vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out,
+	.vidioc_g_fmt_vid_out_mplane = ipu3_videoc_g_fmt,
+	.vidioc_s_fmt_vid_out_mplane = ipu3_videoc_s_fmt,
+	.vidioc_try_fmt_vid_out_mplane = ipu3_videoc_try_fmt,
+
+	.vidioc_enum_output = ipu3_vidioc_enum_output,
+	.vidioc_g_output = ipu3_vidioc_g_output,
+	.vidioc_s_output = ipu3_vidioc_s_output,
+
+	.vidioc_enum_input = ipu3_vidioc_enum_input,
+	.vidioc_g_input = ipu3_vidioc_g_input,
+	.vidioc_s_input = ipu3_vidioc_s_input,
+
+	/* buffer queue management */
+	.vidioc_reqbufs = vb2_ioctl_reqbufs,
+	.vidioc_create_bufs = vb2_ioctl_create_bufs,
+	.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+	.vidioc_querybuf = vb2_ioctl_querybuf,
+	.vidioc_qbuf = vb2_ioctl_qbuf,
+	.vidioc_dqbuf = vb2_ioctl_dqbuf,
+	.vidioc_streamon = vb2_ioctl_streamon,
+	.vidioc_streamoff = vb2_ioctl_streamoff,
+	.vidioc_expbuf = vb2_ioctl_expbuf,
+};
+
+static const struct v4l2_ioctl_ops ipu3_v4l2_meta_ioctl_ops = {
+	.vidioc_querycap = ipu3_videoc_querycap,
+
+	/* meta capture */
+	.vidioc_enum_fmt_meta_cap = ipu3_meta_enum_format,
+	.vidioc_g_fmt_meta_cap = ipu3_videoc_g_meta_fmt,
+	.vidioc_s_fmt_meta_cap = ipu3_videoc_g_meta_fmt,
+	.vidioc_try_fmt_meta_cap = ipu3_videoc_g_meta_fmt,
+
+	/* meta output */
+	.vidioc_enum_fmt_meta_out = ipu3_meta_enum_format,
+	.vidioc_g_fmt_meta_out = ipu3_videoc_g_meta_fmt,
+	.vidioc_s_fmt_meta_out = ipu3_videoc_g_meta_fmt,
+	.vidioc_try_fmt_meta_out = ipu3_videoc_g_meta_fmt,
+
+	.vidioc_reqbufs = vb2_ioctl_reqbufs,
+	.vidioc_create_bufs = vb2_ioctl_create_bufs,
+	.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+	.vidioc_querybuf = vb2_ioctl_querybuf,
+	.vidioc_qbuf = vb2_ioctl_qbuf,
+	.vidioc_dqbuf = vb2_ioctl_dqbuf,
+	.vidioc_streamon = vb2_ioctl_streamon,
+	.vidioc_streamoff = vb2_ioctl_streamoff,
+	.vidioc_expbuf = vb2_ioctl_expbuf,
+};
+
+/******************** Framework registration ********************/
+
+/* helper function to config node's video properties */
+static void ipu3_node_to_v4l2(u32 node, struct video_device *vdev,
+			      struct v4l2_format *f)
+{
+	u32 cap;
+
+	/* Should not happen */
+	WARN_ON(node >= IMGU_NODE_NUM);
+
+	switch (node) {
+	case IMGU_NODE_IN:
+		cap = V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+		f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+		vdev->ioctl_ops = &ipu3_v4l2_ioctl_ops;
+		break;
+	case IMGU_NODE_PARAMS:
+		cap = V4L2_CAP_META_OUTPUT;
+		f->type = V4L2_BUF_TYPE_META_OUTPUT;
+		f->fmt.meta.dataformat = V4L2_META_FMT_IPU3_PARAMS;
+		vdev->ioctl_ops = &ipu3_v4l2_meta_ioctl_ops;
+		ipu3_css_meta_fmt_set(&f->fmt.meta);
+		break;
+	case IMGU_NODE_STAT_3A:
+		cap = V4L2_CAP_META_CAPTURE;
+		f->type = V4L2_BUF_TYPE_META_CAPTURE;
+		f->fmt.meta.dataformat = V4L2_META_FMT_IPU3_STAT_3A;
+		vdev->ioctl_ops = &ipu3_v4l2_meta_ioctl_ops;
+		ipu3_css_meta_fmt_set(&f->fmt.meta);
+		break;
+	case IMGU_NODE_STAT_DVS:
+		cap = V4L2_CAP_META_CAPTURE;
+		f->type = V4L2_BUF_TYPE_META_CAPTURE;
+		f->fmt.meta.dataformat = V4L2_META_FMT_IPU3_STAT_DVS;
+		vdev->ioctl_ops = &ipu3_v4l2_meta_ioctl_ops;
+		ipu3_css_meta_fmt_set(&f->fmt.meta);
+		break;
+	case IMGU_NODE_STAT_LACE:
+		cap = V4L2_CAP_META_CAPTURE;
+		f->type = V4L2_BUF_TYPE_META_CAPTURE;
+		f->fmt.meta.dataformat = V4L2_META_FMT_IPU3_STAT_LACE;
+		vdev->ioctl_ops = &ipu3_v4l2_meta_ioctl_ops;
+		ipu3_css_meta_fmt_set(&f->fmt.meta);
+		break;
+	default:
+		cap = V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+		f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+		vdev->ioctl_ops = &ipu3_v4l2_ioctl_ops;
+	}
+
+	vdev->device_caps = V4L2_CAP_STREAMING | cap;
+}
+
+int ipu3_v4l2_register(struct imgu_device *dev)
+{
+	struct ipu3_mem2mem2_device *m2m2 = &dev->mem2mem2;
+	struct v4l2_mbus_framefmt def_bus_fmt;
+	struct v4l2_pix_format_mplane def_pix_fmt;
+
+	int i, r;
+
+	/* Initialize miscellaneous variables */
+	m2m2->streaming = false;
+	m2m2->v4l2_file_ops = ipu3_v4l2_fops;
+
+	/* Set up media device */
+	m2m2->media_dev.dev = m2m2->dev;
+	strlcpy(m2m2->media_dev.model, m2m2->model,
+		sizeof(m2m2->media_dev.model));
+	snprintf(m2m2->media_dev.bus_info, sizeof(m2m2->media_dev.bus_info),
+		 "%s", dev_name(m2m2->dev));
+	m2m2->media_dev.hw_revision = 0;
+	media_device_init(&m2m2->media_dev);
+	r = media_device_register(&m2m2->media_dev);
+	if (r) {
+		dev_err(m2m2->dev, "failed to register media device (%d)\n", r);
+		goto fail_media_dev;
+	}
+
+	/* Set up v4l2 device */
+	m2m2->v4l2_dev.mdev = &m2m2->media_dev;
+	m2m2->v4l2_dev.ctrl_handler = m2m2->ctrl_handler;
+	r = v4l2_device_register(m2m2->dev, &m2m2->v4l2_dev);
+	if (r) {
+		dev_err(m2m2->dev, "failed to register V4L2 device (%d)\n", r);
+		goto fail_v4l2_dev;
+	}
+
+	/* Initialize subdev media entity */
+	m2m2->subdev_pads = kzalloc(sizeof(*m2m2->subdev_pads) *
+					m2m2->num_nodes, GFP_KERNEL);
+	if (!m2m2->subdev_pads) {
+		r = -ENOMEM;
+		goto fail_subdev_pads;
+	}
+
+	r = media_entity_pads_init(&m2m2->subdev.entity, m2m2->num_nodes,
+				   m2m2->subdev_pads);
+	if (r) {
+		dev_err(m2m2->dev,
+			"failed initialize subdev media entity (%d)\n", r);
+		goto fail_media_entity;
+	}
+	m2m2->subdev.entity.ops = &ipu3_media_ops;
+	for (i = 0; i < m2m2->num_nodes; i++) {
+		m2m2->subdev_pads[i].flags = m2m2->nodes[i].output ?
+			MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
+	}
+
+	/* Initialize subdev */
+	v4l2_subdev_init(&m2m2->subdev, &ipu3_subdev_ops);
+	m2m2->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(m2m2->subdev.name, sizeof(m2m2->subdev.name),
+		 "%s", m2m2->name);
+	v4l2_set_subdevdata(&m2m2->subdev, m2m2);
+	m2m2->subdev.ctrl_handler = m2m2->ctrl_handler;
+	r = v4l2_device_register_subdev(&m2m2->v4l2_dev, &m2m2->subdev);
+	if (r) {
+		dev_err(m2m2->dev, "failed initialize subdev (%d)\n", r);
+		goto fail_subdev;
+	}
+	r = v4l2_device_register_subdev_nodes(&m2m2->v4l2_dev);
+	if (r) {
+		dev_err(m2m2->dev, "failed to register subdevs (%d)\n", r);
+		goto fail_subdevs;
+	}
+
+	/* Initialize formats to default values */
+	def_bus_fmt.width = 1920;
+	def_bus_fmt.height = 1080;
+	def_bus_fmt.code = MEDIA_BUS_FMT_UYVY8_2X8;
+	def_bus_fmt.field = V4L2_FIELD_NONE;
+	def_bus_fmt.colorspace = V4L2_COLORSPACE_RAW;
+	def_bus_fmt.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+	def_bus_fmt.quantization = V4L2_QUANTIZATION_DEFAULT;
+	def_bus_fmt.xfer_func = V4L2_XFER_FUNC_DEFAULT;
+
+	def_pix_fmt.width = def_bus_fmt.width;
+	def_pix_fmt.height = def_bus_fmt.height;
+	def_pix_fmt.field = def_bus_fmt.field;
+	def_pix_fmt.num_planes = 1;
+	def_pix_fmt.plane_fmt[0].bytesperline = def_pix_fmt.width * 2;
+	def_pix_fmt.plane_fmt[0].sizeimage =
+		def_pix_fmt.height * def_pix_fmt.plane_fmt[0].bytesperline;
+	def_pix_fmt.flags = 0;
+	def_pix_fmt.colorspace = def_bus_fmt.colorspace;
+	def_pix_fmt.ycbcr_enc = def_bus_fmt.ycbcr_enc;
+	def_pix_fmt.quantization = def_bus_fmt.quantization;
+	def_pix_fmt.xfer_func = def_bus_fmt.xfer_func;
+
+	/* Create video nodes and links */
+	for (i = 0; i < m2m2->num_nodes; i++) {
+		struct imgu_video_device *node = &m2m2->nodes[i];
+		struct video_device *vdev = &node->vdev;
+		struct vb2_queue *vbq = &node->vbq;
+		u32 flags;
+
+		/* Initialize miscellaneous variables */
+		mutex_init(&node->lock);
+		INIT_LIST_HEAD(&node->buffers);
+
+		/* Initialize formats to default values */
+		node->pad_fmt = def_bus_fmt;
+		ipu3_node_to_v4l2(i, vdev, &node->vdev_fmt);
+		if (node->vdev_fmt.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ||
+		    node->vdev_fmt.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+			def_pix_fmt.pixelformat = node->output ?
+						V4L2_PIX_FMT_IPU3_SGRBG10 :
+						V4L2_PIX_FMT_NV12;
+			node->vdev_fmt.fmt.pix_mp = def_pix_fmt;
+		}
+
+		/* Initialize media entities */
+		r = media_entity_pads_init(&vdev->entity, 1, &node->vdev_pad);
+		if (r) {
+			dev_err(m2m2->dev,
+				"failed initialize media entity (%d)\n", r);
+			goto fail_vdev_media_entity;
+		}
+		node->vdev_pad.flags = node->output ?
+			MEDIA_PAD_FL_SOURCE : MEDIA_PAD_FL_SINK;
+		vdev->entity.ops = NULL;
+
+		/* Initialize vbq */
+		vbq->type = node->vdev_fmt.type;
+		vbq->io_modes = VB2_USERPTR | VB2_MMAP | VB2_DMABUF;
+		vbq->ops = &ipu3_vb2_ops;
+		vbq->mem_ops = m2m2->vb2_mem_ops;
+		if (m2m2->buf_struct_size <= 0)
+			m2m2->buf_struct_size =
+				sizeof(struct ipu3_mem2mem2_buffer);
+		vbq->buf_struct_size = m2m2->buf_struct_size;
+		vbq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+		vbq->min_buffers_needed = 0;	/* Can streamon w/o buffers */
+		vbq->drv_priv = m2m2;
+		vbq->lock = &node->lock;
+		r = vb2_queue_init(vbq);
+		if (r) {
+			dev_err(m2m2->dev,
+				"failed to initialize video queue (%d)\n", r);
+			goto fail_vdev;
+		}
+
+		/* Initialize vdev */
+		strlcpy(vdev->name, node->name, sizeof(vdev->name));
+		vdev->release = video_device_release_empty;
+		vdev->fops = &m2m2->v4l2_file_ops;
+		vdev->lock = &node->lock;
+		vdev->v4l2_dev = &m2m2->v4l2_dev;
+		vdev->queue = &node->vbq;
+		vdev->vfl_dir = node->output ? VFL_DIR_TX : VFL_DIR_RX;
+		video_set_drvdata(vdev, m2m2);
+		r = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+		if (r) {
+			dev_err(m2m2->dev,
+				"failed to register video device (%d)\n", r);
+			goto fail_vdev;
+		}
+
+		/* Create link between video node and the subdev pad */
+		flags = 0;
+		if (node->enabled)
+			flags |= MEDIA_LNK_FL_ENABLED;
+		if (node->immutable)
+			flags |= MEDIA_LNK_FL_IMMUTABLE;
+		if (node->output) {
+			r = media_create_pad_link(
+						 &vdev->entity, 0,
+						 &m2m2->subdev.entity,
+						 i, flags);
+		} else {
+			r = media_create_pad_link(
+						 &m2m2->subdev.entity,
+						 i, &vdev->entity, 0,
+						 flags);
+		}
+		if (r)
+			goto fail_link;
+	}
+
+	return 0;
+
+	for (; i >= 0; i--) {
+fail_link:
+		video_unregister_device(&m2m2->nodes[i].vdev);
+fail_vdev:
+		media_entity_cleanup(&m2m2->nodes[i].vdev.entity);
+fail_vdev_media_entity:
+		mutex_destroy(&m2m2->nodes[i].lock);
+	}
+fail_subdevs:
+	v4l2_device_unregister_subdev(&m2m2->subdev);
+fail_subdev:
+	media_entity_cleanup(&m2m2->subdev.entity);
+fail_media_entity:
+	kfree(m2m2->subdev_pads);
+fail_subdev_pads:
+	v4l2_device_unregister(&m2m2->v4l2_dev);
+fail_v4l2_dev:
+	media_device_unregister(&m2m2->media_dev);
+	media_device_cleanup(&m2m2->media_dev);
+fail_media_dev:
+
+	return r;
+}
+EXPORT_SYMBOL_GPL(ipu3_v4l2_register);
+
+int ipu3_v4l2_unregister(struct imgu_device *dev)
+{
+	struct ipu3_mem2mem2_device *m2m2 = &dev->mem2mem2;
+	unsigned int i;
+
+	for (i = 0; i < m2m2->num_nodes; i++) {
+		video_unregister_device(&m2m2->nodes[i].vdev);
+		media_entity_cleanup(&m2m2->nodes[i].vdev.entity);
+		mutex_destroy(&m2m2->nodes[i].lock);
+	}
+
+	v4l2_device_unregister_subdev(&m2m2->subdev);
+	media_entity_cleanup(&m2m2->subdev.entity);
+	kfree(m2m2->subdev_pads);
+	v4l2_device_unregister(&m2m2->v4l2_dev);
+	media_device_unregister(&m2m2->media_dev);
+	media_device_cleanup(&m2m2->media_dev);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu3_v4l2_unregister);
+
+void ipu3_v4l2_buffer_done(struct vb2_buffer *vb,
+			   enum vb2_buffer_state state)
+{
+	struct ipu3_mem2mem2_buffer *b =
+		container_of(vb, struct ipu3_mem2mem2_buffer, vbb.vb2_buf);
+
+	list_del(&b->list);
+	vb2_buffer_done(&b->vbb.vb2_buf, state);
+}
+EXPORT_SYMBOL_GPL(ipu3_v4l2_buffer_done);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH v4 04/12] intel-ipu3: Add user space ABI definitions
  2017-10-18  3:54 [PATCH v4 04/12] intel-ipu3: Add user space ABI definitions Yong Zhi
                   ` (5 preceding siblings ...)
  2017-10-18  3:54 ` [PATCH v4 11/12] intel-ipu3: Add imgu v4l2 driver Yong Zhi
@ 2017-10-20  9:30 ` Sakari Ailus
  2017-11-11  4:07   ` Mani, Rajmohan
  6 siblings, 1 reply; 19+ messages in thread
From: Sakari Ailus @ 2017-10-20  9:30 UTC (permalink / raw)
  To: Yong Zhi
  Cc: linux-media, sakari.ailus, jian.xu.zheng, rajmohan.mani,
	tuukka.toivonen, jerry.w.hu

Hi Yong,

On Tue, Oct 17, 2017 at 10:54:49PM -0500, Yong Zhi wrote:
> The UAPI header defines the structures and macros
> to be used by user space.
> 
> Signed-off-by: Rajmohan Mani <rajmohan.mani@intel.com>
> Signed-off-by: Yong Zhi <yong.zhi@intel.com>
> ---
>  include/uapi/linux/intel-ipu3.h | 2199 +++++++++++++++++++++++++++++++++++++++
>  1 file changed, 2199 insertions(+)
>  create mode 100644 include/uapi/linux/intel-ipu3.h
> 
> diff --git a/include/uapi/linux/intel-ipu3.h b/include/uapi/linux/intel-ipu3.h
> new file mode 100644
> index 000000000000..e27a449b4ec1
> --- /dev/null
> +++ b/include/uapi/linux/intel-ipu3.h
> @@ -0,0 +1,2199 @@
> +/*
> + * Copyright (c) 2017 Intel Corporation.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License version
> + * 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that 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 __IPU3_UAPI_H
> +#define __IPU3_UAPI_H
> +
> +#include <linux/types.h>
> +
> +#define IPU3_UAPI_ISP_VEC_ELEMS				64
> +
> +#define IMGU_ABI_PAD	__aligned(IPU3_UAPI_ISP_WORD_BYTES)
> +#define IPU3_ALIGN	__attribute__((aligned(IPU3_UAPI_ISP_WORD_BYTES)))
> +
> +#define IPU3_UAPI_ISP_WORD_BYTES			32
> +#define IPU3_UAPI_MAX_STRIPES				2
> +
> +/******************* ipu3_uapi_stats_3a *******************/
> +
> +#define IPU3_UAPI_MAX_BUBBLE_SIZE			10
> +
> +#define IPU3_UAPI_AE_COLORS				4
> +#define IPU3_UAPI_AE_BINS				256
> +
> +#define IPU3_UAPI_AWB_MD_ITEM_SIZE			8
> +#define IPU3_UAPI_AWB_MAX_SETS				60
> +#define IPU3_UAPI_AWB_SET_SIZE				0x500
> +#define IPU3_UAPI_AWB_SPARE_FOR_BUBBLES \
> +		(IPU3_UAPI_MAX_BUBBLE_SIZE * IPU3_UAPI_MAX_STRIPES * \
> +		 IPU3_UAPI_AWB_MD_ITEM_SIZE)
> +#define IPU3_UAPI_AWB_MAX_BUFFER_SIZE \
> +		(IPU3_UAPI_AWB_MAX_SETS * \
> +		 (IPU3_UAPI_AWB_SET_SIZE + IPU3_UAPI_AWB_SPARE_FOR_BUBBLES))
> +
> +#define IPU3_UAPI_AF_MAX_SETS				24
> +#define IPU3_UAPI_AF_MD_ITEM_SIZE			4
> +#define IPU3_UAPI_AF_SPARE_FOR_BUBBLES \
> +		(IPU3_UAPI_MAX_BUBBLE_SIZE * IPU3_UAPI_MAX_STRIPES * \
> +		 IPU3_UAPI_AF_MD_ITEM_SIZE)
> +#define IPU3_UAPI_AF_Y_TABLE_SET_SIZE			0x80
> +#define IPU3_UAPI_AF_Y_TABLE_MAX_SIZE \
> +	(IPU3_UAPI_AF_MAX_SETS * \
> +	 (IPU3_UAPI_AF_Y_TABLE_SET_SIZE + IPU3_UAPI_AF_SPARE_FOR_BUBBLES) * \
> +	 IPU3_UAPI_MAX_STRIPES)
> +
> +#define IPU3_UAPI_AWB_FR_MAX_SETS			24
> +#define IPU3_UAPI_AWB_FR_MD_ITEM_SIZE			8
> +#define IPU3_UAPI_AWB_FR_BAYER_TBL_SIZE			0x100
> +#define IPU3_UAPI_AWB_FR_SPARE_FOR_BUBBLES \
> +		(IPU3_UAPI_MAX_BUBBLE_SIZE * IPU3_UAPI_MAX_STRIPES * \
> +		IPU3_UAPI_AWB_FR_MD_ITEM_SIZE)
> +#define IPU3_UAPI_AWB_FR_BAYER_TABLE_MAX_SIZE \
> +	(IPU3_UAPI_AWB_FR_MAX_SETS * \
> +	(IPU3_UAPI_AWB_FR_BAYER_TBL_SIZE + \
> +	 IPU3_UAPI_AWB_FR_SPARE_FOR_BUBBLES) * \
> +	IPU3_UAPI_MAX_STRIPES)
> +
> +struct ipu3_uapi_grid_config {
> +	__u8 width;				/* 6 or 7 (rgbs_grd_cfg) bits */
> +	__u8 height;
> +	__u16 block_width_log2:3;
> +	__u16 block_height_log2:3;
> +	__u16 height_per_slice:8;			/* default value 1 */
> +	__u16 x_start;					/* 12 bits */
> +	__u16 y_start;
> +#define IPU3_UAPI_GRID_START_MASK			((1 << 12) - 1)
> +#define IPU3_UAPI_GRID_Y_START_EN			(1 << 15)
> +	__u16 x_end;					/* 12 bits */
> +	__u16 y_end;
> +} __packed;
> +
> +struct ipu3_uapi_awb_meta_data {
> +	__u8 meta_data_buffer[IPU3_UAPI_AWB_MAX_BUFFER_SIZE];
> +} __packed;
> +
> +struct ipu3_uapi_awb_raw_buffer {
> +	struct ipu3_uapi_awb_meta_data meta_data;
> +} __packed;
> +
> +struct IPU3_ALIGN ipu3_uapi_awb_config_s {
> +	__u16 rgbs_thr_gr;
> +	__u16 rgbs_thr_r;
> +	__u16 rgbs_thr_gb;
> +	__u16 rgbs_thr_b;
> +/* controls generation of meta_data (like FF enable/disable) */
> +#define IPU3_UAPI_AWB_RGBS_THR_B_EN		(1 << 14)
> +#define IPU3_UAPI_AWB_RGBS_THR_B_INCL_SAT	(1 << 15)
> +
> +	struct ipu3_uapi_grid_config grid;
> +} __packed;
> +
> +struct ipu3_uapi_ae_raw_buffer {
> +	__u32 vals[IPU3_UAPI_AE_BINS * IPU3_UAPI_AE_COLORS];
> +} __packed;
> +
> +struct ipu3_uapi_ae_raw_buffer_aligned {
> +	struct ipu3_uapi_ae_raw_buffer buff IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_ae_grid_config {
> +	__u8 width;
> +	__u8 height;
> +	__u8 block_width_log2:4;
> +	__u8 block_height_log2:4;
> +	__u8 __reserved0:5;
> +	__u8 ae_en:1;
> +	__u8 rst_hist_array:1;
> +	__u8 done_rst_hist_array:1;
> +	__u16 x_start;			/* 12 bits */
> +	__u16 y_start;
> +	__u16 x_end;
> +	__u16 y_end;
> +} __packed;
> +
> +struct ipu3_uapi_af_filter_config {
> +	struct {
> +		__u8 a1;
> +		__u8 a2;
> +		__u8 a3;
> +		__u8 a4;
> +	} y1_coeff_0;
> +	struct {
> +		__u8 a5;
> +		__u8 a6;
> +		__u8 a7;
> +		__u8 a8;
> +	} y1_coeff_1;
> +	struct {
> +		__u8 a9;
> +		__u8 a10;
> +		__u8 a11;
> +		__u8 a12;
> +	} y1_coeff_2;
> +
> +	__u32 y1_sign_vec;
> +
> +	struct {
> +		__u8 a1;
> +		__u8 a2;
> +		__u8 a3;
> +		__u8 a4;
> +	} y2_coeff_0;
> +	struct {
> +		__u8 a5;
> +		__u8 a6;
> +		__u8 a7;
> +		__u8 a8;
> +	} y2_coeff_1;
> +	struct {
> +		__u8 a9;
> +		__u8 a10;
> +		__u8 a11;
> +		__u8 a12;
> +	} y2_coeff_2;
> +
> +	__u32 y2_sign_vec;
> +
> +	struct {
> +		__u8 y_gen_rate_gr;	/* 6 bits */
> +		__u8 y_gen_rate_r;
> +		__u8 y_gen_rate_b;
> +		__u8 y_gen_rate_gb;
> +	} y_calc;
> +
> +	struct {
> +		__u32 __reserved0:8;
> +		__u32 y1_nf:4;
> +		__u32 __reserved1:4;
> +		__u32 y2_nf:4;
> +		__u32 __reserved2:12;
> +	} nf;
> +} __packed;
> +
> +struct ipu3_uapi_af_meta_data {
> +	__u8 y_table[IPU3_UAPI_AF_Y_TABLE_MAX_SIZE] IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_af_raw_buffer {
> +	struct ipu3_uapi_af_meta_data meta_data IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_af_frame_size {
> +	__u16 width;
> +	__u16 height;
> +} __packed;
> +
> +struct ipu3_uapi_af_config_s {
> +	struct ipu3_uapi_af_filter_config filter_config IPU3_ALIGN;
> +	struct ipu3_uapi_af_frame_size frame_size;
> +	struct ipu3_uapi_grid_config grid_cfg IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_awb_fr_meta_data {
> +	__u8 bayer_table[IPU3_UAPI_AWB_FR_BAYER_TABLE_MAX_SIZE] IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_awb_fr_raw_buffer {
> +	struct ipu3_uapi_awb_fr_meta_data meta_data;
> +} __packed;
> +
> +struct IPU3_ALIGN ipu3_uapi_awb_fr_config_s {
> +	struct ipu3_uapi_grid_config grid_cfg;
> +	__u8 bayer_coeff[6];
> +	__u16 __reserved1;
> +	__u32 bayer_sign;		/* 11 bits */
> +	__u8 bayer_nf;			/* 4 bits */
> +	__u8 __reserved2[3];
> +} __packed;
> +
> +struct ipu3_uapi_4a_config {
> +	struct ipu3_uapi_awb_config_s awb_config IPU3_ALIGN;
> +	struct ipu3_uapi_ae_grid_config ae_grd_config IPU3_ALIGN;
> +	__u8 padding[20];
> +	struct ipu3_uapi_af_config_s af_config IPU3_ALIGN;
> +	struct ipu3_uapi_awb_fr_config_s awb_fr_config IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_bubble_info {
> +	__u32 num_of_stripes IPU3_ALIGN;
> +	__u8 padding[28];
> +	__u32 num_sets IPU3_ALIGN;
> +	__u8 padding1[28];
> +	__u32 size_of_set IPU3_ALIGN;
> +	__u8 padding2[28];
> +	__u32 bubble_size IPU3_ALIGN;
> +	__u8 padding3[28];
> +} __packed;
> +
> +struct ipu3_uapi_stats_3a_bubble_info_per_stripe {
> +	struct ipu3_uapi_bubble_info awb[IPU3_UAPI_MAX_STRIPES];
> +	struct ipu3_uapi_bubble_info af[IPU3_UAPI_MAX_STRIPES];
> +	struct ipu3_uapi_bubble_info awb_fr[IPU3_UAPI_MAX_STRIPES];
> +} __packed;
> +
> +struct ipu3_uapi_ff_status {
> +	__u32 awb_en IPU3_ALIGN;
> +	__u8 padding[28];
> +	__u32 ae_en IPU3_ALIGN;
> +	__u8 padding1[28];
> +	__u32 af_en IPU3_ALIGN;
> +	__u8 padding2[28];
> +	__u32 awb_fr_en IPU3_ALIGN;
> +	__u8 padding3[28];
> +} __packed;
> +
> +struct ipu3_uapi_stats_3a {
> +	struct ipu3_uapi_awb_raw_buffer awb_raw_buffer IPU3_ALIGN;
> +	struct ipu3_uapi_ae_raw_buffer_aligned
> +			ae_raw_buffer[IPU3_UAPI_MAX_STRIPES] IPU3_ALIGN;
> +	struct ipu3_uapi_af_raw_buffer af_raw_buffer IPU3_ALIGN;
> +	struct ipu3_uapi_awb_fr_raw_buffer awb_fr_raw_buffer IPU3_ALIGN;
> +	struct ipu3_uapi_4a_config stats_4a_config IPU3_ALIGN;
> +	__u32 ae_join_buffers IPU3_ALIGN;
> +	__u8 padding[28];
> +	struct ipu3_uapi_stats_3a_bubble_info_per_stripe
> +			stats_3a_bubble_per_stripe IPU3_ALIGN;
> +	struct ipu3_uapi_ff_status stats_3a_status IPU3_ALIGN;
> +} __packed;
> +
> +/******************* ipu3_uapi_stats_dvs *******************/
> +
> +#define IPU3_UAPI_DVS_STAT_LEVELS			3
> +#define IPU3_UAPI_DVS_STAT_L0_MV_VEC_PER_SET		12
> +#define IPU3_UAPI_DVS_STAT_L1_MV_VEC_PER_SET		11
> +#define IPU3_UAPI_DVS_STAT_L2_MV_VEC_PER_SET		9
> +#define IPU3_UAPI_DVS_STAT_STRIPE_ALIGN_GAP		IPU3_UAPI_MAX_STRIPES
> +#define IPU3_UAPI_DVS_STAT_MAX_VERTICAL_FEATURES		16
> +
> +struct ipu3_uapi_dvs_stat_mv {
> +	__u16 vec_fe_x_pos;		/* 12 bits */
> +	__u16 vec_fe_y_pos;
> +	__u16 vec_fm_x_pos;		/* 12 bits */
> +	__u16 vec_fm_y_pos;
> +	__u32 harris_grade;		/* 28 bits */
> +	__u16 match_grade;		/* 15 bits */
> +	__u16 level;			/* 3 bits */
> +} __packed;
> +
> +struct ipu3_uapi_dvs_stat_mv_single_set_l0 {
> +	struct ipu3_uapi_dvs_stat_mv
> +		mv_entry[IPU3_UAPI_DVS_STAT_L0_MV_VEC_PER_SET +
> +		IPU3_UAPI_DVS_STAT_STRIPE_ALIGN_GAP] IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_dvs_stat_mv_single_set_l1 {
> +	struct ipu3_uapi_dvs_stat_mv
> +		mv_entry[IPU3_UAPI_DVS_STAT_L1_MV_VEC_PER_SET +
> +		IPU3_UAPI_DVS_STAT_STRIPE_ALIGN_GAP] IPU3_ALIGN;
> +	__u8 padding[16];
> +} __packed;
> +
> +struct ipu3_uapi_dvs_stat_mv_single_set_l2 {
> +	struct ipu3_uapi_dvs_stat_mv
> +		mv_entry[IPU3_UAPI_DVS_STAT_L2_MV_VEC_PER_SET +
> +		IPU3_UAPI_DVS_STAT_STRIPE_ALIGN_GAP] IPU3_ALIGN;
> +	__u8 padding[16];
> +} __packed;
> +
> +struct ipu3_uapi_dvs_stat_motion_vec {
> +	struct ipu3_uapi_dvs_stat_mv_single_set_l0
> +		dvs_mv_output_l0[IPU3_UAPI_DVS_STAT_MAX_VERTICAL_FEATURES]
> +		IPU3_ALIGN;
> +	struct ipu3_uapi_dvs_stat_mv_single_set_l1
> +		dvs_mv_output_l1[IPU3_UAPI_DVS_STAT_MAX_VERTICAL_FEATURES]
> +		IPU3_ALIGN;
> +	struct ipu3_uapi_dvs_stat_mv_single_set_l2
> +		dvs_mv_output_l2[IPU3_UAPI_DVS_STAT_MAX_VERTICAL_FEATURES]
> +		IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_dvs_stat_stripe_data {
> +	__u8 grid_width[IPU3_UAPI_MAX_STRIPES][IPU3_UAPI_DVS_STAT_LEVELS];
> +	__u16 stripe_offset;
> +} __packed;
> +
> +struct ipu3_uapi_dvs_stat_gbl_config {
> +	__u8 kappa;					/* 4 bits */
> +	__u8 match_shift:4;
> +	__u8 ybin_mode:1;
> +	__u16 __reserved1;
> +} __packed;
> +
> +struct ipu3_uapi_dvs_stat_grd_config {
> +	__u8 grid_width;				/* 5 bits */
> +	__u8 grid_height;
> +	__u8 block_width;				/* 8 bits */
> +	__u8 block_height;
> +	__u16 x_start;					/* 12 bits */
> +	__u16 y_start;
> +	__u16 enable;
> +	__u16 x_end;					/* 12 bits */
> +	__u16 y_end;
> +} __packed;
> +
> +struct ipu3_uapi_dvs_stat_fe_roi_cfg {
> +	__u8 x_start;
> +	__u8 y_start;
> +	__u8 x_end;
> +	__u8 y_end;
> +} __packed;
> +
> +struct ipu3_uapi_dvs_stat_cfg {
> +	struct ipu3_uapi_dvs_stat_gbl_config gbl_cfg;
> +	struct ipu3_uapi_dvs_stat_grd_config
> +					grd_config[IPU3_UAPI_DVS_STAT_LEVELS];
> +	struct ipu3_uapi_dvs_stat_fe_roi_cfg
> +					fe_roi_cfg[IPU3_UAPI_DVS_STAT_LEVELS];
> +	__u8 __reserved[IPU3_UAPI_ISP_WORD_BYTES -
> +		 (sizeof(struct ipu3_uapi_dvs_stat_gbl_config) +
> +		  (sizeof(struct ipu3_uapi_dvs_stat_grd_config) +
> +		   sizeof(struct ipu3_uapi_dvs_stat_fe_roi_cfg)) *
> +		  IPU3_UAPI_DVS_STAT_LEVELS) % IPU3_UAPI_ISP_WORD_BYTES];
> +} __packed;
> +
> +struct ipu3_uapi_stats_dvs {
> +	struct ipu3_uapi_dvs_stat_motion_vec motion_vec IPU3_ALIGN;
> +	struct ipu3_uapi_dvs_stat_cfg cfg IPU3_ALIGN;
> +	struct ipu3_uapi_dvs_stat_stripe_data stripe_data IPU3_ALIGN;
> +} __packed;
> +
> +/******************* ipu3_uapi_stats_lace *******************/
> +
> +#define IPU3_UAPI_LACE_STAT_REGS_PER_SET		320
> +#define IPU3_UAPI_LACE_STAT_MAX_OPERATIONS		41
> +
> +struct ipu3_uapi_lace_stat_stats_regs {
> +	__u8 bin[4];					/* the bins 0-3 */
> +} __packed;
> +
> +struct ipu3_uapi_lace_stat_hist_single_set {
> +	struct ipu3_uapi_lace_stat_stats_regs
> +		lace_hist_set[IPU3_UAPI_LACE_STAT_REGS_PER_SET] IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_lace_stat_hist_vec {
> +	struct ipu3_uapi_lace_stat_hist_single_set
> +	       lace_hist_output[IPU3_UAPI_LACE_STAT_MAX_OPERATIONS] IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_lace_stat_gbl_cfg {
> +	__u32 lh_mode:3;
> +	__u32 __reserved:3;
> +	__u32 y_ds_mode:2;
> +	__u32 uv_ds_mode_unsupported:1;
> +	__u32 uv_input_unsupported:1;
> +	__u32 __reserved1:10;
> +	__u32 rst_loc_hist:1;
> +	__u32 done_rst_loc_hist:1;
> +	__u32 __reserved2:10;
> +} __packed;
> +
> +struct ipu3_uapi_lace_stat_y_grd_hor_cfg {
> +	__u32 grid_width:6;
> +	__u32 __reserved:10;
> +	__u32 block_width:4;
> +	__u32 __reserved1:12;
> +} __packed;
> +
> +struct ipu3_uapi_lace_stat_y_grd_hor_roi {
> +	__u32 x_start:12;
> +	__u32 __reserved:4;
> +	__u32 x_end:12;
> +	__u32 __reserved1:4;
> +} __packed;
> +
> +struct ipu3_uapi_lace_stat_uv_grd_hor_cfg {
> +	__u32 not_supported;
> +} __packed;
> +
> +struct ipu3_uapi_lace_stat_uv_grd_hor_roi {
> +	__u32 not_supported;
> +} __packed;
> +
> +struct ipu3_uapi_lace_stat_grd_vrt_cfg {
> +	__u32 __reserved:8;
> +	__u32 grid_h:6;
> +	__u32 __reserved1:6;
> +	__u32 block_h:4;
> +	__u32 grid_h_per_slice:7;
> +	__u32 __reserved2:1;
> +} __packed;
> +
> +struct ipu3_uapi_lace_stat_grd_vrt_roi {
> +	__u32 y_start:12;
> +	__u32 __reserved:4;
> +	__u32 y_end:12;
> +	__u32 __reserved1:4;
> +} __packed;
> +
> +struct ipu3_uapi_lace_stat_cfg {
> +	struct ipu3_uapi_lace_stat_gbl_cfg lace_stat_gbl_cfg;
> +	struct ipu3_uapi_lace_stat_y_grd_hor_cfg lace_stat_y_grd_hor_cfg;
> +	struct ipu3_uapi_lace_stat_y_grd_hor_roi lace_stat_y_grd_hor_roi;
> +	struct ipu3_uapi_lace_stat_uv_grd_hor_cfg lace_stat_uv_grd_hor_cfg;
> +	struct ipu3_uapi_lace_stat_uv_grd_hor_roi lace_stat_uv_grd_hor_roi;
> +	struct ipu3_uapi_lace_stat_grd_vrt_cfg lace_stat_grd_vrt_cfg;
> +	struct ipu3_uapi_lace_stat_grd_vrt_roi lace_stat_grd_vrt_roi;
> +} __packed;
> +
> +struct ipu3_uapi_stats_lace {
> +	struct ipu3_uapi_lace_stat_hist_vec lace_hist_vec IPU3_ALIGN;
> +	struct ipu3_uapi_lace_stat_cfg lace_stat_cfg IPU3_ALIGN;
> +	__u8 padding[4];
> +} __packed;
> +
> +/******************* ipu3_uapi_acc_param *******************/
> +
> +#define IPU3_UAPI_BNR_LUT_SIZE				32
> +
> +/* number of elements in gamma correction LUT */
> +#define IPU3_UAPI_GAMMA_CORR_LUT_ENTRIES		256
> +
> +#define IPU3_UAPI_SHD_MAX_OPERATIONS \
> +		(IPU3_UAPI_SHD_MAX_PROCESS_LINES + IPU3_UAPI_SHD_MAX_TRANSFERS)
> +#define IPU3_UAPI_SHD_MAX_PROCESS_LINES			31
> +#define IPU3_UAPI_SHD_MAX_TRANSFERS			31
> +#define IPU3_UAPI_SHD_MAX_CELLS_PER_SET			146
> +/* largest grid is 73x56 */
> +#define IPU3_UAPI_SHD_MAX_CFG_SETS			28
> +
> +#define IPU3_UAPI_DVS_STAT_L0_MD_ENTRIES		84
> +#define IPU3_UAPI_DVS_STAT_PARTS_IN_MD_ENTRY		10
> +#define IPU3_UAPI_DVS_STAT_L1_MD_ENTRIES		66
> +#define IPU3_UAPI_DVS_STAT_L2_MD_ENTRIES		45
> +#define IPU3_UAPI_DVS_STAT_MAX_OPERATIONS		100
> +#define IPU3_UAPI_DVS_STAT_MAX_PROCESS_LINES		52
> +#define IPU3_UAPI_DVS_STAT_MAX_TRANSFERS		52
> +
> +#define IPU3_UAPI_YUVP2_YTM_LUT_ENTRIES			256
> +#define IPU3_UAPI_YUVP2_TCC_MACC_TABLE_ELEMENTS		16
> +#define IPU3_UAPI_YUVP2_TCC_INV_Y_LUT_ELEMENTS		14
> +#define IPU3_UAPI_YUVP2_TCC_GAIN_PCWL_LUT_ELEMENTS	258
> +#define IPU3_UAPI_YUVP2_TCC_R_SQR_LUT_ELEMENTS		24
> +
> +#define IPU3_UAPI_DPC_COMMANDS_PER_TRANSFER		2
> +#define IPU3_UAPI_DPC_MAX_SUPPORTED_HEIGHT		3840
> +#define IPU3_UAPI_DPC_STRIPE_SIZE			50
> +#define IPU3_UAPI_DPC_MAX_OPERATIONS \
> +	(IPU3_UAPI_DPC_COMMANDS_PER_TRANSFER * IPU3_UAPI_DPC_MAX_CFG_SETS)
> +#define IPU3_UAPI_DPC_MAX_PROCESS_LINES		IPU3_UAPI_DPC_MAX_CFG_SETS
> +#define IPU3_UAPI_DPC_MAX_TRANSFERS		IPU3_UAPI_DPC_MAX_CFG_SETS
> +#define IPU3_UAPI_DPC_MAX_DP_FIRST_LINES_PAIR		70
> +#define IPU3_UAPI_DPC_MAX_DP_PER_SET			192
> +#define IPU3_UAPI_DPC_MAX_CFG_SETS \
> +	((IPU3_UAPI_DPC_MAX_SUPPORTED_HEIGHT + IPU3_UAPI_DPC_STRIPE_SIZE - 1) \
> +	/ IPU3_UAPI_DPC_STRIPE_SIZE)
> +
> +#define IPU3_UAPI_BDS_SAMPLE_PATTERN_ARRAY_SIZE		8
> +#define IPU3_UAPI_BDS_PHASE_COEFFS_ARRAY_SIZE		32
> +
> +#define IPU3_UAPI_ANR_LUT_SIZE				26
> +#define IPU3_UAPI_ANR_PYRAMID_SIZE			22
> +
> +#define IPU3_UAPI_AWB_FR_MAX_TRANSFERS			30
> +#define IPU3_UAPI_AWB_FR_MAX_PROCESS_LINES		30
> +#define IPU3_UAPI_AWB_FR_MAX_OPERATIONS \
> +	(IPU3_UAPI_AWB_FR_MAX_TRANSFERS + IPU3_UAPI_AWB_FR_MAX_PROCESS_LINES)
> +
> +#define IPU3_UAPI_AE_WEIGHTS				96
> +
> +#define IPU3_UAPI_AF_MAX_TRANSFERS			30
> +#define IPU3_UAPI_AF_MAX_PROCESS_LINES			30
> +#define IPU3_UAPI_AF_MAX_OPERATIONS \
> +		(IPU3_UAPI_AF_MAX_TRANSFERS + IPU3_UAPI_AF_MAX_PROCESS_LINES)
> +
> +#define IPU3_UAPI_AWB_MAX_PROCESS_LINES			68
> +#define IPU3_UAPI_AWB_MAX_TRANSFERS			68
> +#define IPU3_UAPI_AWB_MAX_OPERATIONS \
> +		(IPU3_UAPI_AWB_MAX_PROCESS_LINES + IPU3_UAPI_AWB_MAX_TRANSFERS)
> +
> +#define IPU3_UAPI_OSYS_PIN_VF				0
> +#define IPU3_UAPI_OSYS_PIN_OUT				1
> +#define IPU3_UAPI_OSYS_PINS				2
> +
> +typedef __u32 imgu_addr_t;
> +
> +struct ipu3_uapi_stripe_input_frame_resolution {
> +	__u16 width;
> +	__u16 height;
> +	__u32 bayer_order;		/* enum ipu3_uapi_bayer_order */
> +	__u32 raw_bit_depth;
> +} __packed;
> +
> +struct ipu3_uapi_acc_operation {
> +	/*
> +	 * zero means on init,
> +	 * others mean upon receiving an ack signal from the BC acc.
> +	 */
> +	__u8 op_indicator;
> +	__u8 op_type;
> +} __packed;
> +
> +struct ipu3_uapi_acc_process_lines_cmd_data {
> +	__u16 lines;
> +	__u8 cfg_set;
> +	__u8 __reserved;		/* Align to 4 bytes */
> +} __packed;
> +
> +struct ipu3_uapi_stripes {
> +	/* offset from start of frame - measured in pixels */
> +	__u16 offset;
> +	/* stripe width - measured in pixels */
> +	__u16 width;
> +	/* stripe width - measured in pixels */
> +	__u16 height;
> +} __packed;
> +
> +struct ipu3_uapi_stripe_data {
> +	/*
> +	 * number of stripes for current processing source
> +	 * - VLIW binary parameter we currently support 1 or 2 stripes
> +	 */
> +	__u16 num_of_stripes;
> +
> +	__u8 padding[2];
> +
> +	/*
> +	 * the following data is derived from resolution-related
> +	 * pipe config and from num_of_stripes
> +	 */
> +
> +	/*
> +	 *'input-stripes' - before input cropping
> +	 * used by input feeder
> +	 */
> +	struct ipu3_uapi_stripe_input_frame_resolution input_frame;
> +
> +	/*'effective-stripes' - after input cropping used dpc, bds */
> +	struct ipu3_uapi_stripes effective_stripes[IPU3_UAPI_MAX_STRIPES];
> +
> +	/* 'down-scaled-stripes' - after down-scaling ONLY. used by BDS */
> +	struct ipu3_uapi_stripes down_scaled_stripes[IPU3_UAPI_MAX_STRIPES];
> +
> +	/*
> +	 *'bds-out-stripes' - after bayer down-scaling and padding.
> +	 * used by all algos starting with norm up to the ref-frame for GDC
> +	 * (currently up to the output kernel)
> +	 */
> +	struct ipu3_uapi_stripes bds_out_stripes[IPU3_UAPI_MAX_STRIPES];
> +
> +	/* 'bds-out-stripes (no overlap)' - used for ref kernel */
> +	struct ipu3_uapi_stripes
> +			bds_out_stripes_no_overlap[IPU3_UAPI_MAX_STRIPES];
> +
> +	/*
> +	 * input resolution for output system (equal to bds_out - envelope)
> +	 * output-system input frame width as configured by user
> +	 */
> +	__u16 output_system_in_frame_width;
> +	/* output-system input frame height as configured by user */
> +	__u16 output_system_in_frame_height;
> +
> +	/*
> +	 * 'output-stripes' - accounts for stiching on the output (no overlap)
> +	 * used by the output kernel
> +	 */
> +	struct ipu3_uapi_stripes output_stripes[IPU3_UAPI_MAX_STRIPES];
> +
> +	/*
> +	 * 'block-stripes' - accounts for stiching by the output system
> +	 * (1 or more blocks overlap)
> +	 * used by DVS, TNR and the output system kernel
> +	 */
> +	struct ipu3_uapi_stripes block_stripes[IPU3_UAPI_MAX_STRIPES];
> +
> +	__u16 effective_frame_width;	/* Needed for vertical cropping */
> +	__u16 bds_frame_width;
> +	__u16 out_frame_width;	/* Output frame width as configured by user */
> +	__u16 out_frame_height;	/* Output frame height as configured by user */
> +
> +	/* GDC in buffer (A.K.A delay frame,ref buffer) info */
> +	__u16 gdc_in_buffer_width;	/* GDC in buffer width  */
> +	__u16 gdc_in_buffer_height;	/* GDC in buffer height */
> +	/* GDC in buffer first valid pixel x offset */
> +	__u16 gdc_in_buffer_offset_x;
> +	/* GDC in buffer first valid pixel y offset */
> +	__u16 gdc_in_buffer_offset_y;
> +
> +	/* Display frame width as configured by user */
> +	__u16 display_frame_width;
> +	/* Display frame height as configured by user */
> +	__u16 display_frame_height;
> +	__u16 bds_aligned_frame_width;
> +	/* Number of vectors to left-crop when writing stripes (not stripe 0) */
> +	__u16 half_overlap_vectors;
> +	/* Decimate ISP and fixed func resolutions after BDS (ir_extraction) */
> +	__u16 ir_ext_decimation;
> +	__u8 padding1[2];
> +} __packed;
> +
> +struct ipu3_uapi_input_feeder_data {
> +	__u32 row_stride;				/* row stride */
> +	__u32 start_row_address;			/* start row address */
> +	__u32 start_pixel;				/* start pixel */
> +} __packed;
> +
> +struct ipu3_uapi_input_feeder_data_aligned {
> +	struct ipu3_uapi_input_feeder_data data IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_input_feeder_data_per_stripe {
> +	struct ipu3_uapi_input_feeder_data_aligned
> +		input_feeder_data[IPU3_UAPI_MAX_STRIPES];
> +} __packed;
> +
> +struct ipu3_uapi_input_feeder_config {
> +	struct ipu3_uapi_input_feeder_data data;
> +	struct ipu3_uapi_input_feeder_data_per_stripe data_per_stripe
> +		IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_bnr_static_config_wb_gains_config {
> +	__u16 gr;
> +	__u16 r;
> +	__u16 b;
> +	__u16 gb;
> +} __packed;
> +
> +struct ipu3_uapi_bnr_static_config_wb_gains_thr_config {
> +	__u8 gr;
> +	__u8 r;
> +	__u8 b;
> +	__u8 gb;
> +} __packed;
> +
> +struct ipu3_uapi_bnr_static_config_thr_coeffs_config {
> +	__u32 cf:13;
> +	__u32 __reserved0:3;
> +	__u32 cg:5;
> +	__u32 ci:5;
> +	__u32 __reserved1:1;
> +	__u32 r_nf:5;
> +} __packed;
> +
> +struct ipu3_uapi_bnr_static_config_thr_ctrl_shd_config {
> +	__u8 gr;
> +	__u8 r;
> +	__u8 b;
> +	__u8 gb;
> +} __packed;
> +
> +struct ipu3_uapi_bnr_static_config_opt_center_config {
> +	__s32 x_reset:13;
> +	__u32 __reserved0:3;
> +	__s32 y_reset:13;
> +	__u32 __reserved2:3;
> +} __packed;
> +
> +struct ipu3_uapi_bnr_static_config_lut_config {
> +	__u8 values[IPU3_UAPI_BNR_LUT_SIZE];
> +} __packed;
> +
> +struct ipu3_uapi_bnr_static_config_bp_ctrl_config {
> +	__u32 bp_thr_gain:5;
> +	__u32 __reserved0:2;
> +	__u32 defect_mode:1;
> +	__u32 bp_gain:6;
> +	__u32 __reserved1:18;
> +	__u32 w0_coeff:4;
> +	__u32 __reserved2:4;
> +	__u32 w1_coeff:4;
> +	__u32 __reserved3:20;
> +} __packed;
> +
> +struct ipu3_uapi_bnr_static_config_dn_detect_ctrl_config {
> +	__u32 alpha:4;
> +	__u32 beta:4;
> +	__u32 gamma:4;
> +	__u32 __reserved0:4;
> +	__u32 max_inf:4;
> +	__u32 __reserved1:7;
> +	/* aka 'green disparity enable' */
> +	__u32 gd_enable:1;
> +	__u32 bpc_enable:1;
> +	__u32 bnr_enable:1;
> +	__u32 ff_enable:1;
> +	__u32 __reserved2:1;
> +} __packed;
> +
> +struct ipu3_uapi_bnr_static_config_opt_center_sqr_config {
> +	__u32 x_sqr_reset;
> +	__u32 y_sqr_reset;
> +} __packed;
> +
> +struct ipu3_uapi_bnr_static_config {
> +	struct ipu3_uapi_bnr_static_config_wb_gains_config wb_gains;
> +	struct ipu3_uapi_bnr_static_config_wb_gains_thr_config wb_gains_thr;
> +	struct ipu3_uapi_bnr_static_config_thr_coeffs_config thr_coeffs;
> +	struct ipu3_uapi_bnr_static_config_thr_ctrl_shd_config thr_ctrl_shd;
> +	struct ipu3_uapi_bnr_static_config_opt_center_config opt_center;
> +	struct ipu3_uapi_bnr_static_config_lut_config lut;
> +	struct ipu3_uapi_bnr_static_config_bp_ctrl_config bp_ctrl;
> +	struct ipu3_uapi_bnr_static_config_dn_detect_ctrl_config dn_detect_ctrl;
> +	__u32 column_size;				/* 0x44 */
> +	struct ipu3_uapi_bnr_static_config_opt_center_sqr_config opt_center_sqr;
> +} __packed;
> +
> +struct ipu3_uapi_bnr_static_config_green_disparity {
> +	__u32 gd_red:6;
> +	__u32 __reserved0:2;
> +	__u32 gd_green:6;
> +	__u32 __reserved1:2;
> +	__u32 gd_blue:6;
> +	__u32 __reserved2:10;
> +	__u32 gd_black:14;
> +	__u32 __reserved3:2;
> +	__u32 gd_shading:7;
> +	__u32 __reserved4:1;
> +	__u32 gd_support:2;
> +	__u32 __reserved5:1;
> +	__u32 gd_clip:1;			/* central weights variables */
> +	__u32 gd_central_weight:4;
> +} __packed;
> +
> +struct ipu3_uapi_dm_config {
> +	/* DWORD0 */
> +	__u32 dm_en:1;
> +	__u32 ch_ar_en:1;
> +	__u32 fcc_en:1;
> +	__u32 __reserved0:13;
> +	__u32 frame_width:16;
> +
> +	/* DWORD1 */
> +	__u32 gamma_sc:5;
> +	__u32 __reserved1:3;
> +	__u32 lc_ctrl:5;
> +	__u32 __reserved2:3;
> +	__u32 cr_param1:5;
> +	__u32 __reserved3:3;
> +	__u32 cr_param2:5;
> +	__u32 __reserved4:3;
> +
> +	/* DWORD2 */
> +	__u32 coring_param:5;
> +	__u32 __reserved5:27;
> +} __packed;
> +
> +struct ipu3_uapi_ccm_mat_config {
> +	__s16 coeff_m11;
> +	__s16 coeff_m12;
> +	__s16 coeff_m13;
> +	__s16 coeff_o_r;
> +	__s16 coeff_m21;
> +	__s16 coeff_m22;
> +	__s16 coeff_m23;
> +	__s16 coeff_o_g;
> +	__s16 coeff_m31;
> +	__s16 coeff_m32;
> +	__s16 coeff_m33;
> +	__s16 coeff_o_b;
> +} __packed;
> +
> +struct ipu3_uapi_gamma_corr_ctrl {
> +	__u32 enable:1;
> +	__u32 __reserved:31;
> +} __packed;
> +
> +struct ipu3_uapi_gamma_corr_lut {
> +	__u16 lut[IPU3_UAPI_GAMMA_CORR_LUT_ENTRIES];
> +} __packed;
> +
> +struct ipu3_uapi_gamma_config {
> +	struct ipu3_uapi_gamma_corr_ctrl gc_ctrl IPU3_ALIGN;
> +	struct ipu3_uapi_gamma_corr_lut gc_lut IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_csc_mat_config {
> +	__s16 coeff_c11;
> +	__s16 coeff_c12;
> +	__s16 coeff_c13;
> +	__s16 coeff_b1;
> +	__s16 coeff_c21;
> +	__s16 coeff_c22;
> +	__s16 coeff_c23;
> +	__s16 coeff_b2;
> +	__s16 coeff_c31;
> +	__s16 coeff_c32;
> +	__s16 coeff_c33;
> +	__s16 coeff_b3;
> +} __packed;
> +
> +struct ipu3_uapi_cds_params {
> +	__u32 ds_c00:2;
> +	__u32 ds_c01:2;
> +	__u32 ds_c02:2;
> +	__u32 ds_c03:2;
> +	__u32 ds_c10:2;
> +	__u32 ds_c11:2;
> +	__u32 ds_c12:2;
> +	__u32 ds_c13:2;
> +	__u32 ds_nf:5;
> +	__u32 __reserved0:3;
> +	__u32 csc_en:1;
> +	__u32 uv_bin_output:1;
> +	__u32 __reserved1:6;
> +} __packed;
> +
> +struct ipu3_uapi_shd_grid_config {
> +	/* reg 0 */
> +	__u8 width;
> +	__u8 height;
> +	__u8 block_width_log2:3;
> +	__u8 __reserved0:1;
> +	__u8 block_height_log2:3;
> +	__u8 __reserved1:1;
> +	__u8 grid_height_per_slice;
> +	/* reg 1 */
> +	__s16 x_start;			/* 13 bits */
> +	__s16 y_start;
> +} __packed;
> +
> +struct ipu3_uapi_shd_general_config {
> +	__u32 init_set_vrt_offst_ul:8;
> +	__u32 shd_enable:1;
> +	/* aka 'gf' */
> +	__u32 gain_factor:2;
> +	__u32 __reserved:21;
> +} __packed;
> +
> +struct ipu3_uapi_shd_black_level_config {
> +	__s16 bl_r;			/* 12 bits */
> +	__s16 bl_gr;
> +#define IPU3_UAPI_SHD_BLGR_NF_SHIFT	13	/* Normalization shift aka nf */
> +#define IPU3_UAPI_SHD_BLGR_NF_MASK	0x7
> +	__s16 bl_gb;			/* 12 bits */
> +	__s16 bl_b;
> +} __packed;
> +
> +struct ipu3_uapi_shd_config_static {
> +	/* B0: Fixed order: one transfer to GAC */
> +	struct ipu3_uapi_shd_grid_config grid;
> +	struct ipu3_uapi_shd_general_config general;
> +	struct ipu3_uapi_shd_black_level_config black_level;
> +} __packed;
> +
> +struct ipu3_uapi_shd_transfer_luts_set_data {
> +	__u8 set_number;
> +	__u8 padding[3];
> +	imgu_addr_t rg_lut_ddr_addr;
> +	imgu_addr_t bg_lut_ddr_addr;
> +	__u32 align_dummy;
> +} __packed;
> +
> +struct ipu3_uapi_shd_intra_frame_operations_data {
> +	struct ipu3_uapi_acc_operation
> +		operation_list[IPU3_UAPI_SHD_MAX_OPERATIONS] IPU3_ALIGN;
> +	struct ipu3_uapi_acc_process_lines_cmd_data
> +		process_lines_data[IPU3_UAPI_SHD_MAX_PROCESS_LINES] IPU3_ALIGN;
> +	struct ipu3_uapi_shd_transfer_luts_set_data
> +		transfer_data[IPU3_UAPI_SHD_MAX_TRANSFERS] IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_shd_lut {
> +	struct {
> +		struct {
> +			__u16 r;
> +			__u16 gr;
> +		} r_and_gr[IPU3_UAPI_SHD_MAX_CELLS_PER_SET];
> +		__u8 __reserved1[24];
> +		struct {
> +			__u16 gb;
> +			__u16 b;
> +		} gb_and_b[IPU3_UAPI_SHD_MAX_CELLS_PER_SET];
> +		__u8 __reserved2[24];
> +	} sets[IPU3_UAPI_SHD_MAX_CFG_SETS];
> +} __packed;
> +
> +struct ipu3_uapi_shd_config {
> +	struct ipu3_uapi_shd_config_static shd IPU3_ALIGN;
> +	struct ipu3_uapi_shd_intra_frame_operations_data shd_ops IPU3_ALIGN;
> +	struct ipu3_uapi_shd_lut shd_lut IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_dvs_stat_stripe_cfg {
> +	struct ipu3_uapi_dvs_stat_cfg stripe_cfg[IPU3_UAPI_MAX_STRIPES];
> +} __packed;
> +
> +struct ipu3_uapi_dvs_stat_transfer_op_data {
> +	__u8 set_number;
> +} __packed;
> +
> +struct ipu3_uapi_dvs_stat_intra_frame_operations_data {
> +	struct ipu3_uapi_acc_operation
> +		ops[IPU3_UAPI_DVS_STAT_MAX_OPERATIONS] IPU3_ALIGN;
> +	struct ipu3_uapi_acc_process_lines_cmd_data
> +		process_lines_data[IPU3_UAPI_DVS_STAT_MAX_PROCESS_LINES]
> +		IPU3_ALIGN;
> +	struct ipu3_uapi_dvs_stat_transfer_op_data
> +		transfer_data[IPU3_UAPI_DVS_STAT_MAX_TRANSFERS] IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_dvs_stat_meta_data_align_p {
> +	imgu_addr_t p_meta_data IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_dvs_stat_config {
> +	struct ipu3_uapi_dvs_stat_cfg cfg IPU3_ALIGN;
> +	struct ipu3_uapi_dvs_stat_stripe_cfg stripe IPU3_ALIGN;
> +	struct ipu3_uapi_dvs_stat_intra_frame_operations_data
> +		operations_data IPU3_ALIGN;
> +	struct ipu3_uapi_dvs_stat_meta_data_align_p
> +		meta_data[IPU3_UAPI_MAX_STRIPES];
> +} __packed;
> +
> +struct ipu3_uapi_lace_stat_operation {
> +	__u8 op_indicator;
> +	__u8 padding;
> +	__u16 lines;
> +} __packed;
> +
> +struct ipu3_uapi_lace_stat_intra_frame_op_data {
> +	struct ipu3_uapi_lace_stat_operation
> +		ops[IPU3_UAPI_LACE_STAT_MAX_OPERATIONS] IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_lace_stat_config {
> +	struct ipu3_uapi_lace_stat_cfg lace_stat_cfg IPU3_ALIGN;
> +	struct ipu3_uapi_lace_stat_intra_frame_op_data operations_data
> +		IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_iefd_cux2 {
> +	__u32 x0:9;
> +	__u32 x1:9;
> +	__u32 a01:9;
> +	__u32 b01:5;				/* NOTE: hardcoded to zero */
> +} __packed;
> +
> +struct ipu3_uapi_iefd_cux6_ed {
> +	__u32 x0:9;
> +	__u32 x1:9;
> +	__u32 x2:9;
> +	__u32 __reserved0:5;
> +
> +	__u32 x3:9;
> +	__u32 x4:9;
> +	__u32 x5:9;
> +	__u32 __reserved1:5;
> +
> +	__u32 a01:9;
> +	__u32 a12:9;
> +	__u32 a23:9;
> +	__u32 __reserved2:5;
> +
> +	__u32 a34:9;
> +	__u32 a45:9;
> +	__u32 __reserved3:14;
> +
> +	__u32 b01:9;
> +	__u32 b12:9;
> +	__u32 b23:9;
> +	__u32 __reserved4:5;
> +
> +	__u32 b34:9;
> +	__u32 b45:9;
> +	__u32 __reserved5:14;
> +} __packed;
> +
> +struct ipu3_uapi_iefd_cux2_1 {
> +	__u32 x0:9;
> +	__u32 x1:9;
> +	__u32 a01:9;
> +	__u32 __reserved1:5;
> +
> +	__u32 b01:8;
> +	__u32 __reserved2:24;
> +} __packed;
> +
> +struct ipu3_uapi_iefd_cux4 {
> +	__u32 x0:9;
> +	__u32 x1:9;
> +	__u32 x2:9;
> +	__u32 __reserved0:5;
> +
> +	__u32 x3:9;
> +	__u32 a01:9;
> +	__u32 a12:9;
> +	__u32 __reserved1:5;
> +
> +	__u32 a23:9;
> +	__u32 b01:8;
> +	__u32 b12:8;
> +	__u32 __reserved2:7;
> +
> +	__u32 b23:8;
> +	__u32 __reserved3:24;
> +} __packed;
> +
> +struct ipu3_uapi_iefd_cux6_rad {
> +	__u32 x0:8;
> +	__u32 x1:8;
> +	__u32 x2:8;
> +	__u32 x3:8;
> +
> +	__u32 x4:8;
> +	__u32 x5:8;
> +	__u32 __reserved1:16;
> +
> +	__u32 a01:16;
> +	__u32 a12:16;
> +
> +	__u32 a23:16;
> +	__u32 a34:16;
> +
> +	__u32 a45:16;
> +	__u32 __reserved2:16;
> +
> +	__u32 b01:10;
> +	__u32 b12:10;
> +	__u32 b23:10;
> +	__u32 __reserved4:2;
> +
> +	__u32 b34:10;
> +	__u32 b45:10;
> +	__u32 __reserved5:12;
> +} __packed;
> +
> +struct ipu3_uapi_yuvp1_iefd_cfg_units {
> +	struct ipu3_uapi_iefd_cux2 cu_1;
> +	struct ipu3_uapi_iefd_cux6_ed cu_ed;
> +	struct ipu3_uapi_iefd_cux2 cu_3;
> +	struct ipu3_uapi_iefd_cux2_1 cu_5;
> +	struct ipu3_uapi_iefd_cux4 cu_6;
> +	struct ipu3_uapi_iefd_cux2 cu_7;
> +	struct ipu3_uapi_iefd_cux4 cu_unsharp;
> +	struct ipu3_uapi_iefd_cux6_rad cu_radial;
> +	struct ipu3_uapi_iefd_cux2 cu_vssnlm;
> +} __packed;
> +
> +struct ipu3_uapi_yuvp1_iefd_config_s {
> +	__u32 horver_diag_coeff:7;	/* Gradiant compensation */
> +	__u32 __reserved0:1;
> +	__u32 clamp_stitch:6;		/* Slope to stitch edge */
> +	__u32 __reserved1:2;
> +	__u32 direct_metric_update:5;	/* Update coeff for direction metric */
> +	__u32 __reserved2:3;
> +	__u32 ed_horver_diag_coeff:7;
> +	__u32 __reserved3:1;
> +} __packed;
> +
> +struct ipu3_uapi_yuvp1_iefd_control {
> +	__u32 iefd_en:1;		/* Enable IEFD */
> +	__u32 denoise_en:1;		/* Enable denoise */
> +	__u32 direct_smooth_en:1;	/* Enable directional smooth */
> +	__u32 rad_en:1;			/* Enable radial update */
> +	__u32 vssnlm_en:1;		/* Enable VSSNLM output filter */
> +	__u32 __reserved:27;
> +} __packed;
> +
> +struct ipu3_uapi_sharp_cfg {
> +	__u32 nega_lmt_txt:13;
> +	__u32 __reserved0:19;
> +	__u32 posi_lmt_txt:13;
> +	__u32 __reserved1:19;
> +	__u32 nega_lmt_dir:13;
> +	__u32 __reserved2:19;
> +	__u32 posi_lmt_dir:13;
> +	__u32 __reserved3:19;
> +} __packed;
> +
> +struct ipu3_uapi_far_w {
> +	__u32 dir_shrp:7;
> +	__u32 __reserved0:1;
> +	__u32 dir_dns:7;
> +	__u32 __reserved1:1;
> +	__u32 ndir_dns_powr:7;
> +	__u32 __reserved2:9;
> +} __packed;
> +
> +struct ipu3_uapi_unsharp_cfg {
> +	__u32 unsharp_weight:7;
> +	__u32 __reserved0:1;
> +	__u32 unsharp_amount:9;
> +	__u32 __reserved1:15;
> +} __packed;
> +
> +struct ipu3_uapi_yuvp1_iefd_shrp_cfg {
> +	struct ipu3_uapi_sharp_cfg cfg;
> +	struct ipu3_uapi_far_w far_w;
> +	struct ipu3_uapi_unsharp_cfg unshrp_cfg;
> +} __packed;
> +
> +struct ipu3_uapi_unsharp_coef0 {
> +	__u32 c00:9;			/* Coeff11 */
> +	__u32 c01:9;			/* Coeff12 */
> +	__u32 c02:9;			/* Coeff13 */
> +	__u32 __reserved:5;
> +} __packed;
> +
> +struct ipu3_uapi_unsharp_coef1 {
> +	__u32 c11:9;			/* Coeff22 */
> +	__u32 c12:9;			/* Coeff23 */
> +	__u32 c22:9;			/* Coeff33 */
> +	__u32 __reserved:5;
> +} __packed;
> +
> +struct ipu3_uapi_yuvp1_iefd_unshrp_cfg {
> +	struct ipu3_uapi_unsharp_coef0 unsharp_coef0;
> +	struct ipu3_uapi_unsharp_coef1 unsharp_coef1;
> +} __packed;
> +
> +struct ipu3_uapi_radial_reset_xy {
> +	__s32 x:13;
> +	__u32 __reserved0:3;
> +	__s32 y:13;
> +	__u32 __reserved1:3;
> +} __packed;
> +
> +struct ipu3_uapi_radial_reset_x2 {
> +	__u32 x2:24;
> +	__u32 __reserved:8;
> +} __packed;
> +
> +struct ipu3_uapi_radial_reset_y2 {
> +	__u32 y2:24;
> +	__u32 __reserved:8;
> +} __packed;
> +
> +struct ipu3_uapi_radial_cfg {
> +	__u32 rad_nf:4;
> +	__u32 __reserved0:4;
> +	__u32 rad_inv_r2:7;
> +	__u32 __reserved1:17;
> +} __packed;
> +
> +struct ipu3_uapi_rad_far_w {
> +	__u32 rad_dir_far_sharp_w:8;
> +	__u32 rad_dir_far_dns_w:8;
> +	__u32 rad_ndir_far_dns_power:8;
> +	__u32 __reserved:8;
> +} __packed;
> +
> +struct ipu3_uapi_cu_cfg0 {
> +	__u32 cu6_pow:7;
> +	__u32 __reserved0:1;
> +	__u32 cu_unsharp_pow:7;
> +	__u32 __reserved1:1;
> +	__u32 rad_cu6_pow:7;
> +	__u32 __reserved2:1;
> +	__u32 rad_cu_unsharp_pow:6;
> +	__u32 __reserved3:2;
> +} __packed;
> +
> +struct ipu3_uapi_cu_cfg1 {
> +	__u32 rad_cu6_x1:9;
> +	__u32 __reserved0:1;
> +	__u32 rad_cu_unsharp_x1:9;
> +	__u32 __reserved1:13;
> +} __packed;
> +
> +struct ipu3_uapi_yuvp1_iefd_rad_cfg {
> +	struct ipu3_uapi_radial_reset_xy reset_xy;
> +	struct ipu3_uapi_radial_reset_x2 reset_x2;
> +	struct ipu3_uapi_radial_reset_y2 reset_y2;
> +	struct ipu3_uapi_radial_cfg cfg;
> +	struct ipu3_uapi_rad_far_w rad_far_w;
> +	struct ipu3_uapi_cu_cfg0 cu_cfg0;
> +	struct ipu3_uapi_cu_cfg1 cu_cfg1;
> +} __packed;
> +
> +struct ipu3_uapi_vss_lut_x {
> +	__u32 vs_x0:8;
> +	__u32 vs_x1:8;
> +	__u32 vs_x2:8;
> +	__u32 __reserved2:8;
> +} __packed;
> +
> +struct ipu3_uapi_vss_lut_y {
> +	__u32 vs_y1:4;
> +	__u32 __reserved0:4;
> +	__u32 vs_y2:4;
> +	__u32 __reserved1:4;
> +	__u32 vs_y3:4;
> +	__u32 __reserved2:12;
> +} __packed;
> +
> +struct ipu3_uapi_yuvp1_iefd_vssnlm_cfg {
> +	struct ipu3_uapi_vss_lut_x vss_lut_x;
> +	struct ipu3_uapi_vss_lut_y vss_lut_y;
> +} __packed;
> +
> +struct ipu3_uapi_yuvp1_iefd_config {
> +	struct ipu3_uapi_yuvp1_iefd_cfg_units units;
> +	struct ipu3_uapi_yuvp1_iefd_config_s config;
> +	struct ipu3_uapi_yuvp1_iefd_control control;
> +	struct ipu3_uapi_yuvp1_iefd_shrp_cfg sharp;
> +	struct ipu3_uapi_yuvp1_iefd_unshrp_cfg unsharp;
> +	struct ipu3_uapi_yuvp1_iefd_rad_cfg rad;
> +	struct ipu3_uapi_yuvp1_iefd_vssnlm_cfg vsslnm;
> +} __packed;
> +
> +struct ipu3_uapi_yuvp1_yds_config {
> +	__u32 c00:2;
> +	__u32 c01:2;
> +	__u32 c02:2;
> +	__u32 c03:2;
> +	__u32 c10:2;
> +	__u32 c11:2;
> +	__u32 c12:2;
> +	__u32 c13:2;
> +	__u32 norm_factor:5;
> +	__u32 __reserved0:4;
> +	__u32 bin_output:1;
> +	__u32 __reserved1:6;
> +} __packed;
> +
> +struct ipu3_uapi_yuvp1_chnr_enable_config {
> +	__u32 enable:1;
> +	__u32 yuv_mode:1;
> +	__u32 __reserved0:14;
> +	__u32 col_size:12;
> +	__u32 __reserved1:4;
> +} __packed;
> +
> +struct ipu3_uapi_yuvp1_chnr_coring_config {
> +	__u32 u:13;
> +	__u32 __reserved0:3;
> +	__u32 v:13;
> +	__u32 __reserved1:3;
> +} __packed;
> +
> +struct ipu3_uapi_yuvp1_chnr_sense_gain_config {
> +	__u32 vy:8;
> +	__u32 vu:8;
> +	__u32 vv:8;
> +	__u32 __reserved0:8;
> +
> +	__u32 hy:8;
> +	__u32 hu:8;
> +	__u32 hv:8;
> +	__u32 __reserved1:8;
> +} __packed;
> +
> +struct ipu3_uapi_yuvp1_chnr_iir_fir_config {
> +	__u32 fir_0h:6;
> +	__u32 __reserved0:2;
> +	__u32 fir_1h:6;
> +	__u32 __reserved1:2;
> +	__u32 fir_2h:6;
> +	__u32 dalpha_clip_val:9;
> +	__u32 __reserved2:1;
> +} __packed;
> +
> +struct ipu3_uapi_yuvp1_chnr_config {
> +	struct ipu3_uapi_yuvp1_chnr_enable_config enable;
> +	struct ipu3_uapi_yuvp1_chnr_coring_config coring;
> +	struct ipu3_uapi_yuvp1_chnr_sense_gain_config sense_gain;
> +	struct ipu3_uapi_yuvp1_chnr_iir_fir_config iir_fir;
> +} __packed;
> +
> +struct ipu3_uapi_yuvp1_y_ee_nr_lpf_config {
> +	__u32 a_diag:5;
> +	__u32 __reserved0:3;
> +	__u32 a_periph:5;
> +	__u32 __reserved1:3;
> +	__u32 a_cent:5;
> +	__u32 __reserved2:9;
> +	__u32 enable:1;
> +} __packed;
> +
> +struct ipu3_uapi_yuvp1_y_ee_nr_sense_config {
> +	__u32 edge_sense_0:13;
> +	__u32 __reserved0:3;
> +	__u32 delta_edge_sense:13;
> +	__u32 __reserved1:3;
> +	__u32 corner_sense_0:13;
> +	__u32 __reserved2:3;
> +	__u32 delta_corner_sense:13;
> +	__u32 __reserved3:3;
> +} __packed;
> +
> +struct ipu3_uapi_yuvp1_y_ee_nr_gain_config {
> +	__u32 gain_pos_0:5;
> +	__u32 __reserved0:3;
> +	__u32 delta_gain_posi:5;
> +	__u32 __reserved1:3;
> +	__u32 gain_neg_0:5;
> +	__u32 __reserved2:3;
> +	__u32 delta_gain_neg:5;
> +	__u32 __reserved3:3;
> +} __packed;
> +
> +struct ipu3_uapi_yuvp1_y_ee_nr_clip_config {
> +	__u32 clip_pos_0:5;
> +	__u32 __reserved0:3;
> +	__u32 delta_clip_posi:5;
> +	__u32 __reserved1:3;
> +	__u32 clip_neg_0:5;
> +	__u32 __reserved2:3;
> +	__u32 delta_clip_neg:5;
> +	__u32 __reserved3:3;
> +} __packed;
> +
> +struct ipu3_uapi_yuvp1_y_ee_nr_frng_config {
> +	__u32 gain_exp:4;
> +	__u32 __reserved0:28;
> +	__u32 min_edge:13;
> +	__u32 __reserved1:3;
> +	__u32 lin_seg_param:4;
> +	__u32 __reserved2:4;
> +	__u32 t1:1;
> +	__u32 t2:1;
> +	__u32 __reserved3:6;
> +} __packed;
> +
> +struct ipu3_uapi_yuvp1_y_ee_nr_diag_config {
> +	__u32 diag_disc_g:4;
> +	__u32 __reserved0:4;
> +	__u32 hvw_hor:4;
> +	__u32 dw_hor:4;
> +	__u32 hvw_diag:4;
> +	__u32 dw_diag:4;
> +	__u32 __reserved1:8;
> +} __packed;
> +
> +struct ipu3_uapi_yuvp1_y_ee_nr_fc_coring_config {
> +	__u32 pos_0:13;
> +	__u32 __reserved0:3;
> +	__u32 pos_delta:13;
> +	__u32 __reserved1:3;
> +	__u32 neg_0:13;
> +	__u32 __reserved2:3;
> +	__u32 neg_delta:13;
> +	__u32 __reserved3:3;
> +} __packed;
> +
> +struct ipu3_uapi_yuvp1_y_ee_nr_config {
> +	struct ipu3_uapi_yuvp1_y_ee_nr_lpf_config lpf;
> +	struct ipu3_uapi_yuvp1_y_ee_nr_sense_config sense;
> +	struct ipu3_uapi_yuvp1_y_ee_nr_gain_config gain;
> +	struct ipu3_uapi_yuvp1_y_ee_nr_clip_config clip;
> +	struct ipu3_uapi_yuvp1_y_ee_nr_frng_config frng;
> +	struct ipu3_uapi_yuvp1_y_ee_nr_diag_config diag;
> +	struct ipu3_uapi_yuvp1_y_ee_nr_fc_coring_config fc_coring;
> +} __packed;
> +
> +struct ipu3_uapi_yuvp2_y_tm_lut_static_config {
> +	__u16 entries[IPU3_UAPI_YUVP2_YTM_LUT_ENTRIES]; /* 13 significand bits*/
> +	__u32 enable;
> +} __packed;
> +
> +struct ipu3_uapi_yuvp2_tcc_gen_control_static_config {
> +	__u32 en:1;
> +	__u32 blend_shift:3;
> +	__u32 gain_according_to_y_only:1;
> +	__u32 __reserved0:11;
> +	__s32 gamma:5;
> +	__u32 __reserved1:3;
> +	__s32 delta:5;
> +	__u32 __reserved2:3;
> +} __packed;
> +
> +struct ipu3_uapi_yuvp2_tcc_macc_elem_static_config {
> +	__s32 a:12;
> +	__u32 __reserved0:4;
> +	__s32 b:12;
> +	__u32 __reserved1:4;
> +	__s32 c:12;
> +	__u32 __reserved2:4;
> +	__s32 d:12;
> +	__u32 __reserved3:4;
> +} __packed;
> +
> +struct ipu3_uapi_yuvp2_tcc_macc_table_static_config {
> +	struct ipu3_uapi_yuvp2_tcc_macc_elem_static_config
> +		entries[IPU3_UAPI_YUVP2_TCC_MACC_TABLE_ELEMENTS];
> +} __packed;
> +
> +struct ipu3_uapi_yuvp2_tcc_inv_y_lut_static_config {
> +	__u16 entries[IPU3_UAPI_YUVP2_TCC_INV_Y_LUT_ELEMENTS];	/* 10 bits */
> +} __packed;
> +
> +struct ipu3_uapi_yuvp2_tcc_gain_pcwl_lut_static_config {
> +	__u16 entries[IPU3_UAPI_YUVP2_TCC_GAIN_PCWL_LUT_ELEMENTS];/* 12 bits */
> +} __packed;
> +
> +struct ipu3_uapi_yuvp2_tcc_r_sqr_lut_static_config {
> +	__s16 entries[IPU3_UAPI_YUVP2_TCC_R_SQR_LUT_ELEMENTS];	/* 11 bits */
> +} __packed;
> +
> +struct ipu3_uapi_yuvp2_tcc_static_config {
> +	struct ipu3_uapi_yuvp2_tcc_gen_control_static_config gen_control;
> +	struct ipu3_uapi_yuvp2_tcc_macc_table_static_config macc_table;
> +	struct ipu3_uapi_yuvp2_tcc_inv_y_lut_static_config inv_y_lut;
> +	struct ipu3_uapi_yuvp2_tcc_gain_pcwl_lut_static_config gain_pcwl;
> +	struct ipu3_uapi_yuvp2_tcc_r_sqr_lut_static_config r_sqr_lut;
> +} __packed;
> +
> +struct ipu3_uapi_dpc_num_of_dp {
> +	__u8 dp_gr;
> +	__u8 dp_bg;
> +	__u16 __reserved;
> +} __packed;
> +
> +struct ipu3_uapi_dpc_params {
> +	__u16 enable;
> +	__u16 grad_threshold;		/* 13 bits */
> +	struct ipu3_uapi_dpc_num_of_dp set[2];
> +	struct ipu3_uapi_dpc_num_of_dp first_line_pair;
> +} __packed;
> +
> +struct ipu3_uapi_dpc_transfer_luts_set_data {
> +	__u8 set_number;
> +	__u8 num_of_dp_gr;
> +	__u8 num_of_dp_bg;
> +	__u8 align_dummy;
> +
> +} __packed;
> +
> +struct ipu3_uapi_dpc_intra_frame_operations_data {
> +	struct ipu3_uapi_acc_operation
> +		operation_list[IPU3_UAPI_DPC_MAX_OPERATIONS] IPU3_ALIGN;
> +	struct ipu3_uapi_acc_process_lines_cmd_data
> +		process_lines_data[IPU3_UAPI_DPC_MAX_PROCESS_LINES] IPU3_ALIGN;
> +	struct ipu3_uapi_dpc_transfer_luts_set_data
> +		transfer_data[IPU3_UAPI_DPC_MAX_TRANSFERS] IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_dpc_1st_pair_of_lines_lut_elem {
> +	__u32 column:13;
> +	__u32 nghbr_sts:5;
> +	__u32 p0:14;
> +	__u32 p1:14;
> +	__u32 __reserved0:2;
> +	__u32 p2:14;
> +	__u32 nghbr_order:1;
> +	__u32 __reserved1:1;
> +} __packed;
> +
> +struct ipu3_uapi_dpc_1st_pair_of_lines_lut {
> +	struct ipu3_uapi_dpc_1st_pair_of_lines_lut_elem
> +		entries[IPU3_UAPI_DPC_MAX_DP_FIRST_LINES_PAIR];
> +
> +} __packed;
> +
> +struct ipu3_uapi_dpc_lut_elem {
> +	__u32 nghbr_sts:5;
> +	__u32 skip:1;
> +	__u32 nghbr_order:1;
> +	__u32 column:13;
> +	__u32 row_pair_delta:4;
> +	__u32 __reserved0:8;
> +} __packed;
> +
> +struct ipu3_uapi_dpc_lut_set {
> +	struct ipu3_uapi_dpc_lut_elem
> +		elems[IPU3_UAPI_DPC_MAX_DP_PER_SET] IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_dpc_lut {
> +	struct ipu3_uapi_dpc_lut_set sets[IPU3_UAPI_DPC_MAX_CFG_SETS];
> +} __packed;
> +
> +struct ipu3_uapi_dpc_stripe_config {
> +	struct ipu3_uapi_dpc_params params IPU3_ALIGN;
> +	struct ipu3_uapi_dpc_intra_frame_operations_data ops IPU3_ALIGN;
> +	struct ipu3_uapi_dpc_1st_pair_of_lines_lut first_lines_lut_gr
> +		IPU3_ALIGN;
> +	struct ipu3_uapi_dpc_1st_pair_of_lines_lut first_lines_lut_bg
> +		IPU3_ALIGN;
> +	struct ipu3_uapi_dpc_lut lut_bg IPU3_ALIGN;
> +	struct ipu3_uapi_dpc_lut lut_gr IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_dpc_config_per_stripe {
> +	struct ipu3_uapi_dpc_stripe_config
> +		dpc_config[IPU3_UAPI_MAX_STRIPES] IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_dpc_config {
> +	struct ipu3_uapi_dpc_config_per_stripe config_per_stripe
> +		IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_bds_hor_ctrl0 {
> +	__u32 sample_patrn_length:9;
> +	__u32 __reserved0:3;
> +	__u32 hor_ds_en:1;
> +	__u32 min_clip_val:1;
> +	__u32 max_clip_val:2;
> +	__u32 out_frame_width:13;
> +	__u32 __reserved1:3;
> +} __packed;
> +
> +struct ipu3_uapi_bds_ptrn_arr {
> +	__u32 elems[IPU3_UAPI_BDS_SAMPLE_PATTERN_ARRAY_SIZE];
> +} __packed;
> +
> +struct ipu3_uapi_bds_phase_entry {
> +	__s8 coeff_min2;
> +	__s8 coeff_min1;
> +	__s8 coeff_0;
> +	__s8 nf;
> +	__s8 coeff_pls1;
> +	__s8 coeff_pls2;
> +	__s8 coeff_pls3;
> +	__u8 __reserved;
> +} __packed;
> +
> +struct ipu3_uapi_bds_phase_arr {
> +	struct ipu3_uapi_bds_phase_entry
> +		even[IPU3_UAPI_BDS_PHASE_COEFFS_ARRAY_SIZE];
> +	struct ipu3_uapi_bds_phase_entry
> +		odd[IPU3_UAPI_BDS_PHASE_COEFFS_ARRAY_SIZE];
> +} __packed;
> +
> +struct ipu3_uapi_bds_hor_ctrl1 {
> +	__u32 hor_crop_start:13;
> +	__u32 __reserved0:3;
> +	__u32 hor_crop_end:13;
> +	__u32 __reserved1:1;
> +	__u32 hor_crop_en:1;
> +	__u32 __reserved2:1;
> +} __packed;
> +
> +struct ipu3_uapi_bds_hor_ctrl2 {
> +	__u32 input_frame_height:13;
> +	__u32 __reserved0:19;
> +} __packed;
> +
> +struct ipu3_uapi_bds_hor {
> +	struct ipu3_uapi_bds_hor_ctrl0 hor_ctrl0;
> +	struct ipu3_uapi_bds_ptrn_arr hor_ptrn_arr;
> +	struct ipu3_uapi_bds_phase_arr hor_phase_arr;
> +	struct ipu3_uapi_bds_hor_ctrl1 hor_ctrl1;
> +	struct ipu3_uapi_bds_hor_ctrl2 hor_ctrl2;
> +} __packed;
> +
> +struct ipu3_uapi_bds_ver_ctrl0 {
> +	__u32 sample_patrn_length:9;
> +	__u32 __reserved0:3;
> +	__u32 ver_ds_en:1;
> +	__u32 min_clip_val:1;
> +	__u32 max_clip_val:2;
> +	__u32 __reserved1:16;
> +} __packed;
> +
> +struct ipu3_uapi_bds_ver_ctrl1 {
> +	__u32 out_frame_width:13;
> +	__u32 __reserved0:3;
> +	__u32 out_frame_height:13;
> +	__u32 __reserved1:3;
> +} __packed;
> +
> +struct ipu3_uapi_bds_ver {
> +	struct ipu3_uapi_bds_ver_ctrl0 ver_ctrl0;
> +	struct ipu3_uapi_bds_ptrn_arr ver_ptrn_arr;
> +	struct ipu3_uapi_bds_phase_arr ver_phase_arr;
> +	struct ipu3_uapi_bds_ver_ctrl1 ver_ctrl1;
> +
> +} __packed;
> +
> +struct ipu3_uapi_bds_per_stripe_data {
> +	struct ipu3_uapi_bds_hor_ctrl0 hor_ctrl0;
> +	struct ipu3_uapi_bds_ver_ctrl1 ver_ctrl1;
> +	struct ipu3_uapi_bds_hor_ctrl1 crop;
> +} __packed;
> +
> +struct ipu3_uapi_ipu3_uapi_bds_per_stripe_data_aligned {
> +	struct ipu3_uapi_bds_per_stripe_data data IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_bds_per_stripe {
> +	struct ipu3_uapi_ipu3_uapi_bds_per_stripe_data_aligned
> +		aligned_data[IPU3_UAPI_MAX_STRIPES];
> +} __packed;
> +
> +struct ipu3_uapi_bds_config {
> +	struct ipu3_uapi_bds_hor hor IPU3_ALIGN;
> +	struct ipu3_uapi_bds_ver ver IPU3_ALIGN;
> +	struct ipu3_uapi_bds_per_stripe per_stripe IPU3_ALIGN;
> +	__u32 enabled;
> +} __packed;
> +
> +struct ipu3_uapi_anr_search_config {
> +	__u32 enable;
> +	__u16 frame_width;
> +	__u16 frame_height;
> +} __packed;
> +
> +struct ipu3_uapi_anr_alpha {
> +	__u16 gr;					/* 9 bits */
> +	__u16 r;
> +	__u16 b;
> +	__u16 gb;
> +	__u16 dc_gr;
> +	__u16 dc_r;
> +	__u16 dc_b;
> +	__u16 dc_gb;
> +} __packed;
> +
> +struct ipu3_uapi_anr_beta {
> +	__u16 beta_gr;					/* 11 bits */
> +	__u16 beta_r;
> +	__u16 beta_b;
> +	__u16 beta_gb;
> +} __packed;
> +
> +struct ipu3_uapi_anr_plain_color {
> +	__u16 reg_w_gr[16];				/* 12 bits */
> +	__u16 reg_w_r[16];
> +	__u16 reg_w_b[16];
> +	__u16 reg_w_gb[16];
> +} __packed;
> +
> +struct ipu3_uapi_anr_transform_config {
> +	__u32 enable:1;			/* 0 or 1, disabled or enabled */
> +	__u32 adaptive_treshhold_en:1;	/* On IPU3, always enabled */
> +
> +	__u32 __reserved1:30;
> +	__u8 __reserved2[40+4];
> +
> +	struct ipu3_uapi_anr_alpha alpha[3];
> +	struct ipu3_uapi_anr_beta beta[3];
> +	struct ipu3_uapi_anr_plain_color color[3];
> +
> +	__u16 sqrt_lut[IPU3_UAPI_ANR_LUT_SIZE];	/* 11 bits per element */
> +
> +	__s16 xreset:13;
> +#define IPU3_UAPI_ANR_MAX_XRESET		((1 << 12) - 1)
> +	__u16 __reserved3:3;
> +	__s16 yreset:13;
> +	__u16 __reserved4:3;
> +
> +	__u32 x_sqr_reset:24;
> +	__u32 r_normfactor:5;
> +	__u32 __reserved5:3;
> +
> +	__u32 y_sqr_reset:24;
> +	__u32 gain_scale:8;
> +} __packed;
> +
> +struct ipu3_uapi_anr_stitch_pyramid {
> +	__u32 entry0:6;
> +	__u32 entry1:6;
> +	__u32 entry2:6;
> +	__u32 __reserved:14;
> +} __packed;
> +
> +struct ipu3_uapi_anr_stitch_config {
> +	__u32 anr_stitch_en;
> +	__u16 frame_width;
> +	__u16 frame_height;
> +	__u8 __reserved[40];
> +	struct ipu3_uapi_anr_stitch_pyramid pyramid[IPU3_UAPI_ANR_PYRAMID_SIZE];
> +} __packed;
> +
> +struct ipu3_uapi_anr_tile2strm_config {
> +	__u32 enable;
> +	__u16 frame_width;
> +	__u16 frame_height;
> +} __packed;
> +
> +struct ipu3_uapi_anr_config {
> +	struct ipu3_uapi_anr_search_config search IPU3_ALIGN;
> +	struct ipu3_uapi_anr_transform_config transform IPU3_ALIGN;
> +	struct ipu3_uapi_anr_stitch_config stitch IPU3_ALIGN;
> +	struct ipu3_uapi_anr_tile2strm_config tile2strm IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_awb_fr_intra_frame_operations_data {
> +	struct ipu3_uapi_acc_operation ops[IPU3_UAPI_AWB_FR_MAX_OPERATIONS]
> +								IPU3_ALIGN;
> +	struct ipu3_uapi_acc_process_lines_cmd_data
> +	      process_lines_data[IPU3_UAPI_AWB_FR_MAX_PROCESS_LINES] IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_awb_fr_config {
> +	struct ipu3_uapi_awb_fr_config_s config;
> +	struct ipu3_uapi_awb_fr_intra_frame_operations_data operations_data;
> +	struct ipu3_uapi_awb_fr_config_s stripes[IPU3_UAPI_MAX_STRIPES];
> +} __packed;
> +
> +struct ipu3_uapi_ae_weight_elem {
> +	__u32 cell0:4;
> +	__u32 cell1:4;
> +	__u32 cell2:4;
> +	__u32 cell3:4;
> +	__u32 cell4:4;
> +	__u32 cell5:4;
> +	__u32 cell6:4;
> +	__u32 cell7:4;
> +} __packed;
> +
> +struct ipu3_uapi_ae_ccm {
> +	__u16 gain_gr;			/* 11 bits */
> +	__u16 gain_r;
> +	__u16 gain_b;
> +	__u16 gain_gb;
> +	__s16 mat[16];
> +} __packed;
> +
> +struct ipu3_uapi_ae_config {
> +	struct ipu3_uapi_ae_grid_config grid_cfg IPU3_ALIGN;
> +	struct ipu3_uapi_ae_weight_elem weights[IPU3_UAPI_AE_WEIGHTS]
> +								IPU3_ALIGN;
> +	struct ipu3_uapi_ae_ccm ae_ccm IPU3_ALIGN;
> +	struct {
> +		struct ipu3_uapi_ae_grid_config grid IPU3_ALIGN;
> +	} stripes[IPU3_UAPI_MAX_STRIPES];
> +} __packed;
> +
> +struct ipu3_uapi_af_intra_frame_operations_data {
> +	struct ipu3_uapi_acc_operation ops[IPU3_UAPI_AF_MAX_OPERATIONS]
> +		IPU3_ALIGN;
> +	struct ipu3_uapi_acc_process_lines_cmd_data
> +		process_lines_data[IPU3_UAPI_AF_MAX_PROCESS_LINES] IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_af_stripe_config {
> +	struct ipu3_uapi_af_frame_size frame_size IPU3_ALIGN;
> +	struct ipu3_uapi_grid_config grid_cfg IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_af_config {
> +	struct ipu3_uapi_af_config_s config;
> +	struct ipu3_uapi_af_intra_frame_operations_data operations_data;
> +	struct ipu3_uapi_af_stripe_config stripes[IPU3_UAPI_MAX_STRIPES];
> +} __packed;
> +
> +struct ipu3_uapi_acc_transfer_op_data {
> +	__u8 set_number;
> +} __packed;
> +
> +struct IPU3_ALIGN ipu3_uapi_awb_intra_frame_operations_data {
> +	struct ipu3_uapi_acc_operation ops[IPU3_UAPI_AWB_MAX_OPERATIONS]
> +		IPU3_ALIGN;
> +	struct ipu3_uapi_acc_process_lines_cmd_data
> +		process_lines_data[IPU3_UAPI_AWB_MAX_PROCESS_LINES] IPU3_ALIGN;
> +	struct ipu3_uapi_acc_transfer_op_data
> +		transfer_data[IPU3_UAPI_AWB_MAX_TRANSFERS] IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_awb_config {
> +	struct ipu3_uapi_awb_config_s config IPU3_ALIGN;
> +	struct ipu3_uapi_awb_intra_frame_operations_data operations_data;
> +	struct ipu3_uapi_awb_config_s stripes[IPU3_UAPI_MAX_STRIPES];
> +} __packed;
> +
> +struct ipu3_uapi_osys_formatter_params {
> +	__u32 format;
> +	__u32 flip;
> +	__u32 mirror;
> +	__u32 tiling;
> +	__u32 reduce_range;
> +	__u32 alpha_blending;	/* FIXME: To figure out the unknown register */
> +	__u32 release_inp_addr;
> +	__u32 release_inp_en;
> +	__u32 process_out_buf_addr;
> +	__u32 image_width_vecs;
> +	__u32 image_height_lines;
> +	__u32 inp_buff_y_st_addr;
> +	__u32 inp_buff_y_line_stride;
> +	__u32 inp_buff_y_buffer_stride;
> +	__u32 int_buff_u_st_addr;
> +	__u32 int_buff_v_st_addr;
> +	__u32 inp_buff_uv_line_stride;
> +	__u32 inp_buff_uv_buffer_stride;
> +	__u32 out_buff_level;
> +	__u32 out_buff_nr_y_lines;
> +	__u32 out_buff_u_st_offset;
> +	__u32 out_buff_v_st_offset;
> +	__u32 out_buff_y_line_stride;
> +	__u32 out_buff_uv_line_stride;
> +	__u32 hist_buff_st_addr;
> +	__u32 hist_buff_line_stride;
> +	__u32 hist_buff_nr_lines;
> +} __packed;
> +
> +struct ipu3_uapi_osys_formatter {
> +	struct ipu3_uapi_osys_formatter_params param IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_osys_scaler_params {
> +	__u32 inp_buf_y_st_addr;
> +	__u32 inp_buf_y_line_stride;
> +	__u32 inp_buf_y_buffer_stride;
> +	__u32 inp_buf_u_st_addr;
> +	__u32 inp_buf_v_st_addr;
> +	__u32 inp_buf_uv_line_stride;
> +	__u32 inp_buf_uv_buffer_stride;
> +	__u32 inp_buf_chunk_width;
> +	__u32 inp_buf_nr_buffers;
> +	/* Output buffers */
> +	__u32 out_buf_y_st_addr;
> +	__u32 out_buf_y_line_stride;
> +	__u32 out_buf_y_buffer_stride;
> +	__u32 out_buf_u_st_addr;
> +	__u32 out_buf_v_st_addr;
> +	__u32 out_buf_uv_line_stride;
> +	__u32 out_buf_uv_buffer_stride;
> +	__u32 out_buf_nr_buffers;
> +	/* Intermediate buffers */
> +	__u32 int_buf_y_st_addr;
> +	__u32 int_buf_y_line_stride;
> +	__u32 int_buf_u_st_addr;
> +	__u32 int_buf_v_st_addr;
> +	__u32 int_buf_uv_line_stride;
> +	__u32 int_buf_height;
> +	__u32 int_buf_chunk_width;
> +	__u32 int_buf_chunk_height;
> +	/* Context buffers */
> +	__u32 ctx_buf_hor_y_st_addr;
> +	__u32 ctx_buf_hor_u_st_addr;
> +	__u32 ctx_buf_hor_v_st_addr;
> +	__u32 ctx_buf_ver_y_st_addr;
> +	__u32 ctx_buf_ver_u_st_addr;
> +	__u32 ctx_buf_ver_v_st_addr;
> +	/* Addresses for release-input and process-output tokens */
> +	__u32 release_inp_buf_addr;
> +	__u32 release_inp_buf_en;
> +	__u32 release_out_buf_en;
> +	__u32 process_out_buf_addr;
> +	/* Settings dimensions, padding, cropping */
> +	__u32 input_image_y_width;
> +	__u32 input_image_y_height;
> +	__u32 input_image_y_start_column;
> +	__u32 input_image_uv_start_column;
> +	__u32 input_image_y_left_pad;
> +	__u32 input_image_uv_left_pad;
> +	__u32 input_image_y_right_pad;
> +	__u32 input_image_uv_right_pad;
> +	__u32 input_image_y_top_pad;
> +	__u32 input_image_uv_top_pad;
> +	__u32 input_image_y_bottom_pad;
> +	__u32 input_image_uv_bottom_pad;
> +	__u32 processing_mode;
> +#define IPU3_UAPI_OSYS_PROCMODE_BYPASS		0
> +#define IPU3_UAPI_OSYS_PROCMODE_UPSCALE		1
> +#define IPU3_UAPI_OSYS_PROCMODE_DOWNSCALE	2
> +	__u32 scaling_ratio;
> +	__u32 y_left_phase_init;
> +	__u32 uv_left_phase_init;
> +	__u32 y_top_phase_init;
> +	__u32 uv_top_phase_init;
> +	__u32 coeffs_exp_shift;
> +	__u32 out_y_left_crop;
> +	__u32 out_uv_left_crop;
> +	__u32 out_y_top_crop;
> +	__u32 out_uv_top_crop;
> +} __packed;
> +
> +struct ipu3_uapi_osys_scaler {
> +	struct ipu3_uapi_osys_scaler_params param IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_osys_frame_params {
> +	/* Output pins */
> +	__u32 enable;
> +	__u32 format;			/* enum ipu3_uapi_osys_format */
> +	__u32 flip;
> +	__u32 mirror;
> +	__u32 tiling;			/* enum ipu3_uapi_osys_tiling */
> +	__u32 width;
> +	__u32 height;
> +	__u32 stride;
> +	__u32 scaled;
> +} __packed;
> +
> +struct ipu3_uapi_osys_frame {
> +	struct ipu3_uapi_osys_frame_params param IPU3_ALIGN;
> +} __packed;
> +
> +struct ipu3_uapi_osys_stripe {
> +	/* Input resolution */
> +	__u32 input_width;
> +	__u32 input_height;
> +	/* Output Stripe */
> +	__u32 output_width[IPU3_UAPI_OSYS_PINS];
> +	__u32 output_height[IPU3_UAPI_OSYS_PINS];
> +	__u32 output_offset[IPU3_UAPI_OSYS_PINS];
> +	__u32 buf_stride[IPU3_UAPI_OSYS_PINS];
> +	/* Scaler params */
> +	__u32 block_width;
> +	__u32 block_height;
> +	/* Output Crop factor */
> +	__u32 crop_top[IPU3_UAPI_OSYS_PINS];
> +	__u32 crop_left[IPU3_UAPI_OSYS_PINS];
> +} __packed;
> +
> +struct ipu3_uapi_osys_config {
> +	struct ipu3_uapi_osys_formatter
> +		formatter[IPU3_UAPI_MAX_STRIPES][IPU3_UAPI_OSYS_PINS];
> +	struct ipu3_uapi_osys_scaler scaler[IPU3_UAPI_MAX_STRIPES];
> +	struct ipu3_uapi_osys_frame frame[IPU3_UAPI_OSYS_PINS];
> +	struct ipu3_uapi_osys_stripe stripe[IPU3_UAPI_MAX_STRIPES];
> +	/* 32 packed coefficients for luma and chroma */
> +	__s8 scaler_coeffs_chroma[128];
> +	__s8 scaler_coeffs_luma[128];
> +} __packed;
> +
> +struct ipu3_uapi_acc_param {
> +	struct ipu3_uapi_stripe_data stripe;
> +	__u8 padding[8];
> +	struct ipu3_uapi_input_feeder_config input_feeder;
> +	struct ipu3_uapi_bnr_static_config bnr;
> +	struct ipu3_uapi_bnr_static_config_green_disparity green_disparity
> +		IPU3_ALIGN;
> +	struct ipu3_uapi_dm_config dm IPU3_ALIGN;
> +	struct ipu3_uapi_ccm_mat_config ccm IPU3_ALIGN;
> +	struct ipu3_uapi_gamma_config gamma IPU3_ALIGN;
> +	struct ipu3_uapi_csc_mat_config csc IPU3_ALIGN;
> +	struct ipu3_uapi_cds_params cds IPU3_ALIGN;
> +	struct ipu3_uapi_shd_config shd IPU3_ALIGN;
> +	struct ipu3_uapi_dvs_stat_config dvs_stat IPU3_ALIGN;
> +	struct ipu3_uapi_lace_stat_config lace_stat IPU3_ALIGN;
> +	struct ipu3_uapi_yuvp1_iefd_config iefd IPU3_ALIGN;
> +	struct ipu3_uapi_yuvp1_yds_config yds_c0 IPU3_ALIGN;
> +	struct ipu3_uapi_yuvp1_chnr_config chnr_c0 IPU3_ALIGN;
> +	struct ipu3_uapi_yuvp1_y_ee_nr_config y_ee_nr IPU3_ALIGN;
> +	struct ipu3_uapi_yuvp1_yds_config yds IPU3_ALIGN;
> +	struct ipu3_uapi_yuvp1_chnr_config chnr IPU3_ALIGN;
> +	struct ipu3_uapi_yuvp2_y_tm_lut_static_config ytm IPU3_ALIGN;
> +	struct ipu3_uapi_yuvp1_yds_config yds2 IPU3_ALIGN;
> +	struct ipu3_uapi_yuvp2_tcc_static_config tcc IPU3_ALIGN;
> +	struct ipu3_uapi_dpc_config dpc IPU3_ALIGN;
> +	struct ipu3_uapi_bds_config bds IPU3_ALIGN;
> +	struct ipu3_uapi_anr_config anr IPU3_ALIGN;
> +	struct ipu3_uapi_awb_fr_config awb_fr IPU3_ALIGN;
> +	struct ipu3_uapi_ae_config ae IPU3_ALIGN;
> +	struct ipu3_uapi_af_config af IPU3_ALIGN;
> +	struct ipu3_uapi_awb_config awb IPU3_ALIGN;
> +	struct ipu3_uapi_osys_config osys IPU3_ALIGN;
> +} __packed;
> +
> +/* Linearization parameters */
> +
> +#define IPU3_UAPI_LIN_LUT_SIZE			64
> +
> +struct ipu3_uapi_isp_lin_vmem_params {
> +	__s16 lin_lutlow_gr[IPU3_UAPI_LIN_LUT_SIZE];
> +	__s16 lin_lutlow_r[IPU3_UAPI_LIN_LUT_SIZE];
> +	__s16 lin_lutlow_b[IPU3_UAPI_LIN_LUT_SIZE];
> +	__s16 lin_lutlow_gb[IPU3_UAPI_LIN_LUT_SIZE];
> +	__s16 lin_lutdif_gr[IPU3_UAPI_LIN_LUT_SIZE];
> +	__s16 lin_lutdif_r[IPU3_UAPI_LIN_LUT_SIZE];
> +	__s16 lin_lutdif_b[IPU3_UAPI_LIN_LUT_SIZE];
> +	__s16 lin_lutdif_gb[IPU3_UAPI_LIN_LUT_SIZE];
> +} __packed;
> +
> +/* TNR3 VMEM parameters */
> +
> +#define IPU3_UAPI_ISP_TNR3_VMEM_LEN	9
> +
> +struct ipu3_uapi_isp_tnr3_vmem_params {
> +	__u16 slope[IPU3_UAPI_ISP_TNR3_VMEM_LEN];
> +	__u16 __reserved1[IPU3_UAPI_ISP_VEC_ELEMS
> +						- IPU3_UAPI_ISP_TNR3_VMEM_LEN];
> +	__u16 sigma[IPU3_UAPI_ISP_TNR3_VMEM_LEN];
> +	__u16 __reserved2[IPU3_UAPI_ISP_VEC_ELEMS
> +						- IPU3_UAPI_ISP_TNR3_VMEM_LEN];
> +} __packed;
> +
> +/* XNR3 VMEM parameters */
> +
> +struct ipu3_uapi_isp_xnr3_vmem_params {
> +	__u16 x[IPU3_UAPI_ISP_VEC_ELEMS];
> +	__u16 a[IPU3_UAPI_ISP_VEC_ELEMS];
> +	__u16 b[IPU3_UAPI_ISP_VEC_ELEMS];
> +	__u16 c[IPU3_UAPI_ISP_VEC_ELEMS];
> +} __packed;
> +
> +/* TNR3 DMEM parameters */
> +
> +struct ipu3_uapi_isp_tnr3_params {
> +	__u32 knee_y1;
> +	__u32 knee_y2;
> +	__u32 maxfb_y;
> +	__u32 maxfb_u;
> +	__u32 maxfb_v;
> +	__u32 round_adj_y;
> +	__u32 round_adj_u;
> +	__u32 round_adj_v;
> +	__u32 ref_buf_select;
> +} __packed;
> +
> +/* XNR3 DMEM parameters */
> +
> +struct ipu3_uapi_xnr3_alpha_params {
> +	__u32 y0;
> +	__u32 u0;
> +	__u32 v0;
> +	__u32 ydiff;
> +	__u32 udiff;
> +	__u32 vdiff;
> +} __packed;
> +
> +struct ipu3_uapi_xnr3_coring_params {
> +	__u32 u0;
> +	__u32 v0;
> +	__u32 udiff;
> +	__u32 vdiff;
> +} __packed;
> +
> +struct ipu3_uapi_xnr3_blending_params {
> +	__u32 strength;
> +} __packed;
> +
> +struct ipu3_uapi_isp_xnr3_params {
> +	struct ipu3_uapi_xnr3_alpha_params alpha;
> +	struct ipu3_uapi_xnr3_coring_params coring;
> +	struct ipu3_uapi_xnr3_blending_params blending;
> +} __packed;
> +
> +/* RGBIR DMEM parameters */
> +
> +#define IPU3_UAPI_RGBIR_LUT_WIDTH	17
> +#define IPU3_UAPI_RGBIR_LUT_HEIGHT	10
> +#define IPU3_UAPI_RGBIR_LUT_SIZE	(IPU3_UAPI_RGBIR_LUT_WIDTH * \
> +					 IPU3_UAPI_RGBIR_LUT_HEIGHT)
> +
> +struct ipu3_uapi_isp_rgbir_params {
> +	__u16 ob;					/* optical black level*/
> +	__u16 ir_height;				/* lut table height */
> +	__u16 ir_width;					/* lut table width */
> +	__u16 ir_weights_r[IPU3_UAPI_RGBIR_LUT_SIZE];	/* lut values for red */
> +	__u16 ir_weights_g[IPU3_UAPI_RGBIR_LUT_SIZE];	/* lut for green */
> +	__u16 ir_weights_b[IPU3_UAPI_RGBIR_LUT_SIZE];	/* lut for blue */
> +	__u16 ir_gain;					/* digital gain */
> +} __packed;
> +
> +/***** Morphing table entry *****/
> +
> +#define IPU3_UAPI_GDC_FRAC_BITS		8
> +
> +struct ipu3_uapi_gdc_warp_param {
> +	__u32 origin_x;
> +	__u32 origin_y;
> +	__u32 in_addr_offset;
> +	__u32 in_block_width;
> +	__u32 in_block_height;
> +	__u32 p0_x;
> +	__u32 p0_y;
> +	__u32 p1_x;
> +	__u32 p1_y;
> +	__u32 p2_x;
> +	__u32 p2_y;
> +	__u32 p3_x;
> +	__u32 p3_y;
> +	__u32 in_block_width_a;
> +	__u32 in_block_width_b;
> +	__u32 padding;			/* struct size multiple of DDR word */
> +} __packed;
> +
> +/***** Obgrid (optical black level compensation) table entry *****/
> +
> +struct ipu3_uapi_obgrid_param {
> +	__u16 gr;
> +	__u16 r;
> +	__u16 b;
> +	__u16 gb;
> +} __packed;
> +
> +/******************* V4L2_PIX_FMT_IPU3_PARAMS *******************/
> +
> +/*
> + * The video queue "parameters" is of format V4L2_PIX_FMT_IPU3_PARAMS.
> + * It is a multiplanar output queue with three planes and type
> + * V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE. User may also configure the
> + * video queue as V4L2_BUF_TYPE_VIDEO_OUTPUT with a single plane, in which
> + * case GDC and Obgrid tables can not be set.
> + *
> + * Plane 0: Defined below in struct ipu3_params, size 288064 bytes.
> + *          This contains a lot of parameters and flags selecting which
> + *          parameters to apply. Its size and resolution (1x1) are fixed.
> + *
> + * Plane 1: Contains geometric distortion correction grid coordinates.
> + *          Each entry in the grid is defined in
> + *          struct ipu3_uapi_gdc_warp_param.
> + *          The plane size is the grid entry size times the number of entries,
> + *          which depends on the main output image resolution and block size.
> + *
> + * Plane 2: Contains Obgrid grid. Each entry in the grid is 8 bytes.
> + *          The plane size depends on user parameters (internally, on chosen
> + *          firmware binary which depends on user parameters).
> + */
> +
> +struct ipu3_uapi_flags {
> +	/* Flags which of the settings below are to be applied */
> +	__u32 gdc:1;		/* Whether to apply GDC and */
> +	__u32 obgrid:1;		/* Obgrid planes */
> +	__u32 __reserved1:30;
> +
> +	__u32 __acc_stripe:1;	/* Whether to apply these fields from */
> +	__u32 __acc_input_feeder:1;	/* acc_param. Fields beginning with */
> +	__u32 acc_bnr:1;		/* two underscores are reserved and */
> +	__u32 acc_green_disparity:1;/* must not be enabled */
> +	__u32 acc_dm:1;
> +	__u32 acc_ccm:1;
> +	__u32 acc_gamma:1;
> +	__u32 acc_csc:1;
> +	__u32 acc_cds:1;
> +	__u32 acc_shd:1;
> +	__u32 acc_dvs_stat:1;
> +	__u32 acc_lace_stat:1;
> +	__u32 acc_iefd:1;
> +	__u32 acc_yds_c0:1;
> +	__u32 acc_chnr_c0:1;
> +	__u32 acc_y_ee_nr:1;
> +	__u32 acc_yds:1;
> +	__u32 acc_chnr:1;
> +	__u32 acc_ytm:1;
> +	__u32 acc_yds2:1;
> +	__u32 acc_tcc:1;
> +	__u32 acc_dpc:1;
> +	__u32 acc_bds:1;
> +	__u32 acc_anr:1;
> +	__u32 acc_awb_fr:1;
> +	__u32 acc_ae:1;
> +	__u32 acc_af:1;
> +	__u32 acc_awb:1;
> +	__u32 __acc_osys:1;
> +	__u32 __reserved2:3;
> +
> +	__u32 lin_vmem_params:1;	/* Whether to apply these structs */
> +	__u32 tnr3_vmem_params:1;
> +	__u32 xnr3_vmem_params:1;
> +	__u32 tnr3_dmem_params:1;
> +	__u32 xnr3_dmem_params:1;
> +	__u32 __rgbir_dmem_params:1;
> +	__u32 obgrid_param:1;
> +	__u32 __reserved3:25;
> +} __packed;
> +
> +struct ipu3_uapi_params {
> +	__u32 fourcc;			/* V4L2_PIX_FMT_IPU3_PARAMS */
> +	__u32 version;			/* Must be 0x100 */

These were called padding1 and padding2 in the previous version. What
happened?

I'd just call them reserved, and maybe also make the use field the first
member of the struct.

> +
> +	struct ipu3_uapi_flags use;
> +
> +	__u8 __reserved4[32 - 4 * 5];	/* Must be zero */

32 - sizeof(struct ipu3_uapi_flags) - sizeof(__u32) * 2

?

> +
> +	/* Acceleration cluster parameters */
> +	struct ipu3_uapi_acc_param acc_param;
> +
> +	/* VMEM parameters */
> +	struct ipu3_uapi_isp_lin_vmem_params lin_vmem_params;
> +	struct ipu3_uapi_isp_tnr3_vmem_params tnr3_vmem_params;
> +	struct ipu3_uapi_isp_xnr3_vmem_params xnr3_vmem_params;
> +
> +	/* DMEM parameters */
> +	struct ipu3_uapi_isp_tnr3_params tnr3_dmem_params;
> +	struct ipu3_uapi_isp_xnr3_params xnr3_dmem_params;
> +	struct ipu3_uapi_isp_rgbir_params rgbir_dmem_params;
> +
> +	struct ipu3_uapi_obgrid_param obgrid_param;
> +	__u8 padding[4];
> +} __packed;

Good to see everything is __packed now. How much there is currently actual
need for IPU3_ALIGN? Could you remover that as well?

> +
> +#endif

-- 
Regards,

Sakari Ailus
e-mail: sakari.ailus@iki.fi

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v4 06/12] intel-ipu3: css: imgu dma buff pool
  2017-10-18  3:54 ` [PATCH v4 06/12] intel-ipu3: css: imgu dma buff pool Yong Zhi
@ 2017-10-20 10:38   ` Sakari Ailus
  2017-10-23  3:10     ` Zhi, Yong
  0 siblings, 1 reply; 19+ messages in thread
From: Sakari Ailus @ 2017-10-20 10:38 UTC (permalink / raw)
  To: Yong Zhi
  Cc: linux-media, sakari.ailus, jian.xu.zheng, rajmohan.mani,
	tuukka.toivonen, jerry.w.hu, Tomasz Figa

On Tue, Oct 17, 2017 at 10:54:51PM -0500, Yong Zhi wrote:
> The pools are used to store previous parameters set by
> user with the parameter queue. Due to pipelining,
> there needs to be multiple sets (up to four)
> of parameters which are queued in a host-to-sp queue.
> 
> Signed-off-by: Yong Zhi <yong.zhi@intel.com>
> Signed-off-by: Tomasz Figa <tfiga@chromium.org>
> ---
>  drivers/media/pci/intel/ipu3/ipu3-css-pool.c | 132 +++++++++++++++++++++++++++
>  drivers/media/pci/intel/ipu3/ipu3-css-pool.h |  54 +++++++++++
>  2 files changed, 186 insertions(+)
>  create mode 100644 drivers/media/pci/intel/ipu3/ipu3-css-pool.c
>  create mode 100644 drivers/media/pci/intel/ipu3/ipu3-css-pool.h
> 
> diff --git a/drivers/media/pci/intel/ipu3/ipu3-css-pool.c b/drivers/media/pci/intel/ipu3/ipu3-css-pool.c
> new file mode 100644
> index 000000000000..d08e2a8b68ed
> --- /dev/null
> +++ b/drivers/media/pci/intel/ipu3/ipu3-css-pool.c
> @@ -0,0 +1,132 @@
> +/*
> + * Copyright (c) 2017 Intel Corporation.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License version
> + * 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that 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/dma-direction.h>
> +#include <linux/scatterlist.h>
> +#include <linux/types.h>
> +
> +#include "ipu3-css-pool.h"
> +#include "ipu3-dmamap.h"
> +
> +int ipu3_css_dma_alloc(struct device *dev,
> +		       struct ipu3_css_map *map, size_t size)
> +{
> +	struct imgu_device *imgu = dev_get_drvdata(dev);
> +
> +	if (size == 0) {
> +		map->vaddr = NULL;
> +		return 0;
> +	}
> +
> +	if (!ipu3_dmamap_alloc(imgu, map, size))
> +		return -ENOMEM;
> +
> +	return 0;
> +}
> +
> +void ipu3_css_dma_free(struct device *dev, struct ipu3_css_map *map)
> +{
> +	struct imgu_device *imgu = dev_get_drvdata(dev);
> +
> +	ipu3_dmamap_free(imgu, map);
> +}
> +
> +void ipu3_css_pool_cleanup(struct device *dev, struct ipu3_css_pool *pool)
> +{
> +	int i;
> +
> +	for (i = 0; i < IPU3_CSS_POOL_SIZE; i++)
> +		ipu3_css_dma_free(dev, &pool->entry[i].param);
> +}
> +
> +int ipu3_css_pool_init(struct device *dev, struct ipu3_css_pool *pool,
> +		       int size)
> +{
> +	int i;
> +
> +	for (i = 0; i < IPU3_CSS_POOL_SIZE; i++) {
> +		pool->entry[i].framenum = INT_MIN;
> +		if (ipu3_css_dma_alloc(dev, &pool->entry[i].param, size))
> +			goto fail;
> +	}
> +
> +	pool->last = IPU3_CSS_POOL_SIZE;
> +
> +	return 0;
> +
> +fail:
> +	ipu3_css_pool_cleanup(dev, pool);
> +	return -ENOMEM;
> +}
> +
> +/*
> + * Check that the following call to pool_get succeeds.
> + * Return negative on error.
> + */
> +static int ipu3_css_pool_check(struct ipu3_css_pool *pool, long framenum)
> +{
> +	/* Get the oldest entry */
> +	int n = (pool->last + 1) % IPU3_CSS_POOL_SIZE;
> +
> +	/*
> +	 * pool->entry[n].framenum stores the frame number where that
> +	 * entry was allocated. If that was allocated more than POOL_SIZE
> +	 * frames back, it is old enough that we know it is no more in
> +	 * use by firmware.
> +	 */
> +	if (pool->entry[n].framenum + IPU3_CSS_POOL_SIZE > framenum)

This will wrap around and the comparison fails when pool->entry[n].framenum
+ IPU3_CSS_POOL_SIZE - 1 reaches LONG_MAX.

You could write this as:

if (framenum - pool->entry[n].franenum < IPU3_CSS_POOL_SIZE)

to avoid the problem.

You could use also int instead of long without any other changes to the
code, or change INT_MAX / INT_MIN assignments to LONG_MAX / LONG_MIN.

> +		return -ENOSPC;
> +
> +	return n;
> +}
> +
> +/*
> + * Allocate a new parameter from pool at frame number `framenum'.
> + * Release the oldest entry in the pool to make space for the new entry.
> + * Return negative on error.
> + */
> +int ipu3_css_pool_get(struct ipu3_css_pool *pool, long framenum)
> +{
> +	int n = ipu3_css_pool_check(pool, framenum);
> +
> +	if (n < 0)
> +		return n;
> +
> +	pool->entry[n].framenum = framenum;
> +	pool->last = n;
> +
> +	return n;
> +}
> +
> +/*
> + * Undo, for all practical purposes, the effect of pool_get().
> + */
> +void ipu3_css_pool_put(struct ipu3_css_pool *pool)
> +{
> +	pool->entry[pool->last].framenum = INT_MIN;
> +	pool->last = (pool->last + IPU3_CSS_POOL_SIZE - 1) % IPU3_CSS_POOL_SIZE;
> +}
> +
> +const struct ipu3_css_map *
> +ipu3_css_pool_last(struct ipu3_css_pool *pool, unsigned int n)
> +{
> +	static const struct ipu3_css_map null_map = { 0 };
> +	int i = (pool->last + IPU3_CSS_POOL_SIZE - n) % IPU3_CSS_POOL_SIZE;
> +
> +	WARN_ON(n >= IPU3_CSS_POOL_SIZE);
> +
> +	if (pool->entry[i].framenum < 0)
> +		return &null_map;
> +
> +	return &pool->entry[i].param;
> +}
> diff --git a/drivers/media/pci/intel/ipu3/ipu3-css-pool.h b/drivers/media/pci/intel/ipu3/ipu3-css-pool.h
> new file mode 100644
> index 000000000000..9b6ac14acfb2
> --- /dev/null
> +++ b/drivers/media/pci/intel/ipu3/ipu3-css-pool.h
> @@ -0,0 +1,54 @@
> +/*
> + * Copyright (c) 2017 Intel Corporation.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License version
> + * 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that 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 __IPU3_UTIL_H
> +#define __IPU3_UTIL_H
> +
> +#include <linux/device.h>
> +
> +#define sqr(x)				((x) * (x))
> +#define DIV_ROUND_CLOSEST_DOWN(a, b)	(((a) + (b / 2) - 1) / (b))
> +#define roundclosest_down(a, b)		(DIV_ROUND_CLOSEST_DOWN(a, b) * (b))
> +#define roundclosest(n, di)				\
> +	({ typeof(n) __n = (n); typeof(di) __di = (di); \
> +	DIV_ROUND_CLOSEST(__n, __di) * __di; })
> +
> +#define IPU3_CSS_POOL_SIZE		4
> +
> +struct ipu3_css_map {
> +	size_t size;
> +	void *vaddr;
> +	dma_addr_t daddr;
> +	struct vm_struct *vma;
> +};
> +
> +struct ipu3_css_pool {
> +	struct {
> +		struct ipu3_css_map param;
> +		long framenum;
> +	} entry[IPU3_CSS_POOL_SIZE];
> +	unsigned int last; /* Latest entry */
> +};
> +
> +int ipu3_css_dma_alloc(struct device *dev, struct ipu3_css_map *map,
> +		       size_t size);
> +void ipu3_css_dma_free(struct device *dev, struct ipu3_css_map *map);
> +void ipu3_css_pool_cleanup(struct device *dev, struct ipu3_css_pool *pool);
> +int ipu3_css_pool_init(struct device *dev, struct ipu3_css_pool *pool,
> +		       int size);
> +int ipu3_css_pool_get(struct ipu3_css_pool *pool, long framenum);
> +void ipu3_css_pool_put(struct ipu3_css_pool *pool);
> +const struct ipu3_css_map *ipu3_css_pool_last(struct ipu3_css_pool *pool,
> +					      unsigned int last);
> +
> +#endif
> -- 
> 2.7.4
> 

-- 
Sakari Ailus
e-mail: sakari.ailus@iki.fi

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v4 11/12] intel-ipu3: Add imgu v4l2 driver
  2017-10-18  3:54 ` [PATCH v4 11/12] intel-ipu3: Add imgu v4l2 driver Yong Zhi
@ 2017-10-20 11:29   ` Sakari Ailus
  2017-10-23 22:41     ` Zhi, Yong
  0 siblings, 1 reply; 19+ messages in thread
From: Sakari Ailus @ 2017-10-20 11:29 UTC (permalink / raw)
  To: Yong Zhi
  Cc: linux-media, sakari.ailus, jian.xu.zheng, rajmohan.mani,
	tuukka.toivonen, jerry.w.hu, Ramya Vijaykumar

Hi Yong,

On Tue, Oct 17, 2017 at 10:54:56PM -0500, Yong Zhi wrote:
> ipu3 imgu video device based on v4l2, vb2 and
> media controller framework.
> 
> Signed-off-by: Yong Zhi <yong.zhi@intel.com>
> Signed-off-by: Ramya Vijaykumar <ramya.vijaykumar@intel.com>
> ---
>  drivers/media/pci/intel/ipu3/ipu3-v4l2.c | 1150 ++++++++++++++++++++++++++++++
>  1 file changed, 1150 insertions(+)
>  create mode 100644 drivers/media/pci/intel/ipu3/ipu3-v4l2.c
> 
> diff --git a/drivers/media/pci/intel/ipu3/ipu3-v4l2.c b/drivers/media/pci/intel/ipu3/ipu3-v4l2.c
> new file mode 100644
> index 000000000000..4618880b8675
> --- /dev/null
> +++ b/drivers/media/pci/intel/ipu3/ipu3-v4l2.c
> @@ -0,0 +1,1150 @@
> +/*
> + * Copyright (c) 2017 Intel Corporation.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License version
> + * 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that 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/module.h>
> +#include <linux/pm_runtime.h>
> +#include <media/v4l2-ioctl.h>
> +#include <media/videobuf2-dma-sg.h>
> +
> +#include "ipu3.h"
> +#include "ipu3-dmamap.h"
> +
> +/******************** v4l2_subdev_ops ********************/
> +
> +static int ipu3_subdev_s_stream(struct v4l2_subdev *sd, int enable)
> +{
> +	struct ipu3_mem2mem2_device *m2m2 =
> +		container_of(sd, struct ipu3_mem2mem2_device, subdev);
> +	int r = 0;
> +
> +	if (m2m2->ops && m2m2->ops->s_stream)
> +		r = m2m2->ops->s_stream(m2m2, enable);
> +
> +	if (!r)
> +		m2m2->streaming = enable;
> +
> +	return r;
> +}
> +
> +static int ipu3_subdev_get_fmt(struct v4l2_subdev *sd,
> +			       struct v4l2_subdev_pad_config *cfg,
> +			       struct v4l2_subdev_format *fmt)
> +{
> +	struct ipu3_mem2mem2_device *m2m2 =
> +		container_of(sd, struct ipu3_mem2mem2_device, subdev);
> +	struct v4l2_mbus_framefmt *mf;
> +	u32 pad = fmt->pad;
> +
> +	if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
> +		fmt->format = m2m2->nodes[pad].pad_fmt;
> +	} else {
> +		mf = v4l2_subdev_get_try_format(sd, cfg, pad);
> +		fmt->format = *mf;
> +	}
> +
> +	return 0;
> +}
> +
> +static int ipu3_subdev_set_fmt(struct v4l2_subdev *sd,
> +			       struct v4l2_subdev_pad_config *cfg,
> +			       struct v4l2_subdev_format *fmt)
> +{
> +	struct ipu3_mem2mem2_device *m2m2 =
> +		container_of(sd, struct ipu3_mem2mem2_device, subdev);
> +	struct v4l2_mbus_framefmt *mf;
> +	u32 pad = fmt->pad;
> +
> +	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
> +		mf = v4l2_subdev_get_try_format(sd, cfg, pad);
> +	else
> +		mf = &m2m2->nodes[pad].pad_fmt;
> +
> +	/* Clamp the w and h based on the hardware capabilities */
> +	if (m2m2->subdev_pads[pad].flags & MEDIA_PAD_FL_SOURCE) {
> +		fmt->format.width = clamp(fmt->format.width,
> +					  IPU3_OUTPUT_MIN_WIDTH,
> +					  IPU3_OUTPUT_MAX_WIDTH);
> +		fmt->format.height = clamp(fmt->format.height,
> +					   IPU3_OUTPUT_MIN_HEIGHT,
> +					   IPU3_OUTPUT_MAX_HEIGHT);
> +	} else {
> +		fmt->format.width = clamp(fmt->format.width,
> +					  IPU3_INPUT_MIN_WIDTH,
> +					  IPU3_INPUT_MAX_WIDTH);
> +		fmt->format.height = clamp(fmt->format.height,
> +					   IPU3_INPUT_MIN_HEIGHT,
> +					   IPU3_INPUT_MAX_HEIGHT);
> +	}
> +
> +	*mf = fmt->format;
> +
> +	return 0;
> +}
> +
> +/******************** media_entity_operations ********************/
> +
> +static int ipu3_link_setup(struct media_entity *entity,
> +			   const struct media_pad *local,
> +			   const struct media_pad *remote, u32 flags)
> +{
> +	struct ipu3_mem2mem2_device *m2m2 =
> +	    container_of(entity, struct ipu3_mem2mem2_device, subdev.entity);
> +	u32 pad = local->index;
> +
> +	WARN_ON(pad >= m2m2->num_nodes);
> +
> +	m2m2->nodes[pad].enabled = !!(flags & MEDIA_LNK_FL_ENABLED);
> +
> +	return 0;
> +}
> +
> +/******************** vb2_ops ********************/
> +
> +static int ipu3_vb2_buf_init(struct vb2_buffer *vb)
> +{
> +	struct sg_table *sg = vb2_dma_sg_plane_desc(vb, 0);
> +	struct ipu3_mem2mem2_device *m2m2 = vb2_get_drv_priv(vb->vb2_queue);
> +	struct imgu_device *imgu =
> +		container_of(m2m2, struct imgu_device, mem2mem2);
> +	struct imgu_buffer *buf = container_of(vb,
> +		struct imgu_buffer, m2m2_buf.vbb.vb2_buf);
> +	struct imgu_video_device *node =
> +		container_of(vb->vb2_queue, struct imgu_video_device, vbq);
> +	int queue = imgu_node_to_queue(node - m2m2->nodes);
> +
> +	if (queue == IPU3_CSS_QUEUE_PARAMS)
> +		return 0;
> +
> +	return ipu3_dmamap_map_sg(imgu, sg->sgl, sg->nents,
> +				  vb->vb2_queue->dma_dir, &buf->map);
> +}
> +
> +/* Called when each buffer is freed */
> +static void ipu3_vb2_buf_cleanup(struct vb2_buffer *vb)
> +{
> +	struct ipu3_mem2mem2_device *m2m2 = vb2_get_drv_priv(vb->vb2_queue);
> +	struct imgu_device *imgu =
> +		container_of(m2m2, struct imgu_device, mem2mem2);
> +	struct imgu_buffer *buf = container_of(vb,
> +		struct imgu_buffer, m2m2_buf.vbb.vb2_buf);
> +	struct imgu_video_device *node =
> +		container_of(vb->vb2_queue, struct imgu_video_device, vbq);
> +	int queue = imgu_node_to_queue(node - m2m2->nodes);
> +
> +	if (queue == IPU3_CSS_QUEUE_PARAMS)
> +		return;
> +
> +	ipu3_dmamap_unmap(imgu, &buf->map);
> +}
> +
> +/* Transfer buffer ownership to me */
> +static void ipu3_vb2_buf_queue(struct vb2_buffer *vb)
> +{
> +	struct ipu3_mem2mem2_device *m2m2 = vb2_get_drv_priv(vb->vb2_queue);
> +	struct imgu_device *imgu =
> +		container_of(m2m2, struct imgu_device, mem2mem2);
> +	struct imgu_video_device *node =
> +		container_of(vb->vb2_queue, struct imgu_video_device, vbq);
> +	int queue;
> +
> +	queue = imgu_node_to_queue(node - m2m2->nodes);
> +
> +	if (queue < 0) {
> +		dev_err(&imgu->pci_dev->dev, "Invalid imgu node.\n");
> +		return;
> +	}
> +
> +	if (queue == IPU3_CSS_QUEUE_PARAMS) {
> +		unsigned long need_bytes = sizeof(struct ipu3_uapi_params);
> +		unsigned long payload = vb2_get_plane_payload(vb, 0);
> +		struct vb2_v4l2_buffer *buf =
> +			container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
> +		int r = -EINVAL;
> +
> +		if (payload == 0) {
> +			payload = need_bytes;
> +			vb2_set_plane_payload(vb, 0, payload);
> +		}
> +		if (payload >= need_bytes)
> +			r = ipu3_css_set_parameters(&imgu->css,
> +						    vb2_plane_vaddr(vb, 0),
> +						    NULL, 0, NULL, 0);
> +		buf->flags = V4L2_BUF_FLAG_DONE;
> +		vb2_buffer_done(vb, r == 0 ? VB2_BUF_STATE_DONE
> +					   : VB2_BUF_STATE_ERROR);
> +
> +	} else {
> +		struct imgu_buffer *buf = container_of(vb,
> +				struct imgu_buffer, m2m2_buf.vbb.vb2_buf);
> +
> +		mutex_lock(&imgu->lock);
> +		ipu3_css_buf_init(&buf->css_buf, queue, buf->map.daddr);
> +		list_add_tail(&buf->m2m2_buf.list,
> +			      &m2m2->nodes[node - m2m2->nodes].buffers);
> +		mutex_unlock(&imgu->lock);
> +
> +		if (imgu->mem2mem2.streaming)
> +			imgu_queue_buffers(imgu, false);
> +	}
> +}
> +
> +static int ipu3_vb2_queue_setup(struct vb2_queue *vq,
> +				unsigned int *num_buffers,
> +				unsigned int *num_planes,
> +				unsigned int sizes[],
> +				struct device *alloc_devs[])
> +{
> +	struct ipu3_mem2mem2_device *m2m2 = vb2_get_drv_priv(vq);
> +	struct imgu_video_device *node =
> +		container_of(vq, struct imgu_video_device, vbq);
> +	const struct v4l2_format *fmt = &node->vdev_fmt;
> +
> +	*num_planes = 1;
> +	*num_buffers = clamp_val(*num_buffers, 1, VB2_MAX_FRAME);
> +
> +	alloc_devs[0] = m2m2->vb2_alloc_dev;
> +
> +	if (vq->type == V4L2_BUF_TYPE_META_CAPTURE ||
> +	    vq->type == V4L2_BUF_TYPE_META_OUTPUT) {
> +		sizes[0] = fmt->fmt.meta.buffersize;
> +	} else {
> +		sizes[0] = fmt->fmt.pix_mp.plane_fmt[0].sizeimage;
> +	}
> +
> +	/* Initialize buffer queue */
> +	INIT_LIST_HEAD(&node->buffers);
> +
> +	return 0;
> +}
> +
> +/* Check if all enabled video nodes are streaming, exception ignored */
> +static bool ipu3_all_nodes_streaming(struct ipu3_mem2mem2_device *m2m2,
> +				     struct imgu_video_device *except)
> +{
> +	int i;
> +
> +	for (i = 0; i < m2m2->num_nodes; i++) {
> +		struct imgu_video_device *node = &m2m2->nodes[i];
> +
> +		if (node == except)
> +			continue;
> +		if (node->enabled && !vb2_start_streaming_called(&node->vbq))
> +			return false;
> +	}
> +
> +	return true;
> +}
> +
> +static void ipu3_return_all_buffers(struct ipu3_mem2mem2_device *m2m2,
> +				    struct imgu_video_device *node,
> +				    enum vb2_buffer_state state)
> +{
> +	struct imgu_device *imgu =
> +			container_of(m2m2, struct imgu_device, mem2mem2);
> +	struct ipu3_mem2mem2_buffer *b, *b0;
> +
> +	/* Return all buffers */
> +	mutex_lock(&imgu->lock);
> +	list_for_each_entry_safe(b, b0, &node->buffers, list) {
> +		list_del(&b->list);
> +		vb2_buffer_done(&b->vbb.vb2_buf, state);
> +	}
> +	mutex_unlock(&imgu->lock);
> +}
> +
> +static int ipu3_vb2_start_streaming(struct vb2_queue *vq, unsigned int count)
> +{
> +	struct ipu3_mem2mem2_device *m2m2 = vb2_get_drv_priv(vq);
> +	struct imgu_video_device *node =
> +		container_of(vq, struct imgu_video_device, vbq);
> +	int r;
> +
> +	if (m2m2->streaming) {
> +		r = -EBUSY;
> +		goto fail_return_bufs;
> +	}
> +
> +	if (!node->enabled) {
> +		r = -EINVAL;
> +		goto fail_return_bufs;
> +	}
> +
> +	r = media_pipeline_start(&node->vdev.entity, &m2m2->pipeline);
> +	if (r < 0)
> +		goto fail_return_bufs;
> +
> +	if (!ipu3_all_nodes_streaming(m2m2, node))
> +		return 0;
> +
> +	/* Start streaming of the whole pipeline now */
> +
> +	r = v4l2_subdev_call(&m2m2->subdev, video, s_stream, 1);
> +	if (r < 0)
> +		goto fail_stop_pipeline;
> +
> +	return 0;
> +
> +fail_stop_pipeline:
> +	media_pipeline_stop(&node->vdev.entity);
> +fail_return_bufs:
> +	ipu3_return_all_buffers(m2m2, node, VB2_BUF_STATE_QUEUED);
> +
> +	return r;
> +}
> +
> +static void ipu3_vb2_stop_streaming(struct vb2_queue *vq)
> +{
> +	struct ipu3_mem2mem2_device *m2m2 = vb2_get_drv_priv(vq);
> +	struct imgu_video_device *node =
> +		container_of(vq, struct imgu_video_device, vbq);
> +	int r;
> +
> +	WARN_ON(!node->enabled);
> +
> +	/* Was this the first node with streaming disabled? */
> +	if (ipu3_all_nodes_streaming(m2m2, node)) {
> +		/* Yes, really stop streaming now */
> +		r = v4l2_subdev_call(&m2m2->subdev, video, s_stream, 0);
> +		if (r)
> +			dev_err(m2m2->dev, "failed to stop streaming\n");
> +	}
> +
> +	ipu3_return_all_buffers(m2m2, node, VB2_BUF_STATE_ERROR);
> +	media_pipeline_stop(&node->vdev.entity);
> +}
> +
> +/******************** v4l2_ioctl_ops ********************/
> +
> +#define M2M_CAPTURE	0
> +#define M2M_OUTPUT	1
> +
> +struct ipu3_fmt {
> +	u32	fourcc;
> +	u16	types; /* M2M_CAPTURE or M2M_OUTPUT not both */
> +};
> +
> +/* format descriptions for capture and preview */
> +static const struct ipu3_fmt formats[] = {
> +	{
> +		.fourcc	= V4L2_PIX_FMT_NV12,
> +		/* Capture format */
> +		.types	= M2M_CAPTURE,
> +	}, {
> +		.fourcc	= V4L2_PIX_FMT_IPU3_SBGGR10,
> +		/* Output format */
> +		.types	= M2M_OUTPUT,
> +	}, {
> +		.fourcc	= V4L2_PIX_FMT_IPU3_SGBRG10,
> +		.types	= M2M_OUTPUT,
> +	}, {
> +		.fourcc	= V4L2_PIX_FMT_IPU3_SGRBG10,
> +		.types	= M2M_OUTPUT,
> +	}, {
> +		.fourcc	= V4L2_PIX_FMT_IPU3_SRGGB10,
> +		.types	= M2M_OUTPUT,
> +	},
> +};
> +
> +/* Find the first matched format, return default if not found */
> +static const struct ipu3_fmt *find_format(struct v4l2_format *f, u32 type)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(formats); i++) {
> +		if (formats[i].fourcc == f->fmt.pix_mp.pixelformat &&
> +		    formats[i].types == type)
> +			return &formats[i];
> +	}
> +
> +	return type == M2M_CAPTURE ? &formats[0] :
> +			&formats[ARRAY_SIZE(formats) - 1];
> +}
> +
> +static int ipu3_videoc_querycap(struct file *file, void *fh,
> +				struct v4l2_capability *cap)
> +{
> +	struct ipu3_mem2mem2_device *m2m2 = video_drvdata(file);
> +	struct imgu_video_device *node = file_to_intel_ipu3_node(file);
> +
> +	strlcpy(cap->driver, m2m2->name, sizeof(cap->driver));
> +	strlcpy(cap->card, m2m2->model, sizeof(cap->card));
> +	snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", node->name);
> +
> +	return 0;
> +}
> +
> +static int enum_fmts(struct v4l2_fmtdesc *f, u32 type)
> +{
> +	unsigned int i, j;
> +
> +	for (i = j = 0; i < ARRAY_SIZE(formats); ++i) {
> +		if (formats[i].types == type) {
> +			if (j == f->index)
> +				break;
> +			++j;
> +		}
> +	}
> +
> +	if (i < ARRAY_SIZE(formats)) {
> +		f->pixelformat = formats[i].fourcc;
> +		return 0;
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
> +				   struct v4l2_fmtdesc *f)
> +{
> +	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
> +		return -EINVAL;
> +
> +	return enum_fmts(f, M2M_CAPTURE);
> +}
> +
> +static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
> +				   struct v4l2_fmtdesc *f)
> +{
> +	if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
> +		return -EINVAL;
> +
> +	return enum_fmts(f, M2M_OUTPUT);
> +}
> +
> +/* Propagate forward always the format from the CIO2 subdev */
> +static int ipu3_videoc_g_fmt(struct file *file, void *fh,
> +			     struct v4l2_format *f)
> +{
> +	struct imgu_video_device *node = file_to_intel_ipu3_node(file);
> +
> +	f->fmt = node->vdev_fmt.fmt;
> +
> +	return 0;
> +}
> +
> +/*
> + * Set input/output format. Unless it is just a try, this also resets
> + * selections (ie. effective and BDS resolutions) to defaults.
> + */
> +static int mem2mem2_fmt(struct ipu3_mem2mem2_device *m2m2_dev,
> +			int node, struct v4l2_format *f, bool try)
> +{
> +	struct imgu_device *imgu =
> +		container_of(m2m2_dev, struct imgu_device, mem2mem2);
> +	struct v4l2_pix_format_mplane try_fmts[IPU3_CSS_QUEUES];
> +	struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES] = { NULL };
> +	struct v4l2_rect *rects[IPU3_CSS_RECTS] = { NULL };
> +	unsigned int i;
> +	int css_q, r;
> +	struct v4l2_mbus_framefmt pad_fmt;
> +
> +	if (m2m2_dev->nodes[IMGU_NODE_PV].enabled &&
> +	    m2m2_dev->nodes[IMGU_NODE_VF].enabled) {
> +		dev_err(&imgu->pci_dev->dev,
> +			"Postview and vf are not supported simultaneously\n");
> +		return -EINVAL;
> +	}
> +	/*
> +	 * Tell css that the vf q is used for PV
> +	 */
> +	if (m2m2_dev->nodes[IMGU_NODE_PV].enabled)
> +		imgu->css.vf_output_en = IPU3_NODE_PV_ENABLED;
> +	else
> +		imgu->css.vf_output_en = IPU3_NODE_VF_ENABLED;
> +
> +	for (i = 0; i < IPU3_CSS_QUEUES; i++) {
> +		int inode = imgu_map_node(imgu, i);
> +
> +		if (inode < 0)
> +			return -EINVAL;
> +
> +		/* Skip the meta node */
> +		if (inode == IMGU_NODE_STAT_3A || inode == IMGU_NODE_STAT_DVS ||
> +		    inode == IMGU_NODE_STAT_LACE || inode == IMGU_NODE_PARAMS)
> +			continue;
> +
> +		if (try) {
> +			try_fmts[i] =
> +				m2m2_dev->nodes[inode].vdev_fmt.fmt.pix_mp;
> +			fmts[i] = &try_fmts[i];
> +		} else {
> +			fmts[i] = &m2m2_dev->nodes[inode].vdev_fmt.fmt.pix_mp;
> +		}
> +
> +		/* CSS expects some format on OUT queue */
> +		if (i != IPU3_CSS_QUEUE_OUT &&
> +		    !m2m2_dev->nodes[inode].enabled && inode != node)
> +			fmts[i] = NULL;
> +	}
> +
> +	if (!try) {
> +		/* eff and bds res got by m2m2_s_sel */
> +		rects[IPU3_CSS_RECT_EFFECTIVE] = &imgu->rect.eff;
> +		rects[IPU3_CSS_RECT_BDS] = &imgu->rect.bds;
> +		rects[IPU3_CSS_RECT_GDC] = &imgu->rect.gdc;
> +
> +		/* suppose that pad fmt was set by subdev s_fmt before */
> +		pad_fmt = m2m2_dev->nodes[IMGU_NODE_IN].pad_fmt;
> +		rects[IPU3_CSS_RECT_GDC]->width = pad_fmt.width;
> +		rects[IPU3_CSS_RECT_GDC]->height = pad_fmt.height;
> +	}
> +
> +	/*
> +	 * ipu3_mem2mem2 doesn't set the node to the value given by user
> +	 * before we return success from this function, so set it here.
> +	 */
> +	css_q = imgu_node_to_queue(node);
> +	if (fmts[css_q])
> +		*fmts[css_q] = f->fmt.pix_mp;
> +
> +	if (try)
> +		r = ipu3_css_fmt_try(&imgu->css, fmts, rects);
> +	else
> +		r = ipu3_css_fmt_set(&imgu->css, fmts, rects);
> +
> +	/* r is the binary number in the firmware blob */
> +	if (r < 0)
> +		return r;
> +
> +	if (try)
> +		f->fmt.pix_mp = *fmts[css_q];
> +	else
> +		f->fmt = m2m2_dev->nodes[node].vdev_fmt.fmt;
> +
> +	return 0;
> +}
> +
> +static int mem2mem2_s_selection(struct ipu3_mem2mem2_device *m2m2_dev,
> +				int node, struct v4l2_selection *s)
> +{
> +	struct imgu_device *const imgu =
> +		container_of(m2m2_dev, struct imgu_device, mem2mem2);
> +	struct v4l2_rect *rect = NULL;
> +
> +	if (node != IPU3_CSS_QUEUE_IN)
> +		return -ENOIOCTLCMD;
> +
> +	switch (s->target) {
> +	case V4L2_SEL_TGT_CROP:
> +		rect = &imgu->rect.eff;
> +		break;
> +	case V4L2_SEL_TGT_COMPOSE:
> +		rect = &imgu->rect.bds;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	*rect = s->r;
> +
> +	return 0;
> +}
> +
> +static int mem2mem2_g_selection(struct ipu3_mem2mem2_device *m2m2_dev,
> +				int node, struct v4l2_selection *s)
> +{
> +	struct imgu_device *const imgu =
> +		container_of(m2m2_dev, struct imgu_device, mem2mem2);
> +
> +	if (node != IPU3_CSS_QUEUE_IN)
> +		return -ENOIOCTLCMD;
> +
> +	switch (s->target) {
> +	case V4L2_SEL_TGT_CROP:
> +		s->r = imgu->rect.eff;
> +		break;
> +	case V4L2_SEL_TGT_CROP_BOUNDS:
> +		break;
> +	case V4L2_SEL_TGT_CROP_DEFAULT:
> +		break;
> +	case V4L2_SEL_TGT_COMPOSE_PADDED:
> +		break;
> +	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
> +		break;
> +	case V4L2_SEL_TGT_COMPOSE:
> +		s->r = imgu->rect.bds;
> +		break;
> +	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
> +		break;
> +

As the driver uses the V4L2 sub-device interface, the selection API
belongsis implemented in the sub-device node, not the video nodes.

> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int ipu3_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
> +{
> +	struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
> +	const struct ipu3_fmt *fmt;
> +
> +	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
> +		fmt = find_format(f, M2M_CAPTURE);
> +	else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
> +		fmt = find_format(f, M2M_OUTPUT);
> +	else
> +		return -EINVAL;
> +
> +	pixm->pixelformat = fmt->fourcc;
> +
> +	memset(pixm->plane_fmt[0].reserved, 0,
> +	       sizeof(pixm->plane_fmt[0].reserved));

No need for the memset here, the framework handles this.

Are there limits on the image size?

> +
> +	return 0;
> +}
> +
> +static int ipu3_videoc_try_fmt(struct file *file, void *fh,
> +			       struct v4l2_format *f)
> +{
> +	struct ipu3_mem2mem2_device *m2m2 = video_drvdata(file);
> +	struct imgu_video_device *node = file_to_intel_ipu3_node(file);
> +	int r;
> +
> +	r = ipu3_try_fmt(file, fh, f);
> +	if (r)
> +		return r;
> +
> +	return mem2mem2_fmt(m2m2, node - m2m2->nodes, f, true);
> +}
> +
> +static int ipu3_videoc_s_fmt(struct file *file, void *fh,
> +			     struct v4l2_format *f)
> +{
> +	struct ipu3_mem2mem2_device *m2m2 = video_drvdata(file);
> +	struct imgu_video_device *node = file_to_intel_ipu3_node(file);
> +	int r;
> +
> +	r = ipu3_try_fmt(file, fh, f);
> +	if (r)
> +		return r;
> +
> +	return mem2mem2_fmt(m2m2, node - m2m2->nodes, f, false);
> +}
> +
> +static int ipu3_videoc_s_selection(struct file *file, void *fh,
> +				   struct v4l2_selection *s)
> +{
> +	struct ipu3_mem2mem2_device *m2m2 = video_drvdata(file);
> +	struct imgu_video_device *node = file_to_intel_ipu3_node(file);
> +
> +	if (!m2m2->ops)
> +		return -ENOIOCTLCMD;
> +
> +	if (s->type != node->vdev_fmt.type)
> +		return -EINVAL;
> +
> +	return mem2mem2_s_selection(m2m2, node - m2m2->nodes, s);
> +}
> +
> +static int ipu3_videoc_g_selection(struct file *file, void *fh,
> +				   struct v4l2_selection *s)
> +{
> +	struct ipu3_mem2mem2_device *m2m2 = video_drvdata(file);
> +	struct imgu_video_device *node = file_to_intel_ipu3_node(file);
> +
> +	if (!m2m2->ops)
> +		return -ENOIOCTLCMD;
> +
> +	if (s->type != node->vdev_fmt.type)
> +		return -EINVAL;
> +
> +	return mem2mem2_g_selection(m2m2, node - m2m2->nodes, s);
> +}
> +
> +static int ipu3_vidioc_enum_input(struct file *file, void *fh,
> +				  struct v4l2_input *input)
> +{
> +	if (input->index > 0)
> +		return -EINVAL;
> +	strlcpy(input->name, "camera", sizeof(input->name));
> +	input->type = V4L2_INPUT_TYPE_CAMERA;
> +
> +	return 0;
> +}
> +
> +static int ipu3_vidioc_g_input(struct file *file, void *fh, unsigned int *input)
> +{
> +	*input = 0;
> +
> +	return 0;
> +}
> +
> +static int ipu3_vidioc_s_input(struct file *file, void *fh,
> +			       unsigned int input)
> +{
> +	return input == 0 ? 0 : -EINVAL;
> +}
> +
> +static int ipu3_vidioc_enum_output(struct file *file, void *fh,
> +				   struct v4l2_output *output)
> +{
> +	if (output->index > 0)
> +		return -EINVAL;
> +	strlcpy(output->name, "camera", sizeof(output->name));
> +	output->type = V4L2_INPUT_TYPE_CAMERA;
> +
> +	return 0;
> +}
> +
> +static int ipu3_vidioc_g_output(struct file *file, void *fh,
> +				unsigned int *output)
> +{
> +	*output = 0;
> +
> +	return 0;
> +}
> +
> +static int ipu3_vidioc_s_output(struct file *file, void *fh,
> +				unsigned int output)
> +{
> +	return output == 0 ? 0 : -EINVAL;
> +}
> +
> +static int ipu3_meta_enum_format(struct file *file, void *fh,
> +				 struct v4l2_fmtdesc *f)
> +{
> +	struct imgu_video_device *node = file_to_intel_ipu3_node(file);
> +
> +	/* Each node is dedicated to only one meta format */
> +	if (f->index > 0 || f->type != node->vbq.type)
> +		return -EINVAL;
> +
> +	f->pixelformat = node->vdev_fmt.fmt.meta.dataformat;
> +
> +	return 0;
> +}
> +
> +static int ipu3_videoc_g_meta_fmt(struct file *file, void *fh,
> +				  struct v4l2_format *f)
> +{
> +	struct imgu_video_device *node = file_to_intel_ipu3_node(file);
> +
> +	if (f->type != node->vbq.type)
> +		return -EINVAL;
> +
> +	f->fmt = node->vdev_fmt.fmt;
> +
> +	return 0;
> +}
> +
> +/******************** function pointers ********************/
> +
> +static const struct v4l2_subdev_video_ops ipu3_subdev_video_ops = {
> +	.s_stream = ipu3_subdev_s_stream,
> +};
> +
> +static const struct v4l2_subdev_pad_ops ipu3_subdev_pad_ops = {
> +	.link_validate = v4l2_subdev_link_validate_default,
> +	.get_fmt = ipu3_subdev_get_fmt,
> +	.set_fmt = ipu3_subdev_set_fmt,
> +};
> +
> +static const struct v4l2_subdev_ops ipu3_subdev_ops = {
> +	.video = &ipu3_subdev_video_ops,
> +	.pad = &ipu3_subdev_pad_ops,
> +};
> +
> +static const struct media_entity_operations ipu3_media_ops = {
> +	.link_setup = ipu3_link_setup,
> +	.link_validate = v4l2_subdev_link_validate,
> +};
> +
> +/****************** vb2_ops of the Q ********************/
> +
> +static const struct vb2_ops ipu3_vb2_ops = {
> +	.buf_init = ipu3_vb2_buf_init,
> +	.buf_cleanup = ipu3_vb2_buf_cleanup,
> +	.buf_queue = ipu3_vb2_buf_queue,
> +	.queue_setup = ipu3_vb2_queue_setup,
> +	.start_streaming = ipu3_vb2_start_streaming,
> +	.stop_streaming = ipu3_vb2_stop_streaming,
> +	.wait_prepare = vb2_ops_wait_prepare,
> +	.wait_finish = vb2_ops_wait_finish,
> +};
> +
> +/****************** v4l2_file_operations *****************/
> +
> +static const struct v4l2_file_operations ipu3_v4l2_fops = {
> +	.unlocked_ioctl = video_ioctl2,
> +	.open = v4l2_fh_open,
> +	.release = vb2_fop_release,
> +	.poll = vb2_fop_poll,
> +	.mmap = vb2_fop_mmap,
> +};
> +
> +/******************** v4l2_ioctl_ops ********************/
> +
> +static const struct v4l2_ioctl_ops ipu3_v4l2_ioctl_ops = {
> +	.vidioc_querycap = ipu3_videoc_querycap,
> +
> +	.vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap,
> +	.vidioc_g_fmt_vid_cap_mplane = ipu3_videoc_g_fmt,
> +	.vidioc_s_fmt_vid_cap_mplane = ipu3_videoc_s_fmt,
> +	.vidioc_try_fmt_vid_cap_mplane = ipu3_videoc_try_fmt,
> +
> +	.vidioc_s_selection = ipu3_videoc_s_selection,
> +	.vidioc_g_selection = ipu3_videoc_g_selection,
> +
> +	.vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out,
> +	.vidioc_g_fmt_vid_out_mplane = ipu3_videoc_g_fmt,
> +	.vidioc_s_fmt_vid_out_mplane = ipu3_videoc_s_fmt,
> +	.vidioc_try_fmt_vid_out_mplane = ipu3_videoc_try_fmt,
> +
> +	.vidioc_enum_output = ipu3_vidioc_enum_output,
> +	.vidioc_g_output = ipu3_vidioc_g_output,
> +	.vidioc_s_output = ipu3_vidioc_s_output,
> +
> +	.vidioc_enum_input = ipu3_vidioc_enum_input,
> +	.vidioc_g_input = ipu3_vidioc_g_input,
> +	.vidioc_s_input = ipu3_vidioc_s_input,
> +
> +	/* buffer queue management */
> +	.vidioc_reqbufs = vb2_ioctl_reqbufs,
> +	.vidioc_create_bufs = vb2_ioctl_create_bufs,
> +	.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
> +	.vidioc_querybuf = vb2_ioctl_querybuf,
> +	.vidioc_qbuf = vb2_ioctl_qbuf,
> +	.vidioc_dqbuf = vb2_ioctl_dqbuf,
> +	.vidioc_streamon = vb2_ioctl_streamon,
> +	.vidioc_streamoff = vb2_ioctl_streamoff,
> +	.vidioc_expbuf = vb2_ioctl_expbuf,
> +};
> +
> +static const struct v4l2_ioctl_ops ipu3_v4l2_meta_ioctl_ops = {
> +	.vidioc_querycap = ipu3_videoc_querycap,
> +
> +	/* meta capture */
> +	.vidioc_enum_fmt_meta_cap = ipu3_meta_enum_format,
> +	.vidioc_g_fmt_meta_cap = ipu3_videoc_g_meta_fmt,
> +	.vidioc_s_fmt_meta_cap = ipu3_videoc_g_meta_fmt,
> +	.vidioc_try_fmt_meta_cap = ipu3_videoc_g_meta_fmt,
> +
> +	/* meta output */
> +	.vidioc_enum_fmt_meta_out = ipu3_meta_enum_format,
> +	.vidioc_g_fmt_meta_out = ipu3_videoc_g_meta_fmt,
> +	.vidioc_s_fmt_meta_out = ipu3_videoc_g_meta_fmt,
> +	.vidioc_try_fmt_meta_out = ipu3_videoc_g_meta_fmt,
> +
> +	.vidioc_reqbufs = vb2_ioctl_reqbufs,
> +	.vidioc_create_bufs = vb2_ioctl_create_bufs,
> +	.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
> +	.vidioc_querybuf = vb2_ioctl_querybuf,
> +	.vidioc_qbuf = vb2_ioctl_qbuf,
> +	.vidioc_dqbuf = vb2_ioctl_dqbuf,
> +	.vidioc_streamon = vb2_ioctl_streamon,
> +	.vidioc_streamoff = vb2_ioctl_streamoff,
> +	.vidioc_expbuf = vb2_ioctl_expbuf,
> +};
> +
> +/******************** Framework registration ********************/
> +
> +/* helper function to config node's video properties */
> +static void ipu3_node_to_v4l2(u32 node, struct video_device *vdev,
> +			      struct v4l2_format *f)
> +{
> +	u32 cap;
> +
> +	/* Should not happen */
> +	WARN_ON(node >= IMGU_NODE_NUM);
> +
> +	switch (node) {
> +	case IMGU_NODE_IN:
> +		cap = V4L2_CAP_VIDEO_OUTPUT_MPLANE;
> +		f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
> +		vdev->ioctl_ops = &ipu3_v4l2_ioctl_ops;
> +		break;
> +	case IMGU_NODE_PARAMS:
> +		cap = V4L2_CAP_META_OUTPUT;
> +		f->type = V4L2_BUF_TYPE_META_OUTPUT;
> +		f->fmt.meta.dataformat = V4L2_META_FMT_IPU3_PARAMS;
> +		vdev->ioctl_ops = &ipu3_v4l2_meta_ioctl_ops;
> +		ipu3_css_meta_fmt_set(&f->fmt.meta);
> +		break;
> +	case IMGU_NODE_STAT_3A:
> +		cap = V4L2_CAP_META_CAPTURE;
> +		f->type = V4L2_BUF_TYPE_META_CAPTURE;
> +		f->fmt.meta.dataformat = V4L2_META_FMT_IPU3_STAT_3A;
> +		vdev->ioctl_ops = &ipu3_v4l2_meta_ioctl_ops;
> +		ipu3_css_meta_fmt_set(&f->fmt.meta);
> +		break;
> +	case IMGU_NODE_STAT_DVS:
> +		cap = V4L2_CAP_META_CAPTURE;
> +		f->type = V4L2_BUF_TYPE_META_CAPTURE;
> +		f->fmt.meta.dataformat = V4L2_META_FMT_IPU3_STAT_DVS;
> +		vdev->ioctl_ops = &ipu3_v4l2_meta_ioctl_ops;
> +		ipu3_css_meta_fmt_set(&f->fmt.meta);
> +		break;
> +	case IMGU_NODE_STAT_LACE:
> +		cap = V4L2_CAP_META_CAPTURE;
> +		f->type = V4L2_BUF_TYPE_META_CAPTURE;
> +		f->fmt.meta.dataformat = V4L2_META_FMT_IPU3_STAT_LACE;
> +		vdev->ioctl_ops = &ipu3_v4l2_meta_ioctl_ops;
> +		ipu3_css_meta_fmt_set(&f->fmt.meta);
> +		break;
> +	default:
> +		cap = V4L2_CAP_VIDEO_CAPTURE_MPLANE;
> +		f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
> +		vdev->ioctl_ops = &ipu3_v4l2_ioctl_ops;
> +	}
> +
> +	vdev->device_caps = V4L2_CAP_STREAMING | cap;
> +}
> +
> +int ipu3_v4l2_register(struct imgu_device *dev)
> +{
> +	struct ipu3_mem2mem2_device *m2m2 = &dev->mem2mem2;
> +	struct v4l2_mbus_framefmt def_bus_fmt;
> +	struct v4l2_pix_format_mplane def_pix_fmt;
> +
> +	int i, r;
> +
> +	/* Initialize miscellaneous variables */
> +	m2m2->streaming = false;
> +	m2m2->v4l2_file_ops = ipu3_v4l2_fops;
> +
> +	/* Set up media device */
> +	m2m2->media_dev.dev = m2m2->dev;
> +	strlcpy(m2m2->media_dev.model, m2m2->model,
> +		sizeof(m2m2->media_dev.model));
> +	snprintf(m2m2->media_dev.bus_info, sizeof(m2m2->media_dev.bus_info),
> +		 "%s", dev_name(m2m2->dev));
> +	m2m2->media_dev.hw_revision = 0;
> +	media_device_init(&m2m2->media_dev);
> +	r = media_device_register(&m2m2->media_dev);
> +	if (r) {
> +		dev_err(m2m2->dev, "failed to register media device (%d)\n", r);
> +		goto fail_media_dev;

If there's nothing to clean up you can simply return the error here.

> +	}
> +
> +	/* Set up v4l2 device */
> +	m2m2->v4l2_dev.mdev = &m2m2->media_dev;
> +	m2m2->v4l2_dev.ctrl_handler = m2m2->ctrl_handler;
> +	r = v4l2_device_register(m2m2->dev, &m2m2->v4l2_dev);
> +	if (r) {
> +		dev_err(m2m2->dev, "failed to register V4L2 device (%d)\n", r);
> +		goto fail_v4l2_dev;
> +	}
> +
> +	/* Initialize subdev media entity */
> +	m2m2->subdev_pads = kzalloc(sizeof(*m2m2->subdev_pads) *
> +					m2m2->num_nodes, GFP_KERNEL);
> +	if (!m2m2->subdev_pads) {
> +		r = -ENOMEM;
> +		goto fail_subdev_pads;
> +	}
> +
> +	r = media_entity_pads_init(&m2m2->subdev.entity, m2m2->num_nodes,
> +				   m2m2->subdev_pads);
> +	if (r) {
> +		dev_err(m2m2->dev,
> +			"failed initialize subdev media entity (%d)\n", r);
> +		goto fail_media_entity;
> +	}
> +	m2m2->subdev.entity.ops = &ipu3_media_ops;
> +	for (i = 0; i < m2m2->num_nodes; i++) {
> +		m2m2->subdev_pads[i].flags = m2m2->nodes[i].output ?
> +			MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
> +	}
> +
> +	/* Initialize subdev */
> +	v4l2_subdev_init(&m2m2->subdev, &ipu3_subdev_ops);
> +	m2m2->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
> +	snprintf(m2m2->subdev.name, sizeof(m2m2->subdev.name),
> +		 "%s", m2m2->name);
> +	v4l2_set_subdevdata(&m2m2->subdev, m2m2);
> +	m2m2->subdev.ctrl_handler = m2m2->ctrl_handler;
> +	r = v4l2_device_register_subdev(&m2m2->v4l2_dev, &m2m2->subdev);
> +	if (r) {
> +		dev_err(m2m2->dev, "failed initialize subdev (%d)\n", r);
> +		goto fail_subdev;
> +	}
> +	r = v4l2_device_register_subdev_nodes(&m2m2->v4l2_dev);
> +	if (r) {
> +		dev_err(m2m2->dev, "failed to register subdevs (%d)\n", r);
> +		goto fail_subdevs;
> +	}
> +
> +	/* Initialize formats to default values */
> +	def_bus_fmt.width = 1920;
> +	def_bus_fmt.height = 1080;
> +	def_bus_fmt.code = MEDIA_BUS_FMT_UYVY8_2X8;
> +	def_bus_fmt.field = V4L2_FIELD_NONE;
> +	def_bus_fmt.colorspace = V4L2_COLORSPACE_RAW;
> +	def_bus_fmt.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
> +	def_bus_fmt.quantization = V4L2_QUANTIZATION_DEFAULT;
> +	def_bus_fmt.xfer_func = V4L2_XFER_FUNC_DEFAULT;
> +
> +	def_pix_fmt.width = def_bus_fmt.width;
> +	def_pix_fmt.height = def_bus_fmt.height;
> +	def_pix_fmt.field = def_bus_fmt.field;
> +	def_pix_fmt.num_planes = 1;
> +	def_pix_fmt.plane_fmt[0].bytesperline = def_pix_fmt.width * 2;
> +	def_pix_fmt.plane_fmt[0].sizeimage =
> +		def_pix_fmt.height * def_pix_fmt.plane_fmt[0].bytesperline;
> +	def_pix_fmt.flags = 0;
> +	def_pix_fmt.colorspace = def_bus_fmt.colorspace;
> +	def_pix_fmt.ycbcr_enc = def_bus_fmt.ycbcr_enc;
> +	def_pix_fmt.quantization = def_bus_fmt.quantization;
> +	def_pix_fmt.xfer_func = def_bus_fmt.xfer_func;
> +
> +	/* Create video nodes and links */
> +	for (i = 0; i < m2m2->num_nodes; i++) {
> +		struct imgu_video_device *node = &m2m2->nodes[i];
> +		struct video_device *vdev = &node->vdev;
> +		struct vb2_queue *vbq = &node->vbq;
> +		u32 flags;
> +
> +		/* Initialize miscellaneous variables */
> +		mutex_init(&node->lock);
> +		INIT_LIST_HEAD(&node->buffers);
> +
> +		/* Initialize formats to default values */
> +		node->pad_fmt = def_bus_fmt;
> +		ipu3_node_to_v4l2(i, vdev, &node->vdev_fmt);
> +		if (node->vdev_fmt.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ||
> +		    node->vdev_fmt.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
> +			def_pix_fmt.pixelformat = node->output ?
> +						V4L2_PIX_FMT_IPU3_SGRBG10 :
> +						V4L2_PIX_FMT_NV12;
> +			node->vdev_fmt.fmt.pix_mp = def_pix_fmt;
> +		}
> +
> +		/* Initialize media entities */
> +		r = media_entity_pads_init(&vdev->entity, 1, &node->vdev_pad);
> +		if (r) {
> +			dev_err(m2m2->dev,
> +				"failed initialize media entity (%d)\n", r);
> +			goto fail_vdev_media_entity;
> +		}
> +		node->vdev_pad.flags = node->output ?
> +			MEDIA_PAD_FL_SOURCE : MEDIA_PAD_FL_SINK;
> +		vdev->entity.ops = NULL;
> +
> +		/* Initialize vbq */
> +		vbq->type = node->vdev_fmt.type;
> +		vbq->io_modes = VB2_USERPTR | VB2_MMAP | VB2_DMABUF;
> +		vbq->ops = &ipu3_vb2_ops;
> +		vbq->mem_ops = m2m2->vb2_mem_ops;

dma_sg is the right one for all except the parameters; they are only
accessed by the driver, aren't they?

> +		if (m2m2->buf_struct_size <= 0)
> +			m2m2->buf_struct_size =
> +				sizeof(struct ipu3_mem2mem2_buffer);
> +		vbq->buf_struct_size = m2m2->buf_struct_size;
> +		vbq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
> +		vbq->min_buffers_needed = 0;	/* Can streamon w/o buffers */
> +		vbq->drv_priv = m2m2;
> +		vbq->lock = &node->lock;
> +		r = vb2_queue_init(vbq);
> +		if (r) {
> +			dev_err(m2m2->dev,
> +				"failed to initialize video queue (%d)\n", r);
> +			goto fail_vdev;
> +		}
> +
> +		/* Initialize vdev */
> +		strlcpy(vdev->name, node->name, sizeof(vdev->name));
> +		vdev->release = video_device_release_empty;
> +		vdev->fops = &m2m2->v4l2_file_ops;
> +		vdev->lock = &node->lock;
> +		vdev->v4l2_dev = &m2m2->v4l2_dev;
> +		vdev->queue = &node->vbq;
> +		vdev->vfl_dir = node->output ? VFL_DIR_TX : VFL_DIR_RX;
> +		video_set_drvdata(vdev, m2m2);
> +		r = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
> +		if (r) {
> +			dev_err(m2m2->dev,
> +				"failed to register video device (%d)\n", r);
> +			goto fail_vdev;
> +		}
> +
> +		/* Create link between video node and the subdev pad */
> +		flags = 0;
> +		if (node->enabled)
> +			flags |= MEDIA_LNK_FL_ENABLED;
> +		if (node->immutable)
> +			flags |= MEDIA_LNK_FL_IMMUTABLE;
> +		if (node->output) {
> +			r = media_create_pad_link(
> +						 &vdev->entity, 0,
> +						 &m2m2->subdev.entity,
> +						 i, flags);
> +		} else {
> +			r = media_create_pad_link(
> +						 &m2m2->subdev.entity,
> +						 i, &vdev->entity, 0,
> +						 flags);
> +		}
> +		if (r)
> +			goto fail_link;
> +	}
> +
> +	return 0;
> +
> +	for (; i >= 0; i--) {
> +fail_link:
> +		video_unregister_device(&m2m2->nodes[i].vdev);
> +fail_vdev:
> +		media_entity_cleanup(&m2m2->nodes[i].vdev.entity);
> +fail_vdev_media_entity:
> +		mutex_destroy(&m2m2->nodes[i].lock);
> +	}
> +fail_subdevs:
> +	v4l2_device_unregister_subdev(&m2m2->subdev);
> +fail_subdev:
> +	media_entity_cleanup(&m2m2->subdev.entity);
> +fail_media_entity:
> +	kfree(m2m2->subdev_pads);
> +fail_subdev_pads:
> +	v4l2_device_unregister(&m2m2->v4l2_dev);
> +fail_v4l2_dev:
> +	media_device_unregister(&m2m2->media_dev);
> +	media_device_cleanup(&m2m2->media_dev);
> +fail_media_dev:
> +
> +	return r;
> +}
> +EXPORT_SYMBOL_GPL(ipu3_v4l2_register);
> +
> +int ipu3_v4l2_unregister(struct imgu_device *dev)
> +{
> +	struct ipu3_mem2mem2_device *m2m2 = &dev->mem2mem2;
> +	unsigned int i;
> +
> +	for (i = 0; i < m2m2->num_nodes; i++) {
> +		video_unregister_device(&m2m2->nodes[i].vdev);
> +		media_entity_cleanup(&m2m2->nodes[i].vdev.entity);
> +		mutex_destroy(&m2m2->nodes[i].lock);
> +	}
> +
> +	v4l2_device_unregister_subdev(&m2m2->subdev);
> +	media_entity_cleanup(&m2m2->subdev.entity);
> +	kfree(m2m2->subdev_pads);
> +	v4l2_device_unregister(&m2m2->v4l2_dev);
> +	media_device_unregister(&m2m2->media_dev);
> +	media_device_cleanup(&m2m2->media_dev);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(ipu3_v4l2_unregister);
> +
> +void ipu3_v4l2_buffer_done(struct vb2_buffer *vb,
> +			   enum vb2_buffer_state state)
> +{
> +	struct ipu3_mem2mem2_buffer *b =
> +		container_of(vb, struct ipu3_mem2mem2_buffer, vbb.vb2_buf);
> +
> +	list_del(&b->list);
> +	vb2_buffer_done(&b->vbb.vb2_buf, state);
> +}
> +EXPORT_SYMBOL_GPL(ipu3_v4l2_buffer_done);
> -- 
> 2.7.4
> 

-- 
Sakari Ailus
e-mail: sakari.ailus@iki.fi

^ permalink raw reply	[flat|nested] 19+ messages in thread

* RE: [PATCH v4 06/12] intel-ipu3: css: imgu dma buff pool
  2017-10-20 10:38   ` Sakari Ailus
@ 2017-10-23  3:10     ` Zhi, Yong
  0 siblings, 0 replies; 19+ messages in thread
From: Zhi, Yong @ 2017-10-23  3:10 UTC (permalink / raw)
  To: 'Sakari Ailus'
  Cc: linux-media, sakari.ailus, Zheng, Jian Xu, Mani, Rajmohan,
	Toivonen, Tuukka, Hu, Jerry W, Tomasz Figa

Hi, Sakari,

Thanks for your review.

> -----Original Message-----
> From: Sakari Ailus [mailto:sakari.ailus@iki.fi]
> Sent: Friday, October 20, 2017 3:38 AM
> To: Zhi, Yong <yong.zhi@intel.com>
> Cc: linux-media@vger.kernel.org; sakari.ailus@linux.intel.com; Zheng, Jian
> Xu <jian.xu.zheng@intel.com>; Mani, Rajmohan
> <rajmohan.mani@intel.com>; Toivonen, Tuukka
> <tuukka.toivonen@intel.com>; Hu, Jerry W <jerry.w.hu@intel.com>; Tomasz
> Figa <tfiga@chromium.org>
> Subject: Re: [PATCH v4 06/12] intel-ipu3: css: imgu dma buff pool
> 
> On Tue, Oct 17, 2017 at 10:54:51PM -0500, Yong Zhi wrote:
> > The pools are used to store previous parameters set by user with the
> > parameter queue. Due to pipelining, there needs to be multiple sets
> > (up to four) of parameters which are queued in a host-to-sp queue.
> >
> > Signed-off-by: Yong Zhi <yong.zhi@intel.com>
> > Signed-off-by: Tomasz Figa <tfiga@chromium.org>
> > ---
> >  drivers/media/pci/intel/ipu3/ipu3-css-pool.c | 132
> > +++++++++++++++++++++++++++
> > drivers/media/pci/intel/ipu3/ipu3-css-pool.h |  54 +++++++++++
> >  2 files changed, 186 insertions(+)
> >  create mode 100644 drivers/media/pci/intel/ipu3/ipu3-css-pool.c
> >  create mode 100644 drivers/media/pci/intel/ipu3/ipu3-css-pool.h
> >
> > diff --git a/drivers/media/pci/intel/ipu3/ipu3-css-pool.c
> > b/drivers/media/pci/intel/ipu3/ipu3-css-pool.c
> > new file mode 100644
> > index 000000000000..d08e2a8b68ed
> > --- /dev/null
> > +++ b/drivers/media/pci/intel/ipu3/ipu3-css-pool.c
> > @@ -0,0 +1,132 @@
> > +/*
> > + * Copyright (c) 2017 Intel Corporation.
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > +version
> > + * 2 as published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope that 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/dma-direction.h>
> > +#include <linux/scatterlist.h>
> > +#include <linux/types.h>
> > +
> > +#include "ipu3-css-pool.h"
> > +#include "ipu3-dmamap.h"
> > +
> > +int ipu3_css_dma_alloc(struct device *dev,
> > +		       struct ipu3_css_map *map, size_t size) {
> > +	struct imgu_device *imgu = dev_get_drvdata(dev);
> > +
> > +	if (size == 0) {
> > +		map->vaddr = NULL;
> > +		return 0;
> > +	}
> > +
> > +	if (!ipu3_dmamap_alloc(imgu, map, size))
> > +		return -ENOMEM;
> > +
> > +	return 0;
> > +}
> > +
> > +void ipu3_css_dma_free(struct device *dev, struct ipu3_css_map *map)
> > +{
> > +	struct imgu_device *imgu = dev_get_drvdata(dev);
> > +
> > +	ipu3_dmamap_free(imgu, map);
> > +}
> > +
> > +void ipu3_css_pool_cleanup(struct device *dev, struct ipu3_css_pool
> > +*pool) {
> > +	int i;
> > +
> > +	for (i = 0; i < IPU3_CSS_POOL_SIZE; i++)
> > +		ipu3_css_dma_free(dev, &pool->entry[i].param); }
> > +
> > +int ipu3_css_pool_init(struct device *dev, struct ipu3_css_pool *pool,
> > +		       int size)
> > +{
> > +	int i;
> > +
> > +	for (i = 0; i < IPU3_CSS_POOL_SIZE; i++) {
> > +		pool->entry[i].framenum = INT_MIN;
> > +		if (ipu3_css_dma_alloc(dev, &pool->entry[i].param, size))
> > +			goto fail;
> > +	}
> > +
> > +	pool->last = IPU3_CSS_POOL_SIZE;
> > +
> > +	return 0;
> > +
> > +fail:
> > +	ipu3_css_pool_cleanup(dev, pool);
> > +	return -ENOMEM;
> > +}
> > +
> > +/*
> > + * Check that the following call to pool_get succeeds.
> > + * Return negative on error.
> > + */
> > +static int ipu3_css_pool_check(struct ipu3_css_pool *pool, long
> > +framenum) {
> > +	/* Get the oldest entry */
> > +	int n = (pool->last + 1) % IPU3_CSS_POOL_SIZE;
> > +
> > +	/*
> > +	 * pool->entry[n].framenum stores the frame number where that
> > +	 * entry was allocated. If that was allocated more than POOL_SIZE
> > +	 * frames back, it is old enough that we know it is no more in
> > +	 * use by firmware.
> > +	 */
> > +	if (pool->entry[n].framenum + IPU3_CSS_POOL_SIZE > framenum)
> 
> This will wrap around and the comparison fails when pool-
> >entry[n].framenum
> + IPU3_CSS_POOL_SIZE - 1 reaches LONG_MAX.
> 
> You could write this as:
> 
> if (framenum - pool->entry[n].franenum < IPU3_CSS_POOL_SIZE)
> 
> to avoid the problem.
> 
> You could use also int instead of long without any other changes to the code,
> or change INT_MAX / INT_MIN assignments to LONG_MAX / LONG_MIN.
> 

Ack the problem, the framenum could also become smaller than pool->entry[n].franenum when it wraps around, will fix in next update.

The pool->entry[n].franenum is initialized to INT_MIN so that it can satisfy the condition to return n, think any negative value greater than IPU3_CSS_POOL_SIZE should work here, I can add a comment for clarify.

> > +		return -ENOSPC;
> > +
> > +	return n;
> > +}
> > +
> > +/*
> > + * Allocate a new parameter from pool at frame number `framenum'.
> > + * Release the oldest entry in the pool to make space for the new entry.
> > + * Return negative on error.
> > + */
> > +int ipu3_css_pool_get(struct ipu3_css_pool *pool, long framenum) {
> > +	int n = ipu3_css_pool_check(pool, framenum);
> > +
> > +	if (n < 0)
> > +		return n;
> > +
> > +	pool->entry[n].framenum = framenum;
> > +	pool->last = n;
> > +
> > +	return n;
> > +}
> > +
> > +/*
> > + * Undo, for all practical purposes, the effect of pool_get().
> > + */
> > +void ipu3_css_pool_put(struct ipu3_css_pool *pool) {
> > +	pool->entry[pool->last].framenum = INT_MIN;
> > +	pool->last = (pool->last + IPU3_CSS_POOL_SIZE - 1) %
> > +IPU3_CSS_POOL_SIZE; }
> > +
> > +const struct ipu3_css_map *
> > +ipu3_css_pool_last(struct ipu3_css_pool *pool, unsigned int n) {
> > +	static const struct ipu3_css_map null_map = { 0 };
> > +	int i = (pool->last + IPU3_CSS_POOL_SIZE - n) % IPU3_CSS_POOL_SIZE;
> > +
> > +	WARN_ON(n >= IPU3_CSS_POOL_SIZE);
> > +
> > +	if (pool->entry[i].framenum < 0)
> > +		return &null_map;
> > +
> > +	return &pool->entry[i].param;
> > +}
> > diff --git a/drivers/media/pci/intel/ipu3/ipu3-css-pool.h
> > b/drivers/media/pci/intel/ipu3/ipu3-css-pool.h
> > new file mode 100644
> > index 000000000000..9b6ac14acfb2
> > --- /dev/null
> > +++ b/drivers/media/pci/intel/ipu3/ipu3-css-pool.h
> > @@ -0,0 +1,54 @@
> > +/*
> > + * Copyright (c) 2017 Intel Corporation.
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > +version
> > + * 2 as published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope that 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 __IPU3_UTIL_H
> > +#define __IPU3_UTIL_H
> > +
> > +#include <linux/device.h>
> > +
> > +#define sqr(x)				((x) * (x))
> > +#define DIV_ROUND_CLOSEST_DOWN(a, b)	(((a) + (b / 2) - 1) / (b))
> > +#define roundclosest_down(a, b)
> 	(DIV_ROUND_CLOSEST_DOWN(a, b) * (b))
> > +#define roundclosest(n, di)				\
> > +	({ typeof(n) __n = (n); typeof(di) __di = (di); \
> > +	DIV_ROUND_CLOSEST(__n, __di) * __di; })
> > +
> > +#define IPU3_CSS_POOL_SIZE		4
> > +
> > +struct ipu3_css_map {
> > +	size_t size;
> > +	void *vaddr;
> > +	dma_addr_t daddr;
> > +	struct vm_struct *vma;
> > +};
> > +
> > +struct ipu3_css_pool {
> > +	struct {
> > +		struct ipu3_css_map param;
> > +		long framenum;
> > +	} entry[IPU3_CSS_POOL_SIZE];
> > +	unsigned int last; /* Latest entry */ };
> > +
> > +int ipu3_css_dma_alloc(struct device *dev, struct ipu3_css_map *map,
> > +		       size_t size);
> > +void ipu3_css_dma_free(struct device *dev, struct ipu3_css_map *map);
> > +void ipu3_css_pool_cleanup(struct device *dev, struct ipu3_css_pool
> > +*pool); int ipu3_css_pool_init(struct device *dev, struct ipu3_css_pool
> *pool,
> > +		       int size);
> > +int ipu3_css_pool_get(struct ipu3_css_pool *pool, long framenum);
> > +void ipu3_css_pool_put(struct ipu3_css_pool *pool); const struct
> > +ipu3_css_map *ipu3_css_pool_last(struct ipu3_css_pool *pool,
> > +					      unsigned int last);
> > +
> > +#endif
> > --
> > 2.7.4
> >
> 
> --
> Sakari Ailus
> e-mail: sakari.ailus@iki.fi

^ permalink raw reply	[flat|nested] 19+ messages in thread

* RE: [PATCH v4 11/12] intel-ipu3: Add imgu v4l2 driver
  2017-10-20 11:29   ` Sakari Ailus
@ 2017-10-23 22:41     ` Zhi, Yong
  2017-11-02  8:43       ` Sakari Ailus
  0 siblings, 1 reply; 19+ messages in thread
From: Zhi, Yong @ 2017-10-23 22:41 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, sakari.ailus, Zheng, Jian Xu, Mani, Rajmohan,
	Toivonen, Tuukka, Hu, Jerry W, Vijaykumar, Ramya

Hi, Sakari,

> -----Original Message-----
> From: linux-media-owner@vger.kernel.org [mailto:linux-media-
> owner@vger.kernel.org] On Behalf Of Sakari Ailus
> Sent: Friday, October 20, 2017 4:30 AM
> To: Zhi, Yong <yong.zhi@intel.com>
> Cc: linux-media@vger.kernel.org; sakari.ailus@linux.intel.com; Zheng, Jian
> Xu <jian.xu.zheng@intel.com>; Mani, Rajmohan
> <rajmohan.mani@intel.com>; Toivonen, Tuukka
> <tuukka.toivonen@intel.com>; Hu, Jerry W <jerry.w.hu@intel.com>;
> Vijaykumar, Ramya <ramya.vijaykumar@intel.com>
> Subject: Re: [PATCH v4 11/12] intel-ipu3: Add imgu v4l2 driver
> 
> Hi Yong,
> 
> On Tue, Oct 17, 2017 at 10:54:56PM -0500, Yong Zhi wrote:
> > ipu3 imgu video device based on v4l2, vb2 and media controller
> > framework.
> >
> > Signed-off-by: Yong Zhi <yong.zhi@intel.com>
> > Signed-off-by: Ramya Vijaykumar <ramya.vijaykumar@intel.com>
> > ---
> >  drivers/media/pci/intel/ipu3/ipu3-v4l2.c | 1150
> > ++++++++++++++++++++++++++++++
> >  1 file changed, 1150 insertions(+)
> >  create mode 100644 drivers/media/pci/intel/ipu3/ipu3-v4l2.c
> >
> > diff --git a/drivers/media/pci/intel/ipu3/ipu3-v4l2.c
> > b/drivers/media/pci/intel/ipu3/ipu3-v4l2.c
> > new file mode 100644
> > index 000000000000..4618880b8675
> > --- /dev/null
> > +++ b/drivers/media/pci/intel/ipu3/ipu3-v4l2.c
> > @@ -0,0 +1,1150 @@
(snip)
> > +static int mem2mem2_g_selection(struct ipu3_mem2mem2_device
> *m2m2_dev,
> > +				int node, struct v4l2_selection *s) {
> > +	struct imgu_device *const imgu =
> > +		container_of(m2m2_dev, struct imgu_device, mem2mem2);
> > +
> > +	if (node != IPU3_CSS_QUEUE_IN)
> > +		return -ENOIOCTLCMD;
> > +
> > +	switch (s->target) {
> > +	case V4L2_SEL_TGT_CROP:
> > +		s->r = imgu->rect.eff;
> > +		break;
> > +	case V4L2_SEL_TGT_CROP_BOUNDS:
> > +		break;
> > +	case V4L2_SEL_TGT_CROP_DEFAULT:
> > +		break;
> > +	case V4L2_SEL_TGT_COMPOSE_PADDED:
> > +		break;
> > +	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
> > +		break;
> > +	case V4L2_SEL_TGT_COMPOSE:
> > +		s->r = imgu->rect.bds;
> > +		break;
> > +	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
> > +		break;
> > +
> 
> As the driver uses the V4L2 sub-device interface, the selection API belongsis
> implemented in the sub-device node, not the video nodes.
> 

Ok, will study how to make necessary changes to use sub-dev interface for above.

> > +	default:
> > +		return -EINVAL;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int ipu3_try_fmt(struct file *file, void *fh, struct
> > +v4l2_format *f) {
> > +	struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
> > +	const struct ipu3_fmt *fmt;
> > +
> > +	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
> > +		fmt = find_format(f, M2M_CAPTURE);
> > +	else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
> > +		fmt = find_format(f, M2M_OUTPUT);
> > +	else
> > +		return -EINVAL;
> > +
> > +	pixm->pixelformat = fmt->fourcc;
> > +
> > +	memset(pixm->plane_fmt[0].reserved, 0,
> > +	       sizeof(pixm->plane_fmt[0].reserved));
> 
> No need for the memset here, the framework handles this.
> 
> Are there limits on the image size?
> 

The memset is added to fix v4l2-compliance failure here.

The image size limit is checked in ipu3-css.c/ipu3_css_queue_init().

(snip)
> > +int ipu3_v4l2_register(struct imgu_device *dev) {
> > +	struct ipu3_mem2mem2_device *m2m2 = &dev->mem2mem2;
> > +	struct v4l2_mbus_framefmt def_bus_fmt;
> > +	struct v4l2_pix_format_mplane def_pix_fmt;
> > +
> > +	int i, r;
> > +
> > +	/* Initialize miscellaneous variables */
> > +	m2m2->streaming = false;
> > +	m2m2->v4l2_file_ops = ipu3_v4l2_fops;
> > +
> > +	/* Set up media device */
> > +	m2m2->media_dev.dev = m2m2->dev;
> > +	strlcpy(m2m2->media_dev.model, m2m2->model,
> > +		sizeof(m2m2->media_dev.model));
> > +	snprintf(m2m2->media_dev.bus_info, sizeof(m2m2-
> >media_dev.bus_info),
> > +		 "%s", dev_name(m2m2->dev));
> > +	m2m2->media_dev.hw_revision = 0;
> > +	media_device_init(&m2m2->media_dev);
> > +	r = media_device_register(&m2m2->media_dev);
> > +	if (r) {
> > +		dev_err(m2m2->dev, "failed to register media device (%d)\n",
> r);
> > +		goto fail_media_dev;
> 
> If there's nothing to clean up you can simply return the error here.

Ack, quite obvious indeed.

> 
> > +	}
> > +
> > +	/* Set up v4l2 device */
> > +	m2m2->v4l2_dev.mdev = &m2m2->media_dev;
> > +	m2m2->v4l2_dev.ctrl_handler = m2m2->ctrl_handler;
> > +	r = v4l2_device_register(m2m2->dev, &m2m2->v4l2_dev);
> > +	if (r) {
> > +		dev_err(m2m2->dev, "failed to register V4L2 device (%d)\n",
> r);
> > +		goto fail_v4l2_dev;
> > +	}
> > +
> > +	/* Initialize subdev media entity */
> > +	m2m2->subdev_pads = kzalloc(sizeof(*m2m2->subdev_pads) *
> > +					m2m2->num_nodes, GFP_KERNEL);
> > +	if (!m2m2->subdev_pads) {
> > +		r = -ENOMEM;
> > +		goto fail_subdev_pads;
> > +	}
> > +
> > +	r = media_entity_pads_init(&m2m2->subdev.entity, m2m2-
> >num_nodes,
> > +				   m2m2->subdev_pads);
> > +	if (r) {
> > +		dev_err(m2m2->dev,
> > +			"failed initialize subdev media entity (%d)\n", r);
> > +		goto fail_media_entity;
> > +	}
> > +	m2m2->subdev.entity.ops = &ipu3_media_ops;
> > +	for (i = 0; i < m2m2->num_nodes; i++) {
> > +		m2m2->subdev_pads[i].flags = m2m2->nodes[i].output ?
> > +			MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
> > +	}
> > +
> > +	/* Initialize subdev */
> > +	v4l2_subdev_init(&m2m2->subdev, &ipu3_subdev_ops);
> > +	m2m2->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
> > +	snprintf(m2m2->subdev.name, sizeof(m2m2->subdev.name),
> > +		 "%s", m2m2->name);
> > +	v4l2_set_subdevdata(&m2m2->subdev, m2m2);
> > +	m2m2->subdev.ctrl_handler = m2m2->ctrl_handler;
> > +	r = v4l2_device_register_subdev(&m2m2->v4l2_dev, &m2m2-
> >subdev);
> > +	if (r) {
> > +		dev_err(m2m2->dev, "failed initialize subdev (%d)\n", r);
> > +		goto fail_subdev;
> > +	}
> > +	r = v4l2_device_register_subdev_nodes(&m2m2->v4l2_dev);
> > +	if (r) {
> > +		dev_err(m2m2->dev, "failed to register subdevs (%d)\n", r);
> > +		goto fail_subdevs;
> > +	}
> > +
> > +	/* Initialize formats to default values */
> > +	def_bus_fmt.width = 1920;
> > +	def_bus_fmt.height = 1080;
> > +	def_bus_fmt.code = MEDIA_BUS_FMT_UYVY8_2X8;
> > +	def_bus_fmt.field = V4L2_FIELD_NONE;
> > +	def_bus_fmt.colorspace = V4L2_COLORSPACE_RAW;
> > +	def_bus_fmt.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
> > +	def_bus_fmt.quantization = V4L2_QUANTIZATION_DEFAULT;
> > +	def_bus_fmt.xfer_func = V4L2_XFER_FUNC_DEFAULT;
> > +
> > +	def_pix_fmt.width = def_bus_fmt.width;
> > +	def_pix_fmt.height = def_bus_fmt.height;
> > +	def_pix_fmt.field = def_bus_fmt.field;
> > +	def_pix_fmt.num_planes = 1;
> > +	def_pix_fmt.plane_fmt[0].bytesperline = def_pix_fmt.width * 2;
> > +	def_pix_fmt.plane_fmt[0].sizeimage =
> > +		def_pix_fmt.height * def_pix_fmt.plane_fmt[0].bytesperline;
> > +	def_pix_fmt.flags = 0;
> > +	def_pix_fmt.colorspace = def_bus_fmt.colorspace;
> > +	def_pix_fmt.ycbcr_enc = def_bus_fmt.ycbcr_enc;
> > +	def_pix_fmt.quantization = def_bus_fmt.quantization;
> > +	def_pix_fmt.xfer_func = def_bus_fmt.xfer_func;
> > +
> > +	/* Create video nodes and links */
> > +	for (i = 0; i < m2m2->num_nodes; i++) {
> > +		struct imgu_video_device *node = &m2m2->nodes[i];
> > +		struct video_device *vdev = &node->vdev;
> > +		struct vb2_queue *vbq = &node->vbq;
> > +		u32 flags;
> > +
> > +		/* Initialize miscellaneous variables */
> > +		mutex_init(&node->lock);
> > +		INIT_LIST_HEAD(&node->buffers);
> > +
> > +		/* Initialize formats to default values */
> > +		node->pad_fmt = def_bus_fmt;
> > +		ipu3_node_to_v4l2(i, vdev, &node->vdev_fmt);
> > +		if (node->vdev_fmt.type ==
> V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ||
> > +		    node->vdev_fmt.type ==
> V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
> > +			def_pix_fmt.pixelformat = node->output ?
> > +
> 	V4L2_PIX_FMT_IPU3_SGRBG10 :
> > +						V4L2_PIX_FMT_NV12;
> > +			node->vdev_fmt.fmt.pix_mp = def_pix_fmt;
> > +		}
> > +
> > +		/* Initialize media entities */
> > +		r = media_entity_pads_init(&vdev->entity, 1, &node-
> >vdev_pad);
> > +		if (r) {
> > +			dev_err(m2m2->dev,
> > +				"failed initialize media entity (%d)\n", r);
> > +			goto fail_vdev_media_entity;
> > +		}
> > +		node->vdev_pad.flags = node->output ?
> > +			MEDIA_PAD_FL_SOURCE : MEDIA_PAD_FL_SINK;
> > +		vdev->entity.ops = NULL;
> > +
> > +		/* Initialize vbq */
> > +		vbq->type = node->vdev_fmt.type;
> > +		vbq->io_modes = VB2_USERPTR | VB2_MMAP |
> VB2_DMABUF;
> > +		vbq->ops = &ipu3_vb2_ops;
> > +		vbq->mem_ops = m2m2->vb2_mem_ops;
> 
> dma_sg is the right one for all except the parameters; they are only accessed
> by the driver, aren't they?
> 

Agree, will set to &vb2_dma_sg_memops directly instead.

> > +		if (m2m2->buf_struct_size <= 0)
> > +			m2m2->buf_struct_size =
> > +				sizeof(struct ipu3_mem2mem2_buffer);
> > +		vbq->buf_struct_size = m2m2->buf_struct_size;
> > +		vbq->timestamp_flags =
> V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
> > +		vbq->min_buffers_needed = 0;	/* Can streamon w/o buffers
> */
> > +		vbq->drv_priv = m2m2;
> > +		vbq->lock = &node->lock;
> > +		r = vb2_queue_init(vbq);
> > +		if (r) {
> > +			dev_err(m2m2->dev,
> > +				"failed to initialize video queue (%d)\n", r);
> > +			goto fail_vdev;
> > +		}
> > +
> > +		/* Initialize vdev */
> > +		strlcpy(vdev->name, node->name, sizeof(vdev->name));
> > +		vdev->release = video_device_release_empty;
> > +		vdev->fops = &m2m2->v4l2_file_ops;
> > +		vdev->lock = &node->lock;
> > +		vdev->v4l2_dev = &m2m2->v4l2_dev;
> > +		vdev->queue = &node->vbq;
> > +		vdev->vfl_dir = node->output ? VFL_DIR_TX : VFL_DIR_RX;
> > +		video_set_drvdata(vdev, m2m2);
> > +		r = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
> > +		if (r) {
> > +			dev_err(m2m2->dev,
> > +				"failed to register video device (%d)\n", r);
> > +			goto fail_vdev;
> > +		}
> > +
> > +		/* Create link between video node and the subdev pad */
> > +		flags = 0;
> > +		if (node->enabled)
> > +			flags |= MEDIA_LNK_FL_ENABLED;
> > +		if (node->immutable)
> > +			flags |= MEDIA_LNK_FL_IMMUTABLE;
> > +		if (node->output) {
> > +			r = media_create_pad_link(
> > +						 &vdev->entity, 0,
> > +						 &m2m2->subdev.entity,
> > +						 i, flags);
> > +		} else {
> > +			r = media_create_pad_link(
> > +						 &m2m2->subdev.entity,
> > +						 i, &vdev->entity, 0,
> > +						 flags);
> > +		}
> > +		if (r)
> > +			goto fail_link;
> > +	}
> > +
> > +	return 0;
> > +
> > +	for (; i >= 0; i--) {
> > +fail_link:
> > +		video_unregister_device(&m2m2->nodes[i].vdev);
> > +fail_vdev:
> > +		media_entity_cleanup(&m2m2->nodes[i].vdev.entity);
> > +fail_vdev_media_entity:
> > +		mutex_destroy(&m2m2->nodes[i].lock);
> > +	}
> > +fail_subdevs:
> > +	v4l2_device_unregister_subdev(&m2m2->subdev);
> > +fail_subdev:
> > +	media_entity_cleanup(&m2m2->subdev.entity);
> > +fail_media_entity:
> > +	kfree(m2m2->subdev_pads);
> > +fail_subdev_pads:
> > +	v4l2_device_unregister(&m2m2->v4l2_dev);
> > +fail_v4l2_dev:
> > +	media_device_unregister(&m2m2->media_dev);
> > +	media_device_cleanup(&m2m2->media_dev);
> > +fail_media_dev:
> > +
> > +	return r;
> > +}
> > +EXPORT_SYMBOL_GPL(ipu3_v4l2_register);
> > +
> > +int ipu3_v4l2_unregister(struct imgu_device *dev) {
> > +	struct ipu3_mem2mem2_device *m2m2 = &dev->mem2mem2;
> > +	unsigned int i;
> > +
> > +	for (i = 0; i < m2m2->num_nodes; i++) {
> > +		video_unregister_device(&m2m2->nodes[i].vdev);
> > +		media_entity_cleanup(&m2m2->nodes[i].vdev.entity);
> > +		mutex_destroy(&m2m2->nodes[i].lock);
> > +	}
> > +
> > +	v4l2_device_unregister_subdev(&m2m2->subdev);
> > +	media_entity_cleanup(&m2m2->subdev.entity);
> > +	kfree(m2m2->subdev_pads);
> > +	v4l2_device_unregister(&m2m2->v4l2_dev);
> > +	media_device_unregister(&m2m2->media_dev);
> > +	media_device_cleanup(&m2m2->media_dev);
> > +
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(ipu3_v4l2_unregister);
> > +
> > +void ipu3_v4l2_buffer_done(struct vb2_buffer *vb,
> > +			   enum vb2_buffer_state state)
> > +{
> > +	struct ipu3_mem2mem2_buffer *b =
> > +		container_of(vb, struct ipu3_mem2mem2_buffer,
> vbb.vb2_buf);
> > +
> > +	list_del(&b->list);
> > +	vb2_buffer_done(&b->vbb.vb2_buf, state); }
> > +EXPORT_SYMBOL_GPL(ipu3_v4l2_buffer_done);
> > --
> > 2.7.4
> >
> 
> --
> Sakari Ailus
> e-mail: sakari.ailus@iki.fi

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v4 10/12] intel-ipu3: css pipeline
  2017-10-18  3:54 ` [PATCH v4 10/12] intel-ipu3: css pipeline Yong Zhi
@ 2017-11-01 18:57   ` Sakari Ailus
  2017-11-10 22:35     ` Zhi, Yong
  0 siblings, 1 reply; 19+ messages in thread
From: Sakari Ailus @ 2017-11-01 18:57 UTC (permalink / raw)
  To: Yong Zhi
  Cc: linux-media, sakari.ailus, jian.xu.zheng, rajmohan.mani,
	tuukka.toivonen, jerry.w.hu

Hi Yong,

Apologies for the late reply. Please find my (few) comments below.

On Tue, Oct 17, 2017 at 10:54:55PM -0500, Yong Zhi wrote:
> Add css pipeline and v4l code.
> 
> Signed-off-by: Yong Zhi <yong.zhi@intel.com>
> ---
>  drivers/media/pci/intel/ipu3/ipu3-css.c | 1761 ++++++++++++++++++++++++++++++-
>  drivers/media/pci/intel/ipu3/ipu3-css.h |   89 ++
>  2 files changed, 1849 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/media/pci/intel/ipu3/ipu3-css.c b/drivers/media/pci/intel/ipu3/ipu3-css.c
> index 6e615bf9378a..11f7ad3514c3 100644
> --- a/drivers/media/pci/intel/ipu3/ipu3-css.c
> +++ b/drivers/media/pci/intel/ipu3/ipu3-css.c
> @@ -13,9 +13,16 @@
>  
>  #include <linux/delay.h>
>  #include <linux/dma-mapping.h>
> +#include <linux/firmware.h>
> +#include <linux/gcd.h>
>  #include <linux/iopoll.h>
> +#include <linux/slab.h>
> +#include <linux/string.h>
> +#include <linux/swab.h>
> +
>  #include "ipu3-css.h"
>  #include "ipu3-css-fw.h"
> +#include "ipu3-css-params.h"
>  #include "ipu3-tables.h"
>  
>  /* IRQ configuration */
> @@ -24,6 +31,159 @@
>  				 IMGU_IRQCTRL_IRQ_SW_PIN(0) | \
>  				 IMGU_IRQCTRL_IRQ_SW_PIN(1))
>  
> +#define IPU3_CSS_FORMAT_BPP_DEN	50	/* Denominator */
> +
> +/* Some sane limits for resolutions */
> +#define IPU3_CSS_MIN_RES	32
> +#define IPU3_CSS_MAX_H		3136
> +#define IPU3_CSS_MAX_W		4224
> +
> +/* filter size from graph settings is fixed as 4 */
> +#define FILTER_SIZE             4
> +#define MIN_ENVELOPE            8
> +
> +/* Formats supported by IPU3 Camera Sub System */
> +static const struct ipu3_css_format ipu3_css_formats[] = {
> +	{
> +		.pixelformat = V4L2_PIX_FMT_NV12,
> +		.colorspace = V4L2_COLORSPACE_SRGB,
> +		.frame_format = IMGU_ABI_FRAME_FORMAT_NV12,
> +		.osys_format = IMGU_ABI_OSYS_FORMAT_NV12,
> +		.osys_tiling = IMGU_ABI_OSYS_TILING_NONE,
> +		.bytesperpixel_num = 1 * IPU3_CSS_FORMAT_BPP_DEN,
> +		.chroma_decim = 4,
> +		.width_align = IPU3_UAPI_ISP_VEC_ELEMS,
> +		.flags = IPU3_CSS_FORMAT_FL_OUT | IPU3_CSS_FORMAT_FL_VF,
> +	}, {
> +		/* Each 32 bytes contains 25 10-bit pixels */
> +		.pixelformat = V4L2_PIX_FMT_IPU3_SBGGR10,
> +		.colorspace = V4L2_COLORSPACE_RAW,
> +		.frame_format = IMGU_ABI_FRAME_FORMAT_RAW_PACKED,
> +		.bayer_order = IMGU_ABI_BAYER_ORDER_BGGR,
> +		.bit_depth = 10,
> +		.bytesperpixel_num = 64,
> +		.width_align = 2 * IPU3_UAPI_ISP_VEC_ELEMS,
> +		.flags = IPU3_CSS_FORMAT_FL_IN,
> +	}, {
> +		.pixelformat = V4L2_PIX_FMT_IPU3_SGBRG10,
> +		.colorspace = V4L2_COLORSPACE_RAW,
> +		.frame_format = IMGU_ABI_FRAME_FORMAT_RAW_PACKED,
> +		.bayer_order = IMGU_ABI_BAYER_ORDER_GBRG,
> +		.bit_depth = 10,
> +		.bytesperpixel_num = 64,
> +		.width_align = 2 * IPU3_UAPI_ISP_VEC_ELEMS,
> +		.flags = IPU3_CSS_FORMAT_FL_IN,
> +	}, {
> +		.pixelformat = V4L2_PIX_FMT_IPU3_SGRBG10,
> +		.colorspace = V4L2_COLORSPACE_RAW,
> +		.frame_format = IMGU_ABI_FRAME_FORMAT_RAW_PACKED,
> +		.bayer_order = IMGU_ABI_BAYER_ORDER_GRBG,
> +		.bit_depth = 10,
> +		.bytesperpixel_num = 64,
> +		.width_align = 2 * IPU3_UAPI_ISP_VEC_ELEMS,
> +		.flags = IPU3_CSS_FORMAT_FL_IN,
> +	}, {
> +		.pixelformat = V4L2_PIX_FMT_IPU3_SRGGB10,
> +		.colorspace = V4L2_COLORSPACE_RAW,
> +		.frame_format = IMGU_ABI_FRAME_FORMAT_RAW_PACKED,
> +		.bayer_order = IMGU_ABI_BAYER_ORDER_RGGB,
> +		.bit_depth = 10,
> +		.bytesperpixel_num = 64,
> +		.width_align = 2 * IPU3_UAPI_ISP_VEC_ELEMS,
> +		.flags = IPU3_CSS_FORMAT_FL_IN,
> +	},
> +};
> +
> +static const struct {
> +	enum imgu_abi_queue_id qid;
> +	size_t ptr_ofs;
> +} ipu3_css_queues[IPU3_CSS_QUEUES] = {
> +	[IPU3_CSS_QUEUE_IN] = {
> +		IMGU_ABI_QUEUE_C_ID,
> +		offsetof(struct imgu_abi_buffer, payload.frame.frame_data)
> +	},
> +	[IPU3_CSS_QUEUE_OUT] = {
> +		IMGU_ABI_QUEUE_D_ID,
> +		offsetof(struct imgu_abi_buffer, payload.frame.frame_data)
> +	},
> +	[IPU3_CSS_QUEUE_VF] = {
> +		IMGU_ABI_QUEUE_E_ID,
> +		offsetof(struct imgu_abi_buffer, payload.frame.frame_data)
> +	},
> +	[IPU3_CSS_QUEUE_STAT_3A] = {
> +		IMGU_ABI_QUEUE_F_ID,
> +		offsetof(struct imgu_abi_buffer, payload.s3a.data_ptr)
> +	},
> +	[IPU3_CSS_QUEUE_STAT_DVS] = {
> +		IMGU_ABI_QUEUE_G_ID,
> +		offsetof(struct imgu_abi_buffer, payload.skc_dvs_statistics)
> +	}
> +};
> +
> +/* Initialize queue based on given format, adjust format as needed */
> +static int ipu3_css_queue_init(struct ipu3_css_queue *queue,
> +			       struct v4l2_pix_format_mplane *fmt, u32 flags)
> +{
> +	struct v4l2_pix_format_mplane *const f = &queue->fmt.mpix;
> +	unsigned int i;
> +	u32 sizeimage;
> +
> +	INIT_LIST_HEAD(&queue->bufs);
> +
> +	queue->css_fmt = NULL;	/* Disable */
> +	if (!fmt)
> +		return 0;
> +
> +	for (i = 0; i < ARRAY_SIZE(ipu3_css_formats); i++) {
> +		if (!(ipu3_css_formats[i].flags & flags))
> +			continue;
> +		queue->css_fmt = &ipu3_css_formats[i];
> +		if (ipu3_css_formats[i].pixelformat == fmt->pixelformat)
> +			break;
> +	}
> +	if (!queue->css_fmt)
> +		return -EINVAL;	/* Could not find any suitable format */
> +
> +	queue->fmt.mpix = *fmt;
> +
> +	f->width = ALIGN(clamp_t(u32, f->width,
> +				 IPU3_CSS_MIN_RES, IPU3_CSS_MAX_W), 2);
> +	f->height = ALIGN(clamp_t(u32, f->height,
> +				  IPU3_CSS_MIN_RES, IPU3_CSS_MAX_H), 2);
> +	queue->width_pad = ALIGN(f->width, queue->css_fmt->width_align);
> +	if (queue->css_fmt->frame_format != IMGU_ABI_FRAME_FORMAT_RAW_PACKED)
> +		f->plane_fmt[0].bytesperline = DIV_ROUND_UP(queue->width_pad *
> +					queue->css_fmt->bytesperpixel_num,
> +					IPU3_CSS_FORMAT_BPP_DEN);
> +	else
> +		/* For packed raw, alignment for bpl is by 50 to the width */
> +		f->plane_fmt[0].bytesperline =
> +				DIV_ROUND_UP(f->width,
> +					     IPU3_CSS_FORMAT_BPP_DEN) *
> +					     queue->css_fmt->bytesperpixel_num;
> +
> +	sizeimage = f->height * f->plane_fmt[0].bytesperline;
> +	if (queue->css_fmt->chroma_decim)
> +		sizeimage += 2 * sizeimage / queue->css_fmt->chroma_decim;
> +
> +	f->plane_fmt[0].sizeimage = sizeimage;
> +	f->field = V4L2_FIELD_NONE;
> +	f->num_planes = 1;
> +	f->colorspace = queue->css_fmt->colorspace;
> +	f->flags = 0;
> +	f->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
> +	f->quantization = V4L2_QUANTIZATION_DEFAULT;
> +	f->xfer_func = V4L2_XFER_FUNC_DEFAULT;
> +	memset(f->reserved, 0, sizeof(f->reserved));
> +
> +	return 0;
> +}
> +
> +static bool ipu3_css_queue_enabled(struct ipu3_css_queue *q)
> +{
> +	return !!q->css_fmt;

No need for !!.

> +}
> +
>  /******************* css hw *******************/
>  
>  /* in the style of writesl() defined in include/asm-generic/io.h */
> @@ -477,6 +637,1605 @@ static void ipu3_css_hw_cleanup(struct ipu3_css *css)
>  	usleep_range(200, 300);
>  }
>  
> +static void ipu3_css_pipeline_cleanup(struct ipu3_css *css)
> +{
> +	struct imgu_fw_info *bi = &css->fwp->binary_header[css->current_binary];
> +	int pipe = 0;
> +	int i;
> +
> +	if (css->current_binary < 0)
> +		return;
> +
> +	ipu3_css_pool_cleanup(css->dev, &css->pool.parameter_set_info);
> +	ipu3_css_pool_cleanup(css->dev, &css->pool.acc);
> +	ipu3_css_pool_cleanup(css->dev, &css->pool.gdc);
> +	ipu3_css_pool_cleanup(css->dev, &css->pool.obgrid);
> +	for (i = 0; i < IMGU_ABI_NUM_MEMORIES; i++)
> +		ipu3_css_pool_cleanup(css->dev,
> +				      &css->pool.binary_params_p[i]);
> +
> +	for (i = 0; i < bi->info.isp.sp.iterator.num_stripes; i++)
> +		ipu3_css_dma_free(css->dev, &css->dvs_meta_data[pipe][i]);
> +}
> +
> +/*
> + * This function initializes various stages of the
> + * IPU3 CSS ISP pipeline
> + */
> +static int ipu3_css_pipeline_init(struct ipu3_css *css)
> +{
> +	static const unsigned int PIPE_ID = IPU3_CSS_PIPE_ID_VIDEO;
> +	static const int BYPC = 2;	/* Bytes per component */
> +	static const struct imgu_abi_buffer_sp buffer_sp_init = {
> +		.buf_src = {.queue_id = IMGU_ABI_QUEUE_EVENT_ID},
> +		.buf_type = IMGU_ABI_BUFFER_TYPE_INVALID,
> +	};
> +
> +	struct imgu_abi_isp_iterator_config *cfg_iter;
> +	struct imgu_abi_isp_ref_config *cfg_ref;
> +	struct imgu_abi_isp_dvs_config *cfg_dvs;
> +	struct imgu_abi_isp_tnr3_config *cfg_tnr;
> +	struct imgu_abi_isp_ref_dmem_state *cfg_ref_state;
> +	struct imgu_abi_isp_tnr3_dmem_state *cfg_tnr_state;
> +
> +	const int pipe = 0, stage = 0, thread = 0;
> +	unsigned int i, j;
> +
> +	const struct imgu_fw_info *bi =
> +	    &css->fwp->binary_header[css->current_binary];
> +	const unsigned int stripes = bi->info.isp.sp.iterator.num_stripes;
> +
> +	struct imgu_fw_config_memory_offsets *cofs = (void *)css->fwp +
> +	    bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_CONFIG];
> +	struct imgu_fw_state_memory_offsets *sofs = (void *)css->fwp +
> +	    bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_STATE];
> +
> +	struct imgu_abi_isp_stage *isp_stage;
> +	struct imgu_abi_sp_stage *sp_stage;
> +	struct imgu_abi_sp_group *sp_group;
> +
> +	const unsigned int bds_width_pad =
> +				ALIGN(css->rect[IPU3_CSS_RECT_BDS].width,
> +				      2 * IPU3_UAPI_ISP_VEC_ELEMS);
> +
> +	const enum imgu_abi_memories m0 = IMGU_ABI_MEM_ISP_DMEM0;
> +	enum imgu_abi_param_class cfg = IMGU_ABI_PARAM_CLASS_CONFIG;
> +	void *vaddr = css->binary_params_cs[cfg - 1][m0].vaddr;
> +
> +	if (css->current_binary == -1)
> +		return -EAGAIN;
> +
> +	/* Configure iterator */
> +
> +	cfg_iter = ipu3_css_fw_pipeline_params(css, cfg, m0,
> +					       &cofs->dmem.iterator,
> +					       sizeof(*cfg_iter), vaddr);
> +	if (!cfg_iter)
> +		goto bad_firmware;
> +
> +	cfg_iter->input_info.res.width =
> +	    css->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.width;
> +	cfg_iter->input_info.res.height =
> +	    css->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.height;
> +	cfg_iter->input_info.padded_width =
> +	    css->queue[IPU3_CSS_QUEUE_IN].width_pad;
> +	cfg_iter->input_info.format =
> +	    css->queue[IPU3_CSS_QUEUE_IN].css_fmt->frame_format;
> +	cfg_iter->input_info.raw_bit_depth =
> +	    css->queue[IPU3_CSS_QUEUE_IN].css_fmt->bit_depth;
> +	cfg_iter->input_info.raw_bayer_order =
> +	    css->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order;
> +	cfg_iter->input_info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
> +
> +	cfg_iter->internal_info.res.width =
> +			css->rect[IPU3_CSS_RECT_BDS].width;
> +	cfg_iter->internal_info.res.height =
> +			css->rect[IPU3_CSS_RECT_BDS].height;
> +	cfg_iter->internal_info.padded_width = bds_width_pad;
> +	cfg_iter->internal_info.format =
> +	    css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
> +	cfg_iter->internal_info.raw_bit_depth =
> +	    css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bit_depth;
> +	cfg_iter->internal_info.raw_bayer_order =
> +	    css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bayer_order;
> +	cfg_iter->internal_info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
> +
> +	cfg_iter->output_info.res.width =
> +	    css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
> +	cfg_iter->output_info.res.height =
> +	    css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
> +	cfg_iter->output_info.padded_width =
> +	    css->queue[IPU3_CSS_QUEUE_OUT].width_pad;
> +	cfg_iter->output_info.format =
> +	    css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
> +	cfg_iter->output_info.raw_bit_depth =
> +	    css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bit_depth;
> +	cfg_iter->output_info.raw_bayer_order =
> +	    css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bayer_order;
> +	cfg_iter->output_info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
> +
> +	cfg_iter->vf_info.res.width =
> +	    css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
> +	cfg_iter->vf_info.res.height =
> +	    css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
> +	cfg_iter->vf_info.padded_width =
> +	    css->queue[IPU3_CSS_QUEUE_VF].width_pad;
> +	cfg_iter->vf_info.format =
> +	    css->queue[IPU3_CSS_QUEUE_VF].css_fmt->frame_format;
> +	cfg_iter->vf_info.raw_bit_depth =
> +	    css->queue[IPU3_CSS_QUEUE_VF].css_fmt->bit_depth;
> +	cfg_iter->vf_info.raw_bayer_order =
> +	    css->queue[IPU3_CSS_QUEUE_VF].css_fmt->bayer_order;
> +	cfg_iter->vf_info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
> +
> +	cfg_iter->dvs_envelope.width = css->rect[IPU3_CSS_RECT_ENVELOPE].width;
> +	cfg_iter->dvs_envelope.height =
> +		css->rect[IPU3_CSS_RECT_ENVELOPE].height;
> +
> +	/* Configure reference (delay) frames */
> +
> +	cfg_ref = ipu3_css_fw_pipeline_params(css, cfg, m0, &cofs->dmem.ref,
> +					      sizeof(*cfg_ref), vaddr);
> +	if (!cfg_ref)
> +		goto bad_firmware;
> +
> +	cfg_ref->port_b.crop = 0;
> +	cfg_ref->port_b.elems = IMGU_ABI_ISP_DDR_WORD_BYTES / BYPC;
> +	cfg_ref->port_b.width  = css->aux_frames[IPU3_CSS_AUX_FRAME_REF].width;
> +	cfg_ref->port_b.stride =
> +	    css->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperline;
> +	cfg_ref->width_a_over_b =
> +	    IPU3_UAPI_ISP_VEC_ELEMS / cfg_ref->port_b.elems;
> +	cfg_ref->dvs_frame_delay = IPU3_CSS_AUX_FRAMES - 1;
> +	for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++) {
> +		cfg_ref->ref_frame_addr_y[i] =
> +		    css->aux_frames[IPU3_CSS_AUX_FRAME_REF].mem[i].daddr;
> +		cfg_ref->ref_frame_addr_c[i] =
> +		    css->aux_frames[IPU3_CSS_AUX_FRAME_REF].mem[i].daddr +
> +		    css->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperline *
> +		    css->aux_frames[IPU3_CSS_AUX_FRAME_REF].height;
> +	}
> +	for (; i < IMGU_ABI_FRAMES_REF; i++) {
> +		cfg_ref->ref_frame_addr_y[i] = 0;
> +		cfg_ref->ref_frame_addr_c[i] = 0;
> +	}
> +
> +	/* Configure DVS (digital video stabilization) */
> +
> +	cfg_dvs = ipu3_css_fw_pipeline_params(css, cfg, m0,
> +					      &cofs->dmem.dvs, sizeof(*cfg_dvs),
> +					      vaddr);
> +	if (!cfg_dvs)
> +		goto bad_firmware;
> +
> +	cfg_dvs->num_horizontal_blocks =
> +	    ALIGN(DIV_ROUND_UP(css->rect[IPU3_CSS_RECT_GDC].width,
> +			       IMGU_DVS_BLOCK_W), 2);
> +	cfg_dvs->num_vertical_blocks =
> +	    DIV_ROUND_UP(css->rect[IPU3_CSS_RECT_GDC].height,
> +			 IMGU_DVS_BLOCK_H);
> +
> +	if (cfg_dvs->num_horizontal_blocks * cfg_dvs->num_vertical_blocks < 0)
> +		return -EPROTO;
> +
> +	/* Configure TNR (temporal noise reduction) */
> +
> +	if (css->pipe_id == IPU3_CSS_PIPE_ID_VIDEO) {
> +		cfg_tnr = ipu3_css_fw_pipeline_params(css, cfg, m0,
> +						      &cofs->dmem.tnr3,
> +						      sizeof(*cfg_tnr),
> +						      vaddr);
> +		if (!cfg_tnr)
> +			goto bad_firmware;
> +
> +		cfg_tnr->port_b.crop = 0;
> +		cfg_tnr->port_b.elems = IMGU_ABI_ISP_DDR_WORD_BYTES;
> +		cfg_tnr->port_b.width =
> +		    css->aux_frames[IPU3_CSS_AUX_FRAME_TNR].width;
> +		cfg_tnr->port_b.stride =
> +		    css->aux_frames[IPU3_CSS_AUX_FRAME_TNR].bytesperline;
> +		cfg_tnr->width_a_over_b =
> +		    IPU3_UAPI_ISP_VEC_ELEMS / cfg_tnr->port_b.elems;
> +		cfg_tnr->frame_height =
> +		    css->aux_frames[IPU3_CSS_AUX_FRAME_TNR].height;
> +		cfg_tnr->delay_frame = IPU3_CSS_AUX_FRAMES - 1;
> +		for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
> +			cfg_tnr->frame_addr[i] =
> +			    css->aux_frames[IPU3_CSS_AUX_FRAME_TNR]
> +			    .mem[i].daddr;
> +		for (; i < IMGU_ABI_FRAMES_TNR; i++)
> +			cfg_tnr->frame_addr[i] = 0;
> +	}
> +
> +	/* Configure ref dmem state parameters */
> +
> +	cfg = IMGU_ABI_PARAM_CLASS_STATE;
> +	vaddr = css->binary_params_cs[cfg - 1][m0].vaddr;
> +
> +	cfg_ref_state = ipu3_css_fw_pipeline_params(css, cfg, m0,
> +						    &sofs->dmem.ref,
> +						    sizeof(*cfg_ref_state),
> +						    vaddr);
> +	if (!cfg_ref_state)
> +		goto bad_firmware;
> +
> +	cfg_ref_state->ref_in_buf_idx = 0;
> +	cfg_ref_state->ref_out_buf_idx = 1;
> +
> +	/* Configure tnr dmem state parameters */
> +	if (css->pipe_id == IPU3_CSS_PIPE_ID_VIDEO) {
> +		cfg_tnr_state =
> +			ipu3_css_fw_pipeline_params(css, cfg, m0,
> +						    &sofs->dmem.tnr3,
> +						    sizeof(*cfg_tnr_state),
> +						    vaddr);
> +		if (!cfg_tnr_state)
> +			goto bad_firmware;
> +
> +		cfg_tnr_state->in_bufidx = 0;
> +		cfg_tnr_state->out_bufidx = 1;
> +		cfg_tnr_state->bypass_filter = 0;
> +		cfg_tnr_state->total_frame_counter = 0;
> +		for (i = 0; i < IMGU_ABI_BUF_SETS_TNR; i++)
> +			cfg_tnr_state->buffer_frame_counter[i] = 0;
> +	}
> +
> +	/* Configure ISP stage */
> +
> +	isp_stage = css->xmem_isp_stage_ptrs[pipe][stage].vaddr;
> +	memset(isp_stage, 0, sizeof(*isp_stage));
> +	isp_stage->blob_info = bi->blob;
> +	isp_stage->binary_info = bi->info.isp.sp;
> +	strcpy(isp_stage->binary_name,
> +	       (char *)css->fwp + bi->blob.prog_name_offset);
> +	isp_stage->mem_initializers = bi->info.isp.sp.mem_initializers;
> +	for (i = IMGU_ABI_PARAM_CLASS_CONFIG; i < IMGU_ABI_PARAM_CLASS_NUM; i++)
> +		for (j = 0; j < IMGU_ABI_NUM_MEMORIES; j++)
> +			isp_stage->mem_initializers.params[i][j].address =
> +			    css->binary_params_cs[i - 1][j].daddr;
> +
> +	/* Configure SP stage */
> +
> +	sp_stage = css->xmem_sp_stage_ptrs[pipe][stage].vaddr;
> +	memset(sp_stage, 0, sizeof(*sp_stage));
> +
> +	sp_stage->frames.in.buf_attr = buffer_sp_init;
> +	for (i = 0; i < IMGU_ABI_BINARY_MAX_OUTPUT_PORTS; i++)
> +		sp_stage->frames.out[i].buf_attr = buffer_sp_init;
> +	sp_stage->frames.out_vf.buf_attr = buffer_sp_init;
> +	sp_stage->frames.s3a_buf = buffer_sp_init;
> +	sp_stage->frames.dvs_buf = buffer_sp_init;
> +	sp_stage->frames.lace_buf = buffer_sp_init;
> +
> +	sp_stage->stage_type = IMGU_ABI_STAGE_TYPE_ISP;
> +	sp_stage->num = stage;
> +	sp_stage->isp_online = 0;
> +	sp_stage->isp_copy_vf = 0;
> +	sp_stage->isp_copy_output = 0;
> +
> +	/* Enable VF output only when VF or PV queue requested by user */
> +
> +	sp_stage->enable.vf_output =
> +		(css->vf_output_en != IPU3_NODE_VF_DISABLED);
> +
> +	sp_stage->frames.effective_in_res.width =
> +		css->rect[IPU3_CSS_RECT_EFFECTIVE].width;
> +	sp_stage->frames.effective_in_res.height =
> +		css->rect[IPU3_CSS_RECT_EFFECTIVE].height;
> +	sp_stage->frames.in.info.res.width =
> +	    css->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.width;
> +	sp_stage->frames.in.info.res.height =
> +	    css->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.height;
> +	sp_stage->frames.in.info.padded_width =
> +	    css->queue[IPU3_CSS_QUEUE_IN].width_pad;
> +	sp_stage->frames.in.info.format =
> +	    css->queue[IPU3_CSS_QUEUE_IN].css_fmt->frame_format;
> +	sp_stage->frames.in.info.raw_bit_depth =
> +	    css->queue[IPU3_CSS_QUEUE_IN].css_fmt->bit_depth;
> +	sp_stage->frames.in.info.raw_bayer_order =
> +	    css->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order;
> +	sp_stage->frames.in.info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
> +	sp_stage->frames.in.buf_attr.buf_src.queue_id = IMGU_ABI_QUEUE_C_ID;
> +	sp_stage->frames.in.buf_attr.buf_type =
> +	    IMGU_ABI_BUFFER_TYPE_INPUT_FRAME;
> +
> +	sp_stage->frames.out[0].info.res.width =
> +	    css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
> +	sp_stage->frames.out[0].info.res.height =
> +	    css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
> +	sp_stage->frames.out[0].info.padded_width =
> +	    css->queue[IPU3_CSS_QUEUE_OUT].width_pad;
> +	sp_stage->frames.out[0].info.format =
> +	    css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
> +	sp_stage->frames.out[0].info.raw_bit_depth =
> +	    css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bit_depth;
> +	sp_stage->frames.out[0].info.raw_bayer_order =
> +	    css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bayer_order;
> +	sp_stage->frames.out[0].info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
> +	sp_stage->frames.out[0].planes.nv.uv.offset =
> +	    css->queue[IPU3_CSS_QUEUE_OUT].width_pad *
> +	    css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
> +	sp_stage->frames.out[0].buf_attr.buf_src.queue_id = IMGU_ABI_QUEUE_D_ID;
> +	sp_stage->frames.out[0].buf_attr.buf_type =
> +	    IMGU_ABI_BUFFER_TYPE_OUTPUT_FRAME;
> +
> +	sp_stage->frames.out[1].buf_attr.buf_src.queue_id =
> +	    IMGU_ABI_QUEUE_EVENT_ID;
> +
> +	sp_stage->frames.internal_frame_info.res.width =
> +					css->rect[IPU3_CSS_RECT_BDS].width;
> +	sp_stage->frames.internal_frame_info.res.height =
> +					css->rect[IPU3_CSS_RECT_BDS].height;
> +	sp_stage->frames.internal_frame_info.padded_width = bds_width_pad;
> +
> +	sp_stage->frames.internal_frame_info.format =
> +	    css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
> +	sp_stage->frames.internal_frame_info.raw_bit_depth =
> +	    css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bit_depth;
> +	sp_stage->frames.internal_frame_info.raw_bayer_order =
> +	    css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bayer_order;
> +	sp_stage->frames.internal_frame_info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
> +
> +	sp_stage->frames.out_vf.info.res.width =
> +	    css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
> +	sp_stage->frames.out_vf.info.res.height =
> +	    css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
> +	sp_stage->frames.out_vf.info.padded_width =
> +	    css->queue[IPU3_CSS_QUEUE_VF].width_pad;
> +	sp_stage->frames.out_vf.info.format =
> +	    css->queue[IPU3_CSS_QUEUE_VF].css_fmt->frame_format;
> +	sp_stage->frames.out_vf.info.raw_bit_depth =
> +	    css->queue[IPU3_CSS_QUEUE_VF].css_fmt->bit_depth;
> +	sp_stage->frames.out_vf.info.raw_bayer_order =
> +	    css->queue[IPU3_CSS_QUEUE_VF].css_fmt->bayer_order;
> +	sp_stage->frames.out_vf.info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
> +	sp_stage->frames.out_vf.planes.yuv.u.offset =
> +	    css->queue[IPU3_CSS_QUEUE_VF].width_pad *
> +	    css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
> +	sp_stage->frames.out_vf.planes.yuv.v.offset =
> +	    css->queue[IPU3_CSS_QUEUE_VF].width_pad *
> +	    css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height * 5 / 4;
> +	sp_stage->frames.out_vf.buf_attr.buf_src.queue_id = IMGU_ABI_QUEUE_E_ID;
> +	sp_stage->frames.out_vf.buf_attr.buf_type =
> +	    IMGU_ABI_BUFFER_TYPE_VF_OUTPUT_FRAME;
> +
> +	sp_stage->frames.s3a_buf.buf_src.queue_id = IMGU_ABI_QUEUE_F_ID;
> +	sp_stage->frames.s3a_buf.buf_type = IMGU_ABI_BUFFER_TYPE_3A_STATISTICS;
> +
> +	sp_stage->frames.dvs_buf.buf_src.queue_id = IMGU_ABI_QUEUE_G_ID;
> +	sp_stage->frames.dvs_buf.buf_type = IMGU_ABI_BUFFER_TYPE_DIS_STATISTICS;
> +
> +	sp_stage->dvs_envelope.width = css->rect[IPU3_CSS_RECT_ENVELOPE].width;
> +	sp_stage->dvs_envelope.height =
> +		css->rect[IPU3_CSS_RECT_ENVELOPE].height;
> +
> +	sp_stage->isp_pipe_version =
> +				bi->info.isp.sp.pipeline.isp_pipe_version;
> +	sp_stage->isp_deci_log_factor = clamp(
> +		max(fls(css->rect[IPU3_CSS_RECT_BDS].width /
> +					IMGU_MAX_BQ_GRID_WIDTH),
> +		    fls(css->rect[IPU3_CSS_RECT_BDS].height /
> +					IMGU_MAX_BQ_GRID_HEIGHT)) - 1, 3, 5);
> +	sp_stage->isp_vf_downscale_bits = 0;
> +	sp_stage->if_config_index = 255;
> +	sp_stage->sp_enable_xnr = 0;
> +	sp_stage->num_stripes = stripes;
> +	sp_stage->enable.s3a = 1;
> +	sp_stage->enable.dvs_stats = 1;
> +
> +	sp_stage->xmem_bin_addr = css->binary[css->current_binary].daddr;
> +	sp_stage->xmem_map_addr = css->sp_ddr_ptrs.daddr;
> +	sp_stage->isp_stage_addr = css->xmem_isp_stage_ptrs[pipe][stage].daddr;
> +
> +	/* Configure SP group */
> +
> +	sp_group = css->xmem_sp_group_ptrs.vaddr;
> +	memset(sp_group, 0, sizeof(*sp_group));
> +
> +	sp_group->pipe[thread].num_stages = 1;
> +	sp_group->pipe[thread].pipe_id = PIPE_ID;
> +	sp_group->pipe[thread].thread_id = thread;
> +	sp_group->pipe[thread].pipe_num = pipe;
> +	sp_group->pipe[thread].num_execs = -1;
> +	sp_group->pipe[thread].pipe_qos_config = -1;
> +	sp_group->pipe[thread].required_bds_factor = 0;
> +	sp_group->pipe[thread].dvs_frame_delay = IPU3_CSS_AUX_FRAMES - 1;
> +	sp_group->pipe[thread].inout_port_config =
> +	    IMGU_ABI_PORT_CONFIG_TYPE_INPUT_HOST |
> +	    IMGU_ABI_PORT_CONFIG_TYPE_OUTPUT_HOST;

Indentation. Most of this seems to have been fixed but some remains in this
patch at least. Could you address that for the next version, please?

> +	sp_group->pipe[thread].scaler_pp_lut = 0;
> +	sp_group->pipe[thread].shading.internal_frame_origin_x_bqs_on_sctbl = 0;
> +	sp_group->pipe[thread].shading.internal_frame_origin_y_bqs_on_sctbl = 0;
> +	sp_group->pipe[thread].sp_stage_addr[stage] =
> +	    css->xmem_sp_stage_ptrs[pipe][stage].daddr;
> +	sp_group->pipe[thread].pipe_config =
> +	    bi->info.isp.sp.enable.params ? (1 << thread) : 0;
> +	sp_group->pipe[thread].pipe_config |= IMGU_ABI_PIPE_CONFIG_ACQUIRE_ISP;
> +
> +	/* Allocate dvs statistics metadata */
> +
> +	for (i = 0; i < stripes; i++)
> +		if (ipu3_css_dma_alloc(css->dev, &css->dvs_meta_data[pipe][i],
> +				       sizeof(struct imgu_abi_dvs_meta_data)))
> +			goto out_of_memory;
> +
> +	/* Initialize parameter pools */
> +
> +	if (ipu3_css_pool_init(css->dev, &css->pool.parameter_set_info,
> +			       sizeof(struct imgu_abi_parameter_set_info)) ||
> +	    ipu3_css_pool_init(css->dev, &css->pool.acc,
> +			       sizeof(struct ipu3_uapi_acc_param)) ||
> +	    ipu3_css_pool_init(css->dev, &css->pool.gdc,
> +			       sizeof(struct ipu3_uapi_gdc_warp_param) *
> +			       3 * cfg_dvs->num_horizontal_blocks / 2 *
> +			       cfg_dvs->num_vertical_blocks) ||
> +	    ipu3_css_pool_init(css->dev, &css->pool.obgrid,
> +			       ipu3_css_fw_obgrid_size(
> +			       &css->fwp->binary_header[css->current_binary])))
> +		goto out_of_memory;
> +
> +	for (i = 0; i < IMGU_ABI_NUM_MEMORIES; i++)
> +		if (ipu3_css_pool_init(css->dev, &css->pool.binary_params_p[i],
> +				       bi->info.isp.sp.mem_initializers.params
> +				       [IMGU_ABI_PARAM_CLASS_PARAM][i].size))
> +			goto out_of_memory;
> +
> +	return 0;
> +
> +bad_firmware:
> +	ipu3_css_pipeline_cleanup(css);
> +	return -EPROTO;
> +
> +out_of_memory:
> +	ipu3_css_pipeline_cleanup(css);
> +	return -ENOMEM;
> +}
> +
> +static u8 ipu3_css_queue_pos(struct ipu3_css *css, int queue, int thread)
> +{
> +	static const unsigned int sp;
> +	void __iomem *const base = css->base;
> +	struct imgu_fw_info *bi = &css->fwp->binary_header[css->fw_sp[sp]];
> +	struct imgu_abi_queues __iomem *q = base + IMGU_REG_SP_DMEM_BASE(sp) +
> +	    bi->info.sp.host_sp_queue;
> +
> +	return queue >= 0 ? readb(&q->host2sp_bufq_info[thread][queue].end) :
> +	    readb(&q->host2sp_evtq_info.end);
> +}
> +
> +/* Sent data to sp using given buffer queue, or if queue < 0, event queue. */
> +static int ipu3_css_queue_data(struct ipu3_css *css,
> +			       int queue, int thread, u32 data)
> +{
> +	static const unsigned int sp;
> +	void __iomem *const base = css->base;
> +	struct imgu_fw_info *bi = &css->fwp->binary_header[css->fw_sp[sp]];
> +	struct imgu_abi_queues __iomem *q = base + IMGU_REG_SP_DMEM_BASE(sp) +
> +	    bi->info.sp.host_sp_queue;
> +	u8 size, start, end, end2;
> +
> +	if (queue >= 0) {
> +		size = readb(&q->host2sp_bufq_info[thread][queue].size);
> +		start = readb(&q->host2sp_bufq_info[thread][queue].start);
> +		end = readb(&q->host2sp_bufq_info[thread][queue].end);
> +	} else {
> +		size = readb(&q->host2sp_evtq_info.size);
> +		start = readb(&q->host2sp_evtq_info.start);
> +		end = readb(&q->host2sp_evtq_info.end);
> +	}
> +
> +	if (size == 0)
> +		return -EIO;
> +
> +	end2 = (end + 1) % size;
> +	if (end2 == start)
> +		return -EBUSY;	/* Queue full */
> +
> +	if (queue >= 0) {
> +		writel(data, &q->host2sp_bufq[thread][queue][end]);
> +		writeb(end2, &q->host2sp_bufq_info[thread][queue].end);
> +	} else {
> +		writel(data, &q->host2sp_evtq[end]);
> +		writeb(end2, &q->host2sp_evtq_info.end);
> +	}
> +
> +	return 0;
> +}
> +
> +/* Receive data using given buffer queue, or if queue < 0, event queue. */
> +static int ipu3_css_dequeue_data(struct ipu3_css *css, int queue, u32 *data)
> +{
> +	static const unsigned int sp;
> +	void __iomem *const base = css->base;
> +	struct imgu_fw_info *bi = &css->fwp->binary_header[css->fw_sp[sp]];
> +	struct imgu_abi_queues __iomem *q = base + IMGU_REG_SP_DMEM_BASE(sp) +
> +	    bi->info.sp.host_sp_queue;
> +	u8 size, start, end, start2;
> +
> +	if (queue >= 0) {
> +		size = readb(&q->sp2host_bufq_info[queue].size);
> +		start = readb(&q->sp2host_bufq_info[queue].start);
> +		end = readb(&q->sp2host_bufq_info[queue].end);
> +	} else {
> +		size = readb(&q->sp2host_evtq_info.size);
> +		start = readb(&q->sp2host_evtq_info.start);
> +		end = readb(&q->sp2host_evtq_info.end);
> +	}
> +
> +	if (size == 0)
> +		return -EIO;
> +
> +	if (end == start)
> +		return -EBUSY;	/* Queue empty */
> +
> +	start2 = (start + 1) % size;
> +
> +	if (queue >= 0) {
> +		*data = readl(&q->sp2host_bufq[queue][start]);
> +		writeb(start2, &q->sp2host_bufq_info[queue].start);
> +	} else {
> +		int r;
> +
> +		*data = readl(&q->sp2host_evtq[start]);
> +		writeb(start2, &q->sp2host_evtq_info.start);
> +
> +		/* Acknowledge events dequeued from event queue */
> +		r = ipu3_css_queue_data(css, queue, 0,
> +					IMGU_ABI_EVENT_EVENT_DEQUEUED);
> +		if (r < 0)
> +			return r;
> +	}
> +
> +	return 0;
> +}
> +
> +/* Free binary-specific resources */
> +static void ipu3_css_binary_cleanup(struct ipu3_css *css)
> +{
> +	unsigned int i, j;
> +
> +	for (j = 0; j < IMGU_ABI_PARAM_CLASS_NUM - 1; j++)
> +		for (i = 0; i < IMGU_ABI_NUM_MEMORIES; i++)
> +			ipu3_css_dma_free(css->dev,
> +					  &css->binary_params_cs[j][i]);
> +
> +	j = IPU3_CSS_AUX_FRAME_REF;
> +	for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
> +		ipu3_css_dma_free(css->dev,
> +				  &css->aux_frames[j].mem[i]);
> +
> +	j = IPU3_CSS_AUX_FRAME_TNR;
> +	for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
> +		ipu3_css_dma_free(css->dev,
> +				  &css->aux_frames[j].mem[i]);
> +}
> +
> +/* allocate binary-specific resources */
> +static int ipu3_css_binary_setup(struct ipu3_css *css)
> +{
> +	struct imgu_fw_info *bi = &css->fwp->binary_header[css->current_binary];
> +	int i, j, sz;
> +	static const int BYPC = 2;	/* Bytes per component */
> +	unsigned int w, h;
> +
> +	/* Allocate parameter memory blocks for this binary */
> +	if (css->current_binary < 0)
> +		return -EINVAL;
> +
> +	for (j = IMGU_ABI_PARAM_CLASS_CONFIG; j < IMGU_ABI_PARAM_CLASS_NUM; j++)
> +		for (i = 0; i < IMGU_ABI_NUM_MEMORIES; i++) {
> +			sz = bi->info.isp.sp.mem_initializers.params[j][i].size;
> +			if (ipu3_css_dma_alloc(css->dev,
> +					       &css->binary_params_cs[j - 1][i],
> +					       sz))
> +				goto out_of_memory;
> +		}
> +
> +	/* Allocate internal frame buffers */
> +
> +	/* Reference frames for DVS, FRAME_FORMAT_YUV420_16 */
> +	css->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperpixel = BYPC;
> +	css->aux_frames[IPU3_CSS_AUX_FRAME_REF].width =
> +	    css->rect[IPU3_CSS_RECT_BDS].width;
> +	css->aux_frames[IPU3_CSS_AUX_FRAME_REF].height =
> +				ALIGN(css->rect[IPU3_CSS_RECT_BDS].height,
> +				      IMGU_DVS_BLOCK_H) + 2 * IMGU_GDC_BUF_Y;
> +	h = css->aux_frames[IPU3_CSS_AUX_FRAME_REF].height;
> +	w = ALIGN(css->rect[IPU3_CSS_RECT_BDS].width,
> +		  2 * IPU3_UAPI_ISP_VEC_ELEMS) + 2 * IMGU_GDC_BUF_X;
> +	css->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperline =
> +		css->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperpixel * w;
> +	sz = w * h * BYPC + (w / 2) * (h / 2) * BYPC * 2;
> +	for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
> +		if (ipu3_css_dma_alloc(css->dev,
> +				       &css->aux_frames
> +					[IPU3_CSS_AUX_FRAME_REF].mem[i], sz))
> +			goto out_of_memory;
> +
> +	/* TNR frames for temporal noise reduction, FRAME_FORMAT_YUV_LINE */
> +	css->aux_frames[IPU3_CSS_AUX_FRAME_TNR].bytesperpixel = 1;
> +	css->aux_frames[IPU3_CSS_AUX_FRAME_TNR].width =
> +			roundup(css->rect[IPU3_CSS_RECT_GDC].width,
> +				bi->info.isp.sp.block.block_width *
> +				IPU3_UAPI_ISP_VEC_ELEMS);
> +	css->aux_frames[IPU3_CSS_AUX_FRAME_TNR].height =
> +			roundup(css->rect[IPU3_CSS_RECT_GDC].height,
> +				bi->info.isp.sp.block.output_block_height);
> +
> +	w = css->aux_frames[IPU3_CSS_AUX_FRAME_TNR].width;
> +	css->aux_frames[IPU3_CSS_AUX_FRAME_TNR].bytesperline = w;
> +	h = css->aux_frames[IPU3_CSS_AUX_FRAME_TNR].height;
> +	sz = w * ALIGN(h * 3 / 2 + 3, 2);	/* +3 for vf_pp prefetch */
> +
> +	for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
> +		if (ipu3_css_dma_alloc(css->dev,
> +				       &css->aux_frames
> +					[IPU3_CSS_AUX_FRAME_TNR].mem[i], sz))
> +			goto out_of_memory;
> +
> +	return 0;
> +
> +out_of_memory:
> +	ipu3_css_binary_cleanup(css);
> +	return -ENOMEM;
> +}
> +
> +int ipu3_css_start_streaming(struct ipu3_css *css)
> +{
> +	u32 data;
> +	int r;
> +
> +	if (css->streaming)
> +		return -EPROTO;
> +
> +	r = ipu3_css_binary_setup(css);
> +	if (r < 0)
> +		return r;
> +
> +	r = ipu3_css_hw_init(css);
> +	if (r < 0)
> +		return r;
> +
> +	r = ipu3_css_hw_start(css);
> +	if (r < 0)
> +		goto fail;
> +
> +	r = ipu3_css_pipeline_init(css);
> +	if (r < 0)
> +		goto fail;
> +
> +	css->streaming = true;
> +	css->frame = 0;
> +
> +	/* Initialize parameters to default */
> +	r = ipu3_css_set_parameters(css, NULL, NULL, 0, NULL, 0);
> +	if (r < 0)
> +		goto fail;
> +
> +	while (!(r = ipu3_css_dequeue_data(css, IMGU_ABI_QUEUE_A_ID, &data)))
> +		;
> +	if (r != -EBUSY)
> +		goto fail;
> +
> +	while (!(r = ipu3_css_dequeue_data(css, IMGU_ABI_QUEUE_B_ID, &data)))
> +		;
> +	if (r != -EBUSY)
> +		goto fail;
> +
> +	r = ipu3_css_queue_data(css, IMGU_ABI_QUEUE_EVENT_ID, 0,
> +				IMGU_ABI_EVENT_START_STREAM);
> +	if (r < 0)
> +		goto fail;
> +
> +	return 0;
> +
> +fail:
> +	css->streaming = false;
> +	ipu3_css_hw_cleanup(css);
> +	ipu3_css_pipeline_cleanup(css);
> +	ipu3_css_binary_cleanup(css);
> +
> +	return r;
> +}
> +
> +void ipu3_css_stop_streaming(struct ipu3_css *css)
> +{
> +	struct ipu3_css_buffer *b, *b0;
> +	int q, r;
> +
> +	r = ipu3_css_queue_data(css, IMGU_ABI_QUEUE_EVENT_ID, 0,
> +				IMGU_ABI_EVENT_STOP_STREAM);
> +
> +	if (r < 0)
> +		dev_warn(css->dev, "failed on stop stream event\n");
> +
> +	if (!css->streaming)
> +		return;
> +
> +	ipu3_css_hw_cleanup(css);
> +
> +	ipu3_css_pipeline_cleanup(css);
> +
> +	for (q = 0; q < IPU3_CSS_QUEUES; q++)
> +		list_for_each_entry_safe(b, b0, &css->queue[q].bufs, list) {
> +			b->state = IPU3_CSS_BUFFER_FAILED;
> +			list_del(&b->list);
> +		}
> +
> +	ipu3_css_binary_cleanup(css);
> +
> +	css->streaming = false;
> +}
> +
> +bool ipu3_css_queue_empty(struct ipu3_css *css)
> +{
> +	int q;
> +
> +	for (q = 0; q < IPU3_CSS_QUEUES; q++)
> +		if (!list_empty(&css->queue[q].bufs))
> +			return false;
> +	return true;
> +}
> +
> +bool ipu3_css_is_streaming(struct ipu3_css *css)
> +{
> +	return css->streaming;
> +}
> +
> +void ipu3_css_cleanup(struct ipu3_css *css)
> +{
> +	int p, q, i;
> +
> +	ipu3_css_stop_streaming(css);
> +	ipu3_css_binary_cleanup(css);
> +
> +	for (q = 0; q < IPU3_CSS_QUEUES; q++)
> +		for (i = 0; i < ARRAY_SIZE(css->abi_buffers[q]); i++)
> +			ipu3_css_dma_free(css->dev, &css->abi_buffers[q][i]);
> +
> +	for (p = 0; p < IPU3_CSS_PIPE_ID_NUM; p++)
> +		for (i = 0; i < IMGU_ABI_MAX_STAGES; i++) {
> +			ipu3_css_dma_free(css->dev,
> +					  &css->xmem_sp_stage_ptrs[p][i]);
> +			ipu3_css_dma_free(css->dev,
> +					  &css->xmem_isp_stage_ptrs[p][i]);
> +		}
> +
> +	ipu3_css_dma_free(css->dev, &css->sp_ddr_ptrs);
> +	ipu3_css_dma_free(css->dev, &css->xmem_sp_group_ptrs);
> +
> +	ipu3_css_fw_cleanup(css);
> +}
> +
> +int ipu3_css_init(struct device *dev, struct ipu3_css *css,
> +		  void __iomem *base, int length)
> +{
> +	int r, p, q, i;
> +	struct imgu_abi_sp_stage *sp_stage;
> +	/* Initialize main data structure */
> +
> +	css->dev = dev;
> +	css->base = base;
> +	css->iomem_length = length;
> +	css->current_binary = -1;
> +	css->pipe_id = IPU3_CSS_PIPE_ID_NUM;
> +
> +	for (q = 0; q < IPU3_CSS_QUEUES; q++) {
> +		r = ipu3_css_queue_init(&css->queue[q], NULL, 0);
> +		if (r)
> +			return r;
> +	}
> +
> +	r = ipu3_css_fw_init(css);
> +	if (r)
> +		return r;
> +
> +	/* Allocate and map common structures with imgu hardware */
> +
> +	for (p = 0; p < IPU3_CSS_PIPE_ID_NUM; p++)
> +		for (i = 0; i < IMGU_ABI_MAX_STAGES; i++) {
> +			if (ipu3_css_dma_alloc(dev,
> +					       &css->xmem_sp_stage_ptrs[p][i],
> +					       sizeof(*sp_stage)))
> +				goto error_no_memory;
> +			if (ipu3_css_dma_alloc(dev,
> +					       &css->xmem_isp_stage_ptrs[p][i],
> +					       sizeof(*sp_stage)))
> +				goto error_no_memory;
> +		}
> +
> +	if (ipu3_css_dma_alloc(dev, &css->sp_ddr_ptrs,
> +			       ALIGN(sizeof(struct imgu_abi_ddr_address_map),
> +				     IMGU_ABI_ISP_DDR_WORD_BYTES)))
> +		goto error_no_memory;
> +
> +	if (ipu3_css_dma_alloc(dev, &css->xmem_sp_group_ptrs,
> +			       sizeof(struct imgu_abi_sp_group)))
> +		goto error_no_memory;
> +
> +	for (q = 0; q < IPU3_CSS_QUEUES; q++)
> +		for (i = 0; i < ARRAY_SIZE(css->abi_buffers[q]); i++)
> +			if (ipu3_css_dma_alloc(dev, &css->abi_buffers[q][i],
> +					       sizeof(struct imgu_abi_buffer)))
> +				goto error_no_memory;
> +
> +	return 0;
> +
> +error_no_memory:
> +	ipu3_css_cleanup(css);
> +
> +	return -ENOMEM;
> +}
> +
> +static u32 ipu3_css_adjust(u32 res, u32 align)
> +{
> +	if (res < IPU3_CSS_MIN_RES)
> +		res = IPU3_CSS_MIN_RES;
> +	res = roundclosest(res, align);
> +
> +	return res;
> +}
> +
> +/* Select a binary matching the required resolutions and formats */
> +static int ipu3_css_find_binary(struct ipu3_css *css,
> +				struct ipu3_css_queue queue[IPU3_CSS_QUEUES],
> +				struct v4l2_rect rects[IPU3_CSS_RECTS])
> +{
> +	const int binary_nr = css->fwp->file_header.binary_nr;
> +	unsigned int binary_mode = (css->pipe_id == IPU3_CSS_PIPE_ID_CAPTURE) ?
> +		IA_CSS_BINARY_MODE_PRIMARY : IA_CSS_BINARY_MODE_VIDEO;
> +	const char *name;
> +
> +	const struct v4l2_pix_format_mplane *in =
> +			&queue[IPU3_CSS_QUEUE_IN].fmt.mpix;
> +	const struct v4l2_pix_format_mplane *out =
> +			&queue[IPU3_CSS_QUEUE_OUT].fmt.mpix;
> +	const struct v4l2_pix_format_mplane *vf =
> +			&queue[IPU3_CSS_QUEUE_VF].fmt.mpix;
> +
> +	int i, j;
> +	u32 stripe_w = 0;
> +	u32 stripe_h = 0;
> +
> +	if (!ipu3_css_queue_enabled(&queue[IPU3_CSS_QUEUE_IN]))
> +		return -EINVAL;
> +
> +	/* Find out the strip size boundary */
> +	for (i = 0; i < binary_nr; i++) {
> +		struct imgu_fw_info *bi = &css->fwp->binary_header[i];
> +
> +		u32 max_width = bi->info.isp.sp.output.max_width;
> +		u32 max_height = bi->info.isp.sp.output.max_height;
> +
> +		if (bi->info.isp.sp.iterator.num_stripes <= 1) {
> +			stripe_w = stripe_w ?
> +				min(stripe_w, max_width) : max_width;
> +			stripe_h = stripe_h ?
> +				min(stripe_h, max_height) : max_height;
> +		}
> +	}
> +
> +	for (i = 0; i < binary_nr; i++) {
> +		struct imgu_fw_info *bi = &css->fwp->binary_header[i];
> +		enum imgu_abi_frame_format q_fmt;
> +
> +		name = (void *)css->fwp + bi->blob.prog_name_offset;
> +
> +		/* Check that binary supports memory-to-memory processing */
> +		if (bi->info.isp.sp.input.source !=
> +		    IMGU_ABI_BINARY_INPUT_SOURCE_MEMORY)
> +			continue;
> +
> +		/* Check that binary supports raw10 input */
> +		if (!bi->info.isp.sp.enable.input_feeder &&
> +		    !bi->info.isp.sp.enable.input_raw)
> +			continue;
> +
> +		/* Check binary mode */
> +		if (bi->info.isp.sp.pipeline.mode != binary_mode)
> +			continue;
> +
> +		/* Since input is RGGB bayer, need to process colors */
> +		if (bi->info.isp.sp.enable.luma_only)
> +			continue;
> +
> +		if (in->width < bi->info.isp.sp.input.min_width ||
> +		    in->width > bi->info.isp.sp.input.max_width ||
> +		    in->height < bi->info.isp.sp.input.min_height ||
> +		    in->height > bi->info.isp.sp.input.max_height)
> +			continue;
> +
> +		if (ipu3_css_queue_enabled(&queue[IPU3_CSS_QUEUE_OUT])) {
> +			if (bi->info.isp.num_output_pins <= 0)
> +				continue;
> +
> +			q_fmt = queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
> +
> +			for (j = 0; j < bi->info.isp.num_output_formats; j++)
> +				if (bi->info.isp.output_formats[j] == q_fmt)
> +					break;
> +			if (j >= bi->info.isp.num_output_formats)
> +				continue;
> +
> +			if (out->width < bi->info.isp.sp.output.min_width ||
> +			    out->width > bi->info.isp.sp.output.max_width ||
> +			    out->height < bi->info.isp.sp.output.min_height ||
> +			    out->height > bi->info.isp.sp.output.max_height)
> +				continue;
> +
> +			if (out->width > bi->info.isp.sp.internal.max_width ||
> +			    out->height > bi->info.isp.sp.internal.max_height)
> +				continue;
> +		}
> +
> +		if (ipu3_css_queue_enabled(&queue[IPU3_CSS_QUEUE_VF])) {
> +			if (bi->info.isp.num_output_pins <= 1)
> +				continue;
> +			q_fmt = queue[IPU3_CSS_QUEUE_VF].css_fmt->frame_format;
> +			for (j = 0; j < bi->info.isp.num_output_formats; j++)
> +				if (bi->info.isp.output_formats[j] == q_fmt)
> +					break;
> +			if (j >= bi->info.isp.num_output_formats)
> +				continue;
> +
> +			if (vf->width < bi->info.isp.sp.output.min_width ||
> +			    vf->width > bi->info.isp.sp.output.max_width ||
> +			    vf->height < bi->info.isp.sp.output.min_height ||
> +			    vf->height > bi->info.isp.sp.output.max_height)
> +				continue;
> +		}
> +
> +		/* All checks passed, select the binary */
> +		dev_dbg(css->dev, "using binary %s\n", name);
> +		return i;
> +	}
> +
> +	/* Can not find suitable binary for these parameters */
> +	return -EINVAL;
> +}
> +
> +/*
> + * Check that there is a binary matching requirements. Parameters may be
> + * NULL indicating disabled input/output. Return negative if given
> + * parameters can not be supported or on error, zero or positive indicating
> + * found binary number. May modify the given parameters if not exact match
> + * is found.
> + */
> +int ipu3_css_fmt_try(struct ipu3_css *css,
> +		     struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES],
> +		     struct v4l2_rect *rects[IPU3_CSS_RECTS])
> +{
> +	static const u32 EFF_ALIGN_W = 2;
> +	static const u32 BDS_ALIGN_W = 4;
> +	static const u32 OUT_ALIGN_W = 8;
> +	static const u32 OUT_ALIGN_H = 4;
> +	static const u32 VF_ALIGN_W  = 2;
> +	static const char *qnames[IPU3_CSS_QUEUES] = {
> +		[IPU3_CSS_QUEUE_IN] = "in",
> +		[IPU3_CSS_QUEUE_PARAMS]    = "params",
> +		[IPU3_CSS_QUEUE_OUT] = "out",
> +		[IPU3_CSS_QUEUE_VF] = "vf",
> +		[IPU3_CSS_QUEUE_STAT_3A]   = "3a",
> +		[IPU3_CSS_QUEUE_STAT_DVS]  = "dvs",
> +		[IPU3_CSS_QUEUE_STAT_LACE] = "lace",
> +	};
> +	static const char *rnames[IPU3_CSS_RECTS] = {
> +		[IPU3_CSS_RECT_EFFECTIVE] = "effective resolution",
> +		[IPU3_CSS_RECT_BDS]       = "bayer-domain scaled resolution",
> +		[IPU3_CSS_RECT_ENVELOPE]  = "DVS envelope size",
> +		[IPU3_CSS_RECT_GDC]  = "GDC output res",
> +	};
> +	struct v4l2_rect r[IPU3_CSS_RECTS] = { };
> +	struct v4l2_rect *const eff = &r[IPU3_CSS_RECT_EFFECTIVE];
> +	struct v4l2_rect *const bds = &r[IPU3_CSS_RECT_BDS];
> +	struct v4l2_rect *const env = &r[IPU3_CSS_RECT_ENVELOPE];
> +	struct v4l2_rect *const gdc = &r[IPU3_CSS_RECT_GDC];
> +	struct ipu3_css_queue q[IPU3_CSS_QUEUES];
> +	struct v4l2_pix_format_mplane *const in =
> +			&q[IPU3_CSS_QUEUE_IN].fmt.mpix;
> +	struct v4l2_pix_format_mplane *const out =
> +			&q[IPU3_CSS_QUEUE_OUT].fmt.mpix;
> +	struct v4l2_pix_format_mplane *const vf =
> +			&q[IPU3_CSS_QUEUE_VF].fmt.mpix;
> +	int binary, i, s;
> +
> +	/* Decide which pipe to use */
> +	if (css->vf_output_en == IPU3_NODE_PV_ENABLED)
> +		css->pipe_id = IPU3_CSS_PIPE_ID_CAPTURE;
> +	else if (css->vf_output_en == IPU3_NODE_VF_ENABLED)
> +		css->pipe_id = IPU3_CSS_PIPE_ID_VIDEO;
> +
> +	/* Adjust all formats, get statistics buffer sizes and formats */
> +	for (i = 0; i < IPU3_CSS_QUEUES; i++) {
> +		if (fmts[i])
> +			dev_dbg(css->dev, "%s %s: (%i,%i) fmt 0x%x\n", __func__,
> +				qnames[i], fmts[i]->width, fmts[i]->height,
> +				fmts[i]->pixelformat);
> +		else
> +			dev_dbg(css->dev, "%s %s: (not set)\n", __func__,
> +				qnames[i]);
> +		if (ipu3_css_queue_init(&q[i], fmts[i],
> +					IPU3_CSS_QUEUE_TO_FLAGS(i))) {
> +			dev_notice(css->dev, "can not initialize queue %s\n",
> +				   qnames[i]);
> +			return -EINVAL;
> +		}
> +	}
> +	for (i = 0; i < IPU3_CSS_RECTS; i++) {
> +		if (rects[i]) {
> +			dev_dbg(css->dev, "%s %s: (%i,%i)\n", __func__,
> +				rnames[i], rects[i]->width, rects[i]->height);
> +			r[i].width  = rects[i]->width;
> +			r[i].height = rects[i]->height;
> +		} else {
> +			dev_dbg(css->dev, "%s %s: (not set)\n", __func__,
> +				rnames[i]);
> +		}
> +		/* For now, force known good resolutions */
> +		r[i].left = 0;
> +		r[i].top  = 0;
> +	}
> +
> +	/* Always require one input and vf only if out is also enabled */
> +	if (!ipu3_css_queue_enabled(&q[IPU3_CSS_QUEUE_IN]) ||
> +	    (ipu3_css_queue_enabled(&q[IPU3_CSS_QUEUE_VF]) &&
> +	    !ipu3_css_queue_enabled(&q[IPU3_CSS_QUEUE_OUT]))) {
> +		dev_dbg(css->dev, "required queues are disabled\n");
> +		return -EINVAL;
> +	}
> +
> +	if (!ipu3_css_queue_enabled(&q[IPU3_CSS_QUEUE_OUT])) {
> +		out->width = in->width;
> +		out->height = in->height;
> +	}
> +	if (eff->width <= 0 || eff->height <= 0) {
> +		eff->width = in->width;
> +		eff->height = in->height;
> +	}
> +	if (bds->width <= 0 || bds->height <= 0) {
> +		bds->width = out->width;
> +		bds->height = out->height;
> +	}
> +	if (gdc->width <= 0 || gdc->height <= 0) {
> +		gdc->width = out->width;
> +		gdc->height = out->height;
> +	}
> +
> +	in->width   = ipu3_css_adjust(in->width, 1);
> +	in->height  = ipu3_css_adjust(in->height, 1);
> +	eff->width  = ipu3_css_adjust(eff->width, EFF_ALIGN_W);
> +	eff->height = ipu3_css_adjust(eff->height, 1);
> +	bds->width  = ipu3_css_adjust(bds->width, BDS_ALIGN_W);
> +	bds->height = ipu3_css_adjust(bds->height, 1);
> +	gdc->width  = ipu3_css_adjust(gdc->width, OUT_ALIGN_W);
> +	gdc->height = ipu3_css_adjust(gdc->height, OUT_ALIGN_H);
> +	out->width  = ipu3_css_adjust(out->width, OUT_ALIGN_W);
> +	out->height = ipu3_css_adjust(out->height, OUT_ALIGN_H);
> +	vf->width   = ipu3_css_adjust(vf->width, VF_ALIGN_W);
> +	vf->height  = ipu3_css_adjust(vf->height, 1);
> +
> +	s = (bds->width - gdc->width) / 2 - FILTER_SIZE;
> +	env->width = s < MIN_ENVELOPE ? MIN_ENVELOPE : s;
> +	s = (bds->height - gdc->height) / 2 - FILTER_SIZE;
> +	env->height = s < MIN_ENVELOPE ? MIN_ENVELOPE : s;
> +
> +	binary = ipu3_css_find_binary(css, q, r);
> +	if (binary < 0) {
> +		dev_err(css->dev, "failed to find suitable binary\n");
> +		return -EINVAL;
> +	}
> +
> +	/* Final adjustment and set back the queried formats */
> +	for (i = 0; i < IPU3_CSS_QUEUES; i++) {
> +		if (fmts[i]) {
> +			if (ipu3_css_queue_init(&q[i], &q[i].fmt.mpix,
> +						IPU3_CSS_QUEUE_TO_FLAGS(i))) {
> +				dev_err(css->dev,
> +					"final resolution adjustment failed\n");
> +				return -EINVAL;
> +			}
> +			*fmts[i] = q[i].fmt.mpix;
> +		}
> +	}
> +
> +	for (i = 0; i < IPU3_CSS_RECTS; i++)
> +		if (rects[i])
> +			*rects[i] = r[i];
> +
> +	dev_dbg(css->dev,
> +		"in(%u,%u) if(%u,%u) ds(%u,%u) gdc(%u,%u) out(%u,%u) vf(%u,%u)",
> +		 in->width, in->height, eff->width, eff->height,
> +		 bds->width, bds->height, gdc->width, gdc->height,
> +		 out->width, out->height, vf->width, vf->height);
> +
> +	return binary;
> +}
> +
> +int ipu3_css_fmt_set(struct ipu3_css *css,
> +		     struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES],
> +		     struct v4l2_rect *rects[IPU3_CSS_RECTS])
> +{
> +	struct v4l2_rect rect_data[IPU3_CSS_RECTS];
> +	struct v4l2_rect *all_rects[IPU3_CSS_RECTS];
> +	int i, r;
> +
> +	for (i = 0; i < IPU3_CSS_RECTS; i++) {
> +		if (rects[i])
> +			rect_data[i] = *rects[i];
> +		else
> +			memset(&rect_data[i], 0, sizeof(rect_data[i]));
> +		all_rects[i] = &rect_data[i];
> +	}
> +	r = ipu3_css_fmt_try(css, fmts, all_rects);
> +	if (r < 0)
> +		return r;
> +	css->current_binary = r;
> +
> +	for (i = 0; i < IPU3_CSS_QUEUES; i++)
> +		if (ipu3_css_queue_init(&css->queue[i], fmts[i],
> +					IPU3_CSS_QUEUE_TO_FLAGS(i)))
> +			return -EINVAL;
> +	for (i = 0; i < IPU3_CSS_RECTS; i++) {
> +		css->rect[i] = rect_data[i];
> +		if (rects[i])
> +			*rects[i] = rect_data[i];
> +	}
> +
> +	return 0;
> +}
> +
> +int ipu3_css_meta_fmt_set(struct v4l2_meta_format *fmt)
> +{
> +	switch (fmt->dataformat) {
> +	case V4L2_META_FMT_IPU3_PARAMS:
> +		fmt->buffersize = sizeof(struct ipu3_uapi_params);
> +		break;
> +	case V4L2_META_FMT_IPU3_STAT_3A:
> +		fmt->buffersize = sizeof(struct ipu3_uapi_stats_3a);
> +		break;
> +	case V4L2_META_FMT_IPU3_STAT_DVS:
> +		fmt->buffersize = sizeof(struct ipu3_uapi_stats_dvs);
> +		break;
> +	case V4L2_META_FMT_IPU3_STAT_LACE:
> +		fmt->buffersize = sizeof(struct ipu3_uapi_stats_lace);
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * Queue given buffer to CSS. ipu3_css_buf_prepare() must have been first
> + * called for the buffer. May be called from interrupt context.
> + * Returns 0 on success, -EBUSY if the buffer queue is full, or some other
> + * code on error conditions.
> + */
> +int ipu3_css_buf_queue(struct ipu3_css *css, struct ipu3_css_buffer *b)
> +{
> +	static const int thread;
> +	struct imgu_abi_buffer *abi_buf;
> +	struct imgu_addr_t *buf_addr;
> +	u32 data;
> +	int r;
> +
> +	if (!css->streaming)
> +		return -EPROTO;	/* CSS or buffer in wrong state */
> +
> +	if (b->queue >= IPU3_CSS_QUEUES || !ipu3_css_queues[b->queue].qid)
> +		return -EINVAL;
> +
> +	b->queue_pos = ipu3_css_queue_pos(
> +				css, ipu3_css_queues[b->queue].qid, thread);
> +
> +	if (b->queue_pos >= ARRAY_SIZE(css->abi_buffers[b->queue]))
> +		return -EIO;
> +	abi_buf = css->abi_buffers[b->queue][b->queue_pos].vaddr;
> +
> +	/* Fill struct abi_buffer for firmware */
> +	memset(abi_buf, 0, sizeof(*abi_buf));
> +
> +	buf_addr = (void *)abi_buf + ipu3_css_queues[b->queue].ptr_ofs;
> +	*(imgu_addr_t *)buf_addr = b->daddr;
> +
> +	if (b->queue == IPU3_CSS_QUEUE_STAT_3A)
> +		abi_buf->payload.s3a.data.dmem.s3a_tbl = b->daddr;
> +
> +	if (b->queue == IPU3_CSS_QUEUE_OUT)
> +		abi_buf->payload.frame.padded_width =
> +			css->queue[IPU3_CSS_QUEUE_OUT].width_pad;
> +
> +	if (b->queue == IPU3_CSS_QUEUE_VF)
> +		abi_buf->payload.frame.padded_width =
> +			css->queue[IPU3_CSS_QUEUE_VF].width_pad;
> +
> +	list_add_tail(&b->list, &css->queue[b->queue].bufs);
> +	b->state = IPU3_CSS_BUFFER_QUEUED;
> +
> +	data = css->abi_buffers[b->queue][b->queue_pos].daddr;
> +	r = ipu3_css_queue_data(css, ipu3_css_queues[b->queue].qid,
> +				thread, data);
> +	if (r < 0)
> +		goto queueing_failed;
> +
> +	data = IMGU_ABI_EVENT_BUFFER_ENQUEUED(thread,
> +					      ipu3_css_queues[b->queue].qid);
> +	r = ipu3_css_queue_data(css, IMGU_ABI_QUEUE_EVENT_ID,
> +				0, data);
> +	if (r < 0)
> +		goto queueing_failed;
> +
> +	dev_dbg(css->dev, "queued buffer %p to css queue %i\n", b, b->queue);
> +
> +	return 0;
> +
> +queueing_failed:
> +	b->state = (r == -EBUSY || r == -EAGAIN) ?
> +		IPU3_CSS_BUFFER_NEW : IPU3_CSS_BUFFER_FAILED;
> +	list_del(&b->list);
> +
> +	return r;
> +}
> +
> +/*
> + * Get next ready CSS buffer. Returns -EAGAIN in which case the function
> + * should be called again, or -EBUSY which means that there are no more
> + * buffers available. May be called from interrupt context.
> + */
> +struct ipu3_css_buffer *ipu3_css_buf_dequeue(struct ipu3_css *css)
> +{
> +	static const int thread;
> +	static const unsigned char evtype_to_queue[] = {
> +		[IMGU_ABI_EVTTYPE_INPUT_FRAME_DONE] = IPU3_CSS_QUEUE_IN,
> +		[IMGU_ABI_EVTTYPE_OUT_FRAME_DONE] = IPU3_CSS_QUEUE_OUT,
> +		[IMGU_ABI_EVTTYPE_VF_OUT_FRAME_DONE] = IPU3_CSS_QUEUE_VF,
> +		[IMGU_ABI_EVTTYPE_3A_STATS_DONE] = IPU3_CSS_QUEUE_STAT_3A,
> +		[IMGU_ABI_EVTTYPE_DIS_STATS_DONE] = IPU3_CSS_QUEUE_STAT_DVS,
> +		[IMGU_ABI_EVTTYPE_LACE_STATS_DONE] = IPU3_CSS_QUEUE_STAT_LACE,
> +	};
> +	struct ipu3_css_buffer *b = ERR_PTR(-EAGAIN);
> +	u32 event, daddr;
> +	int evtype, pipe, pipeid, queue, qid, r;
> +
> +	if (!css->streaming)
> +		return ERR_PTR(-EPROTO);
> +
> +	r = ipu3_css_dequeue_data(css, IMGU_ABI_QUEUE_EVENT_ID, &event);
> +	if (r < 0)
> +		return ERR_PTR(r);
> +
> +	evtype = (event & IMGU_ABI_EVTTYPE_EVENT_MASK) >>
> +	    IMGU_ABI_EVTTYPE_EVENT_SHIFT;
> +
> +	switch (evtype) {
> +	case IMGU_ABI_EVTTYPE_OUT_FRAME_DONE:
> +	case IMGU_ABI_EVTTYPE_VF_OUT_FRAME_DONE:
> +	case IMGU_ABI_EVTTYPE_3A_STATS_DONE:
> +	case IMGU_ABI_EVTTYPE_DIS_STATS_DONE:
> +	case IMGU_ABI_EVTTYPE_INPUT_FRAME_DONE:
> +	case IMGU_ABI_EVTTYPE_LACE_STATS_DONE:
> +		pipe = (event & IMGU_ABI_EVTTYPE_PIPE_MASK) >>
> +		    IMGU_ABI_EVTTYPE_PIPE_SHIFT;
> +		pipeid = (event & IMGU_ABI_EVTTYPE_PIPEID_MASK) >>
> +		    IMGU_ABI_EVTTYPE_PIPEID_SHIFT;
> +		queue = evtype_to_queue[evtype];
> +		qid = ipu3_css_queues[queue].qid;
> +
> +		if (qid >= IMGU_ABI_QUEUE_NUM) {
> +			dev_err(css->dev, "Invalid qid: %i\n", qid);
> +			return ERR_PTR(-EIO);
> +		}
> +
> +		dev_dbg(css->dev,
> +			"event: buffer done 0x%x queue %i pipe %i pipeid %i\n",
> +			event, queue, pipe, pipeid);
> +
> +		r = ipu3_css_dequeue_data(css, qid, &daddr);
> +		if (r < 0) {
> +			dev_err(css->dev, "failed to dequeue buffer\n");
> +			/* Force real error, not -EBUSY */
> +			return ERR_PTR(-EIO);
> +		}
> +
> +		r = ipu3_css_queue_data(css, IMGU_ABI_QUEUE_EVENT_ID, thread,
> +					IMGU_ABI_EVENT_BUFFER_DEQUEUED(qid));
> +		if (r < 0) {
> +			dev_err(css->dev, "failed to queue event\n");
> +			return ERR_PTR(-EIO);
> +		}
> +
> +		if (list_empty(&css->queue[queue].bufs)) {
> +			dev_err(css->dev, "event on empty queue\n");
> +			return ERR_PTR(-EIO);
> +		}
> +		b = list_first_entry(&css->queue[queue].bufs,
> +				     struct ipu3_css_buffer, list);
> +		if (queue != b->queue ||
> +		    daddr != css->abi_buffers[b->queue][b->queue_pos].daddr) {
> +			dev_err(css->dev, "dequeued bad buffer 0x%x\n", daddr);
> +			return ERR_PTR(-EIO);
> +		}
> +		b->state = IPU3_CSS_BUFFER_DONE;
> +		list_del(&b->list);
> +		break;
> +	case IMGU_ABI_EVTTYPE_PIPELINE_DONE:
> +		dev_dbg(css->dev, "event: pipeline done 0x%x for frame %ld\n",
> +			event, css->frame);
> +
> +		if (css->frame == LONG_MAX)
> +			css->frame = 0;
> +		else
> +			css->frame++;
> +		break;
> +	case IMGU_ABI_EVTTYPE_TIMER:
> +		r = ipu3_css_dequeue_data(css, IMGU_ABI_QUEUE_EVENT_ID, &event);
> +		if (r < 0)
> +			return ERR_PTR(r);
> +
> +		if ((event & IMGU_ABI_EVTTYPE_EVENT_MASK) >>
> +		    IMGU_ABI_EVTTYPE_EVENT_SHIFT == IMGU_ABI_EVTTYPE_TIMER)
> +			dev_dbg(css->dev, "event: timer\n");
> +		else
> +			dev_warn(css->dev, "half of timer event missing\n");
> +		break;
> +	case IMGU_ABI_EVTTYPE_FW_WARNING:
> +		dev_warn(css->dev, "event: firmware warning 0x%x\n", event);
> +		break;
> +	case IMGU_ABI_EVTTYPE_FW_ASSERT:
> +		dev_err(css->dev,
> +			"event: firmware assert 0x%x module_id %i line_no %i\n",
> +			event,
> +			(event & IMGU_ABI_EVTTYPE_MODULEID_MASK) >>
> +			IMGU_ABI_EVTTYPE_MODULEID_SHIFT,
> +			swab16((event & IMGU_ABI_EVTTYPE_LINENO_MASK) >>
> +			       IMGU_ABI_EVTTYPE_LINENO_SHIFT));
> +		break;
> +	default:
> +		dev_warn(css->dev, "received unknown event 0x%x\n", event);
> +	}
> +
> +	return b;
> +}
> +
> +/*
> + * Get a new set of parameters from pool and initialize them based on
> + * the parameters params, gdc, and obgrid. Any of these may be NULL,
> + * in which case the previously set parameters are used.
> + * If parameters haven't been set previously, initialize from scratch.
> + *
> + * Return index to css->parameter_set_info which has the newly created
> + * parameters or negative value on error.
> + */
> +int ipu3_css_set_parameters(struct ipu3_css *css,
> +			    struct ipu3_uapi_params *set_params,
> +			    struct ipu3_uapi_gdc_warp_param *set_gdc,
> +			    unsigned int gdc_bytes,
> +			    struct ipu3_uapi_obgrid_param *set_obgrid,
> +			    unsigned int obgrid_bytes)
> +{
> +	static const unsigned int queue_id = IMGU_ABI_QUEUE_A_ID;
> +	const int stage = 0, thread = 0;
> +	const struct imgu_fw_info *bi;
> +	int obgrid_size;
> +	unsigned int stripes;
> +	struct ipu3_uapi_flags *use = set_params ? &set_params->use : NULL;
> +
> +	/* Destination buffers which are filled here */
> +	struct imgu_abi_parameter_set_info *param_set;
> +	struct ipu3_uapi_acc_param *acc = NULL;
> +	struct ipu3_uapi_gdc_warp_param *gdc = NULL;
> +	struct ipu3_uapi_obgrid_param *obgrid = NULL;
> +	const struct ipu3_css_map *map;
> +	void *vmem0 = NULL;
> +	void *dmem0 = NULL;
> +
> +	enum imgu_abi_memories m;
> +	int r = -EBUSY;
> +	int s;
> +
> +	if (!css->streaming)
> +		return -EPROTO;
> +
> +	bi = &css->fwp->binary_header[css->current_binary];
> +	obgrid_size = ipu3_css_fw_obgrid_size(bi);
> +	stripes = bi->info.isp.sp.iterator.num_stripes ? : 1;
> +
> +	/*
> +	 * Check that we can get a new parameter_set_info from the pool.
> +	 * If this succeeds, then all of the other pool_get() calls below
> +	 * should also succeed.
> +	 */
> +	if (ipu3_css_pool_get(&css->pool.parameter_set_info, css->frame) < 0)
> +		goto fail_no_put;

The size of the pool is always four. If there were four parameter buffers
queued, this would fails, wouldn't it? And that would lead to a failure in
queueing the buffer, too, right?

How about associating a kernel-only buffer with each parameter buffer?

> +	param_set = ipu3_css_pool_last(&css->pool.parameter_set_info, 0)->vaddr;
> +
> +	/* Get a new acc only if new parameters given, or none yet */
> +	if (set_params || !ipu3_css_pool_last(&css->pool.acc, 0)->vaddr) {
> +		if (ipu3_css_pool_get(&css->pool.acc, css->frame) < 0)
> +			goto fail;
> +		acc = ipu3_css_pool_last(&css->pool.acc, 0)->vaddr;
> +	}
> +
> +	/* Get new VMEM0 only if needed, or none yet */
> +	m = IMGU_ABI_MEM_ISP_VMEM0;
> +	if (!ipu3_css_pool_last(&css->pool.binary_params_p[m], 0)->vaddr ||
> +	    (set_params && (set_params->use.lin_vmem_params ||
> +			    set_params->use.tnr3_vmem_params ||
> +			    set_params->use.xnr3_vmem_params))) {
> +		if (ipu3_css_pool_get(&css->pool.binary_params_p[m],
> +				      css->frame) < 0)
> +			goto fail;
> +		vmem0 = ipu3_css_pool_last(&css->pool.binary_params_p[m], 0)
> +		    ->vaddr;
> +	}
> +
> +	/* Get new DMEM0 only if needed, or none yet */
> +	m = IMGU_ABI_MEM_ISP_DMEM0;
> +	if (!ipu3_css_pool_last(&css->pool.binary_params_p[m], 0)->vaddr ||
> +	    (set_params && (set_params->use.tnr3_dmem_params ||
> +			    set_params->use.xnr3_dmem_params))) {
> +		if (ipu3_css_pool_get(&css->pool.binary_params_p[m],
> +				      css->frame) < 0)
> +			goto fail;
> +		dmem0 = ipu3_css_pool_last(&css->pool.binary_params_p[m], 0)
> +		    ->vaddr;
> +	}
> +
> +	/* Configure acc parameter cluster */
> +	if (acc) {
> +		map = ipu3_css_pool_last(&css->pool.acc, 1);
> +		r = ipu3_css_cfg_acc(css, use, acc, map->vaddr, set_params ?
> +				     &set_params->acc_param : NULL);
> +		if (r < 0)
> +			goto fail;
> +	}
> +
> +	/* Configure late binding parameters */
> +	if (vmem0) {
> +		m = IMGU_ABI_MEM_ISP_VMEM0;
> +		map = ipu3_css_pool_last(&css->pool.binary_params_p[m], 1);
> +		r = ipu3_css_cfg_vmem0(css, use, vmem0, map->vaddr, set_params);
> +		if (r < 0)
> +			goto fail;
> +	}
> +
> +	if (dmem0) {
> +		m = IMGU_ABI_MEM_ISP_DMEM0;
> +		map = ipu3_css_pool_last(&css->pool.binary_params_p[m], 1);
> +		r = ipu3_css_cfg_dmem0(css, use, dmem0, map->vaddr, set_params);
> +		if (r < 0)
> +			goto fail;
> +	}
> +
> +	/* Get a new gdc only if a new gdc is given, or none yet */
> +	if (bi->info.isp.sp.enable.dvs_6axis) {
> +		unsigned int a = IPU3_CSS_AUX_FRAME_REF;
> +		unsigned int g = IPU3_CSS_RECT_GDC;
> +
> +		map = ipu3_css_pool_last(&css->pool.gdc, 0);
> +
> +		if (set_params && !set_params->use.gdc)
> +			set_gdc = NULL;
> +		if (set_gdc || !map->vaddr) {
> +			if (ipu3_css_pool_get(&css->pool.gdc, css->frame) < 0)
> +
> +				goto fail;
> +			map = ipu3_css_pool_last(&css->pool.gdc, 0);
> +			gdc =  map->vaddr;
> +			ipu3_css_cfg_gdc_table(gdc,
> +					       css->aux_frames[a].bytesperline /
> +					       css->aux_frames[a].bytesperpixel,
> +					       css->aux_frames[a].height,
> +					       css->rect[g].width,
> +					       css->rect[g].height);
> +		}
> +	}
> +
> +	/* Get a new obgrid only if a new obgrid is given, or none yet */
> +	if (set_params && !set_params->use.obgrid)
> +		set_obgrid = NULL;
> +	if (set_obgrid && obgrid_bytes < obgrid_size / stripes)
> +		goto fail;
> +	if (set_obgrid || (set_params && set_params->use.obgrid_param) ||
> +	    !ipu3_css_pool_last(&css->pool.obgrid, 0)->vaddr) {
> +		if (ipu3_css_pool_get(&css->pool.obgrid, css->frame) < 0)
> +			goto fail;
> +		map = ipu3_css_pool_last(&css->pool.obgrid, 0);
> +		obgrid = map->vaddr;
> +
> +		/* Configure optical black level grid (obgrid) */
> +		if (set_obgrid) {
> +			for (s = 0; s < stripes; s++)
> +				memcpy((void *)obgrid +
> +					(obgrid_size / stripes) * s, set_obgrid,
> +					obgrid_size / stripes);
> +
> +		} else if (set_params && set_params->use.obgrid_param) {
> +			for (s = 0; s < obgrid_size / sizeof(*obgrid); s++)
> +				obgrid[s] = set_params->obgrid_param;
> +		} else {
> +			memset(obgrid, 0, obgrid_size);
> +		}
> +	}
> +
> +	/* Configure parameter set info, queued to `queue_id' */
> +
> +	memset(param_set, 0, sizeof(*param_set));
> +
> +	param_set->mem_map.acc_cluster_params_for_sp =
> +	    ipu3_css_pool_last(&css->pool.acc, 0)->daddr;
> +
> +	param_set->mem_map.dvs_6axis_params_y =
> +	    ipu3_css_pool_last(&css->pool.gdc, 0)->daddr;
> +
> +	for (s = 0; s < stripes; s++)
> +		param_set->mem_map.obgrid_tbl[s] =
> +		    ipu3_css_pool_last(&css->pool.obgrid, 0)->daddr +
> +		    (obgrid_size / stripes) * s;
> +
> +	for (m = 0; m < IMGU_ABI_NUM_MEMORIES; m++)
> +		param_set->mem_map.isp_mem_param[stage][m] =
> +		    ipu3_css_pool_last(&css->pool.binary_params_p[m], 0)
> +		    ->daddr;
> +
> +	/* Then queue the new parameter buffer */
> +	map = ipu3_css_pool_last(&css->pool.parameter_set_info, 0);
> +	r = ipu3_css_queue_data(css, queue_id, thread, map->daddr);
> +	if (r < 0)
> +		goto fail;
> +
> +	r = ipu3_css_queue_data(css, IMGU_ABI_QUEUE_EVENT_ID, 0,
> +				IMGU_ABI_EVENT_BUFFER_ENQUEUED(thread,
> +							       queue_id));
> +	if (r < 0)
> +		goto fail_no_put;
> +
> +	/* Finally dequeue all old parameter buffers */
> +
> +	do {
> +		u32 daddr;
> +
> +		r = ipu3_css_dequeue_data(css, queue_id, &daddr);
> +		if (r == -EBUSY)
> +			break;
> +		if (r)
> +			goto fail_no_put;
> +		r = ipu3_css_queue_data(css, IMGU_ABI_QUEUE_EVENT_ID, thread,
> +					IMGU_ABI_EVENT_BUFFER_DEQUEUED
> +					(queue_id));
> +		if (r < 0) {
> +			dev_err(css->dev, "failed to queue parameter event\n");
> +			goto fail_no_put;
> +		}
> +	} while (1);
> +
> +	return 0;
> +
> +fail:
> +	/*
> +	 * A failure, most likely the parameter queue was full.
> +	 * Return error but continue streaming. User can try submitting new
> +	 * parameters again later.
> +	 */
> +
> +	ipu3_css_pool_put(&css->pool.parameter_set_info);
> +	if (acc)
> +		ipu3_css_pool_put(&css->pool.acc);
> +	if (gdc)
> +		ipu3_css_pool_put(&css->pool.gdc);
> +	if (obgrid)
> +		ipu3_css_pool_put(&css->pool.obgrid);
> +	if (vmem0)
> +		ipu3_css_pool_put(
> +			&css->pool.binary_params_p[IMGU_ABI_MEM_ISP_VMEM0]);
> +	if (dmem0)
> +		ipu3_css_pool_put(
> +			&css->pool.binary_params_p[IMGU_ABI_MEM_ISP_DMEM0]);
> +
> +fail_no_put:
> +	return r;
> +}
>  
>  void ipu3_css_irq_ack(struct ipu3_css *css)
>  {
> @@ -501,7 +2260,7 @@ void ipu3_css_irq_ack(struct ipu3_css *css)
>  					bi->info.sp.output + 4 + 4 * i);
>  
>  			dev_dbg(css->dev, "%s: swirq %i cnt %i val 0x%x\n",
> -				 __func__, i, cnt, val);
> +				__func__, i, cnt, val);
>  		}
>  	}
>  
> diff --git a/drivers/media/pci/intel/ipu3/ipu3-css.h b/drivers/media/pci/intel/ipu3/ipu3-css.h
> index 5b8e92d47f5d..43627df9910d 100644
> --- a/drivers/media/pci/intel/ipu3/ipu3-css.h
> +++ b/drivers/media/pci/intel/ipu3/ipu3-css.h
> @@ -16,6 +16,8 @@
>  
>  #include <linux/videodev2.h>
>  #include <linux/types.h>
> +#include <media/v4l2-ctrls.h>
> +#include <media/videobuf2-core.h>
>  #include "ipu3-abi.h"
>  #include "ipu3-css-pool.h"
>  
> @@ -39,6 +41,12 @@
>  #define IPU3_CSS_QUEUE_STAT_LACE	6
>  #define IPU3_CSS_QUEUES			7
>  
> +#define IPU3_CSS_RECT_EFFECTIVE		0       /* Effective resolution */
> +#define IPU3_CSS_RECT_BDS		1       /* Resolution after BDS */
> +#define IPU3_CSS_RECT_ENVELOPE		2       /* DVS envelope size */
> +#define IPU3_CSS_RECT_GDC		3       /* gdc output res */
> +#define IPU3_CSS_RECTS			4       /* number of rects */
> +
>  #define IA_CSS_BINARY_MODE_PRIMARY	2
>  #define IA_CSS_BINARY_MODE_VIDEO	3
>  
> @@ -56,6 +64,33 @@ enum ipu3_css_pipe_id {
>  	IPU3_CSS_PIPE_ID_NUM
>  };
>  
> +struct ipu3_css_resolution {
> +	u32 w;
> +	u32 h;
> +};
> +
> +enum ipu3_css_vf_status {
> +	IPU3_NODE_VF_ENABLED,
> +	IPU3_NODE_PV_ENABLED,
> +	IPU3_NODE_VF_DISABLED
> +};
> +
> +enum ipu3_css_buffer_state {
> +	IPU3_CSS_BUFFER_NEW,	/* Not yet queued */
> +	IPU3_CSS_BUFFER_QUEUED,	/* Queued, waiting to be filled */
> +	IPU3_CSS_BUFFER_DONE,	/* Finished processing, removed from queue */
> +	IPU3_CSS_BUFFER_FAILED,	/* Was not processed, removed from queue */
> +};
> +
> +struct ipu3_css_buffer {
> +	/* Private fields: user doesn't touch */
> +	dma_addr_t daddr;
> +	unsigned int queue;
> +	enum ipu3_css_buffer_state state;
> +	struct list_head list;
> +	u8 queue_pos;
> +};
> +
>  struct ipu3_css_format {
>  	u32 pixelformat;
>  	enum v4l2_colorspace colorspace;
> @@ -126,11 +161,65 @@ struct ipu3_css {
>  
>  	struct ipu3_css_queue queue[IPU3_CSS_QUEUES];
>  	struct v4l2_rect rect[IPU3_CSS_RECTS];
> +	struct ipu3_css_map abi_buffers[IPU3_CSS_QUEUES]
> +				    [IMGU_ABI_HOST2SP_BUFQ_SIZE];
> +
> +	struct {
> +		struct ipu3_css_pool parameter_set_info;
> +		struct ipu3_css_pool acc;
> +		struct ipu3_css_pool gdc;
> +		struct ipu3_css_pool obgrid;
> +		/* PARAM_CLASS_PARAM parameters for binding while streaming */
> +		struct ipu3_css_pool binary_params_p[IMGU_ABI_NUM_MEMORIES];
> +	} pool;
> +
> +	enum ipu3_css_vf_status vf_output_en;
>  };
>  
> +/******************* css v4l *******************/
> +int ipu3_css_init(struct device *dev, struct ipu3_css *css,
> +		  void __iomem *base, int length);
> +void ipu3_css_cleanup(struct ipu3_css *css);
> +int ipu3_css_fmt_try(struct ipu3_css *css,
> +		     struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES],
> +		     struct v4l2_rect *rects[IPU3_CSS_RECTS]);
> +int ipu3_css_fmt_set(struct ipu3_css *css,
> +		     struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES],
> +		     struct v4l2_rect *rects[IPU3_CSS_RECTS]);
> +int ipu3_css_meta_fmt_set(struct v4l2_meta_format *fmt);
> +int ipu3_css_buf_queue(struct ipu3_css *css, struct ipu3_css_buffer *b);
> +struct ipu3_css_buffer *ipu3_css_buf_dequeue(struct ipu3_css *css);
> +int ipu3_css_start_streaming(struct ipu3_css *css);
> +void ipu3_css_stop_streaming(struct ipu3_css *css);
> +bool ipu3_css_queue_empty(struct ipu3_css *css);
> +bool ipu3_css_is_streaming(struct ipu3_css *css);
> +
>  /******************* css hw *******************/
>  int ipu3_css_set_powerup(struct device *dev, void __iomem *base);
>  int ipu3_css_set_powerdown(struct device *dev, void __iomem *base);
>  void ipu3_css_irq_ack(struct ipu3_css *css);
>  
> +/******************* set parameters ************/
> +int ipu3_css_set_parameters(struct ipu3_css *css,
> +		struct ipu3_uapi_params *set_params,
> +		struct ipu3_uapi_gdc_warp_param *set_gdc,
> +		unsigned int gdc_bytes,
> +		struct ipu3_uapi_obgrid_param *set_obgrid,
> +		unsigned int obgrid_bytes);
> +
> +/******************* css misc *******************/
> +static inline enum ipu3_css_buffer_state
> +ipu3_css_buf_state(struct ipu3_css_buffer *b)
> +{
> +	return b->state;
> +}
> +
> +/* Initialize given buffer. May be called several times. */
> +static inline void ipu3_css_buf_init(struct ipu3_css_buffer *b,
> +				     unsigned int queue, dma_addr_t daddr)
> +{
> +	b->state = IPU3_CSS_BUFFER_NEW;
> +	b->queue = queue;
> +	b->daddr = daddr;
> +}
>  #endif

-- 
Kind regards,

Sakari Ailus
e-mail: sakari.ailus@iki.fi

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v4 11/12] intel-ipu3: Add imgu v4l2 driver
  2017-10-23 22:41     ` Zhi, Yong
@ 2017-11-02  8:43       ` Sakari Ailus
  0 siblings, 0 replies; 19+ messages in thread
From: Sakari Ailus @ 2017-11-02  8:43 UTC (permalink / raw)
  To: Zhi, Yong
  Cc: linux-media, sakari.ailus, Zheng, Jian Xu, Mani, Rajmohan,
	Toivonen, Tuukka, Hu, Jerry W, Vijaykumar, Ramya

Hi Yong,

On Mon, Oct 23, 2017 at 10:41:57PM +0000, Zhi, Yong wrote:
> > > +	default:
> > > +		return -EINVAL;
> > > +	}
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int ipu3_try_fmt(struct file *file, void *fh, struct
> > > +v4l2_format *f) {
> > > +	struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
> > > +	const struct ipu3_fmt *fmt;
> > > +
> > > +	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
> > > +		fmt = find_format(f, M2M_CAPTURE);
> > > +	else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
> > > +		fmt = find_format(f, M2M_OUTPUT);
> > > +	else
> > > +		return -EINVAL;
> > > +
> > > +	pixm->pixelformat = fmt->fourcc;
> > > +
> > > +	memset(pixm->plane_fmt[0].reserved, 0,
> > > +	       sizeof(pixm->plane_fmt[0].reserved));
> > 
> > No need for the memset here, the framework handles this.
> > 
> > Are there limits on the image size?
> > 
> 
> The memset is added to fix v4l2-compliance failure here.

Oops. Indeed, this is about the plane format. Please ignore the comment.

-- 
Sakari Ailus
e-mail: sakari.ailus@iki.fi

^ permalink raw reply	[flat|nested] 19+ messages in thread

* RE: [PATCH v4 10/12] intel-ipu3: css pipeline
  2017-11-01 18:57   ` Sakari Ailus
@ 2017-11-10 22:35     ` Zhi, Yong
  2017-11-13 13:26       ` Sakari Ailus
  0 siblings, 1 reply; 19+ messages in thread
From: Zhi, Yong @ 2017-11-10 22:35 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, sakari.ailus, Zheng, Jian Xu, Mani, Rajmohan,
	Toivonen, Tuukka, Hu, Jerry W

Hi, Sakari,

Thanks for the review.

> -----Original Message-----
> From: linux-media-owner@vger.kernel.org [mailto:linux-media-
> owner@vger.kernel.org] On Behalf Of Sakari Ailus
> Sent: Wednesday, November 1, 2017 11:57 AM
> To: Zhi, Yong <yong.zhi@intel.com>
> Cc: linux-media@vger.kernel.org; sakari.ailus@linux.intel.com; Zheng, Jian
> Xu <jian.xu.zheng@intel.com>; Mani, Rajmohan
> <rajmohan.mani@intel.com>; Toivonen, Tuukka
> <tuukka.toivonen@intel.com>; Hu, Jerry W <jerry.w.hu@intel.com>
> Subject: Re: [PATCH v4 10/12] intel-ipu3: css pipeline
> 
> Hi Yong,
> 
> Apologies for the late reply. Please find my (few) comments below.
> 
> On Tue, Oct 17, 2017 at 10:54:55PM -0500, Yong Zhi wrote:
> > Add css pipeline and v4l code.
> >
> > Signed-off-by: Yong Zhi <yong.zhi@intel.com>
> > ---
> >  drivers/media/pci/intel/ipu3/ipu3-css.c | 1761
> ++++++++++++++++++++++++++++++-
> >  drivers/media/pci/intel/ipu3/ipu3-css.h |   89 ++
> >  2 files changed, 1849 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/media/pci/intel/ipu3/ipu3-css.c
> b/drivers/media/pci/intel/ipu3/ipu3-css.c
> > index 6e615bf9378a..11f7ad3514c3 100644
> > --- a/drivers/media/pci/intel/ipu3/ipu3-css.c
> > +++ b/drivers/media/pci/intel/ipu3/ipu3-css.c
> > @@ -13,9 +13,16 @@

(snip)

> > +static bool ipu3_css_queue_enabled(struct ipu3_css_queue *q)
> > +{
> > +	return !!q->css_fmt;
> 
> No need for !!.
> 

The original code "return q->css_fmt !=NULL;" is more explicit, I changed to the current form to silent checkpatch.pl CHECK for null comparison.

> > +}
> > +
> >  /******************* css hw *******************/
> >

(snip)

> > +	/* Configure SP group */
> > +
> > +	sp_group = css->xmem_sp_group_ptrs.vaddr;
> > +	memset(sp_group, 0, sizeof(*sp_group));
> > +
> > +	sp_group->pipe[thread].num_stages = 1;
> > +	sp_group->pipe[thread].pipe_id = PIPE_ID;
> > +	sp_group->pipe[thread].thread_id = thread;
> > +	sp_group->pipe[thread].pipe_num = pipe;
> > +	sp_group->pipe[thread].num_execs = -1;
> > +	sp_group->pipe[thread].pipe_qos_config = -1;
> > +	sp_group->pipe[thread].required_bds_factor = 0;
> > +	sp_group->pipe[thread].dvs_frame_delay = IPU3_CSS_AUX_FRAMES
> - 1;
> > +	sp_group->pipe[thread].inout_port_config =
> > +	    IMGU_ABI_PORT_CONFIG_TYPE_INPUT_HOST |
> > +	    IMGU_ABI_PORT_CONFIG_TYPE_OUTPUT_HOST;
> 
> Indentation. Most of this seems to have been fixed but some remains in this
> patch at least. Could you address that for the next version, please?

Yes, will fix all indentation in next version.

> 
> > +	sp_group->pipe[thread].scaler_pp_lut = 0;
> > +	sp_group-
> >pipe[thread].shading.internal_frame_origin_x_bqs_on_sctbl = 0;
> > +	sp_group-
> >pipe[thread].shading.internal_frame_origin_y_bqs_on_sctbl = 0;
> > +	sp_group->pipe[thread].sp_stage_addr[stage] =
> > +	    css->xmem_sp_stage_ptrs[pipe][stage].daddr;
> > +	sp_group->pipe[thread].pipe_config =
> > +	    bi->info.isp.sp.enable.params ? (1 << thread) : 0;

(snip)

> > +int ipu3_css_set_parameters(struct ipu3_css *css,
> > +			    struct ipu3_uapi_params *set_params,
> > +			    struct ipu3_uapi_gdc_warp_param *set_gdc,
> > +			    unsigned int gdc_bytes,
> > +			    struct ipu3_uapi_obgrid_param *set_obgrid,
> > +			    unsigned int obgrid_bytes)
> > +{
> > +	static const unsigned int queue_id = IMGU_ABI_QUEUE_A_ID;
> > +	const int stage = 0, thread = 0;
> > +	const struct imgu_fw_info *bi;
> > +	int obgrid_size;
> > +	unsigned int stripes;
> > +	struct ipu3_uapi_flags *use = set_params ? &set_params->use : NULL;
> > +
> > +	/* Destination buffers which are filled here */
> > +	struct imgu_abi_parameter_set_info *param_set;
> > +	struct ipu3_uapi_acc_param *acc = NULL;
> > +	struct ipu3_uapi_gdc_warp_param *gdc = NULL;
> > +	struct ipu3_uapi_obgrid_param *obgrid = NULL;
> > +	const struct ipu3_css_map *map;
> > +	void *vmem0 = NULL;
> > +	void *dmem0 = NULL;
> > +
> > +	enum imgu_abi_memories m;
> > +	int r = -EBUSY;
> > +	int s;
> > +
> > +	if (!css->streaming)
> > +		return -EPROTO;
> > +
> > +	bi = &css->fwp->binary_header[css->current_binary];
> > +	obgrid_size = ipu3_css_fw_obgrid_size(bi);
> > +	stripes = bi->info.isp.sp.iterator.num_stripes ? : 1;
> > +
> > +	/*
> > +	 * Check that we can get a new parameter_set_info from the pool.
> > +	 * If this succeeds, then all of the other pool_get() calls below
> > +	 * should also succeed.
> > +	 */
> > +	if (ipu3_css_pool_get(&css->pool.parameter_set_info, css->frame) <
> 0)
> > +		goto fail_no_put;
> 
> The size of the pool is always four. If there were four parameter buffers
> queued, this would fails, wouldn't it? And that would lead to a failure in
> queueing the buffer, too, right?
> 
> How about associating a kernel-only buffer with each parameter buffer?
> 

I learned from the engineer who knows the use pattern of above API between user space and kernel, that the size of the pool is rather safe, 
Queuing parameter failure should not happen under normal condition. 

> > +	param_set = ipu3_css_pool_last(&css->pool.parameter_set_info, 0)-
> >vaddr;
> > +
> > +	/* Get a new acc only if new parameters given, or none yet */
> > +	if (set_params || !ipu3_css_pool_last(&css->pool.acc, 0)->vaddr) {
> > +		if (ipu3_css_pool_get(&css->pool.acc, css->frame) < 0)
> > +			goto fail;
> > +		acc = ipu3_css_pool_last(&css->pool.acc, 0)->vaddr;
> > +	}
> > +
> > +	/* Get new VMEM0 only if needed, or none yet */
> > +	m = IMGU_ABI_MEM_ISP_VMEM0;
> > +	if (!ipu3_css_pool_last(&css->pool.binary_params_p[m], 0)->vaddr
> ||
> > +	    (set_params && (set_params->use.lin_vmem_params ||
> > +			    set_params->use.tnr3_vmem_params ||
> > +			    set_params->use.xnr3_vmem_params))) {
> > +		if (ipu3_css_pool_get(&css->pool.binary_params_p[m],
> > +				      css->frame) < 0)
> > +			goto fail;
> > +		vmem0 = ipu3_css_pool_last(&css-
> >pool.binary_params_p[m], 0)
> > +		    ->vaddr;
> > +	}
> > +
> > +	/* Get new DMEM0 only if needed, or none yet */
> > +	m = IMGU_ABI_MEM_ISP_DMEM0;
> > +	if (!ipu3_css_pool_last(&css->pool.binary_params_p[m], 0)->vaddr
> ||
> > +	    (set_params && (set_params->use.tnr3_dmem_params ||
> > +			    set_params->use.xnr3_dmem_params))) {
> > +		if (ipu3_css_pool_get(&css->pool.binary_params_p[m],
> > +				      css->frame) < 0)
> > +			goto fail;
> > +		dmem0 = ipu3_css_pool_last(&css-
> >pool.binary_params_p[m], 0)
> > +		    ->vaddr;
> > +	}
> > +
> > +	/* Configure acc parameter cluster */
> > +	if (acc) {
> > +		map = ipu3_css_pool_last(&css->pool.acc, 1);
> > +		r = ipu3_css_cfg_acc(css, use, acc, map->vaddr, set_params ?
> > +				     &set_params->acc_param : NULL);
> > +		if (r < 0)
> > +			goto fail;
> > +	}
> > +
> > +	/* Configure late binding parameters */
> > +	if (vmem0) {
> > +		m = IMGU_ABI_MEM_ISP_VMEM0;
> > +		map = ipu3_css_pool_last(&css->pool.binary_params_p[m],
> 1);
> > +		r = ipu3_css_cfg_vmem0(css, use, vmem0, map->vaddr,
> set_params);
> > +		if (r < 0)
> > +			goto fail;
> > +	}
> > +
> > +	if (dmem0) {
> > +		m = IMGU_ABI_MEM_ISP_DMEM0;
> > +		map = ipu3_css_pool_last(&css->pool.binary_params_p[m],
> 1);
> > +		r = ipu3_css_cfg_dmem0(css, use, dmem0, map->vaddr,
> set_params);
> > +		if (r < 0)
> > +			goto fail;
> > +	}
> > +
> > +	/* Get a new gdc only if a new gdc is given, or none yet */
> > +	if (bi->info.isp.sp.enable.dvs_6axis) {
> > +		unsigned int a = IPU3_CSS_AUX_FRAME_REF;
> > +		unsigned int g = IPU3_CSS_RECT_GDC;
> > +
> > +		map = ipu3_css_pool_last(&css->pool.gdc, 0);
> > +
> > +		if (set_params && !set_params->use.gdc)
> > +			set_gdc = NULL;
> > +		if (set_gdc || !map->vaddr) {
> > +			if (ipu3_css_pool_get(&css->pool.gdc, css->frame) < 0)
> > +
> > +				goto fail;
> > +			map = ipu3_css_pool_last(&css->pool.gdc, 0);
> > +			gdc =  map->vaddr;
> > +			ipu3_css_cfg_gdc_table(gdc,
> > +					       css->aux_frames[a].bytesperline
> /
> > +					       css->aux_frames[a].bytesperpixel,
> > +					       css->aux_frames[a].height,
> > +					       css->rect[g].width,
> > +					       css->rect[g].height);
> > +		}
> > +	}
> > +
> > +	/* Get a new obgrid only if a new obgrid is given, or none yet */
> > +	if (set_params && !set_params->use.obgrid)
> > +		set_obgrid = NULL;
> > +	if (set_obgrid && obgrid_bytes < obgrid_size / stripes)
> > +		goto fail;
> > +	if (set_obgrid || (set_params && set_params->use.obgrid_param) ||
> > +	    !ipu3_css_pool_last(&css->pool.obgrid, 0)->vaddr) {
> > +		if (ipu3_css_pool_get(&css->pool.obgrid, css->frame) < 0)
> > +			goto fail;
> > +		map = ipu3_css_pool_last(&css->pool.obgrid, 0);
> > +		obgrid = map->vaddr;
> > +
> > +		/* Configure optical black level grid (obgrid) */
> > +		if (set_obgrid) {
> > +			for (s = 0; s < stripes; s++)
> > +				memcpy((void *)obgrid +
> > +					(obgrid_size / stripes) * s, set_obgrid,
> > +					obgrid_size / stripes);
> > +
> > +		} else if (set_params && set_params->use.obgrid_param) {
> > +			for (s = 0; s < obgrid_size / sizeof(*obgrid); s++)
> > +				obgrid[s] = set_params->obgrid_param;
> > +		} else {
> > +			memset(obgrid, 0, obgrid_size);
> > +		}
> > +	}
> > +
> > +	/* Configure parameter set info, queued to `queue_id' */
> > +
> > +	memset(param_set, 0, sizeof(*param_set));
> > +
> > +	param_set->mem_map.acc_cluster_params_for_sp =
> > +	    ipu3_css_pool_last(&css->pool.acc, 0)->daddr;
> > +
> > +	param_set->mem_map.dvs_6axis_params_y =
> > +	    ipu3_css_pool_last(&css->pool.gdc, 0)->daddr;
> > +
> > +	for (s = 0; s < stripes; s++)
> > +		param_set->mem_map.obgrid_tbl[s] =
> > +		    ipu3_css_pool_last(&css->pool.obgrid, 0)->daddr +
> > +		    (obgrid_size / stripes) * s;
> > +
> > +	for (m = 0; m < IMGU_ABI_NUM_MEMORIES; m++)
> > +		param_set->mem_map.isp_mem_param[stage][m] =
> > +		    ipu3_css_pool_last(&css->pool.binary_params_p[m], 0)
> > +		    ->daddr;
> > +
> > +	/* Then queue the new parameter buffer */
> > +	map = ipu3_css_pool_last(&css->pool.parameter_set_info, 0);
> > +	r = ipu3_css_queue_data(css, queue_id, thread, map->daddr);
> > +	if (r < 0)
> > +		goto fail;
> > +
> > +	r = ipu3_css_queue_data(css, IMGU_ABI_QUEUE_EVENT_ID, 0,
> > +
> 	IMGU_ABI_EVENT_BUFFER_ENQUEUED(thread,
> > +							       queue_id));
> > +	if (r < 0)
> > +		goto fail_no_put;
> > +
> > +	/* Finally dequeue all old parameter buffers */
> > +
> > +	do {
> > +		u32 daddr;
> > +
> > +		r = ipu3_css_dequeue_data(css, queue_id, &daddr);
> > +		if (r == -EBUSY)
> > +			break;
> > +		if (r)
> > +			goto fail_no_put;
> > +		r = ipu3_css_queue_data(css, IMGU_ABI_QUEUE_EVENT_ID,
> thread,
> > +
> 	IMGU_ABI_EVENT_BUFFER_DEQUEUED
> > +					(queue_id));
> > +		if (r < 0) {
> > +			dev_err(css->dev, "failed to queue parameter
> event\n");
> > +			goto fail_no_put;
> > +		}
> > +	} while (1);
> > +
> > +	return 0;
> > +
> > +fail:
> > +	/*
> > +	 * A failure, most likely the parameter queue was full.
> > +	 * Return error but continue streaming. User can try submitting new
> > +	 * parameters again later.
> > +	 */
> > +
> > +	ipu3_css_pool_put(&css->pool.parameter_set_info);
> > +	if (acc)
> > +		ipu3_css_pool_put(&css->pool.acc);
> > +	if (gdc)
> > +		ipu3_css_pool_put(&css->pool.gdc);
> > +	if (obgrid)
> > +		ipu3_css_pool_put(&css->pool.obgrid);
> > +	if (vmem0)
> > +		ipu3_css_pool_put(
> > +			&css-
> >pool.binary_params_p[IMGU_ABI_MEM_ISP_VMEM0]);
> > +	if (dmem0)
> > +		ipu3_css_pool_put(
> > +			&css-
> >pool.binary_params_p[IMGU_ABI_MEM_ISP_DMEM0]);
> > +
> > +fail_no_put:
> > +	return r;
> > +}
> >
> >  void ipu3_css_irq_ack(struct ipu3_css *css)
> >  {
> > @@ -501,7 +2260,7 @@ void ipu3_css_irq_ack(struct ipu3_css *css)
> >  					bi->info.sp.output + 4 + 4 * i);
> >
> >  			dev_dbg(css->dev, "%s: swirq %i cnt %i val 0x%x\n",
> > -				 __func__, i, cnt, val);
> > +				__func__, i, cnt, val);
> >  		}
> >  	}
> >
> > diff --git a/drivers/media/pci/intel/ipu3/ipu3-css.h
> b/drivers/media/pci/intel/ipu3/ipu3-css.h
> > index 5b8e92d47f5d..43627df9910d 100644
> > --- a/drivers/media/pci/intel/ipu3/ipu3-css.h
> > +++ b/drivers/media/pci/intel/ipu3/ipu3-css.h
> > @@ -16,6 +16,8 @@
> >
> >  #include <linux/videodev2.h>
> >  #include <linux/types.h>
> > +#include <media/v4l2-ctrls.h>
> > +#include <media/videobuf2-core.h>
> >  #include "ipu3-abi.h"
> >  #include "ipu3-css-pool.h"
> >
> > @@ -39,6 +41,12 @@
> >  #define IPU3_CSS_QUEUE_STAT_LACE	6
> >  #define IPU3_CSS_QUEUES			7
> >
> > +#define IPU3_CSS_RECT_EFFECTIVE		0       /* Effective resolution */
> > +#define IPU3_CSS_RECT_BDS		1       /* Resolution after BDS
> */
> > +#define IPU3_CSS_RECT_ENVELOPE		2       /* DVS envelope size */
> > +#define IPU3_CSS_RECT_GDC		3       /* gdc output res */
> > +#define IPU3_CSS_RECTS			4       /* number of rects */
> > +
> >  #define IA_CSS_BINARY_MODE_PRIMARY	2
> >  #define IA_CSS_BINARY_MODE_VIDEO	3
> >
> > @@ -56,6 +64,33 @@ enum ipu3_css_pipe_id {
> >  	IPU3_CSS_PIPE_ID_NUM
> >  };
> >
> > +struct ipu3_css_resolution {
> > +	u32 w;
> > +	u32 h;
> > +};
> > +
> > +enum ipu3_css_vf_status {
> > +	IPU3_NODE_VF_ENABLED,
> > +	IPU3_NODE_PV_ENABLED,
> > +	IPU3_NODE_VF_DISABLED
> > +};
> > +
> > +enum ipu3_css_buffer_state {
> > +	IPU3_CSS_BUFFER_NEW,	/* Not yet queued */
> > +	IPU3_CSS_BUFFER_QUEUED,	/* Queued, waiting to be filled */
> > +	IPU3_CSS_BUFFER_DONE,	/* Finished processing, removed
> from queue */
> > +	IPU3_CSS_BUFFER_FAILED,	/* Was not processed, removed from
> queue */
> > +};
> > +
> > +struct ipu3_css_buffer {
> > +	/* Private fields: user doesn't touch */
> > +	dma_addr_t daddr;
> > +	unsigned int queue;
> > +	enum ipu3_css_buffer_state state;
> > +	struct list_head list;
> > +	u8 queue_pos;
> > +};
> > +
> >  struct ipu3_css_format {
> >  	u32 pixelformat;
> >  	enum v4l2_colorspace colorspace;
> > @@ -126,11 +161,65 @@ struct ipu3_css {
> >
> >  	struct ipu3_css_queue queue[IPU3_CSS_QUEUES];
> >  	struct v4l2_rect rect[IPU3_CSS_RECTS];
> > +	struct ipu3_css_map abi_buffers[IPU3_CSS_QUEUES]
> > +				    [IMGU_ABI_HOST2SP_BUFQ_SIZE];
> > +
> > +	struct {
> > +		struct ipu3_css_pool parameter_set_info;
> > +		struct ipu3_css_pool acc;
> > +		struct ipu3_css_pool gdc;
> > +		struct ipu3_css_pool obgrid;
> > +		/* PARAM_CLASS_PARAM parameters for binding while
> streaming */
> > +		struct ipu3_css_pool
> binary_params_p[IMGU_ABI_NUM_MEMORIES];
> > +	} pool;
> > +
> > +	enum ipu3_css_vf_status vf_output_en;
> >  };
> >
> > +/******************* css v4l *******************/
> > +int ipu3_css_init(struct device *dev, struct ipu3_css *css,
> > +		  void __iomem *base, int length);
> > +void ipu3_css_cleanup(struct ipu3_css *css);
> > +int ipu3_css_fmt_try(struct ipu3_css *css,
> > +		     struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES],
> > +		     struct v4l2_rect *rects[IPU3_CSS_RECTS]);
> > +int ipu3_css_fmt_set(struct ipu3_css *css,
> > +		     struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES],
> > +		     struct v4l2_rect *rects[IPU3_CSS_RECTS]);
> > +int ipu3_css_meta_fmt_set(struct v4l2_meta_format *fmt);
> > +int ipu3_css_buf_queue(struct ipu3_css *css, struct ipu3_css_buffer *b);
> > +struct ipu3_css_buffer *ipu3_css_buf_dequeue(struct ipu3_css *css);
> > +int ipu3_css_start_streaming(struct ipu3_css *css);
> > +void ipu3_css_stop_streaming(struct ipu3_css *css);
> > +bool ipu3_css_queue_empty(struct ipu3_css *css);
> > +bool ipu3_css_is_streaming(struct ipu3_css *css);
> > +
> >  /******************* css hw *******************/
> >  int ipu3_css_set_powerup(struct device *dev, void __iomem *base);
> >  int ipu3_css_set_powerdown(struct device *dev, void __iomem *base);
> >  void ipu3_css_irq_ack(struct ipu3_css *css);
> >
> > +/******************* set parameters ************/
> > +int ipu3_css_set_parameters(struct ipu3_css *css,
> > +		struct ipu3_uapi_params *set_params,
> > +		struct ipu3_uapi_gdc_warp_param *set_gdc,
> > +		unsigned int gdc_bytes,
> > +		struct ipu3_uapi_obgrid_param *set_obgrid,
> > +		unsigned int obgrid_bytes);
> > +
> > +/******************* css misc *******************/
> > +static inline enum ipu3_css_buffer_state
> > +ipu3_css_buf_state(struct ipu3_css_buffer *b)
> > +{
> > +	return b->state;
> > +}
> > +
> > +/* Initialize given buffer. May be called several times. */
> > +static inline void ipu3_css_buf_init(struct ipu3_css_buffer *b,
> > +				     unsigned int queue, dma_addr_t daddr)
> > +{
> > +	b->state = IPU3_CSS_BUFFER_NEW;
> > +	b->queue = queue;
> > +	b->daddr = daddr;
> > +}
> >  #endif
> 
> --
> Kind regards,
> 
> Sakari Ailus
> e-mail: sakari.ailus@iki.fi

^ permalink raw reply	[flat|nested] 19+ messages in thread

* RE: [PATCH v4 04/12] intel-ipu3: Add user space ABI definitions
  2017-10-20  9:30 ` [PATCH v4 04/12] intel-ipu3: Add user space ABI definitions Sakari Ailus
@ 2017-11-11  4:07   ` Mani, Rajmohan
  2017-11-21 17:21     ` sakari.ailus
  0 siblings, 1 reply; 19+ messages in thread
From: Mani, Rajmohan @ 2017-11-11  4:07 UTC (permalink / raw)
  To: Sakari Ailus, Zhi, Yong
  Cc: linux-media, sakari.ailus, Zheng, Jian Xu, Toivonen, Tuukka, Hu, Jerry W

Hi Sakari,

> -----Original Message-----
> From: Sakari Ailus [mailto:sakari.ailus@iki.fi]
> Sent: Friday, October 20, 2017 2:30 AM
> To: Zhi, Yong <yong.zhi@intel.com>
> Cc: linux-media@vger.kernel.org; sakari.ailus@linux.intel.com; Zheng, Jian Xu
> <jian.xu.zheng@intel.com>; Mani, Rajmohan <rajmohan.mani@intel.com>;
> Toivonen, Tuukka <tuukka.toivonen@intel.com>; Hu, Jerry W
> <jerry.w.hu@intel.com>
> Subject: Re: [PATCH v4 04/12] intel-ipu3: Add user space ABI definitions
> 
> Hi Yong,
> 
> On Tue, Oct 17, 2017 at 10:54:49PM -0500, Yong Zhi wrote:
> > The UAPI header defines the structures and macros
> > to be used by user space.
> >
> > Signed-off-by: Rajmohan Mani <rajmohan.mani@intel.com>
> > Signed-off-by: Yong Zhi <yong.zhi@intel.com>
> > ---
> >  include/uapi/linux/intel-ipu3.h | 2199
> +++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 2199 insertions(+)
> >  create mode 100644 include/uapi/linux/intel-ipu3.h
> >
> > diff --git a/include/uapi/linux/intel-ipu3.h b/include/uapi/linux/intel-ipu3.h
> > new file mode 100644
> > index 000000000000..e27a449b4ec1
> > --- /dev/null
> > +++ b/include/uapi/linux/intel-ipu3.h
> > @@ -0,0 +1,2199 @@
> > +/*
> > + * Copyright (c) 2017 Intel Corporation.
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License version
> > + * 2 as published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope that 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 __IPU3_UAPI_H
> > +#define __IPU3_UAPI_H
> > +
> > +#include <linux/types.h>
> > +
> > +#define IPU3_UAPI_ISP_VEC_ELEMS				64
> > +
> > +#define IMGU_ABI_PAD	__aligned(IPU3_UAPI_ISP_WORD_BYTES)
> > +#define IPU3_ALIGN
> 	__attribute__((aligned(IPU3_UAPI_ISP_WORD_BYTES)))
> > +
> > +#define IPU3_UAPI_ISP_WORD_BYTES			32
> > +#define IPU3_UAPI_MAX_STRIPES				2
> > +
> > +/******************* ipu3_uapi_stats_3a *******************/
> > +
> > +#define IPU3_UAPI_MAX_BUBBLE_SIZE			10
> > +
> > +#define IPU3_UAPI_AE_COLORS				4
> > +#define IPU3_UAPI_AE_BINS				256
> > +
> > +#define IPU3_UAPI_AWB_MD_ITEM_SIZE			8
> > +#define IPU3_UAPI_AWB_MAX_SETS				60
> > +#define IPU3_UAPI_AWB_SET_SIZE				0x500
> > +#define IPU3_UAPI_AWB_SPARE_FOR_BUBBLES \
> > +		(IPU3_UAPI_MAX_BUBBLE_SIZE * IPU3_UAPI_MAX_STRIPES * \
> > +		 IPU3_UAPI_AWB_MD_ITEM_SIZE)
> > +#define IPU3_UAPI_AWB_MAX_BUFFER_SIZE \
> > +		(IPU3_UAPI_AWB_MAX_SETS * \
> > +		 (IPU3_UAPI_AWB_SET_SIZE +
> IPU3_UAPI_AWB_SPARE_FOR_BUBBLES))
> > +
> > +#define IPU3_UAPI_AF_MAX_SETS				24
> > +#define IPU3_UAPI_AF_MD_ITEM_SIZE			4
> > +#define IPU3_UAPI_AF_SPARE_FOR_BUBBLES \
> > +		(IPU3_UAPI_MAX_BUBBLE_SIZE * IPU3_UAPI_MAX_STRIPES * \
> > +		 IPU3_UAPI_AF_MD_ITEM_SIZE)
> > +#define IPU3_UAPI_AF_Y_TABLE_SET_SIZE			0x80
> > +#define IPU3_UAPI_AF_Y_TABLE_MAX_SIZE \
> > +	(IPU3_UAPI_AF_MAX_SETS * \
> > +	 (IPU3_UAPI_AF_Y_TABLE_SET_SIZE +
> IPU3_UAPI_AF_SPARE_FOR_BUBBLES) * \
> > +	 IPU3_UAPI_MAX_STRIPES)
> > +
> > +#define IPU3_UAPI_AWB_FR_MAX_SETS			24
> > +#define IPU3_UAPI_AWB_FR_MD_ITEM_SIZE			8
> > +#define IPU3_UAPI_AWB_FR_BAYER_TBL_SIZE			0x100
> > +#define IPU3_UAPI_AWB_FR_SPARE_FOR_BUBBLES \
> > +		(IPU3_UAPI_MAX_BUBBLE_SIZE * IPU3_UAPI_MAX_STRIPES * \
> > +		IPU3_UAPI_AWB_FR_MD_ITEM_SIZE)
> > +#define IPU3_UAPI_AWB_FR_BAYER_TABLE_MAX_SIZE \
> > +	(IPU3_UAPI_AWB_FR_MAX_SETS * \
> > +	(IPU3_UAPI_AWB_FR_BAYER_TBL_SIZE + \
> > +	 IPU3_UAPI_AWB_FR_SPARE_FOR_BUBBLES) * \
> > +	IPU3_UAPI_MAX_STRIPES)
> > +
> > +struct ipu3_uapi_grid_config {
> > +	__u8 width;				/* 6 or 7 (rgbs_grd_cfg) bits */
> > +	__u8 height;
> > +	__u16 block_width_log2:3;
> > +	__u16 block_height_log2:3;
> > +	__u16 height_per_slice:8;			/* default value 1 */
> > +	__u16 x_start;					/* 12 bits */
> > +	__u16 y_start;
> > +#define IPU3_UAPI_GRID_START_MASK			((1 << 12) - 1)
> > +#define IPU3_UAPI_GRID_Y_START_EN			(1 << 15)
> > +	__u16 x_end;					/* 12 bits */
> > +	__u16 y_end;
> > +} __packed;
> > +
> > +struct ipu3_uapi_awb_meta_data {
> > +	__u8 meta_data_buffer[IPU3_UAPI_AWB_MAX_BUFFER_SIZE];
> > +} __packed;
> > +
> > +struct ipu3_uapi_awb_raw_buffer {
> > +	struct ipu3_uapi_awb_meta_data meta_data;
> > +} __packed;
> > +
> > +struct IPU3_ALIGN ipu3_uapi_awb_config_s {
> > +	__u16 rgbs_thr_gr;
> > +	__u16 rgbs_thr_r;
> > +	__u16 rgbs_thr_gb;
> > +	__u16 rgbs_thr_b;
> > +/* controls generation of meta_data (like FF enable/disable) */
> > +#define IPU3_UAPI_AWB_RGBS_THR_B_EN		(1 << 14)
> > +#define IPU3_UAPI_AWB_RGBS_THR_B_INCL_SAT	(1 << 15)
> > +
> > +	struct ipu3_uapi_grid_config grid;
> > +} __packed;
> > +
> > +struct ipu3_uapi_ae_raw_buffer {
> > +	__u32 vals[IPU3_UAPI_AE_BINS * IPU3_UAPI_AE_COLORS];
> > +} __packed;
> > +
> > +struct ipu3_uapi_ae_raw_buffer_aligned {
> > +	struct ipu3_uapi_ae_raw_buffer buff IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_ae_grid_config {
> > +	__u8 width;
> > +	__u8 height;
> > +	__u8 block_width_log2:4;
> > +	__u8 block_height_log2:4;
> > +	__u8 __reserved0:5;
> > +	__u8 ae_en:1;
> > +	__u8 rst_hist_array:1;
> > +	__u8 done_rst_hist_array:1;
> > +	__u16 x_start;			/* 12 bits */
> > +	__u16 y_start;
> > +	__u16 x_end;
> > +	__u16 y_end;
> > +} __packed;
> > +
> > +struct ipu3_uapi_af_filter_config {
> > +	struct {
> > +		__u8 a1;
> > +		__u8 a2;
> > +		__u8 a3;
> > +		__u8 a4;
> > +	} y1_coeff_0;
> > +	struct {
> > +		__u8 a5;
> > +		__u8 a6;
> > +		__u8 a7;
> > +		__u8 a8;
> > +	} y1_coeff_1;
> > +	struct {
> > +		__u8 a9;
> > +		__u8 a10;
> > +		__u8 a11;
> > +		__u8 a12;
> > +	} y1_coeff_2;
> > +
> > +	__u32 y1_sign_vec;
> > +
> > +	struct {
> > +		__u8 a1;
> > +		__u8 a2;
> > +		__u8 a3;
> > +		__u8 a4;
> > +	} y2_coeff_0;
> > +	struct {
> > +		__u8 a5;
> > +		__u8 a6;
> > +		__u8 a7;
> > +		__u8 a8;
> > +	} y2_coeff_1;
> > +	struct {
> > +		__u8 a9;
> > +		__u8 a10;
> > +		__u8 a11;
> > +		__u8 a12;
> > +	} y2_coeff_2;
> > +
> > +	__u32 y2_sign_vec;
> > +
> > +	struct {
> > +		__u8 y_gen_rate_gr;	/* 6 bits */
> > +		__u8 y_gen_rate_r;
> > +		__u8 y_gen_rate_b;
> > +		__u8 y_gen_rate_gb;
> > +	} y_calc;
> > +
> > +	struct {
> > +		__u32 __reserved0:8;
> > +		__u32 y1_nf:4;
> > +		__u32 __reserved1:4;
> > +		__u32 y2_nf:4;
> > +		__u32 __reserved2:12;
> > +	} nf;
> > +} __packed;
> > +
> > +struct ipu3_uapi_af_meta_data {
> > +	__u8 y_table[IPU3_UAPI_AF_Y_TABLE_MAX_SIZE] IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_af_raw_buffer {
> > +	struct ipu3_uapi_af_meta_data meta_data IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_af_frame_size {
> > +	__u16 width;
> > +	__u16 height;
> > +} __packed;
> > +
> > +struct ipu3_uapi_af_config_s {
> > +	struct ipu3_uapi_af_filter_config filter_config IPU3_ALIGN;
> > +	struct ipu3_uapi_af_frame_size frame_size;
> > +	struct ipu3_uapi_grid_config grid_cfg IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_awb_fr_meta_data {
> > +	__u8 bayer_table[IPU3_UAPI_AWB_FR_BAYER_TABLE_MAX_SIZE]
> IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_awb_fr_raw_buffer {
> > +	struct ipu3_uapi_awb_fr_meta_data meta_data;
> > +} __packed;
> > +
> > +struct IPU3_ALIGN ipu3_uapi_awb_fr_config_s {
> > +	struct ipu3_uapi_grid_config grid_cfg;
> > +	__u8 bayer_coeff[6];
> > +	__u16 __reserved1;
> > +	__u32 bayer_sign;		/* 11 bits */
> > +	__u8 bayer_nf;			/* 4 bits */
> > +	__u8 __reserved2[3];
> > +} __packed;
> > +
> > +struct ipu3_uapi_4a_config {
> > +	struct ipu3_uapi_awb_config_s awb_config IPU3_ALIGN;
> > +	struct ipu3_uapi_ae_grid_config ae_grd_config IPU3_ALIGN;
> > +	__u8 padding[20];
> > +	struct ipu3_uapi_af_config_s af_config IPU3_ALIGN;
> > +	struct ipu3_uapi_awb_fr_config_s awb_fr_config IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_bubble_info {
> > +	__u32 num_of_stripes IPU3_ALIGN;
> > +	__u8 padding[28];
> > +	__u32 num_sets IPU3_ALIGN;
> > +	__u8 padding1[28];
> > +	__u32 size_of_set IPU3_ALIGN;
> > +	__u8 padding2[28];
> > +	__u32 bubble_size IPU3_ALIGN;
> > +	__u8 padding3[28];
> > +} __packed;
> > +
> > +struct ipu3_uapi_stats_3a_bubble_info_per_stripe {
> > +	struct ipu3_uapi_bubble_info awb[IPU3_UAPI_MAX_STRIPES];
> > +	struct ipu3_uapi_bubble_info af[IPU3_UAPI_MAX_STRIPES];
> > +	struct ipu3_uapi_bubble_info awb_fr[IPU3_UAPI_MAX_STRIPES];
> > +} __packed;
> > +
> > +struct ipu3_uapi_ff_status {
> > +	__u32 awb_en IPU3_ALIGN;
> > +	__u8 padding[28];
> > +	__u32 ae_en IPU3_ALIGN;
> > +	__u8 padding1[28];
> > +	__u32 af_en IPU3_ALIGN;
> > +	__u8 padding2[28];
> > +	__u32 awb_fr_en IPU3_ALIGN;
> > +	__u8 padding3[28];
> > +} __packed;
> > +
> > +struct ipu3_uapi_stats_3a {
> > +	struct ipu3_uapi_awb_raw_buffer awb_raw_buffer IPU3_ALIGN;
> > +	struct ipu3_uapi_ae_raw_buffer_aligned
> > +			ae_raw_buffer[IPU3_UAPI_MAX_STRIPES]
> IPU3_ALIGN;
> > +	struct ipu3_uapi_af_raw_buffer af_raw_buffer IPU3_ALIGN;
> > +	struct ipu3_uapi_awb_fr_raw_buffer awb_fr_raw_buffer IPU3_ALIGN;
> > +	struct ipu3_uapi_4a_config stats_4a_config IPU3_ALIGN;
> > +	__u32 ae_join_buffers IPU3_ALIGN;
> > +	__u8 padding[28];
> > +	struct ipu3_uapi_stats_3a_bubble_info_per_stripe
> > +			stats_3a_bubble_per_stripe IPU3_ALIGN;
> > +	struct ipu3_uapi_ff_status stats_3a_status IPU3_ALIGN;
> > +} __packed;
> > +
> > +/******************* ipu3_uapi_stats_dvs *******************/
> > +
> > +#define IPU3_UAPI_DVS_STAT_LEVELS			3
> > +#define IPU3_UAPI_DVS_STAT_L0_MV_VEC_PER_SET		12
> > +#define IPU3_UAPI_DVS_STAT_L1_MV_VEC_PER_SET		11
> > +#define IPU3_UAPI_DVS_STAT_L2_MV_VEC_PER_SET		9
> > +#define IPU3_UAPI_DVS_STAT_STRIPE_ALIGN_GAP
> 	IPU3_UAPI_MAX_STRIPES
> > +#define IPU3_UAPI_DVS_STAT_MAX_VERTICAL_FEATURES		16
> > +
> > +struct ipu3_uapi_dvs_stat_mv {
> > +	__u16 vec_fe_x_pos;		/* 12 bits */
> > +	__u16 vec_fe_y_pos;
> > +	__u16 vec_fm_x_pos;		/* 12 bits */
> > +	__u16 vec_fm_y_pos;
> > +	__u32 harris_grade;		/* 28 bits */
> > +	__u16 match_grade;		/* 15 bits */
> > +	__u16 level;			/* 3 bits */
> > +} __packed;
> > +
> > +struct ipu3_uapi_dvs_stat_mv_single_set_l0 {
> > +	struct ipu3_uapi_dvs_stat_mv
> > +		mv_entry[IPU3_UAPI_DVS_STAT_L0_MV_VEC_PER_SET +
> > +		IPU3_UAPI_DVS_STAT_STRIPE_ALIGN_GAP] IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_dvs_stat_mv_single_set_l1 {
> > +	struct ipu3_uapi_dvs_stat_mv
> > +		mv_entry[IPU3_UAPI_DVS_STAT_L1_MV_VEC_PER_SET +
> > +		IPU3_UAPI_DVS_STAT_STRIPE_ALIGN_GAP] IPU3_ALIGN;
> > +	__u8 padding[16];
> > +} __packed;
> > +
> > +struct ipu3_uapi_dvs_stat_mv_single_set_l2 {
> > +	struct ipu3_uapi_dvs_stat_mv
> > +		mv_entry[IPU3_UAPI_DVS_STAT_L2_MV_VEC_PER_SET +
> > +		IPU3_UAPI_DVS_STAT_STRIPE_ALIGN_GAP] IPU3_ALIGN;
> > +	__u8 padding[16];
> > +} __packed;
> > +
> > +struct ipu3_uapi_dvs_stat_motion_vec {
> > +	struct ipu3_uapi_dvs_stat_mv_single_set_l0
> > +
> 	dvs_mv_output_l0[IPU3_UAPI_DVS_STAT_MAX_VERTICAL_FEATURES]
> > +		IPU3_ALIGN;
> > +	struct ipu3_uapi_dvs_stat_mv_single_set_l1
> > +
> 	dvs_mv_output_l1[IPU3_UAPI_DVS_STAT_MAX_VERTICAL_FEATURES]
> > +		IPU3_ALIGN;
> > +	struct ipu3_uapi_dvs_stat_mv_single_set_l2
> > +
> 	dvs_mv_output_l2[IPU3_UAPI_DVS_STAT_MAX_VERTICAL_FEATURES]
> > +		IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_dvs_stat_stripe_data {
> > +	__u8
> grid_width[IPU3_UAPI_MAX_STRIPES][IPU3_UAPI_DVS_STAT_LEVELS];
> > +	__u16 stripe_offset;
> > +} __packed;
> > +
> > +struct ipu3_uapi_dvs_stat_gbl_config {
> > +	__u8 kappa;					/* 4 bits */
> > +	__u8 match_shift:4;
> > +	__u8 ybin_mode:1;
> > +	__u16 __reserved1;
> > +} __packed;
> > +
> > +struct ipu3_uapi_dvs_stat_grd_config {
> > +	__u8 grid_width;				/* 5 bits */
> > +	__u8 grid_height;
> > +	__u8 block_width;				/* 8 bits */
> > +	__u8 block_height;
> > +	__u16 x_start;					/* 12 bits */
> > +	__u16 y_start;
> > +	__u16 enable;
> > +	__u16 x_end;					/* 12 bits */
> > +	__u16 y_end;
> > +} __packed;
> > +
> > +struct ipu3_uapi_dvs_stat_fe_roi_cfg {
> > +	__u8 x_start;
> > +	__u8 y_start;
> > +	__u8 x_end;
> > +	__u8 y_end;
> > +} __packed;
> > +
> > +struct ipu3_uapi_dvs_stat_cfg {
> > +	struct ipu3_uapi_dvs_stat_gbl_config gbl_cfg;
> > +	struct ipu3_uapi_dvs_stat_grd_config
> > +
> 	grd_config[IPU3_UAPI_DVS_STAT_LEVELS];
> > +	struct ipu3_uapi_dvs_stat_fe_roi_cfg
> > +
> 	fe_roi_cfg[IPU3_UAPI_DVS_STAT_LEVELS];
> > +	__u8 __reserved[IPU3_UAPI_ISP_WORD_BYTES -
> > +		 (sizeof(struct ipu3_uapi_dvs_stat_gbl_config) +
> > +		  (sizeof(struct ipu3_uapi_dvs_stat_grd_config) +
> > +		   sizeof(struct ipu3_uapi_dvs_stat_fe_roi_cfg)) *
> > +		  IPU3_UAPI_DVS_STAT_LEVELS) %
> IPU3_UAPI_ISP_WORD_BYTES];
> > +} __packed;
> > +
> > +struct ipu3_uapi_stats_dvs {
> > +	struct ipu3_uapi_dvs_stat_motion_vec motion_vec IPU3_ALIGN;
> > +	struct ipu3_uapi_dvs_stat_cfg cfg IPU3_ALIGN;
> > +	struct ipu3_uapi_dvs_stat_stripe_data stripe_data IPU3_ALIGN;
> > +} __packed;
> > +
> > +/******************* ipu3_uapi_stats_lace *******************/
> > +
> > +#define IPU3_UAPI_LACE_STAT_REGS_PER_SET		320
> > +#define IPU3_UAPI_LACE_STAT_MAX_OPERATIONS		41
> > +
> > +struct ipu3_uapi_lace_stat_stats_regs {
> > +	__u8 bin[4];					/* the bins 0-3 */
> > +} __packed;
> > +
> > +struct ipu3_uapi_lace_stat_hist_single_set {
> > +	struct ipu3_uapi_lace_stat_stats_regs
> > +		lace_hist_set[IPU3_UAPI_LACE_STAT_REGS_PER_SET]
> IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_lace_stat_hist_vec {
> > +	struct ipu3_uapi_lace_stat_hist_single_set
> > +	       lace_hist_output[IPU3_UAPI_LACE_STAT_MAX_OPERATIONS]
> IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_lace_stat_gbl_cfg {
> > +	__u32 lh_mode:3;
> > +	__u32 __reserved:3;
> > +	__u32 y_ds_mode:2;
> > +	__u32 uv_ds_mode_unsupported:1;
> > +	__u32 uv_input_unsupported:1;
> > +	__u32 __reserved1:10;
> > +	__u32 rst_loc_hist:1;
> > +	__u32 done_rst_loc_hist:1;
> > +	__u32 __reserved2:10;
> > +} __packed;
> > +
> > +struct ipu3_uapi_lace_stat_y_grd_hor_cfg {
> > +	__u32 grid_width:6;
> > +	__u32 __reserved:10;
> > +	__u32 block_width:4;
> > +	__u32 __reserved1:12;
> > +} __packed;
> > +
> > +struct ipu3_uapi_lace_stat_y_grd_hor_roi {
> > +	__u32 x_start:12;
> > +	__u32 __reserved:4;
> > +	__u32 x_end:12;
> > +	__u32 __reserved1:4;
> > +} __packed;
> > +
> > +struct ipu3_uapi_lace_stat_uv_grd_hor_cfg {
> > +	__u32 not_supported;
> > +} __packed;
> > +
> > +struct ipu3_uapi_lace_stat_uv_grd_hor_roi {
> > +	__u32 not_supported;
> > +} __packed;
> > +
> > +struct ipu3_uapi_lace_stat_grd_vrt_cfg {
> > +	__u32 __reserved:8;
> > +	__u32 grid_h:6;
> > +	__u32 __reserved1:6;
> > +	__u32 block_h:4;
> > +	__u32 grid_h_per_slice:7;
> > +	__u32 __reserved2:1;
> > +} __packed;
> > +
> > +struct ipu3_uapi_lace_stat_grd_vrt_roi {
> > +	__u32 y_start:12;
> > +	__u32 __reserved:4;
> > +	__u32 y_end:12;
> > +	__u32 __reserved1:4;
> > +} __packed;
> > +
> > +struct ipu3_uapi_lace_stat_cfg {
> > +	struct ipu3_uapi_lace_stat_gbl_cfg lace_stat_gbl_cfg;
> > +	struct ipu3_uapi_lace_stat_y_grd_hor_cfg lace_stat_y_grd_hor_cfg;
> > +	struct ipu3_uapi_lace_stat_y_grd_hor_roi lace_stat_y_grd_hor_roi;
> > +	struct ipu3_uapi_lace_stat_uv_grd_hor_cfg lace_stat_uv_grd_hor_cfg;
> > +	struct ipu3_uapi_lace_stat_uv_grd_hor_roi lace_stat_uv_grd_hor_roi;
> > +	struct ipu3_uapi_lace_stat_grd_vrt_cfg lace_stat_grd_vrt_cfg;
> > +	struct ipu3_uapi_lace_stat_grd_vrt_roi lace_stat_grd_vrt_roi;
> > +} __packed;
> > +
> > +struct ipu3_uapi_stats_lace {
> > +	struct ipu3_uapi_lace_stat_hist_vec lace_hist_vec IPU3_ALIGN;
> > +	struct ipu3_uapi_lace_stat_cfg lace_stat_cfg IPU3_ALIGN;
> > +	__u8 padding[4];
> > +} __packed;
> > +
> > +/******************* ipu3_uapi_acc_param *******************/
> > +
> > +#define IPU3_UAPI_BNR_LUT_SIZE				32
> > +
> > +/* number of elements in gamma correction LUT */
> > +#define IPU3_UAPI_GAMMA_CORR_LUT_ENTRIES		256
> > +
> > +#define IPU3_UAPI_SHD_MAX_OPERATIONS \
> > +		(IPU3_UAPI_SHD_MAX_PROCESS_LINES +
> IPU3_UAPI_SHD_MAX_TRANSFERS)
> > +#define IPU3_UAPI_SHD_MAX_PROCESS_LINES			31
> > +#define IPU3_UAPI_SHD_MAX_TRANSFERS			31
> > +#define IPU3_UAPI_SHD_MAX_CELLS_PER_SET			146
> > +/* largest grid is 73x56 */
> > +#define IPU3_UAPI_SHD_MAX_CFG_SETS			28
> > +
> > +#define IPU3_UAPI_DVS_STAT_L0_MD_ENTRIES		84
> > +#define IPU3_UAPI_DVS_STAT_PARTS_IN_MD_ENTRY		10
> > +#define IPU3_UAPI_DVS_STAT_L1_MD_ENTRIES		66
> > +#define IPU3_UAPI_DVS_STAT_L2_MD_ENTRIES		45
> > +#define IPU3_UAPI_DVS_STAT_MAX_OPERATIONS		100
> > +#define IPU3_UAPI_DVS_STAT_MAX_PROCESS_LINES		52
> > +#define IPU3_UAPI_DVS_STAT_MAX_TRANSFERS		52
> > +
> > +#define IPU3_UAPI_YUVP2_YTM_LUT_ENTRIES			256
> > +#define IPU3_UAPI_YUVP2_TCC_MACC_TABLE_ELEMENTS		16
> > +#define IPU3_UAPI_YUVP2_TCC_INV_Y_LUT_ELEMENTS		14
> > +#define IPU3_UAPI_YUVP2_TCC_GAIN_PCWL_LUT_ELEMENTS	258
> > +#define IPU3_UAPI_YUVP2_TCC_R_SQR_LUT_ELEMENTS		24
> > +
> > +#define IPU3_UAPI_DPC_COMMANDS_PER_TRANSFER		2
> > +#define IPU3_UAPI_DPC_MAX_SUPPORTED_HEIGHT		3840
> > +#define IPU3_UAPI_DPC_STRIPE_SIZE			50
> > +#define IPU3_UAPI_DPC_MAX_OPERATIONS \
> > +	(IPU3_UAPI_DPC_COMMANDS_PER_TRANSFER *
> IPU3_UAPI_DPC_MAX_CFG_SETS)
> > +#define IPU3_UAPI_DPC_MAX_PROCESS_LINES
> 	IPU3_UAPI_DPC_MAX_CFG_SETS
> > +#define IPU3_UAPI_DPC_MAX_TRANSFERS
> 	IPU3_UAPI_DPC_MAX_CFG_SETS
> > +#define IPU3_UAPI_DPC_MAX_DP_FIRST_LINES_PAIR		70
> > +#define IPU3_UAPI_DPC_MAX_DP_PER_SET			192
> > +#define IPU3_UAPI_DPC_MAX_CFG_SETS \
> > +	((IPU3_UAPI_DPC_MAX_SUPPORTED_HEIGHT +
> IPU3_UAPI_DPC_STRIPE_SIZE - 1) \
> > +	/ IPU3_UAPI_DPC_STRIPE_SIZE)
> > +
> > +#define IPU3_UAPI_BDS_SAMPLE_PATTERN_ARRAY_SIZE		8
> > +#define IPU3_UAPI_BDS_PHASE_COEFFS_ARRAY_SIZE		32
> > +
> > +#define IPU3_UAPI_ANR_LUT_SIZE				26
> > +#define IPU3_UAPI_ANR_PYRAMID_SIZE			22
> > +
> > +#define IPU3_UAPI_AWB_FR_MAX_TRANSFERS			30
> > +#define IPU3_UAPI_AWB_FR_MAX_PROCESS_LINES		30
> > +#define IPU3_UAPI_AWB_FR_MAX_OPERATIONS \
> > +	(IPU3_UAPI_AWB_FR_MAX_TRANSFERS +
> IPU3_UAPI_AWB_FR_MAX_PROCESS_LINES)
> > +
> > +#define IPU3_UAPI_AE_WEIGHTS				96
> > +
> > +#define IPU3_UAPI_AF_MAX_TRANSFERS			30
> > +#define IPU3_UAPI_AF_MAX_PROCESS_LINES			30
> > +#define IPU3_UAPI_AF_MAX_OPERATIONS \
> > +		(IPU3_UAPI_AF_MAX_TRANSFERS +
> IPU3_UAPI_AF_MAX_PROCESS_LINES)
> > +
> > +#define IPU3_UAPI_AWB_MAX_PROCESS_LINES			68
> > +#define IPU3_UAPI_AWB_MAX_TRANSFERS			68
> > +#define IPU3_UAPI_AWB_MAX_OPERATIONS \
> > +		(IPU3_UAPI_AWB_MAX_PROCESS_LINES +
> IPU3_UAPI_AWB_MAX_TRANSFERS)
> > +
> > +#define IPU3_UAPI_OSYS_PIN_VF				0
> > +#define IPU3_UAPI_OSYS_PIN_OUT				1
> > +#define IPU3_UAPI_OSYS_PINS				2
> > +
> > +typedef __u32 imgu_addr_t;
> > +
> > +struct ipu3_uapi_stripe_input_frame_resolution {
> > +	__u16 width;
> > +	__u16 height;
> > +	__u32 bayer_order;		/* enum ipu3_uapi_bayer_order */
> > +	__u32 raw_bit_depth;
> > +} __packed;
> > +
> > +struct ipu3_uapi_acc_operation {
> > +	/*
> > +	 * zero means on init,
> > +	 * others mean upon receiving an ack signal from the BC acc.
> > +	 */
> > +	__u8 op_indicator;
> > +	__u8 op_type;
> > +} __packed;
> > +
> > +struct ipu3_uapi_acc_process_lines_cmd_data {
> > +	__u16 lines;
> > +	__u8 cfg_set;
> > +	__u8 __reserved;		/* Align to 4 bytes */
> > +} __packed;
> > +
> > +struct ipu3_uapi_stripes {
> > +	/* offset from start of frame - measured in pixels */
> > +	__u16 offset;
> > +	/* stripe width - measured in pixels */
> > +	__u16 width;
> > +	/* stripe width - measured in pixels */
> > +	__u16 height;
> > +} __packed;
> > +
> > +struct ipu3_uapi_stripe_data {
> > +	/*
> > +	 * number of stripes for current processing source
> > +	 * - VLIW binary parameter we currently support 1 or 2 stripes
> > +	 */
> > +	__u16 num_of_stripes;
> > +
> > +	__u8 padding[2];
> > +
> > +	/*
> > +	 * the following data is derived from resolution-related
> > +	 * pipe config and from num_of_stripes
> > +	 */
> > +
> > +	/*
> > +	 *'input-stripes' - before input cropping
> > +	 * used by input feeder
> > +	 */
> > +	struct ipu3_uapi_stripe_input_frame_resolution input_frame;
> > +
> > +	/*'effective-stripes' - after input cropping used dpc, bds */
> > +	struct ipu3_uapi_stripes effective_stripes[IPU3_UAPI_MAX_STRIPES];
> > +
> > +	/* 'down-scaled-stripes' - after down-scaling ONLY. used by BDS */
> > +	struct ipu3_uapi_stripes
> down_scaled_stripes[IPU3_UAPI_MAX_STRIPES];
> > +
> > +	/*
> > +	 *'bds-out-stripes' - after bayer down-scaling and padding.
> > +	 * used by all algos starting with norm up to the ref-frame for GDC
> > +	 * (currently up to the output kernel)
> > +	 */
> > +	struct ipu3_uapi_stripes bds_out_stripes[IPU3_UAPI_MAX_STRIPES];
> > +
> > +	/* 'bds-out-stripes (no overlap)' - used for ref kernel */
> > +	struct ipu3_uapi_stripes
> > +
> 	bds_out_stripes_no_overlap[IPU3_UAPI_MAX_STRIPES];
> > +
> > +	/*
> > +	 * input resolution for output system (equal to bds_out - envelope)
> > +	 * output-system input frame width as configured by user
> > +	 */
> > +	__u16 output_system_in_frame_width;
> > +	/* output-system input frame height as configured by user */
> > +	__u16 output_system_in_frame_height;
> > +
> > +	/*
> > +	 * 'output-stripes' - accounts for stiching on the output (no overlap)
> > +	 * used by the output kernel
> > +	 */
> > +	struct ipu3_uapi_stripes output_stripes[IPU3_UAPI_MAX_STRIPES];
> > +
> > +	/*
> > +	 * 'block-stripes' - accounts for stiching by the output system
> > +	 * (1 or more blocks overlap)
> > +	 * used by DVS, TNR and the output system kernel
> > +	 */
> > +	struct ipu3_uapi_stripes block_stripes[IPU3_UAPI_MAX_STRIPES];
> > +
> > +	__u16 effective_frame_width;	/* Needed for vertical cropping */
> > +	__u16 bds_frame_width;
> > +	__u16 out_frame_width;	/* Output frame width as configured
> by user */
> > +	__u16 out_frame_height;	/* Output frame height as configured
> by user */
> > +
> > +	/* GDC in buffer (A.K.A delay frame,ref buffer) info */
> > +	__u16 gdc_in_buffer_width;	/* GDC in buffer width  */
> > +	__u16 gdc_in_buffer_height;	/* GDC in buffer height */
> > +	/* GDC in buffer first valid pixel x offset */
> > +	__u16 gdc_in_buffer_offset_x;
> > +	/* GDC in buffer first valid pixel y offset */
> > +	__u16 gdc_in_buffer_offset_y;
> > +
> > +	/* Display frame width as configured by user */
> > +	__u16 display_frame_width;
> > +	/* Display frame height as configured by user */
> > +	__u16 display_frame_height;
> > +	__u16 bds_aligned_frame_width;
> > +	/* Number of vectors to left-crop when writing stripes (not stripe 0) */
> > +	__u16 half_overlap_vectors;
> > +	/* Decimate ISP and fixed func resolutions after BDS (ir_extraction) */
> > +	__u16 ir_ext_decimation;
> > +	__u8 padding1[2];
> > +} __packed;
> > +
> > +struct ipu3_uapi_input_feeder_data {
> > +	__u32 row_stride;				/* row stride */
> > +	__u32 start_row_address;			/* start row address */
> > +	__u32 start_pixel;				/* start pixel */
> > +} __packed;
> > +
> > +struct ipu3_uapi_input_feeder_data_aligned {
> > +	struct ipu3_uapi_input_feeder_data data IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_input_feeder_data_per_stripe {
> > +	struct ipu3_uapi_input_feeder_data_aligned
> > +		input_feeder_data[IPU3_UAPI_MAX_STRIPES];
> > +} __packed;
> > +
> > +struct ipu3_uapi_input_feeder_config {
> > +	struct ipu3_uapi_input_feeder_data data;
> > +	struct ipu3_uapi_input_feeder_data_per_stripe data_per_stripe
> > +		IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_bnr_static_config_wb_gains_config {
> > +	__u16 gr;
> > +	__u16 r;
> > +	__u16 b;
> > +	__u16 gb;
> > +} __packed;
> > +
> > +struct ipu3_uapi_bnr_static_config_wb_gains_thr_config {
> > +	__u8 gr;
> > +	__u8 r;
> > +	__u8 b;
> > +	__u8 gb;
> > +} __packed;
> > +
> > +struct ipu3_uapi_bnr_static_config_thr_coeffs_config {
> > +	__u32 cf:13;
> > +	__u32 __reserved0:3;
> > +	__u32 cg:5;
> > +	__u32 ci:5;
> > +	__u32 __reserved1:1;
> > +	__u32 r_nf:5;
> > +} __packed;
> > +
> > +struct ipu3_uapi_bnr_static_config_thr_ctrl_shd_config {
> > +	__u8 gr;
> > +	__u8 r;
> > +	__u8 b;
> > +	__u8 gb;
> > +} __packed;
> > +
> > +struct ipu3_uapi_bnr_static_config_opt_center_config {
> > +	__s32 x_reset:13;
> > +	__u32 __reserved0:3;
> > +	__s32 y_reset:13;
> > +	__u32 __reserved2:3;
> > +} __packed;
> > +
> > +struct ipu3_uapi_bnr_static_config_lut_config {
> > +	__u8 values[IPU3_UAPI_BNR_LUT_SIZE];
> > +} __packed;
> > +
> > +struct ipu3_uapi_bnr_static_config_bp_ctrl_config {
> > +	__u32 bp_thr_gain:5;
> > +	__u32 __reserved0:2;
> > +	__u32 defect_mode:1;
> > +	__u32 bp_gain:6;
> > +	__u32 __reserved1:18;
> > +	__u32 w0_coeff:4;
> > +	__u32 __reserved2:4;
> > +	__u32 w1_coeff:4;
> > +	__u32 __reserved3:20;
> > +} __packed;
> > +
> > +struct ipu3_uapi_bnr_static_config_dn_detect_ctrl_config {
> > +	__u32 alpha:4;
> > +	__u32 beta:4;
> > +	__u32 gamma:4;
> > +	__u32 __reserved0:4;
> > +	__u32 max_inf:4;
> > +	__u32 __reserved1:7;
> > +	/* aka 'green disparity enable' */
> > +	__u32 gd_enable:1;
> > +	__u32 bpc_enable:1;
> > +	__u32 bnr_enable:1;
> > +	__u32 ff_enable:1;
> > +	__u32 __reserved2:1;
> > +} __packed;
> > +
> > +struct ipu3_uapi_bnr_static_config_opt_center_sqr_config {
> > +	__u32 x_sqr_reset;
> > +	__u32 y_sqr_reset;
> > +} __packed;
> > +
> > +struct ipu3_uapi_bnr_static_config {
> > +	struct ipu3_uapi_bnr_static_config_wb_gains_config wb_gains;
> > +	struct ipu3_uapi_bnr_static_config_wb_gains_thr_config
> wb_gains_thr;
> > +	struct ipu3_uapi_bnr_static_config_thr_coeffs_config thr_coeffs;
> > +	struct ipu3_uapi_bnr_static_config_thr_ctrl_shd_config thr_ctrl_shd;
> > +	struct ipu3_uapi_bnr_static_config_opt_center_config opt_center;
> > +	struct ipu3_uapi_bnr_static_config_lut_config lut;
> > +	struct ipu3_uapi_bnr_static_config_bp_ctrl_config bp_ctrl;
> > +	struct ipu3_uapi_bnr_static_config_dn_detect_ctrl_config
> dn_detect_ctrl;
> > +	__u32 column_size;				/* 0x44 */
> > +	struct ipu3_uapi_bnr_static_config_opt_center_sqr_config
> opt_center_sqr;
> > +} __packed;
> > +
> > +struct ipu3_uapi_bnr_static_config_green_disparity {
> > +	__u32 gd_red:6;
> > +	__u32 __reserved0:2;
> > +	__u32 gd_green:6;
> > +	__u32 __reserved1:2;
> > +	__u32 gd_blue:6;
> > +	__u32 __reserved2:10;
> > +	__u32 gd_black:14;
> > +	__u32 __reserved3:2;
> > +	__u32 gd_shading:7;
> > +	__u32 __reserved4:1;
> > +	__u32 gd_support:2;
> > +	__u32 __reserved5:1;
> > +	__u32 gd_clip:1;			/* central weights variables */
> > +	__u32 gd_central_weight:4;
> > +} __packed;
> > +
> > +struct ipu3_uapi_dm_config {
> > +	/* DWORD0 */
> > +	__u32 dm_en:1;
> > +	__u32 ch_ar_en:1;
> > +	__u32 fcc_en:1;
> > +	__u32 __reserved0:13;
> > +	__u32 frame_width:16;
> > +
> > +	/* DWORD1 */
> > +	__u32 gamma_sc:5;
> > +	__u32 __reserved1:3;
> > +	__u32 lc_ctrl:5;
> > +	__u32 __reserved2:3;
> > +	__u32 cr_param1:5;
> > +	__u32 __reserved3:3;
> > +	__u32 cr_param2:5;
> > +	__u32 __reserved4:3;
> > +
> > +	/* DWORD2 */
> > +	__u32 coring_param:5;
> > +	__u32 __reserved5:27;
> > +} __packed;
> > +
> > +struct ipu3_uapi_ccm_mat_config {
> > +	__s16 coeff_m11;
> > +	__s16 coeff_m12;
> > +	__s16 coeff_m13;
> > +	__s16 coeff_o_r;
> > +	__s16 coeff_m21;
> > +	__s16 coeff_m22;
> > +	__s16 coeff_m23;
> > +	__s16 coeff_o_g;
> > +	__s16 coeff_m31;
> > +	__s16 coeff_m32;
> > +	__s16 coeff_m33;
> > +	__s16 coeff_o_b;
> > +} __packed;
> > +
> > +struct ipu3_uapi_gamma_corr_ctrl {
> > +	__u32 enable:1;
> > +	__u32 __reserved:31;
> > +} __packed;
> > +
> > +struct ipu3_uapi_gamma_corr_lut {
> > +	__u16 lut[IPU3_UAPI_GAMMA_CORR_LUT_ENTRIES];
> > +} __packed;
> > +
> > +struct ipu3_uapi_gamma_config {
> > +	struct ipu3_uapi_gamma_corr_ctrl gc_ctrl IPU3_ALIGN;
> > +	struct ipu3_uapi_gamma_corr_lut gc_lut IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_csc_mat_config {
> > +	__s16 coeff_c11;
> > +	__s16 coeff_c12;
> > +	__s16 coeff_c13;
> > +	__s16 coeff_b1;
> > +	__s16 coeff_c21;
> > +	__s16 coeff_c22;
> > +	__s16 coeff_c23;
> > +	__s16 coeff_b2;
> > +	__s16 coeff_c31;
> > +	__s16 coeff_c32;
> > +	__s16 coeff_c33;
> > +	__s16 coeff_b3;
> > +} __packed;
> > +
> > +struct ipu3_uapi_cds_params {
> > +	__u32 ds_c00:2;
> > +	__u32 ds_c01:2;
> > +	__u32 ds_c02:2;
> > +	__u32 ds_c03:2;
> > +	__u32 ds_c10:2;
> > +	__u32 ds_c11:2;
> > +	__u32 ds_c12:2;
> > +	__u32 ds_c13:2;
> > +	__u32 ds_nf:5;
> > +	__u32 __reserved0:3;
> > +	__u32 csc_en:1;
> > +	__u32 uv_bin_output:1;
> > +	__u32 __reserved1:6;
> > +} __packed;
> > +
> > +struct ipu3_uapi_shd_grid_config {
> > +	/* reg 0 */
> > +	__u8 width;
> > +	__u8 height;
> > +	__u8 block_width_log2:3;
> > +	__u8 __reserved0:1;
> > +	__u8 block_height_log2:3;
> > +	__u8 __reserved1:1;
> > +	__u8 grid_height_per_slice;
> > +	/* reg 1 */
> > +	__s16 x_start;			/* 13 bits */
> > +	__s16 y_start;
> > +} __packed;
> > +
> > +struct ipu3_uapi_shd_general_config {
> > +	__u32 init_set_vrt_offst_ul:8;
> > +	__u32 shd_enable:1;
> > +	/* aka 'gf' */
> > +	__u32 gain_factor:2;
> > +	__u32 __reserved:21;
> > +} __packed;
> > +
> > +struct ipu3_uapi_shd_black_level_config {
> > +	__s16 bl_r;			/* 12 bits */
> > +	__s16 bl_gr;
> > +#define IPU3_UAPI_SHD_BLGR_NF_SHIFT	13	/* Normalization shift
> aka nf */
> > +#define IPU3_UAPI_SHD_BLGR_NF_MASK	0x7
> > +	__s16 bl_gb;			/* 12 bits */
> > +	__s16 bl_b;
> > +} __packed;
> > +
> > +struct ipu3_uapi_shd_config_static {
> > +	/* B0: Fixed order: one transfer to GAC */
> > +	struct ipu3_uapi_shd_grid_config grid;
> > +	struct ipu3_uapi_shd_general_config general;
> > +	struct ipu3_uapi_shd_black_level_config black_level;
> > +} __packed;
> > +
> > +struct ipu3_uapi_shd_transfer_luts_set_data {
> > +	__u8 set_number;
> > +	__u8 padding[3];
> > +	imgu_addr_t rg_lut_ddr_addr;
> > +	imgu_addr_t bg_lut_ddr_addr;
> > +	__u32 align_dummy;
> > +} __packed;
> > +
> > +struct ipu3_uapi_shd_intra_frame_operations_data {
> > +	struct ipu3_uapi_acc_operation
> > +		operation_list[IPU3_UAPI_SHD_MAX_OPERATIONS]
> IPU3_ALIGN;
> > +	struct ipu3_uapi_acc_process_lines_cmd_data
> > +		process_lines_data[IPU3_UAPI_SHD_MAX_PROCESS_LINES]
> IPU3_ALIGN;
> > +	struct ipu3_uapi_shd_transfer_luts_set_data
> > +		transfer_data[IPU3_UAPI_SHD_MAX_TRANSFERS]
> IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_shd_lut {
> > +	struct {
> > +		struct {
> > +			__u16 r;
> > +			__u16 gr;
> > +		} r_and_gr[IPU3_UAPI_SHD_MAX_CELLS_PER_SET];
> > +		__u8 __reserved1[24];
> > +		struct {
> > +			__u16 gb;
> > +			__u16 b;
> > +		} gb_and_b[IPU3_UAPI_SHD_MAX_CELLS_PER_SET];
> > +		__u8 __reserved2[24];
> > +	} sets[IPU3_UAPI_SHD_MAX_CFG_SETS];
> > +} __packed;
> > +
> > +struct ipu3_uapi_shd_config {
> > +	struct ipu3_uapi_shd_config_static shd IPU3_ALIGN;
> > +	struct ipu3_uapi_shd_intra_frame_operations_data shd_ops
> IPU3_ALIGN;
> > +	struct ipu3_uapi_shd_lut shd_lut IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_dvs_stat_stripe_cfg {
> > +	struct ipu3_uapi_dvs_stat_cfg stripe_cfg[IPU3_UAPI_MAX_STRIPES];
> > +} __packed;
> > +
> > +struct ipu3_uapi_dvs_stat_transfer_op_data {
> > +	__u8 set_number;
> > +} __packed;
> > +
> > +struct ipu3_uapi_dvs_stat_intra_frame_operations_data {
> > +	struct ipu3_uapi_acc_operation
> > +		ops[IPU3_UAPI_DVS_STAT_MAX_OPERATIONS] IPU3_ALIGN;
> > +	struct ipu3_uapi_acc_process_lines_cmd_data
> > +
> 	process_lines_data[IPU3_UAPI_DVS_STAT_MAX_PROCESS_LINES]
> > +		IPU3_ALIGN;
> > +	struct ipu3_uapi_dvs_stat_transfer_op_data
> > +		transfer_data[IPU3_UAPI_DVS_STAT_MAX_TRANSFERS]
> IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_dvs_stat_meta_data_align_p {
> > +	imgu_addr_t p_meta_data IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_dvs_stat_config {
> > +	struct ipu3_uapi_dvs_stat_cfg cfg IPU3_ALIGN;
> > +	struct ipu3_uapi_dvs_stat_stripe_cfg stripe IPU3_ALIGN;
> > +	struct ipu3_uapi_dvs_stat_intra_frame_operations_data
> > +		operations_data IPU3_ALIGN;
> > +	struct ipu3_uapi_dvs_stat_meta_data_align_p
> > +		meta_data[IPU3_UAPI_MAX_STRIPES];
> > +} __packed;
> > +
> > +struct ipu3_uapi_lace_stat_operation {
> > +	__u8 op_indicator;
> > +	__u8 padding;
> > +	__u16 lines;
> > +} __packed;
> > +
> > +struct ipu3_uapi_lace_stat_intra_frame_op_data {
> > +	struct ipu3_uapi_lace_stat_operation
> > +		ops[IPU3_UAPI_LACE_STAT_MAX_OPERATIONS] IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_lace_stat_config {
> > +	struct ipu3_uapi_lace_stat_cfg lace_stat_cfg IPU3_ALIGN;
> > +	struct ipu3_uapi_lace_stat_intra_frame_op_data operations_data
> > +		IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_iefd_cux2 {
> > +	__u32 x0:9;
> > +	__u32 x1:9;
> > +	__u32 a01:9;
> > +	__u32 b01:5;				/* NOTE: hardcoded to zero */
> > +} __packed;
> > +
> > +struct ipu3_uapi_iefd_cux6_ed {
> > +	__u32 x0:9;
> > +	__u32 x1:9;
> > +	__u32 x2:9;
> > +	__u32 __reserved0:5;
> > +
> > +	__u32 x3:9;
> > +	__u32 x4:9;
> > +	__u32 x5:9;
> > +	__u32 __reserved1:5;
> > +
> > +	__u32 a01:9;
> > +	__u32 a12:9;
> > +	__u32 a23:9;
> > +	__u32 __reserved2:5;
> > +
> > +	__u32 a34:9;
> > +	__u32 a45:9;
> > +	__u32 __reserved3:14;
> > +
> > +	__u32 b01:9;
> > +	__u32 b12:9;
> > +	__u32 b23:9;
> > +	__u32 __reserved4:5;
> > +
> > +	__u32 b34:9;
> > +	__u32 b45:9;
> > +	__u32 __reserved5:14;
> > +} __packed;
> > +
> > +struct ipu3_uapi_iefd_cux2_1 {
> > +	__u32 x0:9;
> > +	__u32 x1:9;
> > +	__u32 a01:9;
> > +	__u32 __reserved1:5;
> > +
> > +	__u32 b01:8;
> > +	__u32 __reserved2:24;
> > +} __packed;
> > +
> > +struct ipu3_uapi_iefd_cux4 {
> > +	__u32 x0:9;
> > +	__u32 x1:9;
> > +	__u32 x2:9;
> > +	__u32 __reserved0:5;
> > +
> > +	__u32 x3:9;
> > +	__u32 a01:9;
> > +	__u32 a12:9;
> > +	__u32 __reserved1:5;
> > +
> > +	__u32 a23:9;
> > +	__u32 b01:8;
> > +	__u32 b12:8;
> > +	__u32 __reserved2:7;
> > +
> > +	__u32 b23:8;
> > +	__u32 __reserved3:24;
> > +} __packed;
> > +
> > +struct ipu3_uapi_iefd_cux6_rad {
> > +	__u32 x0:8;
> > +	__u32 x1:8;
> > +	__u32 x2:8;
> > +	__u32 x3:8;
> > +
> > +	__u32 x4:8;
> > +	__u32 x5:8;
> > +	__u32 __reserved1:16;
> > +
> > +	__u32 a01:16;
> > +	__u32 a12:16;
> > +
> > +	__u32 a23:16;
> > +	__u32 a34:16;
> > +
> > +	__u32 a45:16;
> > +	__u32 __reserved2:16;
> > +
> > +	__u32 b01:10;
> > +	__u32 b12:10;
> > +	__u32 b23:10;
> > +	__u32 __reserved4:2;
> > +
> > +	__u32 b34:10;
> > +	__u32 b45:10;
> > +	__u32 __reserved5:12;
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp1_iefd_cfg_units {
> > +	struct ipu3_uapi_iefd_cux2 cu_1;
> > +	struct ipu3_uapi_iefd_cux6_ed cu_ed;
> > +	struct ipu3_uapi_iefd_cux2 cu_3;
> > +	struct ipu3_uapi_iefd_cux2_1 cu_5;
> > +	struct ipu3_uapi_iefd_cux4 cu_6;
> > +	struct ipu3_uapi_iefd_cux2 cu_7;
> > +	struct ipu3_uapi_iefd_cux4 cu_unsharp;
> > +	struct ipu3_uapi_iefd_cux6_rad cu_radial;
> > +	struct ipu3_uapi_iefd_cux2 cu_vssnlm;
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp1_iefd_config_s {
> > +	__u32 horver_diag_coeff:7;	/* Gradiant compensation */
> > +	__u32 __reserved0:1;
> > +	__u32 clamp_stitch:6;		/* Slope to stitch edge */
> > +	__u32 __reserved1:2;
> > +	__u32 direct_metric_update:5;	/* Update coeff for direction metric */
> > +	__u32 __reserved2:3;
> > +	__u32 ed_horver_diag_coeff:7;
> > +	__u32 __reserved3:1;
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp1_iefd_control {
> > +	__u32 iefd_en:1;		/* Enable IEFD */
> > +	__u32 denoise_en:1;		/* Enable denoise */
> > +	__u32 direct_smooth_en:1;	/* Enable directional smooth */
> > +	__u32 rad_en:1;			/* Enable radial update */
> > +	__u32 vssnlm_en:1;		/* Enable VSSNLM output filter */
> > +	__u32 __reserved:27;
> > +} __packed;
> > +
> > +struct ipu3_uapi_sharp_cfg {
> > +	__u32 nega_lmt_txt:13;
> > +	__u32 __reserved0:19;
> > +	__u32 posi_lmt_txt:13;
> > +	__u32 __reserved1:19;
> > +	__u32 nega_lmt_dir:13;
> > +	__u32 __reserved2:19;
> > +	__u32 posi_lmt_dir:13;
> > +	__u32 __reserved3:19;
> > +} __packed;
> > +
> > +struct ipu3_uapi_far_w {
> > +	__u32 dir_shrp:7;
> > +	__u32 __reserved0:1;
> > +	__u32 dir_dns:7;
> > +	__u32 __reserved1:1;
> > +	__u32 ndir_dns_powr:7;
> > +	__u32 __reserved2:9;
> > +} __packed;
> > +
> > +struct ipu3_uapi_unsharp_cfg {
> > +	__u32 unsharp_weight:7;
> > +	__u32 __reserved0:1;
> > +	__u32 unsharp_amount:9;
> > +	__u32 __reserved1:15;
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp1_iefd_shrp_cfg {
> > +	struct ipu3_uapi_sharp_cfg cfg;
> > +	struct ipu3_uapi_far_w far_w;
> > +	struct ipu3_uapi_unsharp_cfg unshrp_cfg;
> > +} __packed;
> > +
> > +struct ipu3_uapi_unsharp_coef0 {
> > +	__u32 c00:9;			/* Coeff11 */
> > +	__u32 c01:9;			/* Coeff12 */
> > +	__u32 c02:9;			/* Coeff13 */
> > +	__u32 __reserved:5;
> > +} __packed;
> > +
> > +struct ipu3_uapi_unsharp_coef1 {
> > +	__u32 c11:9;			/* Coeff22 */
> > +	__u32 c12:9;			/* Coeff23 */
> > +	__u32 c22:9;			/* Coeff33 */
> > +	__u32 __reserved:5;
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp1_iefd_unshrp_cfg {
> > +	struct ipu3_uapi_unsharp_coef0 unsharp_coef0;
> > +	struct ipu3_uapi_unsharp_coef1 unsharp_coef1;
> > +} __packed;
> > +
> > +struct ipu3_uapi_radial_reset_xy {
> > +	__s32 x:13;
> > +	__u32 __reserved0:3;
> > +	__s32 y:13;
> > +	__u32 __reserved1:3;
> > +} __packed;
> > +
> > +struct ipu3_uapi_radial_reset_x2 {
> > +	__u32 x2:24;
> > +	__u32 __reserved:8;
> > +} __packed;
> > +
> > +struct ipu3_uapi_radial_reset_y2 {
> > +	__u32 y2:24;
> > +	__u32 __reserved:8;
> > +} __packed;
> > +
> > +struct ipu3_uapi_radial_cfg {
> > +	__u32 rad_nf:4;
> > +	__u32 __reserved0:4;
> > +	__u32 rad_inv_r2:7;
> > +	__u32 __reserved1:17;
> > +} __packed;
> > +
> > +struct ipu3_uapi_rad_far_w {
> > +	__u32 rad_dir_far_sharp_w:8;
> > +	__u32 rad_dir_far_dns_w:8;
> > +	__u32 rad_ndir_far_dns_power:8;
> > +	__u32 __reserved:8;
> > +} __packed;
> > +
> > +struct ipu3_uapi_cu_cfg0 {
> > +	__u32 cu6_pow:7;
> > +	__u32 __reserved0:1;
> > +	__u32 cu_unsharp_pow:7;
> > +	__u32 __reserved1:1;
> > +	__u32 rad_cu6_pow:7;
> > +	__u32 __reserved2:1;
> > +	__u32 rad_cu_unsharp_pow:6;
> > +	__u32 __reserved3:2;
> > +} __packed;
> > +
> > +struct ipu3_uapi_cu_cfg1 {
> > +	__u32 rad_cu6_x1:9;
> > +	__u32 __reserved0:1;
> > +	__u32 rad_cu_unsharp_x1:9;
> > +	__u32 __reserved1:13;
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp1_iefd_rad_cfg {
> > +	struct ipu3_uapi_radial_reset_xy reset_xy;
> > +	struct ipu3_uapi_radial_reset_x2 reset_x2;
> > +	struct ipu3_uapi_radial_reset_y2 reset_y2;
> > +	struct ipu3_uapi_radial_cfg cfg;
> > +	struct ipu3_uapi_rad_far_w rad_far_w;
> > +	struct ipu3_uapi_cu_cfg0 cu_cfg0;
> > +	struct ipu3_uapi_cu_cfg1 cu_cfg1;
> > +} __packed;
> > +
> > +struct ipu3_uapi_vss_lut_x {
> > +	__u32 vs_x0:8;
> > +	__u32 vs_x1:8;
> > +	__u32 vs_x2:8;
> > +	__u32 __reserved2:8;
> > +} __packed;
> > +
> > +struct ipu3_uapi_vss_lut_y {
> > +	__u32 vs_y1:4;
> > +	__u32 __reserved0:4;
> > +	__u32 vs_y2:4;
> > +	__u32 __reserved1:4;
> > +	__u32 vs_y3:4;
> > +	__u32 __reserved2:12;
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp1_iefd_vssnlm_cfg {
> > +	struct ipu3_uapi_vss_lut_x vss_lut_x;
> > +	struct ipu3_uapi_vss_lut_y vss_lut_y;
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp1_iefd_config {
> > +	struct ipu3_uapi_yuvp1_iefd_cfg_units units;
> > +	struct ipu3_uapi_yuvp1_iefd_config_s config;
> > +	struct ipu3_uapi_yuvp1_iefd_control control;
> > +	struct ipu3_uapi_yuvp1_iefd_shrp_cfg sharp;
> > +	struct ipu3_uapi_yuvp1_iefd_unshrp_cfg unsharp;
> > +	struct ipu3_uapi_yuvp1_iefd_rad_cfg rad;
> > +	struct ipu3_uapi_yuvp1_iefd_vssnlm_cfg vsslnm;
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp1_yds_config {
> > +	__u32 c00:2;
> > +	__u32 c01:2;
> > +	__u32 c02:2;
> > +	__u32 c03:2;
> > +	__u32 c10:2;
> > +	__u32 c11:2;
> > +	__u32 c12:2;
> > +	__u32 c13:2;
> > +	__u32 norm_factor:5;
> > +	__u32 __reserved0:4;
> > +	__u32 bin_output:1;
> > +	__u32 __reserved1:6;
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp1_chnr_enable_config {
> > +	__u32 enable:1;
> > +	__u32 yuv_mode:1;
> > +	__u32 __reserved0:14;
> > +	__u32 col_size:12;
> > +	__u32 __reserved1:4;
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp1_chnr_coring_config {
> > +	__u32 u:13;
> > +	__u32 __reserved0:3;
> > +	__u32 v:13;
> > +	__u32 __reserved1:3;
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp1_chnr_sense_gain_config {
> > +	__u32 vy:8;
> > +	__u32 vu:8;
> > +	__u32 vv:8;
> > +	__u32 __reserved0:8;
> > +
> > +	__u32 hy:8;
> > +	__u32 hu:8;
> > +	__u32 hv:8;
> > +	__u32 __reserved1:8;
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp1_chnr_iir_fir_config {
> > +	__u32 fir_0h:6;
> > +	__u32 __reserved0:2;
> > +	__u32 fir_1h:6;
> > +	__u32 __reserved1:2;
> > +	__u32 fir_2h:6;
> > +	__u32 dalpha_clip_val:9;
> > +	__u32 __reserved2:1;
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp1_chnr_config {
> > +	struct ipu3_uapi_yuvp1_chnr_enable_config enable;
> > +	struct ipu3_uapi_yuvp1_chnr_coring_config coring;
> > +	struct ipu3_uapi_yuvp1_chnr_sense_gain_config sense_gain;
> > +	struct ipu3_uapi_yuvp1_chnr_iir_fir_config iir_fir;
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp1_y_ee_nr_lpf_config {
> > +	__u32 a_diag:5;
> > +	__u32 __reserved0:3;
> > +	__u32 a_periph:5;
> > +	__u32 __reserved1:3;
> > +	__u32 a_cent:5;
> > +	__u32 __reserved2:9;
> > +	__u32 enable:1;
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp1_y_ee_nr_sense_config {
> > +	__u32 edge_sense_0:13;
> > +	__u32 __reserved0:3;
> > +	__u32 delta_edge_sense:13;
> > +	__u32 __reserved1:3;
> > +	__u32 corner_sense_0:13;
> > +	__u32 __reserved2:3;
> > +	__u32 delta_corner_sense:13;
> > +	__u32 __reserved3:3;
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp1_y_ee_nr_gain_config {
> > +	__u32 gain_pos_0:5;
> > +	__u32 __reserved0:3;
> > +	__u32 delta_gain_posi:5;
> > +	__u32 __reserved1:3;
> > +	__u32 gain_neg_0:5;
> > +	__u32 __reserved2:3;
> > +	__u32 delta_gain_neg:5;
> > +	__u32 __reserved3:3;
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp1_y_ee_nr_clip_config {
> > +	__u32 clip_pos_0:5;
> > +	__u32 __reserved0:3;
> > +	__u32 delta_clip_posi:5;
> > +	__u32 __reserved1:3;
> > +	__u32 clip_neg_0:5;
> > +	__u32 __reserved2:3;
> > +	__u32 delta_clip_neg:5;
> > +	__u32 __reserved3:3;
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp1_y_ee_nr_frng_config {
> > +	__u32 gain_exp:4;
> > +	__u32 __reserved0:28;
> > +	__u32 min_edge:13;
> > +	__u32 __reserved1:3;
> > +	__u32 lin_seg_param:4;
> > +	__u32 __reserved2:4;
> > +	__u32 t1:1;
> > +	__u32 t2:1;
> > +	__u32 __reserved3:6;
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp1_y_ee_nr_diag_config {
> > +	__u32 diag_disc_g:4;
> > +	__u32 __reserved0:4;
> > +	__u32 hvw_hor:4;
> > +	__u32 dw_hor:4;
> > +	__u32 hvw_diag:4;
> > +	__u32 dw_diag:4;
> > +	__u32 __reserved1:8;
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp1_y_ee_nr_fc_coring_config {
> > +	__u32 pos_0:13;
> > +	__u32 __reserved0:3;
> > +	__u32 pos_delta:13;
> > +	__u32 __reserved1:3;
> > +	__u32 neg_0:13;
> > +	__u32 __reserved2:3;
> > +	__u32 neg_delta:13;
> > +	__u32 __reserved3:3;
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp1_y_ee_nr_config {
> > +	struct ipu3_uapi_yuvp1_y_ee_nr_lpf_config lpf;
> > +	struct ipu3_uapi_yuvp1_y_ee_nr_sense_config sense;
> > +	struct ipu3_uapi_yuvp1_y_ee_nr_gain_config gain;
> > +	struct ipu3_uapi_yuvp1_y_ee_nr_clip_config clip;
> > +	struct ipu3_uapi_yuvp1_y_ee_nr_frng_config frng;
> > +	struct ipu3_uapi_yuvp1_y_ee_nr_diag_config diag;
> > +	struct ipu3_uapi_yuvp1_y_ee_nr_fc_coring_config fc_coring;
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp2_y_tm_lut_static_config {
> > +	__u16 entries[IPU3_UAPI_YUVP2_YTM_LUT_ENTRIES]; /* 13
> significand bits*/
> > +	__u32 enable;
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp2_tcc_gen_control_static_config {
> > +	__u32 en:1;
> > +	__u32 blend_shift:3;
> > +	__u32 gain_according_to_y_only:1;
> > +	__u32 __reserved0:11;
> > +	__s32 gamma:5;
> > +	__u32 __reserved1:3;
> > +	__s32 delta:5;
> > +	__u32 __reserved2:3;
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp2_tcc_macc_elem_static_config {
> > +	__s32 a:12;
> > +	__u32 __reserved0:4;
> > +	__s32 b:12;
> > +	__u32 __reserved1:4;
> > +	__s32 c:12;
> > +	__u32 __reserved2:4;
> > +	__s32 d:12;
> > +	__u32 __reserved3:4;
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp2_tcc_macc_table_static_config {
> > +	struct ipu3_uapi_yuvp2_tcc_macc_elem_static_config
> > +		entries[IPU3_UAPI_YUVP2_TCC_MACC_TABLE_ELEMENTS];
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp2_tcc_inv_y_lut_static_config {
> > +	__u16 entries[IPU3_UAPI_YUVP2_TCC_INV_Y_LUT_ELEMENTS];	/* 10
> bits */
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp2_tcc_gain_pcwl_lut_static_config {
> > +	__u16
> entries[IPU3_UAPI_YUVP2_TCC_GAIN_PCWL_LUT_ELEMENTS];/* 12 bits */
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp2_tcc_r_sqr_lut_static_config {
> > +	__s16 entries[IPU3_UAPI_YUVP2_TCC_R_SQR_LUT_ELEMENTS];	/* 11
> bits */
> > +} __packed;
> > +
> > +struct ipu3_uapi_yuvp2_tcc_static_config {
> > +	struct ipu3_uapi_yuvp2_tcc_gen_control_static_config gen_control;
> > +	struct ipu3_uapi_yuvp2_tcc_macc_table_static_config macc_table;
> > +	struct ipu3_uapi_yuvp2_tcc_inv_y_lut_static_config inv_y_lut;
> > +	struct ipu3_uapi_yuvp2_tcc_gain_pcwl_lut_static_config gain_pcwl;
> > +	struct ipu3_uapi_yuvp2_tcc_r_sqr_lut_static_config r_sqr_lut;
> > +} __packed;
> > +
> > +struct ipu3_uapi_dpc_num_of_dp {
> > +	__u8 dp_gr;
> > +	__u8 dp_bg;
> > +	__u16 __reserved;
> > +} __packed;
> > +
> > +struct ipu3_uapi_dpc_params {
> > +	__u16 enable;
> > +	__u16 grad_threshold;		/* 13 bits */
> > +	struct ipu3_uapi_dpc_num_of_dp set[2];
> > +	struct ipu3_uapi_dpc_num_of_dp first_line_pair;
> > +} __packed;
> > +
> > +struct ipu3_uapi_dpc_transfer_luts_set_data {
> > +	__u8 set_number;
> > +	__u8 num_of_dp_gr;
> > +	__u8 num_of_dp_bg;
> > +	__u8 align_dummy;
> > +
> > +} __packed;
> > +
> > +struct ipu3_uapi_dpc_intra_frame_operations_data {
> > +	struct ipu3_uapi_acc_operation
> > +		operation_list[IPU3_UAPI_DPC_MAX_OPERATIONS]
> IPU3_ALIGN;
> > +	struct ipu3_uapi_acc_process_lines_cmd_data
> > +		process_lines_data[IPU3_UAPI_DPC_MAX_PROCESS_LINES]
> IPU3_ALIGN;
> > +	struct ipu3_uapi_dpc_transfer_luts_set_data
> > +		transfer_data[IPU3_UAPI_DPC_MAX_TRANSFERS]
> IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_dpc_1st_pair_of_lines_lut_elem {
> > +	__u32 column:13;
> > +	__u32 nghbr_sts:5;
> > +	__u32 p0:14;
> > +	__u32 p1:14;
> > +	__u32 __reserved0:2;
> > +	__u32 p2:14;
> > +	__u32 nghbr_order:1;
> > +	__u32 __reserved1:1;
> > +} __packed;
> > +
> > +struct ipu3_uapi_dpc_1st_pair_of_lines_lut {
> > +	struct ipu3_uapi_dpc_1st_pair_of_lines_lut_elem
> > +		entries[IPU3_UAPI_DPC_MAX_DP_FIRST_LINES_PAIR];
> > +
> > +} __packed;
> > +
> > +struct ipu3_uapi_dpc_lut_elem {
> > +	__u32 nghbr_sts:5;
> > +	__u32 skip:1;
> > +	__u32 nghbr_order:1;
> > +	__u32 column:13;
> > +	__u32 row_pair_delta:4;
> > +	__u32 __reserved0:8;
> > +} __packed;
> > +
> > +struct ipu3_uapi_dpc_lut_set {
> > +	struct ipu3_uapi_dpc_lut_elem
> > +		elems[IPU3_UAPI_DPC_MAX_DP_PER_SET] IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_dpc_lut {
> > +	struct ipu3_uapi_dpc_lut_set sets[IPU3_UAPI_DPC_MAX_CFG_SETS];
> > +} __packed;
> > +
> > +struct ipu3_uapi_dpc_stripe_config {
> > +	struct ipu3_uapi_dpc_params params IPU3_ALIGN;
> > +	struct ipu3_uapi_dpc_intra_frame_operations_data ops IPU3_ALIGN;
> > +	struct ipu3_uapi_dpc_1st_pair_of_lines_lut first_lines_lut_gr
> > +		IPU3_ALIGN;
> > +	struct ipu3_uapi_dpc_1st_pair_of_lines_lut first_lines_lut_bg
> > +		IPU3_ALIGN;
> > +	struct ipu3_uapi_dpc_lut lut_bg IPU3_ALIGN;
> > +	struct ipu3_uapi_dpc_lut lut_gr IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_dpc_config_per_stripe {
> > +	struct ipu3_uapi_dpc_stripe_config
> > +		dpc_config[IPU3_UAPI_MAX_STRIPES] IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_dpc_config {
> > +	struct ipu3_uapi_dpc_config_per_stripe config_per_stripe
> > +		IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_bds_hor_ctrl0 {
> > +	__u32 sample_patrn_length:9;
> > +	__u32 __reserved0:3;
> > +	__u32 hor_ds_en:1;
> > +	__u32 min_clip_val:1;
> > +	__u32 max_clip_val:2;
> > +	__u32 out_frame_width:13;
> > +	__u32 __reserved1:3;
> > +} __packed;
> > +
> > +struct ipu3_uapi_bds_ptrn_arr {
> > +	__u32 elems[IPU3_UAPI_BDS_SAMPLE_PATTERN_ARRAY_SIZE];
> > +} __packed;
> > +
> > +struct ipu3_uapi_bds_phase_entry {
> > +	__s8 coeff_min2;
> > +	__s8 coeff_min1;
> > +	__s8 coeff_0;
> > +	__s8 nf;
> > +	__s8 coeff_pls1;
> > +	__s8 coeff_pls2;
> > +	__s8 coeff_pls3;
> > +	__u8 __reserved;
> > +} __packed;
> > +
> > +struct ipu3_uapi_bds_phase_arr {
> > +	struct ipu3_uapi_bds_phase_entry
> > +		even[IPU3_UAPI_BDS_PHASE_COEFFS_ARRAY_SIZE];
> > +	struct ipu3_uapi_bds_phase_entry
> > +		odd[IPU3_UAPI_BDS_PHASE_COEFFS_ARRAY_SIZE];
> > +} __packed;
> > +
> > +struct ipu3_uapi_bds_hor_ctrl1 {
> > +	__u32 hor_crop_start:13;
> > +	__u32 __reserved0:3;
> > +	__u32 hor_crop_end:13;
> > +	__u32 __reserved1:1;
> > +	__u32 hor_crop_en:1;
> > +	__u32 __reserved2:1;
> > +} __packed;
> > +
> > +struct ipu3_uapi_bds_hor_ctrl2 {
> > +	__u32 input_frame_height:13;
> > +	__u32 __reserved0:19;
> > +} __packed;
> > +
> > +struct ipu3_uapi_bds_hor {
> > +	struct ipu3_uapi_bds_hor_ctrl0 hor_ctrl0;
> > +	struct ipu3_uapi_bds_ptrn_arr hor_ptrn_arr;
> > +	struct ipu3_uapi_bds_phase_arr hor_phase_arr;
> > +	struct ipu3_uapi_bds_hor_ctrl1 hor_ctrl1;
> > +	struct ipu3_uapi_bds_hor_ctrl2 hor_ctrl2;
> > +} __packed;
> > +
> > +struct ipu3_uapi_bds_ver_ctrl0 {
> > +	__u32 sample_patrn_length:9;
> > +	__u32 __reserved0:3;
> > +	__u32 ver_ds_en:1;
> > +	__u32 min_clip_val:1;
> > +	__u32 max_clip_val:2;
> > +	__u32 __reserved1:16;
> > +} __packed;
> > +
> > +struct ipu3_uapi_bds_ver_ctrl1 {
> > +	__u32 out_frame_width:13;
> > +	__u32 __reserved0:3;
> > +	__u32 out_frame_height:13;
> > +	__u32 __reserved1:3;
> > +} __packed;
> > +
> > +struct ipu3_uapi_bds_ver {
> > +	struct ipu3_uapi_bds_ver_ctrl0 ver_ctrl0;
> > +	struct ipu3_uapi_bds_ptrn_arr ver_ptrn_arr;
> > +	struct ipu3_uapi_bds_phase_arr ver_phase_arr;
> > +	struct ipu3_uapi_bds_ver_ctrl1 ver_ctrl1;
> > +
> > +} __packed;
> > +
> > +struct ipu3_uapi_bds_per_stripe_data {
> > +	struct ipu3_uapi_bds_hor_ctrl0 hor_ctrl0;
> > +	struct ipu3_uapi_bds_ver_ctrl1 ver_ctrl1;
> > +	struct ipu3_uapi_bds_hor_ctrl1 crop;
> > +} __packed;
> > +
> > +struct ipu3_uapi_ipu3_uapi_bds_per_stripe_data_aligned {
> > +	struct ipu3_uapi_bds_per_stripe_data data IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_bds_per_stripe {
> > +	struct ipu3_uapi_ipu3_uapi_bds_per_stripe_data_aligned
> > +		aligned_data[IPU3_UAPI_MAX_STRIPES];
> > +} __packed;
> > +
> > +struct ipu3_uapi_bds_config {
> > +	struct ipu3_uapi_bds_hor hor IPU3_ALIGN;
> > +	struct ipu3_uapi_bds_ver ver IPU3_ALIGN;
> > +	struct ipu3_uapi_bds_per_stripe per_stripe IPU3_ALIGN;
> > +	__u32 enabled;
> > +} __packed;
> > +
> > +struct ipu3_uapi_anr_search_config {
> > +	__u32 enable;
> > +	__u16 frame_width;
> > +	__u16 frame_height;
> > +} __packed;
> > +
> > +struct ipu3_uapi_anr_alpha {
> > +	__u16 gr;					/* 9 bits */
> > +	__u16 r;
> > +	__u16 b;
> > +	__u16 gb;
> > +	__u16 dc_gr;
> > +	__u16 dc_r;
> > +	__u16 dc_b;
> > +	__u16 dc_gb;
> > +} __packed;
> > +
> > +struct ipu3_uapi_anr_beta {
> > +	__u16 beta_gr;					/* 11 bits */
> > +	__u16 beta_r;
> > +	__u16 beta_b;
> > +	__u16 beta_gb;
> > +} __packed;
> > +
> > +struct ipu3_uapi_anr_plain_color {
> > +	__u16 reg_w_gr[16];				/* 12 bits */
> > +	__u16 reg_w_r[16];
> > +	__u16 reg_w_b[16];
> > +	__u16 reg_w_gb[16];
> > +} __packed;
> > +
> > +struct ipu3_uapi_anr_transform_config {
> > +	__u32 enable:1;			/* 0 or 1, disabled or enabled
> */
> > +	__u32 adaptive_treshhold_en:1;	/* On IPU3, always enabled */
> > +
> > +	__u32 __reserved1:30;
> > +	__u8 __reserved2[40+4];
> > +
> > +	struct ipu3_uapi_anr_alpha alpha[3];
> > +	struct ipu3_uapi_anr_beta beta[3];
> > +	struct ipu3_uapi_anr_plain_color color[3];
> > +
> > +	__u16 sqrt_lut[IPU3_UAPI_ANR_LUT_SIZE];	/* 11 bits per element
> */
> > +
> > +	__s16 xreset:13;
> > +#define IPU3_UAPI_ANR_MAX_XRESET		((1 << 12) - 1)
> > +	__u16 __reserved3:3;
> > +	__s16 yreset:13;
> > +	__u16 __reserved4:3;
> > +
> > +	__u32 x_sqr_reset:24;
> > +	__u32 r_normfactor:5;
> > +	__u32 __reserved5:3;
> > +
> > +	__u32 y_sqr_reset:24;
> > +	__u32 gain_scale:8;
> > +} __packed;
> > +
> > +struct ipu3_uapi_anr_stitch_pyramid {
> > +	__u32 entry0:6;
> > +	__u32 entry1:6;
> > +	__u32 entry2:6;
> > +	__u32 __reserved:14;
> > +} __packed;
> > +
> > +struct ipu3_uapi_anr_stitch_config {
> > +	__u32 anr_stitch_en;
> > +	__u16 frame_width;
> > +	__u16 frame_height;
> > +	__u8 __reserved[40];
> > +	struct ipu3_uapi_anr_stitch_pyramid
> pyramid[IPU3_UAPI_ANR_PYRAMID_SIZE];
> > +} __packed;
> > +
> > +struct ipu3_uapi_anr_tile2strm_config {
> > +	__u32 enable;
> > +	__u16 frame_width;
> > +	__u16 frame_height;
> > +} __packed;
> > +
> > +struct ipu3_uapi_anr_config {
> > +	struct ipu3_uapi_anr_search_config search IPU3_ALIGN;
> > +	struct ipu3_uapi_anr_transform_config transform IPU3_ALIGN;
> > +	struct ipu3_uapi_anr_stitch_config stitch IPU3_ALIGN;
> > +	struct ipu3_uapi_anr_tile2strm_config tile2strm IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_awb_fr_intra_frame_operations_data {
> > +	struct ipu3_uapi_acc_operation
> ops[IPU3_UAPI_AWB_FR_MAX_OPERATIONS]
> > +								IPU3_ALIGN;
> > +	struct ipu3_uapi_acc_process_lines_cmd_data
> > +	      process_lines_data[IPU3_UAPI_AWB_FR_MAX_PROCESS_LINES]
> IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_awb_fr_config {
> > +	struct ipu3_uapi_awb_fr_config_s config;
> > +	struct ipu3_uapi_awb_fr_intra_frame_operations_data
> operations_data;
> > +	struct ipu3_uapi_awb_fr_config_s stripes[IPU3_UAPI_MAX_STRIPES];
> > +} __packed;
> > +
> > +struct ipu3_uapi_ae_weight_elem {
> > +	__u32 cell0:4;
> > +	__u32 cell1:4;
> > +	__u32 cell2:4;
> > +	__u32 cell3:4;
> > +	__u32 cell4:4;
> > +	__u32 cell5:4;
> > +	__u32 cell6:4;
> > +	__u32 cell7:4;
> > +} __packed;
> > +
> > +struct ipu3_uapi_ae_ccm {
> > +	__u16 gain_gr;			/* 11 bits */
> > +	__u16 gain_r;
> > +	__u16 gain_b;
> > +	__u16 gain_gb;
> > +	__s16 mat[16];
> > +} __packed;
> > +
> > +struct ipu3_uapi_ae_config {
> > +	struct ipu3_uapi_ae_grid_config grid_cfg IPU3_ALIGN;
> > +	struct ipu3_uapi_ae_weight_elem weights[IPU3_UAPI_AE_WEIGHTS]
> > +								IPU3_ALIGN;
> > +	struct ipu3_uapi_ae_ccm ae_ccm IPU3_ALIGN;
> > +	struct {
> > +		struct ipu3_uapi_ae_grid_config grid IPU3_ALIGN;
> > +	} stripes[IPU3_UAPI_MAX_STRIPES];
> > +} __packed;
> > +
> > +struct ipu3_uapi_af_intra_frame_operations_data {
> > +	struct ipu3_uapi_acc_operation
> ops[IPU3_UAPI_AF_MAX_OPERATIONS]
> > +		IPU3_ALIGN;
> > +	struct ipu3_uapi_acc_process_lines_cmd_data
> > +		process_lines_data[IPU3_UAPI_AF_MAX_PROCESS_LINES]
> IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_af_stripe_config {
> > +	struct ipu3_uapi_af_frame_size frame_size IPU3_ALIGN;
> > +	struct ipu3_uapi_grid_config grid_cfg IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_af_config {
> > +	struct ipu3_uapi_af_config_s config;
> > +	struct ipu3_uapi_af_intra_frame_operations_data operations_data;
> > +	struct ipu3_uapi_af_stripe_config stripes[IPU3_UAPI_MAX_STRIPES];
> > +} __packed;
> > +
> > +struct ipu3_uapi_acc_transfer_op_data {
> > +	__u8 set_number;
> > +} __packed;
> > +
> > +struct IPU3_ALIGN ipu3_uapi_awb_intra_frame_operations_data {
> > +	struct ipu3_uapi_acc_operation
> ops[IPU3_UAPI_AWB_MAX_OPERATIONS]
> > +		IPU3_ALIGN;
> > +	struct ipu3_uapi_acc_process_lines_cmd_data
> > +		process_lines_data[IPU3_UAPI_AWB_MAX_PROCESS_LINES]
> IPU3_ALIGN;
> > +	struct ipu3_uapi_acc_transfer_op_data
> > +		transfer_data[IPU3_UAPI_AWB_MAX_TRANSFERS]
> IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_awb_config {
> > +	struct ipu3_uapi_awb_config_s config IPU3_ALIGN;
> > +	struct ipu3_uapi_awb_intra_frame_operations_data operations_data;
> > +	struct ipu3_uapi_awb_config_s stripes[IPU3_UAPI_MAX_STRIPES];
> > +} __packed;
> > +
> > +struct ipu3_uapi_osys_formatter_params {
> > +	__u32 format;
> > +	__u32 flip;
> > +	__u32 mirror;
> > +	__u32 tiling;
> > +	__u32 reduce_range;
> > +	__u32 alpha_blending;	/* FIXME: To figure out the unknown register
> */
> > +	__u32 release_inp_addr;
> > +	__u32 release_inp_en;
> > +	__u32 process_out_buf_addr;
> > +	__u32 image_width_vecs;
> > +	__u32 image_height_lines;
> > +	__u32 inp_buff_y_st_addr;
> > +	__u32 inp_buff_y_line_stride;
> > +	__u32 inp_buff_y_buffer_stride;
> > +	__u32 int_buff_u_st_addr;
> > +	__u32 int_buff_v_st_addr;
> > +	__u32 inp_buff_uv_line_stride;
> > +	__u32 inp_buff_uv_buffer_stride;
> > +	__u32 out_buff_level;
> > +	__u32 out_buff_nr_y_lines;
> > +	__u32 out_buff_u_st_offset;
> > +	__u32 out_buff_v_st_offset;
> > +	__u32 out_buff_y_line_stride;
> > +	__u32 out_buff_uv_line_stride;
> > +	__u32 hist_buff_st_addr;
> > +	__u32 hist_buff_line_stride;
> > +	__u32 hist_buff_nr_lines;
> > +} __packed;
> > +
> > +struct ipu3_uapi_osys_formatter {
> > +	struct ipu3_uapi_osys_formatter_params param IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_osys_scaler_params {
> > +	__u32 inp_buf_y_st_addr;
> > +	__u32 inp_buf_y_line_stride;
> > +	__u32 inp_buf_y_buffer_stride;
> > +	__u32 inp_buf_u_st_addr;
> > +	__u32 inp_buf_v_st_addr;
> > +	__u32 inp_buf_uv_line_stride;
> > +	__u32 inp_buf_uv_buffer_stride;
> > +	__u32 inp_buf_chunk_width;
> > +	__u32 inp_buf_nr_buffers;
> > +	/* Output buffers */
> > +	__u32 out_buf_y_st_addr;
> > +	__u32 out_buf_y_line_stride;
> > +	__u32 out_buf_y_buffer_stride;
> > +	__u32 out_buf_u_st_addr;
> > +	__u32 out_buf_v_st_addr;
> > +	__u32 out_buf_uv_line_stride;
> > +	__u32 out_buf_uv_buffer_stride;
> > +	__u32 out_buf_nr_buffers;
> > +	/* Intermediate buffers */
> > +	__u32 int_buf_y_st_addr;
> > +	__u32 int_buf_y_line_stride;
> > +	__u32 int_buf_u_st_addr;
> > +	__u32 int_buf_v_st_addr;
> > +	__u32 int_buf_uv_line_stride;
> > +	__u32 int_buf_height;
> > +	__u32 int_buf_chunk_width;
> > +	__u32 int_buf_chunk_height;
> > +	/* Context buffers */
> > +	__u32 ctx_buf_hor_y_st_addr;
> > +	__u32 ctx_buf_hor_u_st_addr;
> > +	__u32 ctx_buf_hor_v_st_addr;
> > +	__u32 ctx_buf_ver_y_st_addr;
> > +	__u32 ctx_buf_ver_u_st_addr;
> > +	__u32 ctx_buf_ver_v_st_addr;
> > +	/* Addresses for release-input and process-output tokens */
> > +	__u32 release_inp_buf_addr;
> > +	__u32 release_inp_buf_en;
> > +	__u32 release_out_buf_en;
> > +	__u32 process_out_buf_addr;
> > +	/* Settings dimensions, padding, cropping */
> > +	__u32 input_image_y_width;
> > +	__u32 input_image_y_height;
> > +	__u32 input_image_y_start_column;
> > +	__u32 input_image_uv_start_column;
> > +	__u32 input_image_y_left_pad;
> > +	__u32 input_image_uv_left_pad;
> > +	__u32 input_image_y_right_pad;
> > +	__u32 input_image_uv_right_pad;
> > +	__u32 input_image_y_top_pad;
> > +	__u32 input_image_uv_top_pad;
> > +	__u32 input_image_y_bottom_pad;
> > +	__u32 input_image_uv_bottom_pad;
> > +	__u32 processing_mode;
> > +#define IPU3_UAPI_OSYS_PROCMODE_BYPASS		0
> > +#define IPU3_UAPI_OSYS_PROCMODE_UPSCALE		1
> > +#define IPU3_UAPI_OSYS_PROCMODE_DOWNSCALE	2
> > +	__u32 scaling_ratio;
> > +	__u32 y_left_phase_init;
> > +	__u32 uv_left_phase_init;
> > +	__u32 y_top_phase_init;
> > +	__u32 uv_top_phase_init;
> > +	__u32 coeffs_exp_shift;
> > +	__u32 out_y_left_crop;
> > +	__u32 out_uv_left_crop;
> > +	__u32 out_y_top_crop;
> > +	__u32 out_uv_top_crop;
> > +} __packed;
> > +
> > +struct ipu3_uapi_osys_scaler {
> > +	struct ipu3_uapi_osys_scaler_params param IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_osys_frame_params {
> > +	/* Output pins */
> > +	__u32 enable;
> > +	__u32 format;			/* enum ipu3_uapi_osys_format */
> > +	__u32 flip;
> > +	__u32 mirror;
> > +	__u32 tiling;			/* enum ipu3_uapi_osys_tiling */
> > +	__u32 width;
> > +	__u32 height;
> > +	__u32 stride;
> > +	__u32 scaled;
> > +} __packed;
> > +
> > +struct ipu3_uapi_osys_frame {
> > +	struct ipu3_uapi_osys_frame_params param IPU3_ALIGN;
> > +} __packed;
> > +
> > +struct ipu3_uapi_osys_stripe {
> > +	/* Input resolution */
> > +	__u32 input_width;
> > +	__u32 input_height;
> > +	/* Output Stripe */
> > +	__u32 output_width[IPU3_UAPI_OSYS_PINS];
> > +	__u32 output_height[IPU3_UAPI_OSYS_PINS];
> > +	__u32 output_offset[IPU3_UAPI_OSYS_PINS];
> > +	__u32 buf_stride[IPU3_UAPI_OSYS_PINS];
> > +	/* Scaler params */
> > +	__u32 block_width;
> > +	__u32 block_height;
> > +	/* Output Crop factor */
> > +	__u32 crop_top[IPU3_UAPI_OSYS_PINS];
> > +	__u32 crop_left[IPU3_UAPI_OSYS_PINS];
> > +} __packed;
> > +
> > +struct ipu3_uapi_osys_config {
> > +	struct ipu3_uapi_osys_formatter
> > +		formatter[IPU3_UAPI_MAX_STRIPES][IPU3_UAPI_OSYS_PINS];
> > +	struct ipu3_uapi_osys_scaler scaler[IPU3_UAPI_MAX_STRIPES];
> > +	struct ipu3_uapi_osys_frame frame[IPU3_UAPI_OSYS_PINS];
> > +	struct ipu3_uapi_osys_stripe stripe[IPU3_UAPI_MAX_STRIPES];
> > +	/* 32 packed coefficients for luma and chroma */
> > +	__s8 scaler_coeffs_chroma[128];
> > +	__s8 scaler_coeffs_luma[128];
> > +} __packed;
> > +
> > +struct ipu3_uapi_acc_param {
> > +	struct ipu3_uapi_stripe_data stripe;
> > +	__u8 padding[8];
> > +	struct ipu3_uapi_input_feeder_config input_feeder;
> > +	struct ipu3_uapi_bnr_static_config bnr;
> > +	struct ipu3_uapi_bnr_static_config_green_disparity green_disparity
> > +		IPU3_ALIGN;
> > +	struct ipu3_uapi_dm_config dm IPU3_ALIGN;
> > +	struct ipu3_uapi_ccm_mat_config ccm IPU3_ALIGN;
> > +	struct ipu3_uapi_gamma_config gamma IPU3_ALIGN;
> > +	struct ipu3_uapi_csc_mat_config csc IPU3_ALIGN;
> > +	struct ipu3_uapi_cds_params cds IPU3_ALIGN;
> > +	struct ipu3_uapi_shd_config shd IPU3_ALIGN;
> > +	struct ipu3_uapi_dvs_stat_config dvs_stat IPU3_ALIGN;
> > +	struct ipu3_uapi_lace_stat_config lace_stat IPU3_ALIGN;
> > +	struct ipu3_uapi_yuvp1_iefd_config iefd IPU3_ALIGN;
> > +	struct ipu3_uapi_yuvp1_yds_config yds_c0 IPU3_ALIGN;
> > +	struct ipu3_uapi_yuvp1_chnr_config chnr_c0 IPU3_ALIGN;
> > +	struct ipu3_uapi_yuvp1_y_ee_nr_config y_ee_nr IPU3_ALIGN;
> > +	struct ipu3_uapi_yuvp1_yds_config yds IPU3_ALIGN;
> > +	struct ipu3_uapi_yuvp1_chnr_config chnr IPU3_ALIGN;
> > +	struct ipu3_uapi_yuvp2_y_tm_lut_static_config ytm IPU3_ALIGN;
> > +	struct ipu3_uapi_yuvp1_yds_config yds2 IPU3_ALIGN;
> > +	struct ipu3_uapi_yuvp2_tcc_static_config tcc IPU3_ALIGN;
> > +	struct ipu3_uapi_dpc_config dpc IPU3_ALIGN;
> > +	struct ipu3_uapi_bds_config bds IPU3_ALIGN;
> > +	struct ipu3_uapi_anr_config anr IPU3_ALIGN;
> > +	struct ipu3_uapi_awb_fr_config awb_fr IPU3_ALIGN;
> > +	struct ipu3_uapi_ae_config ae IPU3_ALIGN;
> > +	struct ipu3_uapi_af_config af IPU3_ALIGN;
> > +	struct ipu3_uapi_awb_config awb IPU3_ALIGN;
> > +	struct ipu3_uapi_osys_config osys IPU3_ALIGN;
> > +} __packed;
> > +
> > +/* Linearization parameters */
> > +
> > +#define IPU3_UAPI_LIN_LUT_SIZE			64
> > +
> > +struct ipu3_uapi_isp_lin_vmem_params {
> > +	__s16 lin_lutlow_gr[IPU3_UAPI_LIN_LUT_SIZE];
> > +	__s16 lin_lutlow_r[IPU3_UAPI_LIN_LUT_SIZE];
> > +	__s16 lin_lutlow_b[IPU3_UAPI_LIN_LUT_SIZE];
> > +	__s16 lin_lutlow_gb[IPU3_UAPI_LIN_LUT_SIZE];
> > +	__s16 lin_lutdif_gr[IPU3_UAPI_LIN_LUT_SIZE];
> > +	__s16 lin_lutdif_r[IPU3_UAPI_LIN_LUT_SIZE];
> > +	__s16 lin_lutdif_b[IPU3_UAPI_LIN_LUT_SIZE];
> > +	__s16 lin_lutdif_gb[IPU3_UAPI_LIN_LUT_SIZE];
> > +} __packed;
> > +
> > +/* TNR3 VMEM parameters */
> > +
> > +#define IPU3_UAPI_ISP_TNR3_VMEM_LEN	9
> > +
> > +struct ipu3_uapi_isp_tnr3_vmem_params {
> > +	__u16 slope[IPU3_UAPI_ISP_TNR3_VMEM_LEN];
> > +	__u16 __reserved1[IPU3_UAPI_ISP_VEC_ELEMS
> > +						-
> IPU3_UAPI_ISP_TNR3_VMEM_LEN];
> > +	__u16 sigma[IPU3_UAPI_ISP_TNR3_VMEM_LEN];
> > +	__u16 __reserved2[IPU3_UAPI_ISP_VEC_ELEMS
> > +						-
> IPU3_UAPI_ISP_TNR3_VMEM_LEN];
> > +} __packed;
> > +
> > +/* XNR3 VMEM parameters */
> > +
> > +struct ipu3_uapi_isp_xnr3_vmem_params {
> > +	__u16 x[IPU3_UAPI_ISP_VEC_ELEMS];
> > +	__u16 a[IPU3_UAPI_ISP_VEC_ELEMS];
> > +	__u16 b[IPU3_UAPI_ISP_VEC_ELEMS];
> > +	__u16 c[IPU3_UAPI_ISP_VEC_ELEMS];
> > +} __packed;
> > +
> > +/* TNR3 DMEM parameters */
> > +
> > +struct ipu3_uapi_isp_tnr3_params {
> > +	__u32 knee_y1;
> > +	__u32 knee_y2;
> > +	__u32 maxfb_y;
> > +	__u32 maxfb_u;
> > +	__u32 maxfb_v;
> > +	__u32 round_adj_y;
> > +	__u32 round_adj_u;
> > +	__u32 round_adj_v;
> > +	__u32 ref_buf_select;
> > +} __packed;
> > +
> > +/* XNR3 DMEM parameters */
> > +
> > +struct ipu3_uapi_xnr3_alpha_params {
> > +	__u32 y0;
> > +	__u32 u0;
> > +	__u32 v0;
> > +	__u32 ydiff;
> > +	__u32 udiff;
> > +	__u32 vdiff;
> > +} __packed;
> > +
> > +struct ipu3_uapi_xnr3_coring_params {
> > +	__u32 u0;
> > +	__u32 v0;
> > +	__u32 udiff;
> > +	__u32 vdiff;
> > +} __packed;
> > +
> > +struct ipu3_uapi_xnr3_blending_params {
> > +	__u32 strength;
> > +} __packed;
> > +
> > +struct ipu3_uapi_isp_xnr3_params {
> > +	struct ipu3_uapi_xnr3_alpha_params alpha;
> > +	struct ipu3_uapi_xnr3_coring_params coring;
> > +	struct ipu3_uapi_xnr3_blending_params blending;
> > +} __packed;
> > +
> > +/* RGBIR DMEM parameters */
> > +
> > +#define IPU3_UAPI_RGBIR_LUT_WIDTH	17
> > +#define IPU3_UAPI_RGBIR_LUT_HEIGHT	10
> > +#define IPU3_UAPI_RGBIR_LUT_SIZE	(IPU3_UAPI_RGBIR_LUT_WIDTH * \
> > +					 IPU3_UAPI_RGBIR_LUT_HEIGHT)
> > +
> > +struct ipu3_uapi_isp_rgbir_params {
> > +	__u16 ob;					/* optical black
> level*/
> > +	__u16 ir_height;				/* lut table height */
> > +	__u16 ir_width;					/* lut table width */
> > +	__u16 ir_weights_r[IPU3_UAPI_RGBIR_LUT_SIZE];	/* lut values
> for red */
> > +	__u16 ir_weights_g[IPU3_UAPI_RGBIR_LUT_SIZE];	/* lut for
> green */
> > +	__u16 ir_weights_b[IPU3_UAPI_RGBIR_LUT_SIZE];	/* lut for blue
> */
> > +	__u16 ir_gain;					/* digital gain */
> > +} __packed;
> > +
> > +/***** Morphing table entry *****/
> > +
> > +#define IPU3_UAPI_GDC_FRAC_BITS		8
> > +
> > +struct ipu3_uapi_gdc_warp_param {
> > +	__u32 origin_x;
> > +	__u32 origin_y;
> > +	__u32 in_addr_offset;
> > +	__u32 in_block_width;
> > +	__u32 in_block_height;
> > +	__u32 p0_x;
> > +	__u32 p0_y;
> > +	__u32 p1_x;
> > +	__u32 p1_y;
> > +	__u32 p2_x;
> > +	__u32 p2_y;
> > +	__u32 p3_x;
> > +	__u32 p3_y;
> > +	__u32 in_block_width_a;
> > +	__u32 in_block_width_b;
> > +	__u32 padding;			/* struct size multiple of DDR word */
> > +} __packed;
> > +
> > +/***** Obgrid (optical black level compensation) table entry *****/
> > +
> > +struct ipu3_uapi_obgrid_param {
> > +	__u16 gr;
> > +	__u16 r;
> > +	__u16 b;
> > +	__u16 gb;
> > +} __packed;
> > +
> > +/******************* V4L2_PIX_FMT_IPU3_PARAMS
> *******************/
> > +
> > +/*
> > + * The video queue "parameters" is of format
> V4L2_PIX_FMT_IPU3_PARAMS.
> > + * It is a multiplanar output queue with three planes and type
> > + * V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE. User may also configure the
> > + * video queue as V4L2_BUF_TYPE_VIDEO_OUTPUT with a single plane, in
> which
> > + * case GDC and Obgrid tables can not be set.
> > + *
> > + * Plane 0: Defined below in struct ipu3_params, size 288064 bytes.
> > + *          This contains a lot of parameters and flags selecting which
> > + *          parameters to apply. Its size and resolution (1x1) are fixed.
> > + *
> > + * Plane 1: Contains geometric distortion correction grid coordinates.
> > + *          Each entry in the grid is defined in
> > + *          struct ipu3_uapi_gdc_warp_param.
> > + *          The plane size is the grid entry size times the number of entries,
> > + *          which depends on the main output image resolution and block size.
> > + *
> > + * Plane 2: Contains Obgrid grid. Each entry in the grid is 8 bytes.
> > + *          The plane size depends on user parameters (internally, on chosen
> > + *          firmware binary which depends on user parameters).
> > + */
> > +
> > +struct ipu3_uapi_flags {
> > +	/* Flags which of the settings below are to be applied */
> > +	__u32 gdc:1;		/* Whether to apply GDC and */
> > +	__u32 obgrid:1;		/* Obgrid planes */
> > +	__u32 __reserved1:30;
> > +
> > +	__u32 __acc_stripe:1;	/* Whether to apply these fields from */
> > +	__u32 __acc_input_feeder:1;	/* acc_param. Fields beginning with
> */
> > +	__u32 acc_bnr:1;		/* two underscores are reserved and
> */
> > +	__u32 acc_green_disparity:1;/* must not be enabled */
> > +	__u32 acc_dm:1;
> > +	__u32 acc_ccm:1;
> > +	__u32 acc_gamma:1;
> > +	__u32 acc_csc:1;
> > +	__u32 acc_cds:1;
> > +	__u32 acc_shd:1;
> > +	__u32 acc_dvs_stat:1;
> > +	__u32 acc_lace_stat:1;
> > +	__u32 acc_iefd:1;
> > +	__u32 acc_yds_c0:1;
> > +	__u32 acc_chnr_c0:1;
> > +	__u32 acc_y_ee_nr:1;
> > +	__u32 acc_yds:1;
> > +	__u32 acc_chnr:1;
> > +	__u32 acc_ytm:1;
> > +	__u32 acc_yds2:1;
> > +	__u32 acc_tcc:1;
> > +	__u32 acc_dpc:1;
> > +	__u32 acc_bds:1;
> > +	__u32 acc_anr:1;
> > +	__u32 acc_awb_fr:1;
> > +	__u32 acc_ae:1;
> > +	__u32 acc_af:1;
> > +	__u32 acc_awb:1;
> > +	__u32 __acc_osys:1;
> > +	__u32 __reserved2:3;
> > +
> > +	__u32 lin_vmem_params:1;	/* Whether to apply these structs */
> > +	__u32 tnr3_vmem_params:1;
> > +	__u32 xnr3_vmem_params:1;
> > +	__u32 tnr3_dmem_params:1;
> > +	__u32 xnr3_dmem_params:1;
> > +	__u32 __rgbir_dmem_params:1;
> > +	__u32 obgrid_param:1;
> > +	__u32 __reserved3:25;
> > +} __packed;
> > +
> > +struct ipu3_uapi_params {
> > +	__u32 fourcc;			/* V4L2_PIX_FMT_IPU3_PARAMS */
> > +	__u32 version;			/* Must be 0x100 */
> 
> These were called padding1 and padding2 in the previous version. What
> happened?
> 
> I'd just call them reserved, and maybe also make the use field the first
> member of the struct.
> 

These fields were repurposed after v3 of this patch series. Please see the user space code that uses these fields.
https://chromium.googlesource.com/chromiumos/platform/arc-camera/+/master/hal/intel/psl/ipu3/workers/IPU3AicToFwEncoder.cpp

> > +
> > +	struct ipu3_uapi_flags use;
> > +
> > +	__u8 __reserved4[32 - 4 * 5];	/* Must be zero */
> 
> 32 - sizeof(struct ipu3_uapi_flags) - sizeof(__u32) * 2
> 
> ?

Ack

> 
> > +
> > +	/* Acceleration cluster parameters */
> > +	struct ipu3_uapi_acc_param acc_param;
> > +
> > +	/* VMEM parameters */
> > +	struct ipu3_uapi_isp_lin_vmem_params lin_vmem_params;
> > +	struct ipu3_uapi_isp_tnr3_vmem_params tnr3_vmem_params;
> > +	struct ipu3_uapi_isp_xnr3_vmem_params xnr3_vmem_params;
> > +
> > +	/* DMEM parameters */
> > +	struct ipu3_uapi_isp_tnr3_params tnr3_dmem_params;
> > +	struct ipu3_uapi_isp_xnr3_params xnr3_dmem_params;
> > +	struct ipu3_uapi_isp_rgbir_params rgbir_dmem_params;
> > +
> > +	struct ipu3_uapi_obgrid_param obgrid_param;
> > +	__u8 padding[4];
> > +} __packed;
> 
> Good to see everything is __packed now. How much there is currently actual
> need for IPU3_ALIGN? Could you remover that as well?
> 

IPU3_ALIGN (32 byte alignment) is needed for data structures that are used by the ImgU for DMA accesses.

However, I can remove IPU3_ALIGN for fields where it is redundant (which are already 32 byte aligned).

> > +
> > +#endif
> 
> --
> Regards,
> 
> Sakari Ailus
> e-mail: sakari.ailus@iki.fi

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v4 10/12] intel-ipu3: css pipeline
  2017-11-10 22:35     ` Zhi, Yong
@ 2017-11-13 13:26       ` Sakari Ailus
  0 siblings, 0 replies; 19+ messages in thread
From: Sakari Ailus @ 2017-11-13 13:26 UTC (permalink / raw)
  To: Zhi, Yong
  Cc: linux-media, sakari.ailus, Zheng, Jian Xu, Mani, Rajmohan,
	Toivonen, Tuukka, Hu, Jerry W

Hi Yong,

On Fri, Nov 10, 2017 at 10:35:43PM +0000, Zhi, Yong wrote:
> Hi, Sakari,
> 
> Thanks for the review.
> 
> > -----Original Message-----
> > From: linux-media-owner@vger.kernel.org [mailto:linux-media-
> > owner@vger.kernel.org] On Behalf Of Sakari Ailus
> > Sent: Wednesday, November 1, 2017 11:57 AM
> > To: Zhi, Yong <yong.zhi@intel.com>
> > Cc: linux-media@vger.kernel.org; sakari.ailus@linux.intel.com; Zheng, Jian
> > Xu <jian.xu.zheng@intel.com>; Mani, Rajmohan
> > <rajmohan.mani@intel.com>; Toivonen, Tuukka
> > <tuukka.toivonen@intel.com>; Hu, Jerry W <jerry.w.hu@intel.com>
> > Subject: Re: [PATCH v4 10/12] intel-ipu3: css pipeline
> > 
> > Hi Yong,
> > 
> > Apologies for the late reply. Please find my (few) comments below.
> > 
> > On Tue, Oct 17, 2017 at 10:54:55PM -0500, Yong Zhi wrote:
> > > Add css pipeline and v4l code.
> > >
> > > Signed-off-by: Yong Zhi <yong.zhi@intel.com>
> > > ---
> > >  drivers/media/pci/intel/ipu3/ipu3-css.c | 1761
> > ++++++++++++++++++++++++++++++-
> > >  drivers/media/pci/intel/ipu3/ipu3-css.h |   89 ++
> > >  2 files changed, 1849 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/media/pci/intel/ipu3/ipu3-css.c
> > b/drivers/media/pci/intel/ipu3/ipu3-css.c
> > > index 6e615bf9378a..11f7ad3514c3 100644
> > > --- a/drivers/media/pci/intel/ipu3/ipu3-css.c
> > > +++ b/drivers/media/pci/intel/ipu3/ipu3-css.c
> > > @@ -13,9 +13,16 @@
> 
> (snip)
> 
> > > +static bool ipu3_css_queue_enabled(struct ipu3_css_queue *q)
> > > +{
> > > +	return !!q->css_fmt;
> > 
> > No need for !!.
> > 
> 
> The original code "return q->css_fmt !=NULL;" is more explicit, I changed
> to the current form to silent checkpatch.pl CHECK for null comparison.

Ok. You're still basically checking whether it's non-NULL, and casting an
non-zero value to bool converts it as true. So you don't need !!.

> 
> > > +}
> > > +
> > >  /******************* css hw *******************/
> > >
> 
> (snip)
> 
> > > +	/* Configure SP group */
> > > +
> > > +	sp_group = css->xmem_sp_group_ptrs.vaddr;
> > > +	memset(sp_group, 0, sizeof(*sp_group));
> > > +
> > > +	sp_group->pipe[thread].num_stages = 1;
> > > +	sp_group->pipe[thread].pipe_id = PIPE_ID;
> > > +	sp_group->pipe[thread].thread_id = thread;
> > > +	sp_group->pipe[thread].pipe_num = pipe;
> > > +	sp_group->pipe[thread].num_execs = -1;
> > > +	sp_group->pipe[thread].pipe_qos_config = -1;
> > > +	sp_group->pipe[thread].required_bds_factor = 0;
> > > +	sp_group->pipe[thread].dvs_frame_delay = IPU3_CSS_AUX_FRAMES
> > - 1;
> > > +	sp_group->pipe[thread].inout_port_config =
> > > +	    IMGU_ABI_PORT_CONFIG_TYPE_INPUT_HOST |
> > > +	    IMGU_ABI_PORT_CONFIG_TYPE_OUTPUT_HOST;
> > 
> > Indentation. Most of this seems to have been fixed but some remains in this
> > patch at least. Could you address that for the next version, please?
> 
> Yes, will fix all indentation in next version.
> 
> > 
> > > +	sp_group->pipe[thread].scaler_pp_lut = 0;
> > > +	sp_group-
> > >pipe[thread].shading.internal_frame_origin_x_bqs_on_sctbl = 0;
> > > +	sp_group-
> > >pipe[thread].shading.internal_frame_origin_y_bqs_on_sctbl = 0;
> > > +	sp_group->pipe[thread].sp_stage_addr[stage] =
> > > +	    css->xmem_sp_stage_ptrs[pipe][stage].daddr;
> > > +	sp_group->pipe[thread].pipe_config =
> > > +	    bi->info.isp.sp.enable.params ? (1 << thread) : 0;
> 
> (snip)
> 
> > > +int ipu3_css_set_parameters(struct ipu3_css *css,
> > > +			    struct ipu3_uapi_params *set_params,
> > > +			    struct ipu3_uapi_gdc_warp_param *set_gdc,
> > > +			    unsigned int gdc_bytes,
> > > +			    struct ipu3_uapi_obgrid_param *set_obgrid,
> > > +			    unsigned int obgrid_bytes)
> > > +{
> > > +	static const unsigned int queue_id = IMGU_ABI_QUEUE_A_ID;
> > > +	const int stage = 0, thread = 0;
> > > +	const struct imgu_fw_info *bi;
> > > +	int obgrid_size;
> > > +	unsigned int stripes;
> > > +	struct ipu3_uapi_flags *use = set_params ? &set_params->use : NULL;
> > > +
> > > +	/* Destination buffers which are filled here */
> > > +	struct imgu_abi_parameter_set_info *param_set;
> > > +	struct ipu3_uapi_acc_param *acc = NULL;
> > > +	struct ipu3_uapi_gdc_warp_param *gdc = NULL;
> > > +	struct ipu3_uapi_obgrid_param *obgrid = NULL;
> > > +	const struct ipu3_css_map *map;
> > > +	void *vmem0 = NULL;
> > > +	void *dmem0 = NULL;
> > > +
> > > +	enum imgu_abi_memories m;
> > > +	int r = -EBUSY;
> > > +	int s;
> > > +
> > > +	if (!css->streaming)
> > > +		return -EPROTO;
> > > +
> > > +	bi = &css->fwp->binary_header[css->current_binary];
> > > +	obgrid_size = ipu3_css_fw_obgrid_size(bi);
> > > +	stripes = bi->info.isp.sp.iterator.num_stripes ? : 1;
> > > +
> > > +	/*
> > > +	 * Check that we can get a new parameter_set_info from the pool.
> > > +	 * If this succeeds, then all of the other pool_get() calls below
> > > +	 * should also succeed.
> > > +	 */
> > > +	if (ipu3_css_pool_get(&css->pool.parameter_set_info, css->frame) <
> > 0)
> > > +		goto fail_no_put;
> > 
> > The size of the pool is always four. If there were four parameter buffers
> > queued, this would fails, wouldn't it? And that would lead to a failure in
> > queueing the buffer, too, right?
> > 
> > How about associating a kernel-only buffer with each parameter buffer?
> > 
> 
> I learned from the engineer who knows the use pattern of above API
> between user space and kernel, that the size of the pool is rather safe,
> Queuing parameter failure should not happen under normal condition.

>From the API point of view the limit is still arbitrary. You could address
this at least by either limit the number of buffers to four, or increasing
the number of pool buffers. The internal logic could be changed, too, so
that the parameters are copied just before sending the buffers to the
device for processing. That's same some memory, too.

-- 
Kind regards,

Sakari Ailus
e-mail: sakari.ailus@iki.fi

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v4 04/12] intel-ipu3: Add user space ABI definitions
  2017-11-11  4:07   ` Mani, Rajmohan
@ 2017-11-21 17:21     ` sakari.ailus
  2017-12-02  0:00       ` Mani, Rajmohan
  0 siblings, 1 reply; 19+ messages in thread
From: sakari.ailus @ 2017-11-21 17:21 UTC (permalink / raw)
  To: Mani, Rajmohan
  Cc: Sakari Ailus, Zhi, Yong, linux-media, Zheng, Jian Xu, Toivonen,
	Tuukka, Hu, Jerry W

Hi Rajmohan,

My apologies for the late reply.

On Sat, Nov 11, 2017 at 04:07:22AM +0000, Mani, Rajmohan wrote:
> Hi Sakari,
> 
> > -----Original Message-----
> > From: Sakari Ailus [mailto:sakari.ailus@iki.fi]
> > Sent: Friday, October 20, 2017 2:30 AM
> > To: Zhi, Yong <yong.zhi@intel.com>
> > Cc: linux-media@vger.kernel.org; sakari.ailus@linux.intel.com; Zheng, Jian Xu
> > <jian.xu.zheng@intel.com>; Mani, Rajmohan <rajmohan.mani@intel.com>;
> > Toivonen, Tuukka <tuukka.toivonen@intel.com>; Hu, Jerry W
> > <jerry.w.hu@intel.com>
> > Subject: Re: [PATCH v4 04/12] intel-ipu3: Add user space ABI definitions
> > 
> > Hi Yong,
> > 
> > On Tue, Oct 17, 2017 at 10:54:49PM -0500, Yong Zhi wrote:

...

> > > +struct ipu3_uapi_params {
> > > +	__u32 fourcc;			/* V4L2_PIX_FMT_IPU3_PARAMS */
> > > +	__u32 version;			/* Must be 0x100 */
> > 
> > These were called padding1 and padding2 in the previous version. What
> > happened?
> > 
> > I'd just call them reserved, and maybe also make the use field the first
> > member of the struct.
> > 
> 
> These fields were repurposed after v3 of this patch series. Please see the user space code that uses these fields.
> https://chromium.googlesource.com/chromiumos/platform/arc-camera/+/master/hal/intel/psl/ipu3/workers/IPU3AicToFwEncoder.cpp

They were fourcc and version in the beginning, and then replaced by
padding1 and padding 2. Is there a particular reason for changing them
back?

-- 
Sakari Ailus
sakari.ailus@linux.intel.com

^ permalink raw reply	[flat|nested] 19+ messages in thread

* RE: [PATCH v4 04/12] intel-ipu3: Add user space ABI definitions
  2017-11-21 17:21     ` sakari.ailus
@ 2017-12-02  0:00       ` Mani, Rajmohan
  0 siblings, 0 replies; 19+ messages in thread
From: Mani, Rajmohan @ 2017-12-02  0:00 UTC (permalink / raw)
  To: sakari.ailus
  Cc: Sakari Ailus, Zhi, Yong, linux-media, Zheng, Jian Xu, Toivonen,
	Tuukka, Hu, Jerry W

Hi Sakari,

> -----Original Message-----
> From: sakari.ailus@linux.intel.com [mailto:sakari.ailus@linux.intel.com]
> Sent: Tuesday, November 21, 2017 9:22 AM
> To: Mani, Rajmohan <rajmohan.mani@intel.com>
> Cc: Sakari Ailus <sakari.ailus@iki.fi>; Zhi, Yong <yong.zhi@intel.com>; linux-
> media@vger.kernel.org; Zheng, Jian Xu <jian.xu.zheng@intel.com>; Toivonen,
> Tuukka <tuukka.toivonen@intel.com>; Hu, Jerry W <jerry.w.hu@intel.com>
> Subject: Re: [PATCH v4 04/12] intel-ipu3: Add user space ABI definitions
> 
> Hi Rajmohan,
> 
> My apologies for the late reply.
> 
> On Sat, Nov 11, 2017 at 04:07:22AM +0000, Mani, Rajmohan wrote:
> > Hi Sakari,
> >
> > > -----Original Message-----
> > > From: Sakari Ailus [mailto:sakari.ailus@iki.fi]
> > > Sent: Friday, October 20, 2017 2:30 AM
> > > To: Zhi, Yong <yong.zhi@intel.com>
> > > Cc: linux-media@vger.kernel.org; sakari.ailus@linux.intel.com;
> > > Zheng, Jian Xu <jian.xu.zheng@intel.com>; Mani, Rajmohan
> > > <rajmohan.mani@intel.com>; Toivonen, Tuukka
> > > <tuukka.toivonen@intel.com>; Hu, Jerry W <jerry.w.hu@intel.com>
> > > Subject: Re: [PATCH v4 04/12] intel-ipu3: Add user space ABI
> > > definitions
> > >
> > > Hi Yong,
> > >
> > > On Tue, Oct 17, 2017 at 10:54:49PM -0500, Yong Zhi wrote:
> 
> ...
> 
> > > > +struct ipu3_uapi_params {
> > > > +	__u32 fourcc;			/* V4L2_PIX_FMT_IPU3_PARAMS */
> > > > +	__u32 version;			/* Must be 0x100 */
> > >
> > > These were called padding1 and padding2 in the previous version.
> > > What happened?
> > >
> > > I'd just call them reserved, and maybe also make the use field the
> > > first member of the struct.
> > >
> >
> > These fields were repurposed after v3 of this patch series. Please see the user
> space code that uses these fields.
> > https://chromium.googlesource.com/chromiumos/platform/arc-
> camera/+/mas
> > ter/hal/intel/psl/ipu3/workers/IPU3AicToFwEncoder.cpp
> 
> They were fourcc and version in the beginning, and then replaced by
> padding1 and padding 2. Is there a particular reason for changing them back?
> 

We looked into this further to see that we have no compelling reasons to use these variables.
I will revert these names back to padding1 and padding2, along with the required user space code changes.

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2017-12-02  0:00 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-10-18  3:54 [PATCH v4 04/12] intel-ipu3: Add user space ABI definitions Yong Zhi
2017-10-18  3:54 ` [PATCH v4 06/12] intel-ipu3: css: imgu dma buff pool Yong Zhi
2017-10-20 10:38   ` Sakari Ailus
2017-10-23  3:10     ` Zhi, Yong
2017-10-18  3:54 ` [PATCH v4 07/12] intel-ipu3: css: firmware management Yong Zhi
2017-10-18  3:54 ` [PATCH v4 08/12] intel-ipu3: params: compute and program ccs Yong Zhi
2017-10-18  3:54 ` [PATCH v4 09/12] intel-ipu3: css hardware setup Yong Zhi
2017-10-18  3:54 ` [PATCH v4 10/12] intel-ipu3: css pipeline Yong Zhi
2017-11-01 18:57   ` Sakari Ailus
2017-11-10 22:35     ` Zhi, Yong
2017-11-13 13:26       ` Sakari Ailus
2017-10-18  3:54 ` [PATCH v4 11/12] intel-ipu3: Add imgu v4l2 driver Yong Zhi
2017-10-20 11:29   ` Sakari Ailus
2017-10-23 22:41     ` Zhi, Yong
2017-11-02  8:43       ` Sakari Ailus
2017-10-20  9:30 ` [PATCH v4 04/12] intel-ipu3: Add user space ABI definitions Sakari Ailus
2017-11-11  4:07   ` Mani, Rajmohan
2017-11-21 17:21     ` sakari.ailus
2017-12-02  0:00       ` Mani, Rajmohan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).