lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <19e01dcf-64d3-0c7c-c307-f50d67d59dfb@linaro.org>
Date:   Sat, 20 Feb 2021 21:35:07 +0300
From:   Andrey Konovalov <andrey.konovalov@...aro.org>
To:     Robert Foss <robert.foss@...aro.org>, agross@...nel.org,
        bjorn.andersson@...aro.org, todor.too@...il.com,
        mchehab@...nel.org, robh+dt@...nel.org,
        angelogioacchino.delregno@...ainline.org,
        linux-arm-msm@...r.kernel.org, linux-media@...r.kernel.org,
        devicetree@...r.kernel.org, linux-kernel@...r.kernel.org,
        AngeloGioacchino Del Regno <kholk11@...il.com>,
        Sakari Ailus <sakari.ailus@....fi>,
        Nicolas Boichat <drinkcat@...omium.org>
Cc:     Rob Herring <robh@...nel.org>, Tomasz Figa <tfiga@...omium.org>,
        Azam Sadiq Pasha Kapatrala Syed <akapatra@...cinc.com>,
        Sarvesh Sridutt <Sarvesh.Sridutt@...rtwirelesscompute.com>,
        Laurent Pinchart <laurent.pinchart@...asonboard.com>,
        Jonathan Marek <jonathan@...ek.ca>
Subject: Re: [PATCH v5 06/22] media: camss: Refactor VFE HW version support

Hi Robert,

Thank you for your patch!

Just two minor comments below.

On 17.02.2021 14:21, Robert Foss wrote:
> In order to support Qualcomm ISP hardware architectures that diverge
> from older architectures, the VFE subdevice driver needs to be refactored
> to better abstract the different ISP architectures.
> 
> Gen1 represents the CAMSS ISP architecture. The ISP architecture developed
> after CAMSS, Titan, will be referred to as Gen2.
> 
> Signed-off-by: Robert Foss <robert.foss@...aro.org>
> ---
> 
> 
> Changes since v1
>   - kernel test robot: Re-add chunk missing from
>     vfe_output_update_pong_addr
>   - Andrey: Fix file name error
>   - Andrey: Change hardware version number in comment
>   - Changed copyright year to 2021 for camss-vfe-4-8.c
> 
> Changes since v3:
>   - Nicolas: Replace trace_printk() with dev_dbg()
>   - Removed spurious whitespace
> 
> Changes since v4:
>   - Andrey: Refactor to make PIX support optional
> 
> 
>   drivers/media/platform/qcom/camss/Makefile    |    2 +
>   .../media/platform/qcom/camss/camss-vfe-4-1.c |  118 +-
>   .../media/platform/qcom/camss/camss-vfe-4-7.c |  239 ++--
>   .../media/platform/qcom/camss/camss-vfe-4-8.c | 1166 +++++++++++++++++
>   .../platform/qcom/camss/camss-vfe-gen1.c      |  763 +++++++++++
>   .../platform/qcom/camss/camss-vfe-gen1.h      |  110 ++
>   drivers/media/platform/qcom/camss/camss-vfe.c |  790 +----------
>   drivers/media/platform/qcom/camss/camss-vfe.h |  121 +-
>   drivers/media/platform/qcom/camss/camss.c     |    4 +-
>   9 files changed, 2263 insertions(+), 1050 deletions(-)
>   create mode 100644 drivers/media/platform/qcom/camss/camss-vfe-4-8.c
>   create mode 100644 drivers/media/platform/qcom/camss/camss-vfe-gen1.c
>   create mode 100644 drivers/media/platform/qcom/camss/camss-vfe-gen1.h
> 
> diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile
> index 63c1b1b2943c..940c0ae3e003 100644
> --- a/drivers/media/platform/qcom/camss/Makefile
> +++ b/drivers/media/platform/qcom/camss/Makefile
> @@ -10,6 +10,8 @@ qcom-camss-objs += \
>   		camss-ispif.o \
>   		camss-vfe-4-1.o \
>   		camss-vfe-4-7.o \
> +		camss-vfe-4-8.o \
> +		camss-vfe-gen1.o \
>   		camss-vfe.o \
>   		camss-video.o \
>   
> diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
> index 85b9bcbc7321..81756d7fd5c2 100644
> --- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
> +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
> @@ -14,6 +14,7 @@
>   
>   #include "camss.h"
>   #include "camss-vfe.h"
> +#include "camss-vfe-gen1.h"
>   
>   #define VFE_0_HW_VERSION		0x000
>   
> @@ -284,30 +285,6 @@ static void vfe_wm_frame_based(struct vfe_device *vfe, u8 wm, u8 enable)
>   			1 << VFE_0_BUS_IMAGE_MASTER_n_WR_CFG_FRM_BASED_SHIFT);
>   }
>   
> -#define CALC_WORD(width, M, N) (((width) * (M) + (N) - 1) / (N))
> -
> -static int vfe_word_per_line(u32 format, u32 pixel_per_line)
> -{
> -	int val = 0;
> -
> -	switch (format) {
> -	case V4L2_PIX_FMT_NV12:
> -	case V4L2_PIX_FMT_NV21:
> -	case V4L2_PIX_FMT_NV16:
> -	case V4L2_PIX_FMT_NV61:
> -		val = CALC_WORD(pixel_per_line, 1, 8);
> -		break;
> -	case V4L2_PIX_FMT_YUYV:
> -	case V4L2_PIX_FMT_YVYU:
> -	case V4L2_PIX_FMT_UYVY:
> -	case V4L2_PIX_FMT_VYUY:
> -		val = CALC_WORD(pixel_per_line, 2, 8);
> -		break;
> -	}
> -
> -	return val;
> -}
> -
>   static void vfe_get_wm_sizes(struct v4l2_pix_format_mplane *pix, u8 plane,
>   			     u16 *width, u16 *height, u16 *bytesperline)
>   {
> @@ -666,20 +643,6 @@ static void vfe_set_demux_cfg(struct vfe_device *vfe, struct vfe_line *line)
>   	writel_relaxed(odd_cfg, vfe->base + VFE_0_DEMUX_ODD_CFG);
>   }
>   
> -static inline u8 vfe_calc_interp_reso(u16 input, u16 output)
> -{
> -	if (input / output >= 16)
> -		return 0;
> -
> -	if (input / output >= 8)
> -		return 1;
> -
> -	if (input / output >= 4)
> -		return 2;
> -
> -	return 3;
> -}
> -
>   static void vfe_set_scale_cfg(struct vfe_device *vfe, struct vfe_line *line)
>   {
>   	u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat;
> @@ -975,46 +938,63 @@ static irqreturn_t vfe_isr(int irq, void *dev)
>   	return IRQ_HANDLED;
>   }
>   
> -const struct vfe_hw_ops vfe_ops_4_1 = {
> -	.hw_version_read = vfe_hw_version_read,
> +
> +const struct vfe_hw_ops_gen1 vfe_ops_gen1_4_1 = {
> +	.bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi,
> +	.bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi,
> +	.bus_enable_wr_if = vfe_bus_enable_wr_if,
> +	.bus_reload_wm = vfe_bus_reload_wm,
> +	.camif_wait_for_stop = vfe_camif_wait_for_stop,
> +	.enable_irq_common = vfe_enable_irq_common,
> +	.enable_irq_pix_line = vfe_enable_irq_pix_line,
> +	.enable_irq_wm_line = vfe_enable_irq_wm_line,
>   	.get_ub_size = vfe_get_ub_size,
> -	.global_reset = vfe_global_reset,
> -	.halt_request = vfe_halt_request,
>   	.halt_clear = vfe_halt_clear,
> +	.halt_request = vfe_halt_request,
> +	.set_camif_cfg = vfe_set_camif_cfg,
> +	.set_camif_cmd = vfe_set_camif_cmd,
> +	.set_cgc_override = vfe_set_cgc_override,
> +	.set_clamp_cfg = vfe_set_clamp_cfg,
> +	.set_crop_cfg = vfe_set_crop_cfg,
> +	.set_demux_cfg = vfe_set_demux_cfg,
> +	.set_ds = vfe_set_ds,
> +	.set_module_cfg = vfe_set_module_cfg,
> +	.set_qos = vfe_set_qos,
> +	.set_rdi_cid = vfe_set_rdi_cid,
> +	.set_realign_cfg = vfe_set_realign_cfg,
> +	.set_scale_cfg = vfe_set_scale_cfg,
> +	.set_xbar_cfg = vfe_set_xbar_cfg,
>   	.wm_enable = vfe_wm_enable,
>   	.wm_frame_based = vfe_wm_frame_based,
> +	.wm_get_ping_pong_status = vfe_wm_get_ping_pong_status,
>   	.wm_line_based = vfe_wm_line_based,
> -	.wm_set_framedrop_period = vfe_wm_set_framedrop_period,
>   	.wm_set_framedrop_pattern = vfe_wm_set_framedrop_pattern,
> -	.wm_set_ub_cfg = vfe_wm_set_ub_cfg,
> -	.bus_reload_wm = vfe_bus_reload_wm,
> +	.wm_set_framedrop_period = vfe_wm_set_framedrop_period,
>   	.wm_set_ping_addr = vfe_wm_set_ping_addr,
>   	.wm_set_pong_addr = vfe_wm_set_pong_addr,
> -	.wm_get_ping_pong_status = vfe_wm_get_ping_pong_status,
> -	.bus_enable_wr_if = vfe_bus_enable_wr_if,
> -	.bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi,
>   	.wm_set_subsample = vfe_wm_set_subsample,
> -	.bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi,
> -	.set_xbar_cfg = vfe_set_xbar_cfg,
> -	.set_realign_cfg = vfe_set_realign_cfg,
> -	.set_rdi_cid = vfe_set_rdi_cid,
> -	.reg_update = vfe_reg_update,
> -	.reg_update_clear = vfe_reg_update_clear,
> -	.enable_irq_wm_line = vfe_enable_irq_wm_line,
> -	.enable_irq_pix_line = vfe_enable_irq_pix_line,
> -	.enable_irq_common = vfe_enable_irq_common,
> -	.set_demux_cfg = vfe_set_demux_cfg,
> -	.set_scale_cfg = vfe_set_scale_cfg,
> -	.set_crop_cfg = vfe_set_crop_cfg,
> -	.set_clamp_cfg = vfe_set_clamp_cfg,
> -	.set_qos = vfe_set_qos,
> -	.set_ds = vfe_set_ds,
> -	.set_cgc_override = vfe_set_cgc_override,
> -	.set_camif_cfg = vfe_set_camif_cfg,
> -	.set_camif_cmd = vfe_set_camif_cmd,
> -	.set_module_cfg = vfe_set_module_cfg,
> -	.camif_wait_for_stop = vfe_camif_wait_for_stop,
> +	.wm_set_ub_cfg = vfe_wm_set_ub_cfg,
> +};
> +
> +static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe)
> +{
> +	vfe->isr_ops = vfe_isr_ops_gen1;
> +	vfe->ops_gen1 = &vfe_ops_gen1_4_1;
> +	vfe->video_ops = vfe_video_ops_gen1;
> +
> +	vfe->line_num = VFE_LINE_NUM_GEN1;
> +}
> +
> +const struct vfe_hw_ops vfe_ops_4_1 = {
> +	.global_reset = vfe_global_reset,
> +	.hw_version_read = vfe_hw_version_read,
>   	.isr_read = vfe_isr_read,
> -	.violation_read = vfe_violation_read,
>   	.isr = vfe_isr,
> +	.reg_update_clear = vfe_reg_update_clear,
> +	.reg_update = vfe_reg_update,
> +	.subdev_init = vfe_subdev_init,
> +	.vfe_disable = vfe_gen1_disable,
> +	.vfe_enable = vfe_gen1_enable,
> +	.vfe_halt = vfe_gen1_halt,
> +	.violation_read = vfe_violation_read,
>   };
> diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
> index f7e00a2de393..a3f31f38dfed 100644
> --- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
> +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
> @@ -14,6 +14,8 @@
>   
>   #include "camss.h"
>   #include "camss-vfe.h"
> +#include "camss-vfe-gen1.h"
> +
>   
>   #define VFE_0_HW_VERSION		0x000
>   
> @@ -258,7 +260,7 @@ static void vfe_hw_version_read(struct vfe_device *vfe, struct device *dev)
>   	dev_err(dev, "VFE HW Version = 0x%08x\n", hw_version);
>   }
>   
> -static u16 vfe47_get_ub_size(u8 vfe_id)
> +static u16 vfe_get_ub_size(u8 vfe_id)
>   {
>   	if (vfe_id == 0)
>   		return MSM_VFE_VFE0_UB_SIZE_RDI;
> @@ -296,6 +298,8 @@ static void vfe_global_reset(struct vfe_device *vfe)
>   			 VFE_0_GLOBAL_RESET_CMD_CORE;
>   
>   	writel_relaxed(BIT(31), vfe->base + VFE_0_IRQ_MASK_0);
> +
> +	/* Enforce barrier between IRQ mask setup and global reset */
>   	wmb();
>   	writel_relaxed(reset_bits, vfe->base + VFE_0_GLOBAL_RESET_CMD);
>   }
> @@ -311,7 +315,7 @@ static void vfe_halt_clear(struct vfe_device *vfe)
>   	writel_relaxed(0x0, vfe->base + VFE_0_BUS_BDG_CMD);
>   }
>   
> -static void vfe47_wm_enable(struct vfe_device *vfe, u8 wm, u8 enable)
> +static void vfe_wm_enable(struct vfe_device *vfe, u8 wm, u8 enable)
>   {
>   	if (enable)
>   		vfe_reg_set(vfe, VFE_0_BUS_IMAGE_MASTER_n_WR_CFG(wm),
> @@ -460,8 +464,12 @@ static void vfe_wm_set_ub_cfg(struct vfe_device *vfe, u8 wm,
>   
>   static void vfe_bus_reload_wm(struct vfe_device *vfe, u8 wm)
>   {
> +	/* Enforce barrier between any outstanding register write */
>   	wmb();
> +
>   	writel_relaxed(VFE_0_BUS_CMD_Mx_RLD_CMD(wm), vfe->base + VFE_0_BUS_CMD);
> +
> +	/* Use barrier to make sure bus reload is issued before anything else */
>   	wmb();
>   }
>   
> @@ -675,8 +683,12 @@ static void vfe_set_rdi_cid(struct vfe_device *vfe, enum vfe_line_id id, u8 cid)
>   static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
>   {
>   	vfe->reg_update |= VFE_0_REG_UPDATE_line_n(line_id);
> +
> +	/* Enforce barrier between line update and commit */
>   	wmb();
>   	writel_relaxed(vfe->reg_update, vfe->base + VFE_0_REG_UPDATE);
> +
> +	/* Make sure register update is issued before further reg writes */
>   	wmb();
>   }
>   
> @@ -780,20 +792,6 @@ static void vfe_set_demux_cfg(struct vfe_device *vfe, struct vfe_line *line)
>   	writel_relaxed(odd_cfg, vfe->base + VFE_0_DEMUX_ODD_CFG);
>   }
>   
> -static inline u8 vfe_calc_interp_reso(u16 input, u16 output)
> -{
> -	if (input / output >= 16)
> -		return 0;
> -
> -	if (input / output >= 8)
> -		return 1;
> -
> -	if (input / output >= 4)
> -		return 2;
> -
> -	return 3;
> -}
> -
>   static void vfe_set_scale_cfg(struct vfe_device *vfe, struct vfe_line *line)
>   {
>   	u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat;
> @@ -895,7 +893,7 @@ static void vfe_set_clamp_cfg(struct vfe_device *vfe)
>   	writel_relaxed(val, vfe->base + VFE_0_CLAMP_ENC_MIN_CFG);
>   }
>   
> -static void vfe47_set_qos(struct vfe_device *vfe)
> +static void vfe_set_qos(struct vfe_device *vfe)
>   {
>   	u32 val = VFE_0_BUS_BDG_QOS_CFG_0_CFG;
>   	u32 val7 = VFE_0_BUS_BDG_QOS_CFG_7_CFG;
> @@ -910,7 +908,7 @@ static void vfe47_set_qos(struct vfe_device *vfe)
>   	writel_relaxed(val7, vfe->base + VFE_0_BUS_BDG_QOS_CFG_7);
>   }
>   
> -static void vfe47_set_ds(struct vfe_device *vfe)
> +static void vfe_set_ds(struct vfe_device *vfe)
>   {
>   	u32 val = VFE_0_BUS_BDG_DS_CFG_0_CFG;
>   	u32 val16 = VFE_0_BUS_BDG_DS_CFG_16_CFG;
> @@ -994,6 +992,8 @@ static void vfe_set_camif_cmd(struct vfe_device *vfe, u8 enable)
>   
>   	cmd = VFE_0_CAMIF_CMD_CLEAR_CAMIF_STATUS | VFE_0_CAMIF_CMD_NO_CHANGE;
>   	writel_relaxed(cmd, vfe->base + VFE_0_CAMIF_CMD);
> +
> +	/* Make sure camif command is issued written before it is changed again */
>   	wmb();
>   
>   	if (enable)
> @@ -1036,24 +1036,7 @@ static int vfe_camif_wait_for_stop(struct vfe_device *vfe, struct device *dev)
>   	return ret;
>   }
>   
> -static void vfe_isr_read(struct vfe_device *vfe, u32 *value0, u32 *value1)
> -{
> -	*value0 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_0);
> -	*value1 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_1);
>   
> -	writel_relaxed(*value0, vfe->base + VFE_0_IRQ_CLEAR_0);
> -	writel_relaxed(*value1, vfe->base + VFE_0_IRQ_CLEAR_1);
> -
> -	wmb();
> -	writel_relaxed(VFE_0_IRQ_CMD_GLOBAL_CLEAR, vfe->base + VFE_0_IRQ_CMD);
> -}
> -
> -static void vfe_violation_read(struct vfe_device *vfe)
> -{
> -	u32 violation = readl_relaxed(vfe->base + VFE_0_VIOLATION_STATUS);
> -
> -	pr_err_ratelimited("VFE: violation = 0x%08x\n", violation);
> -}
>   
>   /*
>    * vfe_isr - VFE module interrupt handler
> @@ -1108,150 +1091,82 @@ static irqreturn_t vfe_isr(int irq, void *dev)
>   	return IRQ_HANDLED;
>   }
>   
> -const struct vfe_hw_ops vfe_ops_4_7 = {
> -	.hw_version_read = vfe_hw_version_read,
> -	.get_ub_size = vfe47_get_ub_size,
> -	.global_reset = vfe_global_reset,
> -	.halt_request = vfe_halt_request,
> -	.halt_clear = vfe_halt_clear,
> -	.wm_enable = vfe47_wm_enable,
> -	.wm_frame_based = vfe_wm_frame_based,
> -	.wm_line_based = vfe_wm_line_based,
> -	.wm_set_framedrop_period = vfe_wm_set_framedrop_period,
> -	.wm_set_framedrop_pattern = vfe_wm_set_framedrop_pattern,
> -	.wm_set_ub_cfg = vfe_wm_set_ub_cfg,
> -	.bus_reload_wm = vfe_bus_reload_wm,
> -	.wm_set_ping_addr = vfe_wm_set_ping_addr,
> -	.wm_set_pong_addr = vfe_wm_set_pong_addr,
> -	.wm_get_ping_pong_status = vfe_wm_get_ping_pong_status,
> -	.bus_enable_wr_if = vfe_bus_enable_wr_if,
> -	.bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi,
> -	.wm_set_subsample = vfe_wm_set_subsample,
> -	.bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi,
> -	.set_xbar_cfg = vfe_set_xbar_cfg,
> -	.set_realign_cfg = vfe_set_realign_cfg,
> -	.set_rdi_cid = vfe_set_rdi_cid,
> -	.reg_update = vfe_reg_update,
> -	.reg_update_clear = vfe_reg_update_clear,
> -	.enable_irq_wm_line = vfe_enable_irq_wm_line,
> -	.enable_irq_pix_line = vfe_enable_irq_pix_line,
> -	.enable_irq_common = vfe_enable_irq_common,
> -	.set_demux_cfg = vfe_set_demux_cfg,
> -	.set_scale_cfg = vfe_set_scale_cfg,
> -	.set_crop_cfg = vfe_set_crop_cfg,
> -	.set_clamp_cfg = vfe_set_clamp_cfg,
> -	.set_qos = vfe47_set_qos,
> -	.set_ds = vfe47_set_ds,
> -	.set_cgc_override = vfe_set_cgc_override,
> -	.set_camif_cfg = vfe_set_camif_cfg,
> -	.set_camif_cmd = vfe_set_camif_cmd,
> -	.set_module_cfg = vfe_set_module_cfg,
> -	.camif_wait_for_stop = vfe_camif_wait_for_stop,
> -	.isr_read = vfe_isr_read,
> -	.violation_read = vfe_violation_read,
> -	.isr = vfe_isr,
> -};
> -
> -static u16 vfe48_get_ub_size(u8 vfe_id)
> +static void vfe_isr_read(struct vfe_device *vfe, u32 *value0, u32 *value1)
>   {
> -	/* On VFE4.8 the ub-size is the same on both instances */
> -	return MSM_VFE_VFE0_UB_SIZE_RDI;
> -}
> +	*value0 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_0);
> +	*value1 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_1);
>   
> -static void vfe48_wm_enable(struct vfe_device *vfe, u8 wm, u8 enable)
> -{
> -	if (enable)
> -		writel_relaxed(2 << VFE48_0_BUS_IMAGE_MASTER_n_SHIFT(wm),
> -			       vfe->base + VFE48_0_BUS_IMAGE_MASTER_CMD);
> -	else
> -		writel_relaxed(1 << VFE48_0_BUS_IMAGE_MASTER_n_SHIFT(wm),
> -			       vfe->base + VFE48_0_BUS_IMAGE_MASTER_CMD);
> +	writel_relaxed(*value0, vfe->base + VFE_0_IRQ_CLEAR_0);
> +	writel_relaxed(*value1, vfe->base + VFE_0_IRQ_CLEAR_1);
>   
> -	/* The WM must be enabled before sending other commands */
> +	/* Enforce barrier between local & global IRQ clear */
>   	wmb();
> +	writel_relaxed(VFE_0_IRQ_CMD_GLOBAL_CLEAR, vfe->base + VFE_0_IRQ_CMD);
>   }
>   
> -static void vfe48_set_qos(struct vfe_device *vfe)
> -{
> -	u32 val = VFE48_0_BUS_BDG_QOS_CFG_0_CFG;
> -	u32 val3 = VFE48_0_BUS_BDG_QOS_CFG_3_CFG;
> -	u32 val4 = VFE48_0_BUS_BDG_QOS_CFG_4_CFG;
> -	u32 val7 = VFE48_0_BUS_BDG_QOS_CFG_7_CFG;
> -
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_0);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_1);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_2);
> -	writel_relaxed(val3, vfe->base + VFE_0_BUS_BDG_QOS_CFG_3);
> -	writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_4);
> -	writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_5);
> -	writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_6);
> -	writel_relaxed(val7, vfe->base + VFE_0_BUS_BDG_QOS_CFG_7);
> -}
> -
> -static void vfe48_set_ds(struct vfe_device *vfe)
> +static void vfe_violation_read(struct vfe_device *vfe)
>   {
> -	u32 val = VFE48_0_BUS_BDG_DS_CFG_0_CFG;
> -	u32 val16 = VFE48_0_BUS_BDG_DS_CFG_16_CFG;
> +	u32 violation = readl_relaxed(vfe->base + VFE_0_VIOLATION_STATUS);
>   
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_0);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_1);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_2);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_3);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_4);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_5);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_6);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_7);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_8);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_9);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_10);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_11);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_12);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_13);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_14);
> -	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_15);
> -	writel_relaxed(val16, vfe->base + VFE_0_BUS_BDG_DS_CFG_16);
> +	pr_err_ratelimited("VFE: violation = 0x%08x\n", violation);
>   }
>   
> -const struct vfe_hw_ops vfe_ops_4_8 = {
> -	.hw_version_read = vfe_hw_version_read,
> -	.get_ub_size = vfe48_get_ub_size,
> -	.global_reset = vfe_global_reset,
> -	.halt_request = vfe_halt_request,
> +const struct vfe_hw_ops_gen1 vfe_ops_gen1_4_7 = {
> +	.bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi,
> +	.bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi,
> +	.bus_enable_wr_if = vfe_bus_enable_wr_if,
> +	.bus_reload_wm = vfe_bus_reload_wm,
> +	.camif_wait_for_stop = vfe_camif_wait_for_stop,
> +	.enable_irq_common = vfe_enable_irq_common,
> +	.enable_irq_pix_line = vfe_enable_irq_pix_line,
> +	.enable_irq_wm_line = vfe_enable_irq_wm_line,
> +	.get_ub_size = vfe_get_ub_size,
>   	.halt_clear = vfe_halt_clear,
> -	.wm_enable = vfe48_wm_enable,
> +	.halt_request = vfe_halt_request,
> +	.set_camif_cfg = vfe_set_camif_cfg,
> +	.set_camif_cmd = vfe_set_camif_cmd,
> +	.set_cgc_override = vfe_set_cgc_override,
> +	.set_clamp_cfg = vfe_set_clamp_cfg,
> +	.set_crop_cfg = vfe_set_crop_cfg,
> +	.set_demux_cfg = vfe_set_demux_cfg,
> +	.set_ds = vfe_set_ds,
> +	.set_module_cfg = vfe_set_module_cfg,
> +	.set_qos = vfe_set_qos,
> +	.set_rdi_cid = vfe_set_rdi_cid,
> +	.set_realign_cfg = vfe_set_realign_cfg,
> +	.set_scale_cfg = vfe_set_scale_cfg,
> +	.set_xbar_cfg = vfe_set_xbar_cfg,
> +	.wm_enable = vfe_wm_enable,
>   	.wm_frame_based = vfe_wm_frame_based,
> +	.wm_get_ping_pong_status = vfe_wm_get_ping_pong_status,
>   	.wm_line_based = vfe_wm_line_based,
> -	.wm_set_framedrop_period = vfe_wm_set_framedrop_period,
>   	.wm_set_framedrop_pattern = vfe_wm_set_framedrop_pattern,
> -	.wm_set_ub_cfg = vfe_wm_set_ub_cfg,
> -	.bus_reload_wm = vfe_bus_reload_wm,
> +	.wm_set_framedrop_period = vfe_wm_set_framedrop_period,
>   	.wm_set_ping_addr = vfe_wm_set_ping_addr,
>   	.wm_set_pong_addr = vfe_wm_set_pong_addr,
> -	.wm_get_ping_pong_status = vfe_wm_get_ping_pong_status,
> -	.bus_enable_wr_if = vfe_bus_enable_wr_if,
> -	.bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi,
>   	.wm_set_subsample = vfe_wm_set_subsample,
> -	.bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi,
> -	.set_xbar_cfg = vfe_set_xbar_cfg,
> -	.set_realign_cfg = vfe_set_realign_cfg,
> -	.set_rdi_cid = vfe_set_rdi_cid,
> -	.reg_update = vfe_reg_update,
> -	.reg_update_clear = vfe_reg_update_clear,
> -	.enable_irq_wm_line = vfe_enable_irq_wm_line,
> -	.enable_irq_pix_line = vfe_enable_irq_pix_line,
> -	.enable_irq_common = vfe_enable_irq_common,
> -	.set_demux_cfg = vfe_set_demux_cfg,
> -	.set_scale_cfg = vfe_set_scale_cfg,
> -	.set_crop_cfg = vfe_set_crop_cfg,
> -	.set_clamp_cfg = vfe_set_clamp_cfg,
> -	.set_qos = vfe48_set_qos,
> -	.set_ds = vfe48_set_ds,
> -	.set_cgc_override = vfe_set_cgc_override,
> -	.set_camif_cfg = vfe_set_camif_cfg,
> -	.set_camif_cmd = vfe_set_camif_cmd,
> -	.set_module_cfg = vfe_set_module_cfg,
> -	.camif_wait_for_stop = vfe_camif_wait_for_stop,
> +	.wm_set_ub_cfg = vfe_wm_set_ub_cfg,
> +};
> +
> +static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe)
> +{
> +	vfe->isr_ops = vfe_isr_ops_gen1;
> +	vfe->ops_gen1 = &vfe_ops_gen1_4_7;
> +	vfe->video_ops = vfe_video_ops_gen1;
> +
> +	vfe->line_num = VFE_LINE_NUM_GEN1;
> +}
> +
> +const struct vfe_hw_ops vfe_ops_4_7 = {
> +	.global_reset = vfe_global_reset,
> +	.hw_version_read = vfe_hw_version_read,
>   	.isr_read = vfe_isr_read,
> -	.violation_read = vfe_violation_read,
>   	.isr = vfe_isr,
> +	.reg_update_clear = vfe_reg_update_clear,
> +	.reg_update = vfe_reg_update,
> +	.subdev_init = vfe_subdev_init,
> +	.vfe_disable = vfe_gen1_disable,
> +	.vfe_enable = vfe_gen1_enable,
> +	.vfe_halt = vfe_gen1_halt,
> +	.violation_read = vfe_violation_read,
>   };
> diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c
> new file mode 100644
> index 000000000000..241f763f8386
> --- /dev/null
> +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c
> @@ -0,0 +1,1166 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * camss-vfe-4-8.c
> + *
> + * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module v4.8
> + *
> + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
> + * Copyright (C) 2015-2021 Linaro Ltd.
> + */
> +
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/iopoll.h>
> +
> +#include "camss.h"
> +#include "camss-vfe.h"
> +#include "camss-vfe-gen1.h"
> +
> +
> +#define VFE_0_HW_VERSION		0x000
> +
> +#define VFE_0_GLOBAL_RESET_CMD		0x018
> +#define VFE_0_GLOBAL_RESET_CMD_CORE	BIT(0)
> +#define VFE_0_GLOBAL_RESET_CMD_CAMIF	BIT(1)
> +#define VFE_0_GLOBAL_RESET_CMD_BUS	BIT(2)
> +#define VFE_0_GLOBAL_RESET_CMD_BUS_BDG	BIT(3)
> +#define VFE_0_GLOBAL_RESET_CMD_REGISTER	BIT(4)
> +#define VFE_0_GLOBAL_RESET_CMD_PM	BIT(5)
> +#define VFE_0_GLOBAL_RESET_CMD_BUS_MISR	BIT(6)
> +#define VFE_0_GLOBAL_RESET_CMD_TESTGEN	BIT(7)
> +#define VFE_0_GLOBAL_RESET_CMD_DSP	BIT(8)
> +#define VFE_0_GLOBAL_RESET_CMD_IDLE_CGC	BIT(9)
> +
> +#define VFE_0_MODULE_LENS_EN		0x040
> +#define VFE_0_MODULE_LENS_EN_DEMUX		BIT(2)
> +#define VFE_0_MODULE_LENS_EN_CHROMA_UPSAMPLE	BIT(3)
> +
> +#define VFE_0_MODULE_ZOOM_EN		0x04c
> +#define VFE_0_MODULE_ZOOM_EN_SCALE_ENC		BIT(1)
> +#define VFE_0_MODULE_ZOOM_EN_CROP_ENC		BIT(2)
> +#define VFE_0_MODULE_ZOOM_EN_REALIGN_BUF	BIT(9)
> +
> +#define VFE_0_CORE_CFG			0x050
> +#define VFE_0_CORE_CFG_PIXEL_PATTERN_YCBYCR	0x4
> +#define VFE_0_CORE_CFG_PIXEL_PATTERN_YCRYCB	0x5
> +#define VFE_0_CORE_CFG_PIXEL_PATTERN_CBYCRY	0x6
> +#define VFE_0_CORE_CFG_PIXEL_PATTERN_CRYCBY	0x7
> +#define VFE_0_CORE_CFG_COMPOSITE_REG_UPDATE_EN	BIT(4)
> +
> +#define VFE_0_IRQ_CMD			0x058
> +#define VFE_0_IRQ_CMD_GLOBAL_CLEAR	BIT(0)
> +
> +#define VFE_0_IRQ_MASK_0		0x05c
> +#define VFE_0_IRQ_MASK_0_CAMIF_SOF			BIT(0)
> +#define VFE_0_IRQ_MASK_0_CAMIF_EOF			BIT(1)
> +#define VFE_0_IRQ_MASK_0_RDIn_REG_UPDATE(n)		BIT((n) + 5)
> +#define VFE_0_IRQ_MASK_0_line_n_REG_UPDATE(n)		\
> +	((n) == VFE_LINE_PIX ? BIT(4) : VFE_0_IRQ_MASK_0_RDIn_REG_UPDATE(n))
> +#define VFE_0_IRQ_MASK_0_IMAGE_MASTER_n_PING_PONG(n)	BIT((n) + 8)
> +#define VFE_0_IRQ_MASK_0_IMAGE_COMPOSITE_DONE_n(n)	BIT((n) + 25)
> +#define VFE_0_IRQ_MASK_0_RESET_ACK			BIT(31)
> +#define VFE_0_IRQ_MASK_1		0x060
> +#define VFE_0_IRQ_MASK_1_CAMIF_ERROR			BIT(0)
> +#define VFE_0_IRQ_MASK_1_VIOLATION			BIT(7)
> +#define VFE_0_IRQ_MASK_1_BUS_BDG_HALT_ACK		BIT(8)
> +#define VFE_0_IRQ_MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(n)	BIT((n) + 9)
> +#define VFE_0_IRQ_MASK_1_RDIn_SOF(n)			BIT((n) + 29)
> +
> +#define VFE_0_IRQ_CLEAR_0		0x064
> +#define VFE_0_IRQ_CLEAR_1		0x068
> +
> +#define VFE_0_IRQ_STATUS_0		0x06c
> +#define VFE_0_IRQ_STATUS_0_CAMIF_SOF			BIT(0)
> +#define VFE_0_IRQ_STATUS_0_RDIn_REG_UPDATE(n)		BIT((n) + 5)
> +#define VFE_0_IRQ_STATUS_0_line_n_REG_UPDATE(n)		\
> +	((n) == VFE_LINE_PIX ? BIT(4) : VFE_0_IRQ_STATUS_0_RDIn_REG_UPDATE(n))
> +#define VFE_0_IRQ_STATUS_0_IMAGE_MASTER_n_PING_PONG(n)	BIT((n) + 8)
> +#define VFE_0_IRQ_STATUS_0_IMAGE_COMPOSITE_DONE_n(n)	BIT((n) + 25)
> +#define VFE_0_IRQ_STATUS_0_RESET_ACK			BIT(31)
> +#define VFE_0_IRQ_STATUS_1		0x070
> +#define VFE_0_IRQ_STATUS_1_VIOLATION			BIT(7)
> +#define VFE_0_IRQ_STATUS_1_BUS_BDG_HALT_ACK		BIT(8)
> +#define VFE_0_IRQ_STATUS_1_RDIn_SOF(n)			BIT((n) + 29)
> +
> +#define VFE_0_IRQ_COMPOSITE_MASK_0	0x074
> +#define VFE_0_VIOLATION_STATUS		0x07c
> +
> +#define VFE_0_BUS_CMD			0x80
> +#define VFE_0_BUS_CMD_Mx_RLD_CMD(x)	BIT(x)
> +
> +#define VFE_0_BUS_CFG			0x084
> +
> +#define VFE_0_BUS_XBAR_CFG_x(x)		(0x90 + 0x4 * ((x) / 2))
> +#define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_EN			BIT(2)
> +#define VFE_0_BUS_XBAR_CFG_x_M_REALIGN_BUF_EN			BIT(3)
> +#define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTRA		(0x1 << 4)
> +#define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER		(0x2 << 4)
> +#define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER_INTRA	(0x3 << 4)
> +#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT		8
> +#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_LUMA		0x0
> +#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI0	0xc
> +#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI1	0xd
> +#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI2	0xe
> +
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_CFG(n)		(0x0a0 + 0x2c * (n))
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_CFG_WR_PATH_SHIFT	0
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_PING_ADDR(n)	(0x0a4 + 0x2c * (n))
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_PONG_ADDR(n)	(0x0ac + 0x2c * (n))
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(n)		(0x0b4 + 0x2c * (n))
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_BASED_SHIFT	1
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_SHIFT	2
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_MASK	(0x1f << 2)
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_UB_CFG(n)		(0x0b8 + 0x2c * (n))
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_UB_CFG_OFFSET_SHIFT	16
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_IMAGE_SIZE(n)	(0x0bc + 0x2c * (n))
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_BUFFER_CFG(n)	(0x0c0 + 0x2c * (n))
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_FRAMEDROP_PATTERN(n)	\
> +							(0x0c4 + 0x2c * (n))
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_IRQ_SUBSAMPLE_PATTERN(n)	\
> +							(0x0c8 + 0x2c * (n))
> +#define VFE_0_BUS_IMAGE_MASTER_n_WR_IRQ_SUBSAMPLE_PATTERN_DEF	0xffffffff
> +
> +#define VFE_0_BUS_PING_PONG_STATUS	0x338
> +
> +#define VFE_0_BUS_BDG_CMD		0x400
> +#define VFE_0_BUS_BDG_CMD_HALT_REQ	1
> +
> +#define VFE_0_BUS_BDG_QOS_CFG_0		0x404
> +#define VFE_0_BUS_BDG_QOS_CFG_0_CFG	0xaaa5aaa5
> +#define VFE_0_BUS_BDG_QOS_CFG_1		0x408
> +#define VFE_0_BUS_BDG_QOS_CFG_2		0x40c
> +#define VFE_0_BUS_BDG_QOS_CFG_3		0x410
> +#define VFE_0_BUS_BDG_QOS_CFG_3_CFG	0xaa55aaa5
> +#define VFE_0_BUS_BDG_QOS_CFG_4		0x414
> +#define VFE_0_BUS_BDG_QOS_CFG_4_CFG	0xaa55aa55
> +#define VFE_0_BUS_BDG_QOS_CFG_5		0x418
> +#define VFE_0_BUS_BDG_QOS_CFG_6		0x41c
> +#define VFE_0_BUS_BDG_QOS_CFG_7		0x420
> +#define VFE_0_BUS_BDG_QOS_CFG_7_CFG	0x0005aa55
> +
> +#define VFE_0_BUS_BDG_DS_CFG_0		0x424
> +#define VFE_0_BUS_BDG_DS_CFG_0_CFG	0xcccc1111
> +#define VFE_0_BUS_BDG_DS_CFG_1		0x428
> +#define VFE_0_BUS_BDG_DS_CFG_2		0x42c
> +#define VFE_0_BUS_BDG_DS_CFG_3		0x430
> +#define VFE_0_BUS_BDG_DS_CFG_4		0x434
> +#define VFE_0_BUS_BDG_DS_CFG_5		0x438
> +#define VFE_0_BUS_BDG_DS_CFG_6		0x43c
> +#define VFE_0_BUS_BDG_DS_CFG_7		0x440
> +#define VFE_0_BUS_BDG_DS_CFG_8		0x444
> +#define VFE_0_BUS_BDG_DS_CFG_9		0x448
> +#define VFE_0_BUS_BDG_DS_CFG_10		0x44c
> +#define VFE_0_BUS_BDG_DS_CFG_11		0x450
> +#define VFE_0_BUS_BDG_DS_CFG_12		0x454
> +#define VFE_0_BUS_BDG_DS_CFG_13		0x458
> +#define VFE_0_BUS_BDG_DS_CFG_14		0x45c
> +#define VFE_0_BUS_BDG_DS_CFG_15		0x460
> +#define VFE_0_BUS_BDG_DS_CFG_16		0x464
> +#define VFE_0_BUS_BDG_DS_CFG_16_CFG	0x00000110
> +
> +#define VFE_0_RDI_CFG_x(x)		(0x46c + (0x4 * (x)))
> +#define VFE_0_RDI_CFG_x_RDI_STREAM_SEL_SHIFT	28
> +#define VFE_0_RDI_CFG_x_RDI_STREAM_SEL_MASK	(0xf << 28)
> +#define VFE_0_RDI_CFG_x_RDI_M0_SEL_SHIFT	4
> +#define VFE_0_RDI_CFG_x_RDI_M0_SEL_MASK		(0xf << 4)
> +#define VFE_0_RDI_CFG_x_RDI_EN_BIT		BIT(2)
> +#define VFE_0_RDI_CFG_x_MIPI_EN_BITS		0x3
> +
> +#define VFE_0_CAMIF_CMD				0x478
> +#define VFE_0_CAMIF_CMD_DISABLE_FRAME_BOUNDARY	0
> +#define VFE_0_CAMIF_CMD_ENABLE_FRAME_BOUNDARY	1
> +#define VFE_0_CAMIF_CMD_NO_CHANGE		3
> +#define VFE_0_CAMIF_CMD_CLEAR_CAMIF_STATUS	BIT(2)
> +#define VFE_0_CAMIF_CFG				0x47c
> +#define VFE_0_CAMIF_CFG_VFE_OUTPUT_EN		BIT(6)
> +#define VFE_0_CAMIF_FRAME_CFG			0x484
> +#define VFE_0_CAMIF_WINDOW_WIDTH_CFG		0x488
> +#define VFE_0_CAMIF_WINDOW_HEIGHT_CFG		0x48c
> +#define VFE_0_CAMIF_SUBSAMPLE_CFG		0x490
> +#define VFE_0_CAMIF_IRQ_FRAMEDROP_PATTERN	0x498
> +#define VFE_0_CAMIF_IRQ_SUBSAMPLE_PATTERN	0x49c
> +#define VFE_0_CAMIF_STATUS			0x4a4
> +#define VFE_0_CAMIF_STATUS_HALT			BIT(31)
> +
> +#define VFE_0_REG_UPDATE		0x4ac
> +#define VFE_0_REG_UPDATE_RDIn(n)		BIT(1 + (n))
> +#define VFE_0_REG_UPDATE_line_n(n)		\
> +			((n) == VFE_LINE_PIX ? 1 : VFE_0_REG_UPDATE_RDIn(n))
> +
> +#define VFE_0_DEMUX_CFG				0x560
> +#define VFE_0_DEMUX_CFG_PERIOD			0x3
> +#define VFE_0_DEMUX_GAIN_0			0x564
> +#define VFE_0_DEMUX_GAIN_0_CH0_EVEN		(0x80 << 0)
> +#define VFE_0_DEMUX_GAIN_0_CH0_ODD		(0x80 << 16)
> +#define VFE_0_DEMUX_GAIN_1			0x568
> +#define VFE_0_DEMUX_GAIN_1_CH1			(0x80 << 0)
> +#define VFE_0_DEMUX_GAIN_1_CH2			(0x80 << 16)
> +#define VFE_0_DEMUX_EVEN_CFG			0x574
> +#define VFE_0_DEMUX_EVEN_CFG_PATTERN_YUYV	0x9cac
> +#define VFE_0_DEMUX_EVEN_CFG_PATTERN_YVYU	0xac9c
> +#define VFE_0_DEMUX_EVEN_CFG_PATTERN_UYVY	0xc9ca
> +#define VFE_0_DEMUX_EVEN_CFG_PATTERN_VYUY	0xcac9
> +#define VFE_0_DEMUX_ODD_CFG			0x578
> +#define VFE_0_DEMUX_ODD_CFG_PATTERN_YUYV	0x9cac
> +#define VFE_0_DEMUX_ODD_CFG_PATTERN_YVYU	0xac9c
> +#define VFE_0_DEMUX_ODD_CFG_PATTERN_UYVY	0xc9ca
> +#define VFE_0_DEMUX_ODD_CFG_PATTERN_VYUY	0xcac9
> +
> +#define VFE_0_SCALE_ENC_Y_CFG			0x91c
> +#define VFE_0_SCALE_ENC_Y_H_IMAGE_SIZE		0x920
> +#define VFE_0_SCALE_ENC_Y_H_PHASE		0x924
> +#define VFE_0_SCALE_ENC_Y_V_IMAGE_SIZE		0x934
> +#define VFE_0_SCALE_ENC_Y_V_PHASE		0x938
> +#define VFE_0_SCALE_ENC_CBCR_CFG		0x948
> +#define VFE_0_SCALE_ENC_CBCR_H_IMAGE_SIZE	0x94c
> +#define VFE_0_SCALE_ENC_CBCR_H_PHASE		0x950
> +#define VFE_0_SCALE_ENC_CBCR_V_IMAGE_SIZE	0x960
> +#define VFE_0_SCALE_ENC_CBCR_V_PHASE		0x964
> +
> +#define VFE_0_CROP_ENC_Y_WIDTH			0x974
> +#define VFE_0_CROP_ENC_Y_HEIGHT			0x978
> +#define VFE_0_CROP_ENC_CBCR_WIDTH		0x97c
> +#define VFE_0_CROP_ENC_CBCR_HEIGHT		0x980
> +
> +#define VFE_0_CLAMP_ENC_MAX_CFG			0x984
> +#define VFE_0_CLAMP_ENC_MAX_CFG_CH0		(0xff << 0)
> +#define VFE_0_CLAMP_ENC_MAX_CFG_CH1		(0xff << 8)
> +#define VFE_0_CLAMP_ENC_MAX_CFG_CH2		(0xff << 16)
> +#define VFE_0_CLAMP_ENC_MIN_CFG			0x988
> +#define VFE_0_CLAMP_ENC_MIN_CFG_CH0		(0x0 << 0)
> +#define VFE_0_CLAMP_ENC_MIN_CFG_CH1		(0x0 << 8)
> +#define VFE_0_CLAMP_ENC_MIN_CFG_CH2		(0x0 << 16)
> +
> +#define VFE_0_REALIGN_BUF_CFG			0xaac
> +#define VFE_0_REALIGN_BUF_CFG_CB_ODD_PIXEL     BIT(2)
> +#define VFE_0_REALIGN_BUF_CFG_CR_ODD_PIXEL     BIT(3)
> +#define VFE_0_REALIGN_BUF_CFG_HSUB_ENABLE      BIT(4)
> +
> +#define VFE_0_BUS_IMAGE_MASTER_CMD		0xcec
> +#define VFE_0_BUS_IMAGE_MASTER_n_SHIFT(x)	(2 * (x))
> +
> +#define CAMIF_TIMEOUT_SLEEP_US 1000
> +#define CAMIF_TIMEOUT_ALL_US 1000000
> +
> +#define MSM_VFE_VFE0_UB_SIZE 2047
> +#define MSM_VFE_VFE0_UB_SIZE_RDI (MSM_VFE_VFE0_UB_SIZE / 3)
> +#define MSM_VFE_VFE1_UB_SIZE 1535
> +#define MSM_VFE_VFE1_UB_SIZE_RDI (MSM_VFE_VFE1_UB_SIZE / 3)
> +
> +static void vfe_hw_version_read(struct vfe_device *vfe, struct device *dev)
> +{
> +	u32 hw_version = readl_relaxed(vfe->base + VFE_0_HW_VERSION);
> +
> +	dev_err(dev, "VFE HW Version = 0x%08x\n", hw_version);
> +}
> +
> +static inline void vfe_reg_clr(struct vfe_device *vfe, u32 reg, u32 clr_bits)
> +{
> +	u32 bits = readl_relaxed(vfe->base + reg);
> +
> +	writel_relaxed(bits & ~clr_bits, vfe->base + reg);
> +}
> +
> +static inline void vfe_reg_set(struct vfe_device *vfe, u32 reg, u32 set_bits)
> +{
> +	u32 bits = readl_relaxed(vfe->base + reg);
> +
> +	writel_relaxed(bits | set_bits, vfe->base + reg);
> +}
> +
> +static void vfe_global_reset(struct vfe_device *vfe)
> +{
> +	u32 reset_bits = VFE_0_GLOBAL_RESET_CMD_IDLE_CGC	|
> +			 VFE_0_GLOBAL_RESET_CMD_DSP		|
> +			 VFE_0_GLOBAL_RESET_CMD_TESTGEN		|
> +			 VFE_0_GLOBAL_RESET_CMD_BUS_MISR	|
> +			 VFE_0_GLOBAL_RESET_CMD_PM		|
> +			 VFE_0_GLOBAL_RESET_CMD_REGISTER	|
> +			 VFE_0_GLOBAL_RESET_CMD_BUS_BDG		|
> +			 VFE_0_GLOBAL_RESET_CMD_BUS		|
> +			 VFE_0_GLOBAL_RESET_CMD_CAMIF		|
> +			 VFE_0_GLOBAL_RESET_CMD_CORE;
> +
> +	writel_relaxed(BIT(31), vfe->base + VFE_0_IRQ_MASK_0);
> +
> +	/* Enforce barrier between IRQ mask setup and global reset */
> +	wmb();
> +	writel_relaxed(reset_bits, vfe->base + VFE_0_GLOBAL_RESET_CMD);
> +}
> +
> +static void vfe_halt_request(struct vfe_device *vfe)
> +{
> +	writel_relaxed(VFE_0_BUS_BDG_CMD_HALT_REQ,
> +		       vfe->base + VFE_0_BUS_BDG_CMD);
> +}
> +
> +static void vfe_halt_clear(struct vfe_device *vfe)
> +{
> +	writel_relaxed(0x0, vfe->base + VFE_0_BUS_BDG_CMD);
> +}
> +
> +static void vfe_wm_frame_based(struct vfe_device *vfe, u8 wm, u8 enable)
> +{
> +	if (enable)
> +		vfe_reg_set(vfe, VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(wm),
> +			1 << VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_BASED_SHIFT);
> +	else
> +		vfe_reg_clr(vfe, VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(wm),
> +			1 << VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_BASED_SHIFT);
> +}
> +
> +#define CALC_WORD(width, M, N) (((width) * (M) + (N) - 1) / (N))
> +
> +static int vfe_word_per_line_by_pixel(u32 format, u32 pixel_per_line)
> +{
> +	int val = 0;
> +
> +	switch (format) {
> +	case V4L2_PIX_FMT_NV12:
> +	case V4L2_PIX_FMT_NV21:
> +	case V4L2_PIX_FMT_NV16:
> +	case V4L2_PIX_FMT_NV61:
> +		val = CALC_WORD(pixel_per_line, 1, 8);
> +		break;
> +	case V4L2_PIX_FMT_YUYV:
> +	case V4L2_PIX_FMT_YVYU:
> +	case V4L2_PIX_FMT_UYVY:
> +	case V4L2_PIX_FMT_VYUY:
> +		val = CALC_WORD(pixel_per_line, 2, 8);
> +		break;
> +	}
> +
> +	return val;
> +}
> +
> +static int vfe_word_per_line_by_bytes(u32 bytes_per_line)
> +{
> +	return CALC_WORD(bytes_per_line, 1, 8);
> +}
> +
> +static void vfe_get_wm_sizes(struct v4l2_pix_format_mplane *pix, u8 plane,
> +			     u16 *width, u16 *height, u16 *bytesperline)
> +{
> +	switch (pix->pixelformat) {
> +	case V4L2_PIX_FMT_NV12:
> +	case V4L2_PIX_FMT_NV21:
> +		*width = pix->width;
> +		*height = pix->height;
> +		*bytesperline = pix->plane_fmt[0].bytesperline;
> +		if (plane == 1)
> +			*height /= 2;
> +		break;
> +	case V4L2_PIX_FMT_NV16:
> +	case V4L2_PIX_FMT_NV61:
> +		*width = pix->width;
> +		*height = pix->height;
> +		*bytesperline = pix->plane_fmt[0].bytesperline;
> +		break;
> +	case V4L2_PIX_FMT_YUYV:
> +	case V4L2_PIX_FMT_YVYU:
> +	case V4L2_PIX_FMT_VYUY:
> +	case V4L2_PIX_FMT_UYVY:
> +		*width = pix->width;
> +		*height = pix->height;
> +		*bytesperline = pix->plane_fmt[plane].bytesperline;
> +		break;
> +
> +	}
> +}
> +
> +static void vfe_wm_line_based(struct vfe_device *vfe, u32 wm,
> +			      struct v4l2_pix_format_mplane *pix,
> +			      u8 plane, u32 enable)
> +{
> +	u32 reg;
> +
> +	if (enable) {
> +		u16 width = 0, height = 0, bytesperline = 0, wpl;
> +
> +		vfe_get_wm_sizes(pix, plane, &width, &height, &bytesperline);
> +
> +		wpl = vfe_word_per_line_by_pixel(pix->pixelformat, width);
> +
> +		reg = height - 1;
> +		reg |= ((wpl + 3) / 4 - 1) << 16;
> +
> +		writel_relaxed(reg, vfe->base +
> +			       VFE_0_BUS_IMAGE_MASTER_n_WR_IMAGE_SIZE(wm));
> +
> +		wpl = vfe_word_per_line_by_bytes(bytesperline);
> +
> +		reg = 0x3;
> +		reg |= (height - 1) << 2;
> +		reg |= ((wpl + 1) / 2) << 16;
> +
> +		writel_relaxed(reg, vfe->base +
> +			       VFE_0_BUS_IMAGE_MASTER_n_WR_BUFFER_CFG(wm));
> +	} else {
> +		writel_relaxed(0, vfe->base +
> +			       VFE_0_BUS_IMAGE_MASTER_n_WR_IMAGE_SIZE(wm));
> +		writel_relaxed(0, vfe->base +
> +			       VFE_0_BUS_IMAGE_MASTER_n_WR_BUFFER_CFG(wm));
> +	}
> +}
> +
> +static void vfe_wm_set_framedrop_period(struct vfe_device *vfe, u8 wm, u8 per)
> +{
> +	u32 reg;
> +
> +	reg = readl_relaxed(vfe->base +
> +			    VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(wm));
> +
> +	reg &= ~(VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_MASK);
> +
> +	reg |= (per << VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_SHIFT)
> +		& VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_MASK;
> +
> +	writel_relaxed(reg,
> +		       vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(wm));
> +}
> +
> +static void vfe_wm_set_framedrop_pattern(struct vfe_device *vfe, u8 wm,
> +					 u32 pattern)
> +{
> +	writel_relaxed(pattern,
> +	       vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_FRAMEDROP_PATTERN(wm));
> +}
> +
> +static void vfe_wm_set_ub_cfg(struct vfe_device *vfe, u8 wm,
> +			      u16 offset, u16 depth)
> +{
> +	u32 reg;
> +
> +	reg = (offset << VFE_0_BUS_IMAGE_MASTER_n_WR_UB_CFG_OFFSET_SHIFT) |
> +		depth;
> +	writel_relaxed(reg, vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_UB_CFG(wm));
> +}
> +
> +static void vfe_bus_reload_wm(struct vfe_device *vfe, u8 wm)
> +{
> +	/* Enforce barrier between any outstanding register write */
> +	wmb();
> +
> +	writel_relaxed(VFE_0_BUS_CMD_Mx_RLD_CMD(wm), vfe->base + VFE_0_BUS_CMD);
> +
> +	/* Use barrier to make sure bus reload is issued before anything else */
> +	wmb();
> +}
> +
> +static void vfe_wm_set_ping_addr(struct vfe_device *vfe, u8 wm, u32 addr)
> +{
> +	writel_relaxed(addr,
> +		       vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_PING_ADDR(wm));
> +}
> +
> +static void vfe_wm_set_pong_addr(struct vfe_device *vfe, u8 wm, u32 addr)
> +{
> +	writel_relaxed(addr,
> +		       vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_PONG_ADDR(wm));
> +}
> +
> +static int vfe_wm_get_ping_pong_status(struct vfe_device *vfe, u8 wm)
> +{
> +	u32 reg;
> +
> +	reg = readl_relaxed(vfe->base + VFE_0_BUS_PING_PONG_STATUS);
> +
> +	return (reg >> wm) & 0x1;
> +}
> +
> +static void vfe_bus_enable_wr_if(struct vfe_device *vfe, u8 enable)
> +{
> +	if (enable)
> +		writel_relaxed(0x101, vfe->base + VFE_0_BUS_CFG);
> +	else
> +		writel_relaxed(0, vfe->base + VFE_0_BUS_CFG);
> +}
> +
> +static void vfe_bus_connect_wm_to_rdi(struct vfe_device *vfe, u8 wm,
> +				      enum vfe_line_id id)
> +{
> +	u32 reg;
> +
> +	reg = VFE_0_RDI_CFG_x_MIPI_EN_BITS;
> +	vfe_reg_set(vfe, VFE_0_RDI_CFG_x(0), reg);
> +
> +	reg = VFE_0_RDI_CFG_x_RDI_EN_BIT;
> +	reg |= ((3 * id) << VFE_0_RDI_CFG_x_RDI_STREAM_SEL_SHIFT) &
> +		VFE_0_RDI_CFG_x_RDI_STREAM_SEL_MASK;
> +	vfe_reg_set(vfe, VFE_0_RDI_CFG_x(id), reg);
> +
> +	switch (id) {
> +	case VFE_LINE_RDI0:
> +	default:
> +		reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI0 <<
> +		      VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
> +		break;
> +	case VFE_LINE_RDI1:
> +		reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI1 <<
> +		      VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
> +		break;
> +	case VFE_LINE_RDI2:
> +		reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI2 <<
> +		      VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
> +		break;
> +	}
> +
> +	if (wm % 2 == 1)
> +		reg <<= 16;
> +
> +	vfe_reg_set(vfe, VFE_0_BUS_XBAR_CFG_x(wm), reg);
> +}
> +
> +static void vfe_wm_set_subsample(struct vfe_device *vfe, u8 wm)
> +{
> +	writel_relaxed(VFE_0_BUS_IMAGE_MASTER_n_WR_IRQ_SUBSAMPLE_PATTERN_DEF,
> +	       vfe->base +
> +	       VFE_0_BUS_IMAGE_MASTER_n_WR_IRQ_SUBSAMPLE_PATTERN(wm));
> +}
> +
> +static void vfe_bus_disconnect_wm_from_rdi(struct vfe_device *vfe, u8 wm,
> +					   enum vfe_line_id id)
> +{
> +	u32 reg;
> +
> +	reg = VFE_0_RDI_CFG_x_RDI_EN_BIT;
> +	vfe_reg_clr(vfe, VFE_0_RDI_CFG_x(id), reg);
> +
> +	switch (id) {
> +	case VFE_LINE_RDI0:
> +	default:
> +		reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI0 <<
> +		      VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
> +		break;
> +	case VFE_LINE_RDI1:
> +		reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI1 <<
> +		      VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
> +		break;
> +	case VFE_LINE_RDI2:
> +		reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI2 <<
> +		      VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
> +		break;
> +	}
> +
> +	if (wm % 2 == 1)
> +		reg <<= 16;
> +
> +	vfe_reg_clr(vfe, VFE_0_BUS_XBAR_CFG_x(wm), reg);
> +}
> +
> +static void vfe_set_xbar_cfg(struct vfe_device *vfe, struct vfe_output *output,
> +			     u8 enable)
> +{
> +	struct vfe_line *line = container_of(output, struct vfe_line, output);
> +	u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat;
> +	u32 reg;
> +
> +	switch (p) {
> +	case V4L2_PIX_FMT_NV12:
> +	case V4L2_PIX_FMT_NV21:
> +	case V4L2_PIX_FMT_NV16:
> +	case V4L2_PIX_FMT_NV61:
> +		reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_LUMA <<
> +			VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT;
> +
> +		if (output->wm_idx[0] % 2 == 1)
> +			reg <<= 16;
> +
> +		if (enable)
> +			vfe_reg_set(vfe,
> +				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]),
> +				    reg);
> +		else
> +			vfe_reg_clr(vfe,
> +				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]),
> +				    reg);
> +
> +		reg = VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_EN;
> +		if (p == V4L2_PIX_FMT_NV12 || p == V4L2_PIX_FMT_NV16)
> +			reg |= VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER_INTRA;
> +
> +		if (output->wm_idx[1] % 2 == 1)
> +			reg <<= 16;
> +
> +		if (enable)
> +			vfe_reg_set(vfe,
> +				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[1]),
> +				    reg);
> +		else
> +			vfe_reg_clr(vfe,
> +				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[1]),
> +				    reg);
> +		break;
> +	case V4L2_PIX_FMT_YUYV:
> +	case V4L2_PIX_FMT_YVYU:
> +	case V4L2_PIX_FMT_VYUY:
> +	case V4L2_PIX_FMT_UYVY:
> +		reg = VFE_0_BUS_XBAR_CFG_x_M_REALIGN_BUF_EN;
> +		reg |= VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_EN;
> +
> +		if (p == V4L2_PIX_FMT_YUYV || p == V4L2_PIX_FMT_YVYU)
> +			reg |= VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER_INTRA;
> +
> +		if (output->wm_idx[0] % 2 == 1)
> +			reg <<= 16;
> +
> +		if (enable)
> +			vfe_reg_set(vfe,
> +				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]),
> +				    reg);
> +		else
> +			vfe_reg_clr(vfe,
> +				    VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]),
> +				    reg);
> +		break;
> +	default:
> +		break;
> +	}
> +}
> +
> +static void vfe_set_realign_cfg(struct vfe_device *vfe, struct vfe_line *line,
> +				u8 enable)
> +{
> +	u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat;
> +	u32 val = VFE_0_MODULE_ZOOM_EN_REALIGN_BUF;
> +
> +	if (p != V4L2_PIX_FMT_YUYV && p != V4L2_PIX_FMT_YVYU &&
> +			p != V4L2_PIX_FMT_VYUY && p != V4L2_PIX_FMT_UYVY)
> +		return;
> +
> +	if (enable) {
> +		vfe_reg_set(vfe, VFE_0_MODULE_ZOOM_EN, val);
> +	} else {
> +		vfe_reg_clr(vfe, VFE_0_MODULE_ZOOM_EN, val);
> +		return;
> +	}
> +
> +	val = VFE_0_REALIGN_BUF_CFG_HSUB_ENABLE;
> +
> +	if (p == V4L2_PIX_FMT_UYVY || p == V4L2_PIX_FMT_YUYV)
> +		val |= VFE_0_REALIGN_BUF_CFG_CR_ODD_PIXEL;
> +	else
> +		val |= VFE_0_REALIGN_BUF_CFG_CB_ODD_PIXEL;
> +
> +	writel_relaxed(val, vfe->base + VFE_0_REALIGN_BUF_CFG);
> +}
> +
> +static void vfe_set_rdi_cid(struct vfe_device *vfe, enum vfe_line_id id, u8 cid)
> +{
> +	vfe_reg_clr(vfe, VFE_0_RDI_CFG_x(id),
> +		    VFE_0_RDI_CFG_x_RDI_M0_SEL_MASK);
> +
> +	vfe_reg_set(vfe, VFE_0_RDI_CFG_x(id),
> +		    cid << VFE_0_RDI_CFG_x_RDI_M0_SEL_SHIFT);
> +}
> +
> +static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
> +{
> +	vfe->reg_update |= VFE_0_REG_UPDATE_line_n(line_id);
> +
> +	/* Enforce barrier between line update and commit */
> +	wmb();
> +
> +	writel_relaxed(vfe->reg_update, vfe->base + VFE_0_REG_UPDATE);
> +
> +	/* Make sure register update is issued before further reg writes */
> +	wmb();
> +}
> +
> +static inline void vfe_reg_update_clear(struct vfe_device *vfe,
> +					enum vfe_line_id line_id)
> +{
> +	vfe->reg_update &= ~VFE_0_REG_UPDATE_line_n(line_id);
> +}
> +
> +static void vfe_enable_irq_wm_line(struct vfe_device *vfe, u8 wm,
> +				   enum vfe_line_id line_id, u8 enable)
> +{
> +	u32 irq_en0 = VFE_0_IRQ_MASK_0_IMAGE_MASTER_n_PING_PONG(wm) |
> +		      VFE_0_IRQ_MASK_0_line_n_REG_UPDATE(line_id);
> +	u32 irq_en1 = VFE_0_IRQ_MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(wm) |
> +		      VFE_0_IRQ_MASK_1_RDIn_SOF(line_id);
> +
> +	if (enable) {
> +		vfe_reg_set(vfe, VFE_0_IRQ_MASK_0, irq_en0);
> +		vfe_reg_set(vfe, VFE_0_IRQ_MASK_1, irq_en1);
> +	} else {
> +		vfe_reg_clr(vfe, VFE_0_IRQ_MASK_0, irq_en0);
> +		vfe_reg_clr(vfe, VFE_0_IRQ_MASK_1, irq_en1);
> +	}
> +}
> +
> +static void vfe_enable_irq_pix_line(struct vfe_device *vfe, u8 comp,
> +				    enum vfe_line_id line_id, u8 enable)
> +{
> +	struct vfe_output *output = &vfe->line[line_id].output;
> +	unsigned int i;
> +	u32 irq_en0;
> +	u32 irq_en1;
> +	u32 comp_mask = 0;
> +
> +	irq_en0 = VFE_0_IRQ_MASK_0_CAMIF_SOF;
> +	irq_en0 |= VFE_0_IRQ_MASK_0_CAMIF_EOF;
> +	irq_en0 |= VFE_0_IRQ_MASK_0_IMAGE_COMPOSITE_DONE_n(comp);
> +	irq_en0 |= VFE_0_IRQ_MASK_0_line_n_REG_UPDATE(line_id);
> +	irq_en1 = VFE_0_IRQ_MASK_1_CAMIF_ERROR;
> +	for (i = 0; i < output->wm_num; i++) {
> +		irq_en1 |= VFE_0_IRQ_MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(
> +							output->wm_idx[i]);
> +		comp_mask |= (1 << output->wm_idx[i]) << comp * 8;
> +	}
> +
> +	if (enable) {
> +		vfe_reg_set(vfe, VFE_0_IRQ_MASK_0, irq_en0);
> +		vfe_reg_set(vfe, VFE_0_IRQ_MASK_1, irq_en1);
> +		vfe_reg_set(vfe, VFE_0_IRQ_COMPOSITE_MASK_0, comp_mask);
> +	} else {
> +		vfe_reg_clr(vfe, VFE_0_IRQ_MASK_0, irq_en0);
> +		vfe_reg_clr(vfe, VFE_0_IRQ_MASK_1, irq_en1);
> +		vfe_reg_clr(vfe, VFE_0_IRQ_COMPOSITE_MASK_0, comp_mask);
> +	}
> +}
> +
> +static void vfe_enable_irq_common(struct vfe_device *vfe)
> +{
> +	u32 irq_en0 = VFE_0_IRQ_MASK_0_RESET_ACK;
> +	u32 irq_en1 = VFE_0_IRQ_MASK_1_VIOLATION |
> +		      VFE_0_IRQ_MASK_1_BUS_BDG_HALT_ACK;
> +
> +	vfe_reg_set(vfe, VFE_0_IRQ_MASK_0, irq_en0);
> +	vfe_reg_set(vfe, VFE_0_IRQ_MASK_1, irq_en1);
> +}
> +
> +static void vfe_set_demux_cfg(struct vfe_device *vfe, struct vfe_line *line)
> +{
> +	u32 val, even_cfg, odd_cfg;
> +
> +	writel_relaxed(VFE_0_DEMUX_CFG_PERIOD, vfe->base + VFE_0_DEMUX_CFG);
> +
> +	val = VFE_0_DEMUX_GAIN_0_CH0_EVEN | VFE_0_DEMUX_GAIN_0_CH0_ODD;
> +	writel_relaxed(val, vfe->base + VFE_0_DEMUX_GAIN_0);
> +
> +	val = VFE_0_DEMUX_GAIN_1_CH1 | VFE_0_DEMUX_GAIN_1_CH2;
> +	writel_relaxed(val, vfe->base + VFE_0_DEMUX_GAIN_1);
> +
> +	switch (line->fmt[MSM_VFE_PAD_SINK].code) {
> +	case MEDIA_BUS_FMT_YUYV8_2X8:
> +		even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_YUYV;
> +		odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_YUYV;
> +		break;
> +	case MEDIA_BUS_FMT_YVYU8_2X8:
> +		even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_YVYU;
> +		odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_YVYU;
> +		break;
> +	case MEDIA_BUS_FMT_UYVY8_2X8:
> +	default:
> +		even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_UYVY;
> +		odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_UYVY;
> +		break;
> +	case MEDIA_BUS_FMT_VYUY8_2X8:
> +		even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_VYUY;
> +		odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_VYUY;
> +		break;
> +	}
> +
> +	writel_relaxed(even_cfg, vfe->base + VFE_0_DEMUX_EVEN_CFG);
> +	writel_relaxed(odd_cfg, vfe->base + VFE_0_DEMUX_ODD_CFG);
> +}
> +
> +static void vfe_set_scale_cfg(struct vfe_device *vfe, struct vfe_line *line)
> +{
> +	u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat;
> +	u32 reg;
> +	u16 input, output;
> +	u8 interp_reso;
> +	u32 phase_mult;
> +
> +	writel_relaxed(0x3, vfe->base + VFE_0_SCALE_ENC_Y_CFG);
> +
> +	input = line->fmt[MSM_VFE_PAD_SINK].width - 1;
> +	output = line->compose.width - 1;
> +	reg = (output << 16) | input;
> +	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_Y_H_IMAGE_SIZE);
> +
> +	interp_reso = vfe_calc_interp_reso(input, output);
> +	phase_mult = input * (1 << (14 + interp_reso)) / output;
> +	reg = (interp_reso << 28) | phase_mult;
> +	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_Y_H_PHASE);
> +
> +	input = line->fmt[MSM_VFE_PAD_SINK].height - 1;
> +	output = line->compose.height - 1;
> +	reg = (output << 16) | input;
> +	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_Y_V_IMAGE_SIZE);
> +
> +	interp_reso = vfe_calc_interp_reso(input, output);
> +	phase_mult = input * (1 << (14 + interp_reso)) / output;
> +	reg = (interp_reso << 28) | phase_mult;
> +	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_Y_V_PHASE);
> +
> +	writel_relaxed(0x3, vfe->base + VFE_0_SCALE_ENC_CBCR_CFG);
> +
> +	input = line->fmt[MSM_VFE_PAD_SINK].width - 1;
> +	output = line->compose.width / 2 - 1;
> +	reg = (output << 16) | input;
> +	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_CBCR_H_IMAGE_SIZE);
> +
> +	interp_reso = vfe_calc_interp_reso(input, output);
> +	phase_mult = input * (1 << (14 + interp_reso)) / output;
> +	reg = (interp_reso << 28) | phase_mult;
> +	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_CBCR_H_PHASE);
> +
> +	input = line->fmt[MSM_VFE_PAD_SINK].height - 1;
> +	output = line->compose.height - 1;
> +	if (p == V4L2_PIX_FMT_NV12 || p == V4L2_PIX_FMT_NV21)
> +		output = line->compose.height / 2 - 1;
> +	reg = (output << 16) | input;
> +	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_CBCR_V_IMAGE_SIZE);
> +
> +	interp_reso = vfe_calc_interp_reso(input, output);
> +	phase_mult = input * (1 << (14 + interp_reso)) / output;
> +	reg = (interp_reso << 28) | phase_mult;
> +	writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_CBCR_V_PHASE);
> +}
> +
> +static void vfe_set_crop_cfg(struct vfe_device *vfe, struct vfe_line *line)
> +{
> +	u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat;
> +	u32 reg;
> +	u16 first, last;
> +
> +	first = line->crop.left;
> +	last = line->crop.left + line->crop.width - 1;
> +	reg = (first << 16) | last;
> +	writel_relaxed(reg, vfe->base + VFE_0_CROP_ENC_Y_WIDTH);
> +
> +	first = line->crop.top;
> +	last = line->crop.top + line->crop.height - 1;
> +	reg = (first << 16) | last;
> +	writel_relaxed(reg, vfe->base + VFE_0_CROP_ENC_Y_HEIGHT);
> +
> +	first = line->crop.left / 2;
> +	last = line->crop.left / 2 + line->crop.width / 2 - 1;
> +	reg = (first << 16) | last;
> +	writel_relaxed(reg, vfe->base + VFE_0_CROP_ENC_CBCR_WIDTH);
> +
> +	first = line->crop.top;
> +	last = line->crop.top + line->crop.height - 1;
> +	if (p == V4L2_PIX_FMT_NV12 || p == V4L2_PIX_FMT_NV21) {
> +		first = line->crop.top / 2;
> +		last = line->crop.top / 2 + line->crop.height / 2 - 1;
> +	}
> +	reg = (first << 16) | last;
> +	writel_relaxed(reg, vfe->base + VFE_0_CROP_ENC_CBCR_HEIGHT);
> +}
> +
> +static void vfe_set_clamp_cfg(struct vfe_device *vfe)
> +{
> +	u32 val = VFE_0_CLAMP_ENC_MAX_CFG_CH0 |
> +		VFE_0_CLAMP_ENC_MAX_CFG_CH1 |
> +		VFE_0_CLAMP_ENC_MAX_CFG_CH2;
> +
> +	writel_relaxed(val, vfe->base + VFE_0_CLAMP_ENC_MAX_CFG);
> +
> +	val = VFE_0_CLAMP_ENC_MIN_CFG_CH0 |
> +		VFE_0_CLAMP_ENC_MIN_CFG_CH1 |
> +		VFE_0_CLAMP_ENC_MIN_CFG_CH2;
> +
> +	writel_relaxed(val, vfe->base + VFE_0_CLAMP_ENC_MIN_CFG);
> +}
> +
> +static void vfe_set_cgc_override(struct vfe_device *vfe, u8 wm, u8 enable)
> +{
> +	/* empty */
> +}
> +
> +static void vfe_set_camif_cfg(struct vfe_device *vfe, struct vfe_line *line)
> +{
> +	u32 val;
> +
> +	switch (line->fmt[MSM_VFE_PAD_SINK].code) {
> +	case MEDIA_BUS_FMT_YUYV8_2X8:
> +		val = VFE_0_CORE_CFG_PIXEL_PATTERN_YCBYCR;
> +		break;
> +	case MEDIA_BUS_FMT_YVYU8_2X8:
> +		val = VFE_0_CORE_CFG_PIXEL_PATTERN_YCRYCB;
> +		break;
> +	case MEDIA_BUS_FMT_UYVY8_2X8:
> +	default:
> +		val = VFE_0_CORE_CFG_PIXEL_PATTERN_CBYCRY;
> +		break;
> +	case MEDIA_BUS_FMT_VYUY8_2X8:
> +		val = VFE_0_CORE_CFG_PIXEL_PATTERN_CRYCBY;
> +		break;
> +	}
> +
> +	val |= VFE_0_CORE_CFG_COMPOSITE_REG_UPDATE_EN;
> +	writel_relaxed(val, vfe->base + VFE_0_CORE_CFG);
> +
> +	val = line->fmt[MSM_VFE_PAD_SINK].width * 2 - 1;
> +	val |= (line->fmt[MSM_VFE_PAD_SINK].height - 1) << 16;
> +	writel_relaxed(val, vfe->base + VFE_0_CAMIF_FRAME_CFG);
> +
> +	val = line->fmt[MSM_VFE_PAD_SINK].width * 2 - 1;
> +	writel_relaxed(val, vfe->base + VFE_0_CAMIF_WINDOW_WIDTH_CFG);
> +
> +	val = line->fmt[MSM_VFE_PAD_SINK].height - 1;
> +	writel_relaxed(val, vfe->base + VFE_0_CAMIF_WINDOW_HEIGHT_CFG);
> +
> +	val = 0xffffffff;
> +	writel_relaxed(val, vfe->base + VFE_0_CAMIF_SUBSAMPLE_CFG);
> +
> +	val = 0xffffffff;
> +	writel_relaxed(val, vfe->base + VFE_0_CAMIF_IRQ_FRAMEDROP_PATTERN);
> +
> +	val = 0xffffffff;
> +	writel_relaxed(val, vfe->base + VFE_0_CAMIF_IRQ_SUBSAMPLE_PATTERN);
> +
> +	val = VFE_0_RDI_CFG_x_MIPI_EN_BITS;
> +	vfe_reg_set(vfe, VFE_0_RDI_CFG_x(0), val);
> +
> +	val = VFE_0_CAMIF_CFG_VFE_OUTPUT_EN;
> +	writel_relaxed(val, vfe->base + VFE_0_CAMIF_CFG);
> +}
> +
> +static void vfe_set_camif_cmd(struct vfe_device *vfe, u8 enable)
> +{
> +	u32 cmd;
> +
> +	cmd = VFE_0_CAMIF_CMD_CLEAR_CAMIF_STATUS | VFE_0_CAMIF_CMD_NO_CHANGE;
> +	writel_relaxed(cmd, vfe->base + VFE_0_CAMIF_CMD);
> +
> +	/* Make sure camif command is issued written before it is changed again */
> +	wmb();
> +
> +	if (enable)
> +		cmd = VFE_0_CAMIF_CMD_ENABLE_FRAME_BOUNDARY;
> +	else
> +		cmd = VFE_0_CAMIF_CMD_DISABLE_FRAME_BOUNDARY;
> +
> +	writel_relaxed(cmd, vfe->base + VFE_0_CAMIF_CMD);
> +}
> +
> +static void vfe_set_module_cfg(struct vfe_device *vfe, u8 enable)
> +{
> +	u32 val_lens = VFE_0_MODULE_LENS_EN_DEMUX |
> +		       VFE_0_MODULE_LENS_EN_CHROMA_UPSAMPLE;
> +	u32 val_zoom = VFE_0_MODULE_ZOOM_EN_SCALE_ENC |
> +		       VFE_0_MODULE_ZOOM_EN_CROP_ENC;
> +
> +	if (enable) {
> +		vfe_reg_set(vfe, VFE_0_MODULE_LENS_EN, val_lens);
> +		vfe_reg_set(vfe, VFE_0_MODULE_ZOOM_EN, val_zoom);
> +	} else {
> +		vfe_reg_clr(vfe, VFE_0_MODULE_LENS_EN, val_lens);
> +		vfe_reg_clr(vfe, VFE_0_MODULE_ZOOM_EN, val_zoom);
> +	}
> +}
> +
> +static int vfe_camif_wait_for_stop(struct vfe_device *vfe, struct device *dev)
> +{
> +	u32 val;
> +	int ret;
> +
> +	ret = readl_poll_timeout(vfe->base + VFE_0_CAMIF_STATUS,
> +				 val,
> +				 (val & VFE_0_CAMIF_STATUS_HALT),
> +				 CAMIF_TIMEOUT_SLEEP_US,
> +				 CAMIF_TIMEOUT_ALL_US);
> +	if (ret < 0)
> +		dev_err(dev, "%s: camif stop timeout\n", __func__);
> +
> +	return ret;
> +}
> +
> +/*
> + * vfe_isr - VFE module interrupt handler
> + * @irq: Interrupt line
> + * @dev: VFE device
> + *
> + * Return IRQ_HANDLED on success
> + */
> +static irqreturn_t vfe_isr(int irq, void *dev)
> +{
> +	struct vfe_device *vfe = dev;
> +	u32 value0, value1;
> +	int i, j;
> +
> +	vfe->ops->isr_read(vfe, &value0, &value1);
> +
> +	dev_dbg(vfe->camss->dev, "VFE: status0 = 0x%08x, status1 = 0x%08x\n",
> +		value0, value1);
> +
> +	if (value0 & VFE_0_IRQ_STATUS_0_RESET_ACK)
> +		vfe->isr_ops.reset_ack(vfe);
> +
> +	if (value1 & VFE_0_IRQ_STATUS_1_VIOLATION)
> +		vfe->ops->violation_read(vfe);
> +
> +	if (value1 & VFE_0_IRQ_STATUS_1_BUS_BDG_HALT_ACK)
> +		vfe->isr_ops.halt_ack(vfe);
> +
> +	for (i = VFE_LINE_RDI0; i <= VFE_LINE_PIX; i++)
> +		if (value0 & VFE_0_IRQ_STATUS_0_line_n_REG_UPDATE(i))
> +			vfe->isr_ops.reg_update(vfe, i);

- calling this one with i equal to VFE_LINE_PIX would result in using
vfe->line[VFE_LINE_PIX] without explicit check against vfe->line_num.
But as this vfe_isr() implementation is specifically for VFE version 4.8,
this is no problem.
Maybe the "for (i = VFE_LINE_RDI0; i <= VFE_LINE_PIX; i++)" cycle
could be changed to use "i < VFE_LINE_NUM_GEN1" or "i < vfe->line_num"
instead, but I am not sure if it makes the code cleaner (functionally
there is no difference; VFE_LINE_PIX == 3, VFE_LINE_NUM_GEN1 == 4, and
for the 4.8 version vfe->line_num == VFE_LINE_NUM_GEN1).

In any case,

Reviewed-by: Andrey Konovalov <andrey.konovalov@...aro.org>

Thanks,
Andrey

> +	if (value0 & VFE_0_IRQ_STATUS_0_CAMIF_SOF)
> +		vfe->isr_ops.sof(vfe, VFE_LINE_PIX);
> +
> +	for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++)
> +		if (value1 & VFE_0_IRQ_STATUS_1_RDIn_SOF(i))
> +			vfe->isr_ops.sof(vfe, i);
> +
> +	for (i = 0; i < MSM_VFE_COMPOSITE_IRQ_NUM; i++)
> +		if (value0 & VFE_0_IRQ_STATUS_0_IMAGE_COMPOSITE_DONE_n(i)) {
> +			vfe->isr_ops.comp_done(vfe, i);
> +			for (j = 0; j < ARRAY_SIZE(vfe->wm_output_map); j++)
> +				if (vfe->wm_output_map[j] == VFE_LINE_PIX)
> +					value0 &= ~VFE_0_IRQ_MASK_0_IMAGE_MASTER_n_PING_PONG(j);
> +		}
> +
> +	for (i = 0; i < MSM_VFE_IMAGE_MASTERS_NUM; i++)
> +		if (value0 & VFE_0_IRQ_STATUS_0_IMAGE_MASTER_n_PING_PONG(i))
> +			vfe->isr_ops.wm_done(vfe, i);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static u16 vfe_get_ub_size(u8 vfe_id)
> +{
> +	/* On VFE4.8 the ub-size is the same on both instances */
> +	return MSM_VFE_VFE0_UB_SIZE_RDI;
> +}
> +
> +static void vfe_wm_enable(struct vfe_device *vfe, u8 wm, u8 enable)
> +{
> +	if (enable)
> +		writel_relaxed(2 << VFE_0_BUS_IMAGE_MASTER_n_SHIFT(wm),
> +			       vfe->base + VFE_0_BUS_IMAGE_MASTER_CMD);
> +	else
> +		writel_relaxed(1 << VFE_0_BUS_IMAGE_MASTER_n_SHIFT(wm),
> +			       vfe->base + VFE_0_BUS_IMAGE_MASTER_CMD);
> +
> +	/* The WM must be enabled before sending other commands */
> +	wmb();
> +}
> +
> +static void vfe_set_qos(struct vfe_device *vfe)
> +{
> +	u32 val = VFE_0_BUS_BDG_QOS_CFG_0_CFG;
> +	u32 val3 = VFE_0_BUS_BDG_QOS_CFG_3_CFG;
> +	u32 val4 = VFE_0_BUS_BDG_QOS_CFG_4_CFG;
> +	u32 val7 = VFE_0_BUS_BDG_QOS_CFG_7_CFG;
> +
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_0);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_1);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_2);
> +	writel_relaxed(val3, vfe->base + VFE_0_BUS_BDG_QOS_CFG_3);
> +	writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_4);
> +	writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_5);
> +	writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_6);
> +	writel_relaxed(val7, vfe->base + VFE_0_BUS_BDG_QOS_CFG_7);
> +}
> +
> +static void vfe_set_ds(struct vfe_device *vfe)
> +{
> +	u32 val = VFE_0_BUS_BDG_DS_CFG_0_CFG;
> +	u32 val16 = VFE_0_BUS_BDG_DS_CFG_16_CFG;
> +
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_0);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_1);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_2);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_3);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_4);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_5);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_6);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_7);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_8);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_9);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_10);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_11);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_12);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_13);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_14);
> +	writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_15);
> +	writel_relaxed(val16, vfe->base + VFE_0_BUS_BDG_DS_CFG_16);
> +}
> +
> +static void vfe_isr_read(struct vfe_device *vfe, u32 *value0, u32 *value1)
> +{
> +	*value0 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_0);
> +	*value1 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_1);
> +
> +	writel_relaxed(*value0, vfe->base + VFE_0_IRQ_CLEAR_0);
> +	writel_relaxed(*value1, vfe->base + VFE_0_IRQ_CLEAR_1);
> +
> +	/* Enforce barrier between local & global IRQ clear */
> +	wmb();
> +	writel_relaxed(VFE_0_IRQ_CMD_GLOBAL_CLEAR, vfe->base + VFE_0_IRQ_CMD);
> +}
> +
> +static void vfe_violation_read(struct vfe_device *vfe)
> +{
> +	u32 violation = readl_relaxed(vfe->base + VFE_0_VIOLATION_STATUS);
> +
> +	pr_err_ratelimited("VFE: violation = 0x%08x\n", violation);
> +}
> +
> +const struct vfe_hw_ops_gen1 vfe_ops_gen1_4_8 = {
> +	.bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi,
> +	.bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi,
> +	.bus_enable_wr_if = vfe_bus_enable_wr_if,
> +	.bus_reload_wm = vfe_bus_reload_wm,
> +	.camif_wait_for_stop = vfe_camif_wait_for_stop,
> +	.enable_irq_common = vfe_enable_irq_common,
> +	.enable_irq_pix_line = vfe_enable_irq_pix_line,
> +	.enable_irq_wm_line = vfe_enable_irq_wm_line,
> +	.get_ub_size = vfe_get_ub_size,
> +	.halt_clear = vfe_halt_clear,
> +	.halt_request = vfe_halt_request,
> +	.set_camif_cfg = vfe_set_camif_cfg,
> +	.set_camif_cmd = vfe_set_camif_cmd,
> +	.set_cgc_override = vfe_set_cgc_override,
> +	.set_clamp_cfg = vfe_set_clamp_cfg,
> +	.set_crop_cfg = vfe_set_crop_cfg,
> +	.set_demux_cfg = vfe_set_demux_cfg,
> +	.set_ds = vfe_set_ds,
> +	.set_module_cfg = vfe_set_module_cfg,
> +	.set_qos = vfe_set_qos,
> +	.set_rdi_cid = vfe_set_rdi_cid,
> +	.set_realign_cfg = vfe_set_realign_cfg,
> +	.set_scale_cfg = vfe_set_scale_cfg,
> +	.set_xbar_cfg = vfe_set_xbar_cfg,
> +	.wm_enable = vfe_wm_enable,
> +	.wm_frame_based = vfe_wm_frame_based,
> +	.wm_get_ping_pong_status = vfe_wm_get_ping_pong_status,
> +	.wm_line_based = vfe_wm_line_based,
> +	.wm_set_framedrop_pattern = vfe_wm_set_framedrop_pattern,
> +	.wm_set_framedrop_period = vfe_wm_set_framedrop_period,
> +	.wm_set_ping_addr = vfe_wm_set_ping_addr,
> +	.wm_set_pong_addr = vfe_wm_set_pong_addr,
> +	.wm_set_subsample = vfe_wm_set_subsample,
> +	.wm_set_ub_cfg = vfe_wm_set_ub_cfg,
> +};
> +
> +static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe)
> +{
> +	vfe->isr_ops = vfe_isr_ops_gen1;
> +	vfe->ops_gen1 = &vfe_ops_gen1_4_8;
> +	vfe->video_ops = vfe_video_ops_gen1;
> +
> +	vfe->line_num = VFE_LINE_NUM_GEN1;
> +}
> +
> +const struct vfe_hw_ops vfe_ops_4_8 = {
> +	.global_reset = vfe_global_reset,
> +	.hw_version_read = vfe_hw_version_read,
> +	.isr_read = vfe_isr_read,
> +	.isr = vfe_isr,
> +	.reg_update_clear = vfe_reg_update_clear,
> +	.reg_update = vfe_reg_update,
> +	.subdev_init = vfe_subdev_init,
> +	.vfe_disable = vfe_gen1_disable,
> +	.vfe_enable = vfe_gen1_enable,
> +	.vfe_halt = vfe_gen1_halt,
> +	.violation_read = vfe_violation_read,
> +};
> diff --git a/drivers/media/platform/qcom/camss/camss-vfe-gen1.c b/drivers/media/platform/qcom/camss/camss-vfe-gen1.c
> new file mode 100644
> index 000000000000..b98f30f99e89
> --- /dev/null
> +++ b/drivers/media/platform/qcom/camss/camss-vfe-gen1.c
> @@ -0,0 +1,763 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * camss-vfe-gen1.c
> + *
> + * Qualcomm MSM Camera Subsystem - VFE Common functionality for Gen 1 versions of hw (4.1, 4.7..)
> + *
> + * Copyright (C) 2020 Linaro Ltd.
> + */
> +
> +
> +#include "camss.h"
> +#include "camss-vfe.h"
> +#include "camss-vfe-gen1.h"
> +
> +/* Max number of frame drop updates per frame */
> +#define VFE_FRAME_DROP_UPDATES 2
> +#define VFE_NEXT_SOF_MS 500
> +
> +
> +int vfe_gen1_halt(struct vfe_device *vfe)
> +{
> +	unsigned long time;
> +
> +	return 0;
> +
> +	reinit_completion(&vfe->halt_complete);
> +
> +	vfe->ops_gen1->halt_request(vfe);
> +
> +	time = wait_for_completion_timeout(&vfe->halt_complete,
> +					   msecs_to_jiffies(VFE_HALT_TIMEOUT_MS));
> +	if (!time) {
> +		dev_err(vfe->camss->dev, "VFE halt timeout\n");
> +		return -EIO;
> +	}
> +
> +	return 0;
> +}
> +
> +static int vfe_disable_output(struct vfe_line *line)
> +{
> +	struct vfe_device *vfe = to_vfe(line);
> +	struct vfe_output *output = &line->output;
> +	const struct vfe_hw_ops *ops = vfe->ops;
> +	unsigned long flags;
> +	unsigned long time;
> +	unsigned int i;
> +
> +	spin_lock_irqsave(&vfe->output_lock, flags);
> +
> +	output->gen1.wait_sof = 1;
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +
> +	time = wait_for_completion_timeout(&output->sof, msecs_to_jiffies(VFE_NEXT_SOF_MS));
> +	if (!time)
> +		dev_err(vfe->camss->dev, "VFE sof timeout\n");
> +
> +	spin_lock_irqsave(&vfe->output_lock, flags);
> +	for (i = 0; i < output->wm_num; i++)
> +		vfe->ops_gen1->wm_enable(vfe, output->wm_idx[i], 0);
> +
> +	ops->reg_update(vfe, line->id);
> +	output->wait_reg_update = 1;
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +
> +	time = wait_for_completion_timeout(&output->reg_update, msecs_to_jiffies(VFE_NEXT_SOF_MS));
> +	if (!time)
> +		dev_err(vfe->camss->dev, "VFE reg update timeout\n");
> +
> +	spin_lock_irqsave(&vfe->output_lock, flags);
> +
> +	if (line->id != VFE_LINE_PIX) {
> +		vfe->ops_gen1->wm_frame_based(vfe, output->wm_idx[0], 0);
> +		vfe->ops_gen1->bus_disconnect_wm_from_rdi(vfe, output->wm_idx[0], line->id);
> +		vfe->ops_gen1->enable_irq_wm_line(vfe, output->wm_idx[0], line->id, 0);
> +		vfe->ops_gen1->set_cgc_override(vfe, output->wm_idx[0], 0);
> +		spin_unlock_irqrestore(&vfe->output_lock, flags);
> +	} else {
> +		for (i = 0; i < output->wm_num; i++) {
> +			vfe->ops_gen1->wm_line_based(vfe, output->wm_idx[i], NULL, i, 0);
> +			vfe->ops_gen1->set_cgc_override(vfe, output->wm_idx[i], 0);
> +		}
> +
> +		vfe->ops_gen1->enable_irq_pix_line(vfe, 0, line->id, 0);
> +		vfe->ops_gen1->set_module_cfg(vfe, 0);
> +		vfe->ops_gen1->set_realign_cfg(vfe, line, 0);
> +		vfe->ops_gen1->set_xbar_cfg(vfe, output, 0);
> +		vfe->ops_gen1->set_camif_cmd(vfe, 0);
> +
> +		spin_unlock_irqrestore(&vfe->output_lock, flags);
> +
> +		vfe->ops_gen1->camif_wait_for_stop(vfe, vfe->camss->dev);
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * vfe_gen1_disable - Disable streaming on VFE line
> + * @line: VFE line
> + *
> + * Return 0 on success or a negative error code otherwise
> + */
> +int vfe_gen1_disable(struct vfe_line *line)
> +{
> +	struct vfe_device *vfe = to_vfe(line);
> +
> +	vfe_disable_output(line);
> +
> +	vfe_put_output(line);
> +
> +	mutex_lock(&vfe->stream_lock);
> +
> +	if (vfe->stream_count == 1)
> +		vfe->ops_gen1->bus_enable_wr_if(vfe, 0);
> +
> +	vfe->stream_count--;
> +
> +	mutex_unlock(&vfe->stream_lock);
> +
> +	return 0;
> +}
> +
> +static void vfe_output_init_addrs(struct vfe_device *vfe,
> +				  struct vfe_output *output, u8 sync,
> +				  struct vfe_line *line)
> +{
> +	u32 ping_addr;
> +	u32 pong_addr;
> +	unsigned int i;
> +
> +	output->gen1.active_buf = 0;
> +
> +	for (i = 0; i < output->wm_num; i++) {
> +		if (output->buf[0])
> +			ping_addr = output->buf[0]->addr[i];
> +		else
> +			ping_addr = 0;
> +
> +		if (output->buf[1])
> +			pong_addr = output->buf[1]->addr[i];
> +		else
> +			pong_addr = ping_addr;
> +
> +		vfe->ops_gen1->wm_set_ping_addr(vfe, output->wm_idx[i], ping_addr);
> +		vfe->ops_gen1->wm_set_pong_addr(vfe, output->wm_idx[i], pong_addr);
> +		if (sync)
> +			vfe->ops_gen1->bus_reload_wm(vfe, output->wm_idx[i]);
> +	}
> +}
> +
> +static void vfe_output_frame_drop(struct vfe_device *vfe,
> +				  struct vfe_output *output,
> +				  u32 drop_pattern)
> +{
> +	u8 drop_period;
> +	unsigned int i;
> +
> +	/* We need to toggle update period to be valid on next frame */
> +	output->drop_update_idx++;
> +	output->drop_update_idx %= VFE_FRAME_DROP_UPDATES;
> +	drop_period = VFE_FRAME_DROP_VAL + output->drop_update_idx;
> +
> +	for (i = 0; i < output->wm_num; i++) {
> +		vfe->ops_gen1->wm_set_framedrop_period(vfe, output->wm_idx[i], drop_period);
> +		vfe->ops_gen1->wm_set_framedrop_pattern(vfe, output->wm_idx[i], drop_pattern);
> +	}
> +
> +	vfe->ops->reg_update(vfe, container_of(output, struct vfe_line, output)->id);
> +}
> +
> +static int vfe_enable_output(struct vfe_line *line)
> +{
> +	struct vfe_device *vfe = to_vfe(line);
> +	struct vfe_output *output = &line->output;
> +	const struct vfe_hw_ops *ops = vfe->ops;
> +	struct media_entity *sensor;
> +	unsigned long flags;
> +	unsigned int frame_skip = 0;
> +	unsigned int i;
> +	u16 ub_size;
> +
> +	ub_size = vfe->ops_gen1->get_ub_size(vfe->id);
> +	if (!ub_size)
> +		return -EINVAL;
> +
> +	sensor = camss_find_sensor(&line->subdev.entity);
> +	if (sensor) {
> +		struct v4l2_subdev *subdev = media_entity_to_v4l2_subdev(sensor);
> +
> +		v4l2_subdev_call(subdev, sensor, g_skip_frames, &frame_skip);
> +		/* Max frame skip is 29 frames */
> +		if (frame_skip > VFE_FRAME_DROP_VAL - 1)
> +			frame_skip = VFE_FRAME_DROP_VAL - 1;
> +	}
> +
> +	spin_lock_irqsave(&vfe->output_lock, flags);
> +
> +	ops->reg_update_clear(vfe, line->id);
> +
> +	if (output->state != VFE_OUTPUT_RESERVED) {
> +		dev_err(vfe->camss->dev, "Output is not in reserved state %d\n", output->state);
> +		spin_unlock_irqrestore(&vfe->output_lock, flags);
> +		return -EINVAL;
> +	}
> +	output->state = VFE_OUTPUT_IDLE;
> +
> +	output->buf[0] = vfe_buf_get_pending(output);
> +	output->buf[1] = vfe_buf_get_pending(output);
> +
> +	if (!output->buf[0] && output->buf[1]) {
> +		output->buf[0] = output->buf[1];
> +		output->buf[1] = NULL;
> +	}
> +
> +	if (output->buf[0])
> +		output->state = VFE_OUTPUT_SINGLE;
> +
> +	if (output->buf[1])
> +		output->state = VFE_OUTPUT_CONTINUOUS;
> +
> +	switch (output->state) {
> +	case VFE_OUTPUT_SINGLE:
> +		vfe_output_frame_drop(vfe, output, 1 << frame_skip);
> +		break;
> +	case VFE_OUTPUT_CONTINUOUS:
> +		vfe_output_frame_drop(vfe, output, 3 << frame_skip);
> +		break;
> +	default:
> +		vfe_output_frame_drop(vfe, output, 0);
> +		break;
> +	}
> +
> +	output->sequence = 0;
> +	output->gen1.wait_sof = 0;
> +	output->wait_reg_update = 0;
> +	reinit_completion(&output->sof);
> +	reinit_completion(&output->reg_update);
> +
> +	vfe_output_init_addrs(vfe, output, 0, line);
> +
> +	if (line->id != VFE_LINE_PIX) {
> +		vfe->ops_gen1->set_cgc_override(vfe, output->wm_idx[0], 1);
> +		vfe->ops_gen1->enable_irq_wm_line(vfe, output->wm_idx[0], line->id, 1);
> +		vfe->ops_gen1->bus_connect_wm_to_rdi(vfe, output->wm_idx[0], line->id);
> +		vfe->ops_gen1->wm_set_subsample(vfe, output->wm_idx[0]);
> +		vfe->ops_gen1->set_rdi_cid(vfe, line->id, 0);
> +		vfe->ops_gen1->wm_set_ub_cfg(vfe, output->wm_idx[0],
> +					    (ub_size + 1) * output->wm_idx[0], ub_size);
> +		vfe->ops_gen1->wm_frame_based(vfe, output->wm_idx[0], 1);
> +		vfe->ops_gen1->wm_enable(vfe, output->wm_idx[0], 1);
> +		vfe->ops_gen1->bus_reload_wm(vfe, output->wm_idx[0]);
> +	} else {
> +		ub_size /= output->wm_num;
> +		for (i = 0; i < output->wm_num; i++) {
> +			vfe->ops_gen1->set_cgc_override(vfe, output->wm_idx[i], 1);
> +			vfe->ops_gen1->wm_set_subsample(vfe, output->wm_idx[i]);
> +			vfe->ops_gen1->wm_set_ub_cfg(vfe, output->wm_idx[i],
> +						     (ub_size + 1) * output->wm_idx[i], ub_size);
> +			vfe->ops_gen1->wm_line_based(vfe, output->wm_idx[i],
> +						     &line->video_out.active_fmt.fmt.pix_mp, i, 1);
> +			vfe->ops_gen1->wm_enable(vfe, output->wm_idx[i], 1);
> +			vfe->ops_gen1->bus_reload_wm(vfe, output->wm_idx[i]);
> +		}
> +		vfe->ops_gen1->enable_irq_pix_line(vfe, 0, line->id, 1);
> +		vfe->ops_gen1->set_module_cfg(vfe, 1);
> +		vfe->ops_gen1->set_camif_cfg(vfe, line);
> +		vfe->ops_gen1->set_realign_cfg(vfe, line, 1);
> +		vfe->ops_gen1->set_xbar_cfg(vfe, output, 1);
> +		vfe->ops_gen1->set_demux_cfg(vfe, line);
> +		vfe->ops_gen1->set_scale_cfg(vfe, line);
> +		vfe->ops_gen1->set_crop_cfg(vfe, line);
> +		vfe->ops_gen1->set_clamp_cfg(vfe);
> +		vfe->ops_gen1->set_camif_cmd(vfe, 1);
> +	}
> +
> +	ops->reg_update(vfe, line->id);
> +
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +
> +	return 0;
> +}
> +
> +static int vfe_get_output(struct vfe_line *line)
> +{
> +	struct vfe_device *vfe = to_vfe(line);
> +	struct vfe_output *output;
> +	struct v4l2_format *f = &line->video_out.active_fmt;
> +	unsigned long flags;
> +	int i;
> +	int wm_idx;
> +
> +	spin_lock_irqsave(&vfe->output_lock, flags);
> +
> +	output = &line->output;
> +	if (output->state != VFE_OUTPUT_OFF) {
> +		dev_err(vfe->camss->dev, "Output is running\n");
> +		goto error;
> +	}
> +	output->state = VFE_OUTPUT_RESERVED;
> +
> +	output->gen1.active_buf = 0;
> +
> +	switch (f->fmt.pix_mp.pixelformat) {
> +	case V4L2_PIX_FMT_NV12:
> +	case V4L2_PIX_FMT_NV21:
> +	case V4L2_PIX_FMT_NV16:
> +	case V4L2_PIX_FMT_NV61:
> +		output->wm_num = 2;
> +		break;
> +	default:
> +		output->wm_num = 1;
> +		break;
> +	}
> +
> +	for (i = 0; i < output->wm_num; i++) {
> +		wm_idx = vfe_reserve_wm(vfe, line->id);
> +		if (wm_idx < 0) {
> +			dev_err(vfe->camss->dev, "Can not reserve wm\n");
> +			goto error_get_wm;
> +		}
> +		output->wm_idx[i] = wm_idx;
> +	}
> +
> +	output->drop_update_idx = 0;
> +
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +
> +	return 0;
> +
> +error_get_wm:
> +	for (i--; i >= 0; i--)
> +		vfe_release_wm(vfe, output->wm_idx[i]);
> +	output->state = VFE_OUTPUT_OFF;
> +error:
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +
> +	return -EINVAL;
> +}
> +
> +int vfe_gen1_enable(struct vfe_line *line)
> +{
> +	struct vfe_device *vfe = to_vfe(line);
> +	int ret;
> +
> +	mutex_lock(&vfe->stream_lock);
> +
> +	if (!vfe->stream_count) {
> +		vfe->ops_gen1->enable_irq_common(vfe);
> +		vfe->ops_gen1->bus_enable_wr_if(vfe, 1);
> +		vfe->ops_gen1->set_qos(vfe);
> +		vfe->ops_gen1->set_ds(vfe);
> +	}
> +
> +	vfe->stream_count++;
> +
> +	mutex_unlock(&vfe->stream_lock);
> +
> +	ret = vfe_get_output(line);
> +	if (ret < 0)
> +		goto error_get_output;
> +
> +	ret = vfe_enable_output(line);
> +	if (ret < 0)
> +		goto error_enable_output;
> +
> +	vfe->was_streaming = 1;
> +
> +	return 0;
> +
> +
> +error_enable_output:
> +	vfe_put_output(line);
> +
> +error_get_output:
> +	mutex_lock(&vfe->stream_lock);
> +
> +	if (vfe->stream_count == 1)
> +		vfe->ops_gen1->bus_enable_wr_if(vfe, 0);
> +
> +	vfe->stream_count--;
> +
> +	mutex_unlock(&vfe->stream_lock);
> +
> +	return ret;
> +}
> +
> +static void vfe_output_update_ping_addr(struct vfe_device *vfe,
> +					struct vfe_output *output, u8 sync,
> +					struct vfe_line *line)
> +{
> +	u32 addr;
> +	unsigned int i;
> +
> +	for (i = 0; i < output->wm_num; i++) {
> +		if (output->buf[0])
> +			addr = output->buf[0]->addr[i];
> +		else
> +			addr = 0;
> +
> +		vfe->ops_gen1->wm_set_ping_addr(vfe, output->wm_idx[i], addr);
> +		if (sync)
> +			vfe->ops_gen1->bus_reload_wm(vfe, output->wm_idx[i]);
> +	}
> +}
> +
> +static void vfe_output_update_pong_addr(struct vfe_device *vfe,
> +					struct vfe_output *output, u8 sync,
> +					struct vfe_line *line)
> +{
> +	u32 addr;
> +	unsigned int i;
> +
> +	for (i = 0; i < output->wm_num; i++) {
> +		if (output->buf[1])
> +			addr = output->buf[1]->addr[i];
> +		else
> +			addr = 0;
> +
> +		vfe->ops_gen1->wm_set_pong_addr(vfe, output->wm_idx[i], addr);
> +		if (sync)
> +			vfe->ops_gen1->bus_reload_wm(vfe, output->wm_idx[i]);
> +
> +	}
> +
> +}
> +
> +static void vfe_buf_update_wm_on_next(struct vfe_device *vfe,
> +				      struct vfe_output *output)
> +{
> +	switch (output->state) {
> +	case VFE_OUTPUT_CONTINUOUS:
> +		vfe_output_frame_drop(vfe, output, 3);
> +		break;
> +	case VFE_OUTPUT_SINGLE:
> +	default:
> +		dev_err_ratelimited(vfe->camss->dev,
> +				    "Next buf in wrong state! %d\n",
> +				    output->state);
> +		break;
> +	}
> +}
> +
> +static void vfe_buf_update_wm_on_last(struct vfe_device *vfe,
> +				      struct vfe_output *output)
> +{
> +	switch (output->state) {
> +	case VFE_OUTPUT_CONTINUOUS:
> +		output->state = VFE_OUTPUT_SINGLE;
> +		vfe_output_frame_drop(vfe, output, 1);
> +		break;
> +	case VFE_OUTPUT_SINGLE:
> +		output->state = VFE_OUTPUT_STOPPING;
> +		vfe_output_frame_drop(vfe, output, 0);
> +		break;
> +	default:
> +		dev_err_ratelimited(vfe->camss->dev,
> +				    "Last buff in wrong state! %d\n",
> +				    output->state);
> +		break;
> +	}
> +}
> +
> +static void vfe_buf_update_wm_on_new(struct vfe_device *vfe,
> +				     struct vfe_output *output,
> +				     struct camss_buffer *new_buf,
> +				     struct vfe_line *line)
> +{
> +	int inactive_idx;
> +
> +	switch (output->state) {
> +	case VFE_OUTPUT_SINGLE:
> +		inactive_idx = !output->gen1.active_buf;
> +
> +		if (!output->buf[inactive_idx]) {
> +			output->buf[inactive_idx] = new_buf;
> +
> +			if (inactive_idx)
> +				vfe_output_update_pong_addr(vfe, output, 0, line);
> +			else
> +				vfe_output_update_ping_addr(vfe, output, 0, line);
> +
> +			vfe_output_frame_drop(vfe, output, 3);
> +			output->state = VFE_OUTPUT_CONTINUOUS;
> +		} else {
> +			vfe_buf_add_pending(output, new_buf);
> +			dev_err_ratelimited(vfe->camss->dev,
> +					    "Inactive buffer is busy\n");
> +		}
> +		break;
> +
> +	case VFE_OUTPUT_IDLE:
> +		if (!output->buf[0]) {
> +			output->buf[0] = new_buf;
> +
> +			vfe_output_init_addrs(vfe, output, 1, line);
> +			vfe_output_frame_drop(vfe, output, 1);
> +
> +			output->state = VFE_OUTPUT_SINGLE;
> +		} else {
> +			vfe_buf_add_pending(output, new_buf);
> +			dev_err_ratelimited(vfe->camss->dev,
> +					    "Output idle with buffer set!\n");
> +		}
> +		break;
> +
> +	case VFE_OUTPUT_CONTINUOUS:
> +	default:
> +		vfe_buf_add_pending(output, new_buf);
> +		break;
> +	}
> +}
> +
> +/*
> + * vfe_isr_halt_ack - Process start of frame interrupt

- nitpick: wrong description of the function

> + * @vfe: VFE Device
> + */
> +static void vfe_isr_halt_ack(struct vfe_device *vfe)
> +{
> +	complete(&vfe->halt_complete);
> +	vfe->ops_gen1->halt_clear(vfe);
> +}
> +
> +/*
> + * vfe_isr_sof - Process start of frame interrupt
> + * @vfe: VFE Device
> + * @line_id: VFE line
> + */
> +static void vfe_isr_sof(struct vfe_device *vfe, enum vfe_line_id line_id)
> +{
> +	struct vfe_output *output;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&vfe->output_lock, flags);
> +	output = &vfe->line[line_id].output;
> +	if (output->gen1.wait_sof) {
> +		output->gen1.wait_sof = 0;
> +		complete(&output->sof);
> +	}
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +}
> +
> +/*
> + * vfe_isr_reg_update - Process reg update interrupt
> + * @vfe: VFE Device
> + * @line_id: VFE line
> + */
> +static void vfe_isr_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
> +{
> +	struct vfe_output *output;
> +	struct vfe_line *line = &vfe->line[line_id];
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&vfe->output_lock, flags);
> +	vfe->ops->reg_update_clear(vfe, line_id);
> +
> +	output = &line->output;
> +
> +	if (output->wait_reg_update) {
> +		output->wait_reg_update = 0;
> +		complete(&output->reg_update);
> +		spin_unlock_irqrestore(&vfe->output_lock, flags);
> +		return;
> +	}
> +
> +	if (output->state == VFE_OUTPUT_STOPPING) {
> +		/* Release last buffer when hw is idle */
> +		if (output->last_buffer) {
> +			vb2_buffer_done(&output->last_buffer->vb.vb2_buf,
> +					VB2_BUF_STATE_DONE);
> +			output->last_buffer = NULL;
> +		}
> +		output->state = VFE_OUTPUT_IDLE;
> +
> +		/* Buffers received in stopping state are queued in */
> +		/* dma pending queue, start next capture here */
> +
> +		output->buf[0] = vfe_buf_get_pending(output);
> +		output->buf[1] = vfe_buf_get_pending(output);
> +
> +		if (!output->buf[0] && output->buf[1]) {
> +			output->buf[0] = output->buf[1];
> +			output->buf[1] = NULL;
> +		}
> +
> +		if (output->buf[0])
> +			output->state = VFE_OUTPUT_SINGLE;
> +
> +		if (output->buf[1])
> +			output->state = VFE_OUTPUT_CONTINUOUS;
> +
> +		switch (output->state) {
> +		case VFE_OUTPUT_SINGLE:
> +			vfe_output_frame_drop(vfe, output, 2);
> +			break;
> +		case VFE_OUTPUT_CONTINUOUS:
> +			vfe_output_frame_drop(vfe, output, 3);
> +			break;
> +		default:
> +			vfe_output_frame_drop(vfe, output, 0);
> +			break;
> +		}
> +
> +		vfe_output_init_addrs(vfe, output, 1, &vfe->line[line_id]);
> +	}
> +
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +}
> +
> +/*
> + * vfe_isr_wm_done - Process write master done interrupt
> + * @vfe: VFE Device
> + * @wm: Write master id
> + */
> +static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
> +{
> +	struct camss_buffer *ready_buf;
> +	struct vfe_output *output;
> +	dma_addr_t *new_addr;
> +	unsigned long flags;
> +	u32 active_index;
> +	u64 ts = ktime_get_ns();
> +	unsigned int i;
> +
> +	active_index = vfe->ops_gen1->wm_get_ping_pong_status(vfe, wm);
> +
> +	spin_lock_irqsave(&vfe->output_lock, flags);
> +
> +	if (vfe->wm_output_map[wm] == VFE_LINE_NONE) {
> +		dev_err_ratelimited(vfe->camss->dev,
> +				    "Received wm done for unmapped index\n");
> +		goto out_unlock;
> +	}
> +	output = &vfe->line[vfe->wm_output_map[wm]].output;
> +
> +	if (output->gen1.active_buf == active_index && 0) {
> +		dev_err_ratelimited(vfe->camss->dev,
> +				    "Active buffer mismatch!\n");
> +		goto out_unlock;
> +	}
> +	output->gen1.active_buf = active_index;
> +
> +	ready_buf = output->buf[!active_index];
> +	if (!ready_buf) {
> +		dev_err_ratelimited(vfe->camss->dev,
> +				    "Missing ready buf %d %d!\n",
> +				    !active_index, output->state);
> +		goto out_unlock;
> +	}
> +
> +	ready_buf->vb.vb2_buf.timestamp = ts;
> +	ready_buf->vb.sequence = output->sequence++;
> +
> +	/* Get next buffer */
> +	output->buf[!active_index] = vfe_buf_get_pending(output);
> +	if (!output->buf[!active_index]) {
> +		/* No next buffer - set same address */
> +		new_addr = ready_buf->addr;
> +		vfe_buf_update_wm_on_last(vfe, output);
> +	} else {
> +		new_addr = output->buf[!active_index]->addr;
> +		vfe_buf_update_wm_on_next(vfe, output);
> +	}
> +
> +	if (active_index)
> +		for (i = 0; i < output->wm_num; i++)
> +			vfe->ops_gen1->wm_set_ping_addr(vfe, output->wm_idx[i], new_addr[i]);
> +	else
> +		for (i = 0; i < output->wm_num; i++)
> +			vfe->ops_gen1->wm_set_pong_addr(vfe, output->wm_idx[i], new_addr[i]);
> +
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +
> +	if (output->state == VFE_OUTPUT_STOPPING)
> +		output->last_buffer = ready_buf;
> +	else
> +		vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
> +
> +	return;
> +
> +out_unlock:
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +}
> +
> +/*
> + * vfe_queue_buffer - Add empty buffer
> + * @vid: Video device structure
> + * @buf: Buffer to be enqueued
> + *
> + * Add an empty buffer - depending on the current number of buffers it will be
> + * put in pending buffer queue or directly given to the hardware to be filled.
> + *
> + * Return 0 on success or a negative error code otherwise
> + */
> +static int vfe_queue_buffer(struct camss_video *vid, struct camss_buffer *buf)
> +{
> +	struct vfe_line *line = container_of(vid, struct vfe_line, video_out);
> +	struct vfe_device *vfe = to_vfe(line);
> +	struct vfe_output *output;
> +	unsigned long flags;
> +
> +	output = &line->output;
> +
> +	spin_lock_irqsave(&vfe->output_lock, flags);
> +
> +	vfe_buf_update_wm_on_new(vfe, output, buf, line);
> +
> +	spin_unlock_irqrestore(&vfe->output_lock, flags);
> +
> +	return 0;
> +}
> +
> +inline u8 vfe_calc_interp_reso(u16 input, u16 output)
> +{
> +	if (input / output >= 16)
> +		return 0;
> +
> +	if (input / output >= 8)
> +		return 1;
> +
> +	if (input / output >= 4)
> +		return 2;
> +
> +	return 3;
> +}
> +
> +#define CALC_WORD(width, M, N) (((width) * (M) + (N) - 1) / (N))
> +
> +int vfe_word_per_line(u32 format, u32 width)
> +{
> +	int val = 0;
> +
> +	switch (format) {
> +	case V4L2_PIX_FMT_NV12:
> +	case V4L2_PIX_FMT_NV21:
> +	case V4L2_PIX_FMT_NV16:
> +	case V4L2_PIX_FMT_NV61:
> +		val = CALC_WORD(width, 1, 8);
> +		break;
> +	case V4L2_PIX_FMT_YUYV:
> +	case V4L2_PIX_FMT_YVYU:
> +	case V4L2_PIX_FMT_UYVY:
> +	case V4L2_PIX_FMT_VYUY:
> +		val = CALC_WORD(width, 2, 8);
> +		break;
> +	}
> +
> +	return val;
> +}
> +
> +const struct vfe_isr_ops vfe_isr_ops_gen1 = {
> +	.reset_ack = vfe_isr_reset_ack,
> +	.halt_ack = vfe_isr_halt_ack,
> +	.reg_update = vfe_isr_reg_update,
> +	.sof = vfe_isr_sof,
> +	.comp_done = vfe_isr_comp_done,
> +	.wm_done = vfe_isr_wm_done,
> +};
> +
> +const struct camss_video_ops vfe_video_ops_gen1 = {
> +	.queue_buffer = vfe_queue_buffer,
> +	.flush_buffers = vfe_flush_buffers,
> +};
> diff --git a/drivers/media/platform/qcom/camss/camss-vfe-gen1.h b/drivers/media/platform/qcom/camss/camss-vfe-gen1.h
> new file mode 100644
> index 000000000000..42e8a3333034
> --- /dev/null
> +++ b/drivers/media/platform/qcom/camss/camss-vfe-gen1.h
> @@ -0,0 +1,110 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * camss-vfe.h
> + *
> + * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module
> + *
> + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
> + * Copyright (C) 2015-2018 Linaro Ltd.
> + */
> +#ifndef QC_MSM_CAMSS_VFE_GEN1_H
> +#define QC_MSM_CAMSS_VFE_GEN1_H
> +
> +
> +#include "camss-vfe.h"
> +
> +
> +enum vfe_line_id;
> +struct vfe_device;
> +struct vfe_line;
> +struct vfe_output;
> +
> +struct vfe_hw_ops_gen1 {
> +	void (*bus_connect_wm_to_rdi)(struct vfe_device *vfe, u8 wm, enum vfe_line_id id);
> +	void (*bus_disconnect_wm_from_rdi)(struct vfe_device *vfe, u8 wm, enum vfe_line_id id);
> +	void (*bus_enable_wr_if)(struct vfe_device *vfe, u8 enable);
> +	void (*bus_reload_wm)(struct vfe_device *vfe, u8 wm);
> +	int (*camif_wait_for_stop)(struct vfe_device *vfe, struct device *dev);
> +	void (*enable_irq_common)(struct vfe_device *vfe);
> +	void (*enable_irq_wm_line)(struct vfe_device *vfe, u8 wm, enum vfe_line_id line_id,
> +				   u8 enable);
> +	void (*enable_irq_pix_line)(struct vfe_device *vfe, u8 comp, enum vfe_line_id line_id,
> +				    u8 enable);
> +	u16 (*get_ub_size)(u8 vfe_id);
> +	void (*halt_clear)(struct vfe_device *vfe);
> +	void (*halt_request)(struct vfe_device *vfe);
> +	void (*set_camif_cfg)(struct vfe_device *vfe, struct vfe_line *line);
> +	void (*set_camif_cmd)(struct vfe_device *vfe, u8 enable);
> +	void (*set_cgc_override)(struct vfe_device *vfe, u8 wm, u8 enable);
> +	void (*set_clamp_cfg)(struct vfe_device *vfe);
> +	void (*set_crop_cfg)(struct vfe_device *vfe, struct vfe_line *line);
> +	void (*set_demux_cfg)(struct vfe_device *vfe, struct vfe_line *line);
> +	void (*set_ds)(struct vfe_device *vfe);
> +	void (*set_module_cfg)(struct vfe_device *vfe, u8 enable);
> +	void (*set_scale_cfg)(struct vfe_device *vfe, struct vfe_line *line);
> +	void (*set_rdi_cid)(struct vfe_device *vfe, enum vfe_line_id id, u8 cid);
> +	void (*set_realign_cfg)(struct vfe_device *vfe, struct vfe_line *line, u8 enable);
> +	void (*set_qos)(struct vfe_device *vfe);
> +	void (*set_xbar_cfg)(struct vfe_device *vfe, struct vfe_output *output, u8 enable);
> +	void (*wm_frame_based)(struct vfe_device *vfe, u8 wm, u8 enable);
> +	void (*wm_line_based)(struct vfe_device *vfe, u32 wm, struct v4l2_pix_format_mplane *pix,
> +			      u8 plane, u32 enable);
> +	void (*wm_set_ub_cfg)(struct vfe_device *vfe, u8 wm, u16 offset, u16 depth);
> +	void (*wm_set_subsample)(struct vfe_device *vfe, u8 wm);
> +	void (*wm_set_framedrop_period)(struct vfe_device *vfe, u8 wm, u8 per);
> +	void (*wm_set_framedrop_pattern)(struct vfe_device *vfe, u8 wm, u32 pattern);
> +	void (*wm_set_ping_addr)(struct vfe_device *vfe, u8 wm, u32 addr);
> +	void (*wm_set_pong_addr)(struct vfe_device *vfe, u8 wm, u32 addr);
> +	int (*wm_get_ping_pong_status)(struct vfe_device *vfe, u8 wm);
> +	void (*wm_enable)(struct vfe_device *vfe, u8 wm, u8 enable);
> +};
> +
> +/*
> + * vfe_calc_interp_reso - Calculate interpolation mode
> + * @input: Input resolution
> + * @output: Output resolution
> + *
> + * Return interpolation mode
> + */
> +inline u8 vfe_calc_interp_reso(u16 input, u16 output);
> +
> +/*
> + * vfe_gen1_disable - Disable streaming on VFE line
> + * @line: VFE line
> + *
> + * Return 0 on success or a negative error code otherwise
> + */
> +int vfe_gen1_disable(struct vfe_line *line);
> +
> +
> +/*
> + * vfe_gen1_enable - Enable VFE module
> + * @line: VFE line
> + *
> + * Return 0 on success
> + */
> +int vfe_gen1_enable(struct vfe_line *line);
> +
> +/*
> + * vfe_gen1_enable - Halt VFE module
> + * @vfe: VFE device
> + *
> + * Return 0 on success
> + */
> +int vfe_gen1_halt(struct vfe_device *vfe);
> +
> +/*
> + * vfe_word_per_line - Calculate number of words per frame width
> + * @format: V4L2 format
> + * @width: Frame width
> + *
> + * Return number of words per frame width
> + */
> +int vfe_word_per_line(u32 format, u32 width);
> +
> +
> +extern const struct vfe_isr_ops vfe_isr_ops_gen1;
> +extern const struct camss_video_ops vfe_video_ops_gen1;
> +
> +
> +#endif /* QC_MSM_CAMSS_VFE_GEN1_H */
> diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
> index 94c9ca7d5cbb..375843bd16af 100644
> --- a/drivers/media/platform/qcom/camss/camss-vfe.c
> +++ b/drivers/media/platform/qcom/camss/camss-vfe.c
> @@ -26,22 +26,8 @@
>   
>   #define MSM_VFE_NAME "msm_vfe"
>   
> -#define vfe_line_array(ptr_line)	\
> -	((const struct vfe_line (*)[]) &(ptr_line[-(ptr_line->id)]))
> -
> -#define to_vfe(ptr_line)	\
> -	container_of(vfe_line_array(ptr_line), struct vfe_device, line)
> -
>   /* VFE reset timeout */
>   #define VFE_RESET_TIMEOUT_MS 50
> -/* VFE halt timeout */
> -#define VFE_HALT_TIMEOUT_MS 100
> -/* Max number of frame drop updates per frame */
> -#define VFE_FRAME_DROP_UPDATES 2
> -/* Frame drop value. VAL + UPDATES - 1 should not exceed 31 */
> -#define VFE_FRAME_DROP_VAL 30
> -
> -#define VFE_NEXT_SOF_MS 500
>   
>   #define SCALER_RATIO_MAX 16
>   
> @@ -294,35 +280,11 @@ static int vfe_reset(struct vfe_device *vfe)
>   	return 0;
>   }
>   
> -/*
> - * vfe_halt - Trigger halt on VFE module and wait to complete
> - * @vfe: VFE device
> - *
> - * Return 0 on success or a negative error code otherwise
> - */
> -static int vfe_halt(struct vfe_device *vfe)
> -{
> -	unsigned long time;
> -
> -	reinit_completion(&vfe->halt_complete);
> -
> -	vfe->ops->halt_request(vfe);
> -
> -	time = wait_for_completion_timeout(&vfe->halt_complete,
> -		msecs_to_jiffies(VFE_HALT_TIMEOUT_MS));
> -	if (!time) {
> -		dev_err(vfe->camss->dev, "VFE halt timeout\n");
> -		return -EIO;
> -	}
> -
> -	return 0;
> -}
> -
>   static void vfe_init_outputs(struct vfe_device *vfe)
>   {
>   	int i;
>   
> -	for (i = 0; i < ARRAY_SIZE(vfe->line); i++) {
> +	for (i = 0; i < vfe->line_num; i++) {
>   		struct vfe_output *output = &vfe->line[i].output;
>   
>   		output->state = VFE_OUTPUT_OFF;
> @@ -340,71 +302,7 @@ static void vfe_reset_output_maps(struct vfe_device *vfe)
>   		vfe->wm_output_map[i] = VFE_LINE_NONE;
>   }
>   
> -static void vfe_output_init_addrs(struct vfe_device *vfe,
> -				  struct vfe_output *output, u8 sync)
> -{
> -	u32 ping_addr;
> -	u32 pong_addr;
> -	unsigned int i;
> -
> -	output->active_buf = 0;
> -
> -	for (i = 0; i < output->wm_num; i++) {
> -		if (output->buf[0])
> -			ping_addr = output->buf[0]->addr[i];
> -		else
> -			ping_addr = 0;
> -
> -		if (output->buf[1])
> -			pong_addr = output->buf[1]->addr[i];
> -		else
> -			pong_addr = ping_addr;
> -
> -		vfe->ops->wm_set_ping_addr(vfe, output->wm_idx[i], ping_addr);
> -		vfe->ops->wm_set_pong_addr(vfe, output->wm_idx[i], pong_addr);
> -		if (sync)
> -			vfe->ops->bus_reload_wm(vfe, output->wm_idx[i]);
> -	}
> -}
> -
> -static void vfe_output_update_ping_addr(struct vfe_device *vfe,
> -					struct vfe_output *output, u8 sync)
> -{
> -	u32 addr;
> -	unsigned int i;
> -
> -	for (i = 0; i < output->wm_num; i++) {
> -		if (output->buf[0])
> -			addr = output->buf[0]->addr[i];
> -		else
> -			addr = 0;
> -
> -		vfe->ops->wm_set_ping_addr(vfe, output->wm_idx[i], addr);
> -		if (sync)
> -			vfe->ops->bus_reload_wm(vfe, output->wm_idx[i]);
> -	}
> -}
> -
> -static void vfe_output_update_pong_addr(struct vfe_device *vfe,
> -					struct vfe_output *output, u8 sync)
> -{
> -	u32 addr;
> -	unsigned int i;
> -
> -	for (i = 0; i < output->wm_num; i++) {
> -		if (output->buf[1])
> -			addr = output->buf[1]->addr[i];
> -		else
> -			addr = 0;
> -
> -		vfe->ops->wm_set_pong_addr(vfe, output->wm_idx[i], addr);
> -		if (sync)
> -			vfe->ops->bus_reload_wm(vfe, output->wm_idx[i]);
> -	}
> -
> -}
> -
> -static int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id)
> +int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id)
>   {
>   	int ret = -EBUSY;
>   	int i;
> @@ -420,7 +318,7 @@ static int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id)
>   	return ret;
>   }
>   
> -static int vfe_release_wm(struct vfe_device *vfe, u8 wm)
> +int vfe_release_wm(struct vfe_device *vfe, u8 wm)
>   {
>   	if (wm >= ARRAY_SIZE(vfe->wm_output_map))
>   		return -EINVAL;
> @@ -430,29 +328,7 @@ static int vfe_release_wm(struct vfe_device *vfe, u8 wm)
>   	return 0;
>   }
>   
> -static void vfe_output_frame_drop(struct vfe_device *vfe,
> -				  struct vfe_output *output,
> -				  u32 drop_pattern)
> -{
> -	u8 drop_period;
> -	unsigned int i;
> -
> -	/* We need to toggle update period to be valid on next frame */
> -	output->drop_update_idx++;
> -	output->drop_update_idx %= VFE_FRAME_DROP_UPDATES;
> -	drop_period = VFE_FRAME_DROP_VAL + output->drop_update_idx;
> -
> -	for (i = 0; i < output->wm_num; i++) {
> -		vfe->ops->wm_set_framedrop_period(vfe, output->wm_idx[i],
> -						  drop_period);
> -		vfe->ops->wm_set_framedrop_pattern(vfe, output->wm_idx[i],
> -						   drop_pattern);
> -	}
> -	vfe->ops->reg_update(vfe,
> -			     container_of(output, struct vfe_line, output)->id);
> -}
> -
> -static struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output)
> +struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output)
>   {
>   	struct camss_buffer *buffer = NULL;
>   
> @@ -466,13 +342,8 @@ static struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output)
>   	return buffer;
>   }
>   
> -/*
> - * vfe_buf_add_pending - Add output buffer to list of pending
> - * @output: VFE output
> - * @buffer: Video buffer
> - */
> -static void vfe_buf_add_pending(struct vfe_output *output,
> -				struct camss_buffer *buffer)
> +void vfe_buf_add_pending(struct vfe_output *output,
> +			 struct camss_buffer *buffer)
>   {
>   	INIT_LIST_HEAD(&buffer->queue);
>   	list_add_tail(&buffer->queue, &output->pending_bufs);
> @@ -495,149 +366,7 @@ static void vfe_buf_flush_pending(struct vfe_output *output,
>   	}
>   }
>   
> -static void vfe_buf_update_wm_on_next(struct vfe_device *vfe,
> -				      struct vfe_output *output)
> -{
> -	switch (output->state) {
> -	case VFE_OUTPUT_CONTINUOUS:
> -		vfe_output_frame_drop(vfe, output, 3);
> -		break;
> -	case VFE_OUTPUT_SINGLE:
> -	default:
> -		dev_err_ratelimited(vfe->camss->dev,
> -				    "Next buf in wrong state! %d\n",
> -				    output->state);
> -		break;
> -	}
> -}
> -
> -static void vfe_buf_update_wm_on_last(struct vfe_device *vfe,
> -				      struct vfe_output *output)
> -{
> -	switch (output->state) {
> -	case VFE_OUTPUT_CONTINUOUS:
> -		output->state = VFE_OUTPUT_SINGLE;
> -		vfe_output_frame_drop(vfe, output, 1);
> -		break;
> -	case VFE_OUTPUT_SINGLE:
> -		output->state = VFE_OUTPUT_STOPPING;
> -		vfe_output_frame_drop(vfe, output, 0);
> -		break;
> -	default:
> -		dev_err_ratelimited(vfe->camss->dev,
> -				    "Last buff in wrong state! %d\n",
> -				    output->state);
> -		break;
> -	}
> -}
> -
> -static void vfe_buf_update_wm_on_new(struct vfe_device *vfe,
> -				     struct vfe_output *output,
> -				     struct camss_buffer *new_buf)
> -{
> -	int inactive_idx;
> -
> -	switch (output->state) {
> -	case VFE_OUTPUT_SINGLE:
> -		inactive_idx = !output->active_buf;
> -
> -		if (!output->buf[inactive_idx]) {
> -			output->buf[inactive_idx] = new_buf;
> -
> -			if (inactive_idx)
> -				vfe_output_update_pong_addr(vfe, output, 0);
> -			else
> -				vfe_output_update_ping_addr(vfe, output, 0);
> -
> -			vfe_output_frame_drop(vfe, output, 3);
> -			output->state = VFE_OUTPUT_CONTINUOUS;
> -		} else {
> -			vfe_buf_add_pending(output, new_buf);
> -			dev_err_ratelimited(vfe->camss->dev,
> -					    "Inactive buffer is busy\n");
> -		}
> -		break;
> -
> -	case VFE_OUTPUT_IDLE:
> -		if (!output->buf[0]) {
> -			output->buf[0] = new_buf;
> -
> -			vfe_output_init_addrs(vfe, output, 1);
> -
> -			vfe_output_frame_drop(vfe, output, 1);
> -			output->state = VFE_OUTPUT_SINGLE;
> -		} else {
> -			vfe_buf_add_pending(output, new_buf);
> -			dev_err_ratelimited(vfe->camss->dev,
> -					    "Output idle with buffer set!\n");
> -		}
> -		break;
> -
> -	case VFE_OUTPUT_CONTINUOUS:
> -	default:
> -		vfe_buf_add_pending(output, new_buf);
> -		break;
> -	}
> -}
> -
> -static int vfe_get_output(struct vfe_line *line)
> -{
> -	struct vfe_device *vfe = to_vfe(line);
> -	struct vfe_output *output;
> -	struct v4l2_format *f = &line->video_out.active_fmt;
> -	unsigned long flags;
> -	int i;
> -	int wm_idx;
> -
> -	spin_lock_irqsave(&vfe->output_lock, flags);
> -
> -	output = &line->output;
> -	if (output->state != VFE_OUTPUT_OFF) {
> -		dev_err(vfe->camss->dev, "Output is running\n");
> -		goto error;
> -	}
> -	output->state = VFE_OUTPUT_RESERVED;
> -
> -	output->active_buf = 0;
> -
> -	switch (f->fmt.pix_mp.pixelformat) {
> -	case V4L2_PIX_FMT_NV12:
> -	case V4L2_PIX_FMT_NV21:
> -	case V4L2_PIX_FMT_NV16:
> -	case V4L2_PIX_FMT_NV61:
> -		output->wm_num = 2;
> -		break;
> -	default:
> -		output->wm_num = 1;
> -		break;
> -	}
> -
> -	for (i = 0; i < output->wm_num; i++) {
> -		wm_idx = vfe_reserve_wm(vfe, line->id);
> -		if (wm_idx < 0) {
> -			dev_err(vfe->camss->dev, "Can not reserve wm\n");
> -			goto error_get_wm;
> -		}
> -		output->wm_idx[i] = wm_idx;
> -	}
> -
> -	output->drop_update_idx = 0;
> -
> -	spin_unlock_irqrestore(&vfe->output_lock, flags);
> -
> -	return 0;
> -
> -error_get_wm:
> -	for (i--; i >= 0; i--)
> -		vfe_release_wm(vfe, output->wm_idx[i]);
> -	output->state = VFE_OUTPUT_OFF;
> -error:
> -	spin_unlock_irqrestore(&vfe->output_lock, flags);
> -
> -	return -EINVAL;
> -}
> -
> -static int vfe_put_output(struct vfe_line *line)
> +int vfe_put_output(struct vfe_line *line)
>   {
>   	struct vfe_device *vfe = to_vfe(line);
>   	struct vfe_output *output = &line->output;
> @@ -655,454 +384,27 @@ static int vfe_put_output(struct vfe_line *line)
>   	return 0;
>   }
>   
> -static int vfe_enable_output(struct vfe_line *line)
> -{
> -	struct vfe_device *vfe = to_vfe(line);
> -	struct vfe_output *output = &line->output;
> -	const struct vfe_hw_ops *ops = vfe->ops;
> -	struct media_entity *sensor;
> -	unsigned long flags;
> -	unsigned int frame_skip = 0;
> -	unsigned int i;
> -	u16 ub_size;
> -
> -	ub_size = ops->get_ub_size(vfe->id);
> -	if (!ub_size)
> -		return -EINVAL;
> -
> -	sensor = camss_find_sensor(&line->subdev.entity);
> -	if (sensor) {
> -		struct v4l2_subdev *subdev =
> -					media_entity_to_v4l2_subdev(sensor);
> -
> -		v4l2_subdev_call(subdev, sensor, g_skip_frames, &frame_skip);
> -		/* Max frame skip is 29 frames */
> -		if (frame_skip > VFE_FRAME_DROP_VAL - 1)
> -			frame_skip = VFE_FRAME_DROP_VAL - 1;
> -	}
> -
> -	spin_lock_irqsave(&vfe->output_lock, flags);
> -
> -	ops->reg_update_clear(vfe, line->id);
> -
> -	if (output->state != VFE_OUTPUT_RESERVED) {
> -		dev_err(vfe->camss->dev, "Output is not in reserved state %d\n",
> -			output->state);
> -		spin_unlock_irqrestore(&vfe->output_lock, flags);
> -		return -EINVAL;
> -	}
> -	output->state = VFE_OUTPUT_IDLE;
> -
> -	output->buf[0] = vfe_buf_get_pending(output);
> -	output->buf[1] = vfe_buf_get_pending(output);
> -
> -	if (!output->buf[0] && output->buf[1]) {
> -		output->buf[0] = output->buf[1];
> -		output->buf[1] = NULL;
> -	}
> -
> -	if (output->buf[0])
> -		output->state = VFE_OUTPUT_SINGLE;
> -
> -	if (output->buf[1])
> -		output->state = VFE_OUTPUT_CONTINUOUS;
> -
> -	switch (output->state) {
> -	case VFE_OUTPUT_SINGLE:
> -		vfe_output_frame_drop(vfe, output, 1 << frame_skip);
> -		break;
> -	case VFE_OUTPUT_CONTINUOUS:
> -		vfe_output_frame_drop(vfe, output, 3 << frame_skip);
> -		break;
> -	default:
> -		vfe_output_frame_drop(vfe, output, 0);
> -		break;
> -	}
> -
> -	output->sequence = 0;
> -	output->wait_sof = 0;
> -	output->wait_reg_update = 0;
> -	reinit_completion(&output->sof);
> -	reinit_completion(&output->reg_update);
> -
> -	vfe_output_init_addrs(vfe, output, 0);
> -
> -	if (line->id != VFE_LINE_PIX) {
> -		ops->set_cgc_override(vfe, output->wm_idx[0], 1);
> -		ops->enable_irq_wm_line(vfe, output->wm_idx[0], line->id, 1);
> -		ops->bus_connect_wm_to_rdi(vfe, output->wm_idx[0], line->id);
> -		ops->wm_set_subsample(vfe, output->wm_idx[0]);
> -		ops->set_rdi_cid(vfe, line->id, 0);
> -		ops->wm_set_ub_cfg(vfe, output->wm_idx[0],
> -				   (ub_size + 1) * output->wm_idx[0], ub_size);
> -		ops->wm_frame_based(vfe, output->wm_idx[0], 1);
> -		ops->wm_enable(vfe, output->wm_idx[0], 1);
> -		ops->bus_reload_wm(vfe, output->wm_idx[0]);
> -	} else {
> -		ub_size /= output->wm_num;
> -		for (i = 0; i < output->wm_num; i++) {
> -			ops->set_cgc_override(vfe, output->wm_idx[i], 1);
> -			ops->wm_set_subsample(vfe, output->wm_idx[i]);
> -			ops->wm_set_ub_cfg(vfe, output->wm_idx[i],
> -					   (ub_size + 1) * output->wm_idx[i],
> -					   ub_size);
> -			ops->wm_line_based(vfe, output->wm_idx[i],
> -					&line->video_out.active_fmt.fmt.pix_mp,
> -					i, 1);
> -			ops->wm_enable(vfe, output->wm_idx[i], 1);
> -			ops->bus_reload_wm(vfe, output->wm_idx[i]);
> -		}
> -		ops->enable_irq_pix_line(vfe, 0, line->id, 1);
> -		ops->set_module_cfg(vfe, 1);
> -		ops->set_camif_cfg(vfe, line);
> -		ops->set_realign_cfg(vfe, line, 1);
> -		ops->set_xbar_cfg(vfe, output, 1);
> -		ops->set_demux_cfg(vfe, line);
> -		ops->set_scale_cfg(vfe, line);
> -		ops->set_crop_cfg(vfe, line);
> -		ops->set_clamp_cfg(vfe);
> -		ops->set_camif_cmd(vfe, 1);
> -	}
> -
> -	ops->reg_update(vfe, line->id);
> -
> -	spin_unlock_irqrestore(&vfe->output_lock, flags);
> -
> -	return 0;
> -}
> -
> -static int vfe_disable_output(struct vfe_line *line)
> -{
> -	struct vfe_device *vfe = to_vfe(line);
> -	struct vfe_output *output = &line->output;
> -	const struct vfe_hw_ops *ops = vfe->ops;
> -	unsigned long flags;
> -	unsigned long time;
> -	unsigned int i;
> -
> -	spin_lock_irqsave(&vfe->output_lock, flags);
> -
> -	output->wait_sof = 1;
> -	spin_unlock_irqrestore(&vfe->output_lock, flags);
> -
> -	time = wait_for_completion_timeout(&output->sof,
> -					   msecs_to_jiffies(VFE_NEXT_SOF_MS));
> -	if (!time)
> -		dev_err(vfe->camss->dev, "VFE sof timeout\n");
> -
> -	spin_lock_irqsave(&vfe->output_lock, flags);
> -	for (i = 0; i < output->wm_num; i++)
> -		ops->wm_enable(vfe, output->wm_idx[i], 0);
> -
> -	ops->reg_update(vfe, line->id);
> -	output->wait_reg_update = 1;
> -	spin_unlock_irqrestore(&vfe->output_lock, flags);
> -
> -	time = wait_for_completion_timeout(&output->reg_update,
> -					   msecs_to_jiffies(VFE_NEXT_SOF_MS));
> -	if (!time)
> -		dev_err(vfe->camss->dev, "VFE reg update timeout\n");
> -
> -	spin_lock_irqsave(&vfe->output_lock, flags);
> -
> -	if (line->id != VFE_LINE_PIX) {
> -		ops->wm_frame_based(vfe, output->wm_idx[0], 0);
> -		ops->bus_disconnect_wm_from_rdi(vfe, output->wm_idx[0],
> -						line->id);
> -		ops->enable_irq_wm_line(vfe, output->wm_idx[0], line->id, 0);
> -		ops->set_cgc_override(vfe, output->wm_idx[0], 0);
> -		spin_unlock_irqrestore(&vfe->output_lock, flags);
> -	} else {
> -		for (i = 0; i < output->wm_num; i++) {
> -			ops->wm_line_based(vfe, output->wm_idx[i], NULL, i, 0);
> -			ops->set_cgc_override(vfe, output->wm_idx[i], 0);
> -		}
> -
> -		ops->enable_irq_pix_line(vfe, 0, line->id, 0);
> -		ops->set_module_cfg(vfe, 0);
> -		ops->set_realign_cfg(vfe, line, 0);
> -		ops->set_xbar_cfg(vfe, output, 0);
> -
> -		ops->set_camif_cmd(vfe, 0);
> -		spin_unlock_irqrestore(&vfe->output_lock, flags);
> -
> -		ops->camif_wait_for_stop(vfe, vfe->camss->dev);
> -	}
> -
> -	return 0;
> -}
> -
> -/*
> - * vfe_enable - Enable streaming on VFE line
> - * @line: VFE line
> - *
> - * Return 0 on success or a negative error code otherwise
> - */
> -static int vfe_enable(struct vfe_line *line)
> -{
> -	struct vfe_device *vfe = to_vfe(line);
> -	int ret;
> -
> -	mutex_lock(&vfe->stream_lock);
> -
> -	if (!vfe->stream_count) {
> -		vfe->ops->enable_irq_common(vfe);
> -
> -		vfe->ops->bus_enable_wr_if(vfe, 1);
> -
> -		vfe->ops->set_qos(vfe);
> -
> -		vfe->ops->set_ds(vfe);
> -	}
> -
> -	vfe->stream_count++;
> -
> -	mutex_unlock(&vfe->stream_lock);
> -
> -	ret = vfe_get_output(line);
> -	if (ret < 0)
> -		goto error_get_output;
> -
> -	ret = vfe_enable_output(line);
> -	if (ret < 0)
> -		goto error_enable_output;
> -
> -	vfe->was_streaming = 1;
> -
> -	return 0;
> -
> -
> -error_enable_output:
> -	vfe_put_output(line);
> -
> -error_get_output:
> -	mutex_lock(&vfe->stream_lock);
> -
> -	if (vfe->stream_count == 1)
> -		vfe->ops->bus_enable_wr_if(vfe, 0);
> -
> -	vfe->stream_count--;
> -
> -	mutex_unlock(&vfe->stream_lock);
> -
> -	return ret;
> -}
> -
> -/*
> - * vfe_disable - Disable streaming on VFE line
> - * @line: VFE line
> - *
> - * Return 0 on success or a negative error code otherwise
> - */
> -static int vfe_disable(struct vfe_line *line)
> -{
> -	struct vfe_device *vfe = to_vfe(line);
> -
> -	vfe_disable_output(line);
> -
> -	vfe_put_output(line);
> -
> -	mutex_lock(&vfe->stream_lock);
> -
> -	if (vfe->stream_count == 1)
> -		vfe->ops->bus_enable_wr_if(vfe, 0);
> -
> -	vfe->stream_count--;
> -
> -	mutex_unlock(&vfe->stream_lock);
> -
> -	return 0;
> -}
> -
> -/*
> - * vfe_isr_sof - Process start of frame interrupt
> - * @vfe: VFE Device
> - * @line_id: VFE line
> - */
> -static void vfe_isr_sof(struct vfe_device *vfe, enum vfe_line_id line_id)
> -{
> -	struct vfe_output *output;
> -	unsigned long flags;
> -
> -	spin_lock_irqsave(&vfe->output_lock, flags);
> -	output = &vfe->line[line_id].output;
> -	if (output->wait_sof) {
> -		output->wait_sof = 0;
> -		complete(&output->sof);
> -	}
> -	spin_unlock_irqrestore(&vfe->output_lock, flags);
> -}
> -
> -/*
> - * vfe_isr_reg_update - Process reg update interrupt
> - * @vfe: VFE Device
> - * @line_id: VFE line
> - */
> -static void vfe_isr_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
> -{
> -	struct vfe_output *output;
> -	unsigned long flags;
> -
> -	spin_lock_irqsave(&vfe->output_lock, flags);
> -	vfe->ops->reg_update_clear(vfe, line_id);
> -
> -	output = &vfe->line[line_id].output;
> -
> -	if (output->wait_reg_update) {
> -		output->wait_reg_update = 0;
> -		complete(&output->reg_update);
> -		spin_unlock_irqrestore(&vfe->output_lock, flags);
> -		return;
> -	}
> -
> -	if (output->state == VFE_OUTPUT_STOPPING) {
> -		/* Release last buffer when hw is idle */
> -		if (output->last_buffer) {
> -			vb2_buffer_done(&output->last_buffer->vb.vb2_buf,
> -					VB2_BUF_STATE_DONE);
> -			output->last_buffer = NULL;
> -		}
> -		output->state = VFE_OUTPUT_IDLE;
> -
> -		/* Buffers received in stopping state are queued in */
> -		/* dma pending queue, start next capture here */
> -
> -		output->buf[0] = vfe_buf_get_pending(output);
> -		output->buf[1] = vfe_buf_get_pending(output);
> -
> -		if (!output->buf[0] && output->buf[1]) {
> -			output->buf[0] = output->buf[1];
> -			output->buf[1] = NULL;
> -		}
> -
> -		if (output->buf[0])
> -			output->state = VFE_OUTPUT_SINGLE;
> -
> -		if (output->buf[1])
> -			output->state = VFE_OUTPUT_CONTINUOUS;
> -
> -		switch (output->state) {
> -		case VFE_OUTPUT_SINGLE:
> -			vfe_output_frame_drop(vfe, output, 2);
> -			break;
> -		case VFE_OUTPUT_CONTINUOUS:
> -			vfe_output_frame_drop(vfe, output, 3);
> -			break;
> -		default:
> -			vfe_output_frame_drop(vfe, output, 0);
> -			break;
> -		}
> -
> -		vfe_output_init_addrs(vfe, output, 1);
> -	}
> -
> -	spin_unlock_irqrestore(&vfe->output_lock, flags);
> -}
> -
> -/*
> - * vfe_isr_wm_done - Process write master done interrupt
> - * @vfe: VFE Device
> - * @wm: Write master id
> - */
> -static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm)
> -{
> -	struct camss_buffer *ready_buf;
> -	struct vfe_output *output;
> -	dma_addr_t *new_addr;
> -	unsigned long flags;
> -	u32 active_index;
> -	u64 ts = ktime_get_ns();
> -	unsigned int i;
> -
> -	active_index = vfe->ops->wm_get_ping_pong_status(vfe, wm);
> -
> -	spin_lock_irqsave(&vfe->output_lock, flags);
> -
> -	if (vfe->wm_output_map[wm] == VFE_LINE_NONE) {
> -		dev_err_ratelimited(vfe->camss->dev,
> -				    "Received wm done for unmapped index\n");
> -		goto out_unlock;
> -	}
> -	output = &vfe->line[vfe->wm_output_map[wm]].output;
> -
> -	if (output->active_buf == active_index) {
> -		dev_err_ratelimited(vfe->camss->dev,
> -				    "Active buffer mismatch!\n");
> -		goto out_unlock;
> -	}
> -	output->active_buf = active_index;
> -
> -	ready_buf = output->buf[!active_index];
> -	if (!ready_buf) {
> -		dev_err_ratelimited(vfe->camss->dev,
> -				    "Missing ready buf %d %d!\n",
> -				    !active_index, output->state);
> -		goto out_unlock;
> -	}
> -
> -	ready_buf->vb.vb2_buf.timestamp = ts;
> -	ready_buf->vb.sequence = output->sequence++;
> -
> -	/* Get next buffer */
> -	output->buf[!active_index] = vfe_buf_get_pending(output);
> -	if (!output->buf[!active_index]) {
> -		/* No next buffer - set same address */
> -		new_addr = ready_buf->addr;
> -		vfe_buf_update_wm_on_last(vfe, output);
> -	} else {
> -		new_addr = output->buf[!active_index]->addr;
> -		vfe_buf_update_wm_on_next(vfe, output);
> -	}
> -
> -	if (active_index)
> -		for (i = 0; i < output->wm_num; i++)
> -			vfe->ops->wm_set_ping_addr(vfe, output->wm_idx[i],
> -						   new_addr[i]);
> -	else
> -		for (i = 0; i < output->wm_num; i++)
> -			vfe->ops->wm_set_pong_addr(vfe, output->wm_idx[i],
> -						   new_addr[i]);
> -
> -	spin_unlock_irqrestore(&vfe->output_lock, flags);
> -
> -	if (output->state == VFE_OUTPUT_STOPPING)
> -		output->last_buffer = ready_buf;
> -	else
> -		vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
> -
> -	return;
> -
> -out_unlock:
> -	spin_unlock_irqrestore(&vfe->output_lock, flags);
> -}
> -
>   /**
>    * vfe_isr_comp_done() - Process composite image done interrupt
>    * @vfe: VFE Device
>    * @comp: Composite image id
>    */
> -static void vfe_isr_comp_done(struct vfe_device *vfe, u8 comp)
> +void vfe_isr_comp_done(struct vfe_device *vfe, u8 comp)
>   {
>   	unsigned int i;
>   
>   	for (i = 0; i < ARRAY_SIZE(vfe->wm_output_map); i++)
>   		if (vfe->wm_output_map[i] == VFE_LINE_PIX) {
> -			vfe_isr_wm_done(vfe, i);
> +			vfe->isr_ops.wm_done(vfe, i);
>   			break;
>   		}
>   }
>   
> -static inline void vfe_isr_reset_ack(struct vfe_device *vfe)
> +void vfe_isr_reset_ack(struct vfe_device *vfe)
>   {
>   	complete(&vfe->reset_complete);
>   }
>   
> -static inline void vfe_isr_halt_ack(struct vfe_device *vfe)
> -{
> -	complete(&vfe->halt_complete);
> -	vfe->ops->halt_clear(vfe);
> -}
> -
>   /*
>    * vfe_set_clock_rates - Calculate and set clock rates on VFE module
>    * @vfe: VFE device
> @@ -1112,11 +414,11 @@ static inline void vfe_isr_halt_ack(struct vfe_device *vfe)
>   static int vfe_set_clock_rates(struct vfe_device *vfe)
>   {
>   	struct device *dev = vfe->camss->dev;
> -	u32 pixel_clock[MSM_VFE_LINE_NUM];
> +	u32 pixel_clock[VFE_LINE_NUM_MAX];
>   	int i, j;
>   	int ret;
>   
> -	for (i = VFE_LINE_RDI0; i <= VFE_LINE_PIX; i++) {
> +	for (i = VFE_LINE_RDI0; i < vfe->line_num; i++) {
>   		ret = camss_get_pixel_clock(&vfe->line[i].subdev.entity,
>   					    &pixel_clock[i]);
>   		if (ret)
> @@ -1131,7 +433,7 @@ static int vfe_set_clock_rates(struct vfe_device *vfe)
>   			u64 min_rate = 0;
>   			long rate;
>   
> -			for (j = VFE_LINE_RDI0; j <= VFE_LINE_PIX; j++) {
> +			for (j = VFE_LINE_RDI0; j < vfe->line_num; j++) {
>   				u32 tmp;
>   				u8 bpp;
>   
> @@ -1194,11 +496,11 @@ static int vfe_set_clock_rates(struct vfe_device *vfe)
>    */
>   static int vfe_check_clock_rates(struct vfe_device *vfe)
>   {
> -	u32 pixel_clock[MSM_VFE_LINE_NUM];
> +	u32 pixel_clock[VFE_LINE_NUM_MAX];
>   	int i, j;
>   	int ret;
>   
> -	for (i = VFE_LINE_RDI0; i <= VFE_LINE_PIX; i++) {
> +	for (i = VFE_LINE_RDI0; i < vfe->line_num; i++) {
>   		ret = camss_get_pixel_clock(&vfe->line[i].subdev.entity,
>   					    &pixel_clock[i]);
>   		if (ret)
> @@ -1213,7 +515,7 @@ static int vfe_check_clock_rates(struct vfe_device *vfe)
>   			u64 min_rate = 0;
>   			unsigned long rate;
>   
> -			for (j = VFE_LINE_RDI0; j <= VFE_LINE_PIX; j++) {
> +			for (j = VFE_LINE_RDI0; j < vfe->line_num; j++) {
>   				u32 tmp;
>   				u8 bpp;
>   
> @@ -1318,7 +620,7 @@ static void vfe_put(struct vfe_device *vfe)
>   	} else if (vfe->power_count == 1) {
>   		if (vfe->was_streaming) {
>   			vfe->was_streaming = 0;
> -			vfe_halt(vfe);
> +			vfe->ops->vfe_halt(vfe);
>   		}
>   		camss_disable_clocks(vfe->nclocks, vfe->clock);
>   		pm_runtime_put_sync(vfe->camss->dev);
> @@ -1331,35 +633,6 @@ static void vfe_put(struct vfe_device *vfe)
>   	mutex_unlock(&vfe->power_lock);
>   }
>   
> -/*
> - * vfe_queue_buffer - Add empty buffer
> - * @vid: Video device structure
> - * @buf: Buffer to be enqueued
> - *
> - * Add an empty buffer - depending on the current number of buffers it will be
> - * put in pending buffer queue or directly given to the hardware to be filled.
> - *
> - * Return 0 on success or a negative error code otherwise
> - */
> -static int vfe_queue_buffer(struct camss_video *vid,
> -			    struct camss_buffer *buf)
> -{
> -	struct vfe_line *line = container_of(vid, struct vfe_line, video_out);
> -	struct vfe_device *vfe = to_vfe(line);
> -	struct vfe_output *output;
> -	unsigned long flags;
> -
> -	output = &line->output;
> -
> -	spin_lock_irqsave(&vfe->output_lock, flags);
> -
> -	vfe_buf_update_wm_on_new(vfe, output, buf);
> -
> -	spin_unlock_irqrestore(&vfe->output_lock, flags);
> -
> -	return 0;
> -}
> -
>   /*
>    * vfe_flush_buffers - Return all vb2 buffers
>    * @vid: Video device structure
> @@ -1370,8 +643,8 @@ static int vfe_queue_buffer(struct camss_video *vid,
>    *
>    * Return 0 on success or a negative error code otherwise
>    */
> -static int vfe_flush_buffers(struct camss_video *vid,
> -			     enum vb2_buffer_state state)
> +int vfe_flush_buffers(struct camss_video *vid,
> +		      enum vb2_buffer_state state)
>   {
>   	struct vfe_line *line = container_of(vid, struct vfe_line, video_out);
>   	struct vfe_device *vfe = to_vfe(line);
> @@ -1442,12 +715,12 @@ static int vfe_set_stream(struct v4l2_subdev *sd, int enable)
>   	int ret;
>   
>   	if (enable) {
> -		ret = vfe_enable(line);
> +		ret = vfe->ops->vfe_enable(line);
>   		if (ret < 0)
>   			dev_err(vfe->camss->dev,
>   				"Failed to enable vfe outputs\n");
>   	} else {
> -		ret = vfe_disable(line);
> +		ret = vfe->ops->vfe_disable(line);
>   		if (ret < 0)
>   			dev_err(vfe->camss->dev,
>   				"Failed to disable vfe outputs\n");
> @@ -1985,13 +1258,6 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
>   	int i, j;
>   	int ret;
>   
> -	vfe->isr_ops.reset_ack = vfe_isr_reset_ack;
> -	vfe->isr_ops.halt_ack = vfe_isr_halt_ack;
> -	vfe->isr_ops.reg_update = vfe_isr_reg_update;
> -	vfe->isr_ops.sof = vfe_isr_sof;
> -	vfe->isr_ops.comp_done = vfe_isr_comp_done;
> -	vfe->isr_ops.wm_done = vfe_isr_wm_done;
> -
>   	switch (camss->version) {
>   	case CAMSS_8x16:
>   		vfe->ops = &vfe_ops_4_1;
> @@ -2005,6 +1271,7 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
>   	default:
>   		return -EINVAL;
>   	}
> +	vfe->ops->subdev_init(dev, vfe);
>   
>   	/* Memory */
>   
> @@ -2086,7 +1353,7 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
>   	vfe->id = id;
>   	vfe->reg_update = 0;
>   
> -	for (i = VFE_LINE_RDI0; i <= VFE_LINE_PIX; i++) {
> +	for (i = VFE_LINE_RDI0; i < vfe->line_num; i++) {
>   		struct vfe_line *l = &vfe->line[i];
>   
>   		l->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
> @@ -2209,11 +1476,6 @@ static const struct media_entity_operations vfe_media_ops = {
>   	.link_validate = v4l2_subdev_link_validate,
>   };
>   
> -static const struct camss_video_ops camss_vfe_video_ops = {
> -	.queue_buffer = vfe_queue_buffer,
> -	.flush_buffers = vfe_flush_buffers,
> -};
> -
>   /*
>    * msm_vfe_register_entities - Register subdev node for VFE module
>    * @vfe: VFE device
> @@ -2236,7 +1498,7 @@ int msm_vfe_register_entities(struct vfe_device *vfe,
>   	int ret;
>   	int i;
>   
> -	for (i = 0; i < ARRAY_SIZE(vfe->line); i++) {
> +	for (i = 0; i < vfe->line_num; i++) {
>   		char name[32];
>   
>   		sd = &vfe->line[i].subdev;
> @@ -2279,7 +1541,7 @@ int msm_vfe_register_entities(struct vfe_device *vfe,
>   			goto error_reg_subdev;
>   		}
>   
> -		video_out->ops = &camss_vfe_video_ops;
> +		video_out->ops = &vfe->video_ops;
>   		video_out->bpl_alignment = 8;
>   		video_out->line_based = 0;
>   		if (i == VFE_LINE_PIX) {
> @@ -2343,7 +1605,7 @@ void msm_vfe_unregister_entities(struct vfe_device *vfe)
>   	mutex_destroy(&vfe->power_lock);
>   	mutex_destroy(&vfe->stream_lock);
>   
> -	for (i = 0; i < ARRAY_SIZE(vfe->line); i++) {
> +	for (i = 0; i < vfe->line_num; i++) {
>   		struct v4l2_subdev *sd = &vfe->line[i].subdev;
>   		struct camss_video *video_out = &vfe->line[i].video_out;
>   
> diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
> index 5bce6736e4bb..aad5dc74c2c0 100644
> --- a/drivers/media/platform/qcom/camss/camss-vfe.h
> +++ b/drivers/media/platform/qcom/camss/camss-vfe.h
> @@ -17,15 +17,28 @@
>   #include <media/v4l2-subdev.h>
>   
>   #include "camss-video.h"
> +#include "camss-vfe-gen1.h"
> +
>   
>   #define MSM_VFE_PAD_SINK 0
>   #define MSM_VFE_PAD_SRC 1
>   #define MSM_VFE_PADS_NUM 2
>   
> -#define MSM_VFE_LINE_NUM 4
>   #define MSM_VFE_IMAGE_MASTERS_NUM 7
>   #define MSM_VFE_COMPOSITE_IRQ_NUM 4
>   
> +/* VFE halt timeout */
> +#define VFE_HALT_TIMEOUT_MS 100
> +/* Frame drop value. VAL + UPDATES - 1 should not exceed 31 */
> +#define VFE_FRAME_DROP_VAL 30
> +
> +#define vfe_line_array(ptr_line)	\
> +	((const struct vfe_line (*)[]) &(ptr_line[-(ptr_line->id)]))
> +
> +#define to_vfe(ptr_line)	\
> +	container_of(vfe_line_array(ptr_line), struct vfe_device, line)
> +
> +
>   enum vfe_output_state {
>   	VFE_OUTPUT_OFF,
>   	VFE_OUTPUT_RESERVED,
> @@ -40,23 +53,30 @@ enum vfe_line_id {
>   	VFE_LINE_RDI0 = 0,
>   	VFE_LINE_RDI1 = 1,
>   	VFE_LINE_RDI2 = 2,
> -	VFE_LINE_PIX = 3
> +	VFE_LINE_PIX = 3,
> +	VFE_LINE_NUM_GEN1 = 4,
> +	VFE_LINE_NUM_MAX = 4
>   };
>   
>   struct vfe_output {
>   	u8 wm_num;
>   	u8 wm_idx[3];
>   
> -	int active_buf;
>   	struct camss_buffer *buf[2];
>   	struct camss_buffer *last_buffer;
>   	struct list_head pending_bufs;
>   
>   	unsigned int drop_update_idx;
>   
> +	union {
> +		struct {
> +			int active_buf;
> +			int wait_sof;
> +		} gen1;
> +	};
>   	enum vfe_output_state state;
>   	unsigned int sequence;
> -	int wait_sof;
> +
>   	int wait_reg_update;
>   	struct completion sof;
>   	struct completion reg_update;
> @@ -78,59 +98,19 @@ struct vfe_line {
>   struct vfe_device;
>   
>   struct vfe_hw_ops {
> -	void (*hw_version_read)(struct vfe_device *vfe, struct device *dev);
> -	u16 (*get_ub_size)(u8 vfe_id);
> +	void (*enable_irq_common)(struct vfe_device *vfe);
>   	void (*global_reset)(struct vfe_device *vfe);
> -	void (*halt_request)(struct vfe_device *vfe);
> -	void (*halt_clear)(struct vfe_device *vfe);
> -	void (*wm_enable)(struct vfe_device *vfe, u8 wm, u8 enable);
> -	void (*wm_frame_based)(struct vfe_device *vfe, u8 wm, u8 enable);
> -	void (*wm_line_based)(struct vfe_device *vfe, u32 wm,
> -			      struct v4l2_pix_format_mplane *pix,
> -			      u8 plane, u32 enable);
> -	void (*wm_set_framedrop_period)(struct vfe_device *vfe, u8 wm, u8 per);
> -	void (*wm_set_framedrop_pattern)(struct vfe_device *vfe, u8 wm,
> -					 u32 pattern);
> -	void (*wm_set_ub_cfg)(struct vfe_device *vfe, u8 wm, u16 offset,
> -			      u16 depth);
> -	void (*bus_reload_wm)(struct vfe_device *vfe, u8 wm);
> -	void (*wm_set_ping_addr)(struct vfe_device *vfe, u8 wm, u32 addr);
> -	void (*wm_set_pong_addr)(struct vfe_device *vfe, u8 wm, u32 addr);
> -	int (*wm_get_ping_pong_status)(struct vfe_device *vfe, u8 wm);
> -	void (*bus_enable_wr_if)(struct vfe_device *vfe, u8 enable);
> -	void (*bus_connect_wm_to_rdi)(struct vfe_device *vfe, u8 wm,
> -				      enum vfe_line_id id);
> -	void (*wm_set_subsample)(struct vfe_device *vfe, u8 wm);
> -	void (*bus_disconnect_wm_from_rdi)(struct vfe_device *vfe, u8 wm,
> -					   enum vfe_line_id id);
> -	void (*set_xbar_cfg)(struct vfe_device *vfe, struct vfe_output *output,
> -			     u8 enable);
> -	void (*set_rdi_cid)(struct vfe_device *vfe, enum vfe_line_id id,
> -			    u8 cid);
> -	void (*set_realign_cfg)(struct vfe_device *vfe, struct vfe_line *line,
> -				u8 enable);
> +	void (*hw_version_read)(struct vfe_device *vfe, struct device *dev);
> +	irqreturn_t (*isr)(int irq, void *dev);
> +	void (*isr_read)(struct vfe_device *vfe, u32 *value0, u32 *value1);
>   	void (*reg_update)(struct vfe_device *vfe, enum vfe_line_id line_id);
>   	void (*reg_update_clear)(struct vfe_device *vfe,
>   				 enum vfe_line_id line_id);
> -	void (*enable_irq_wm_line)(struct vfe_device *vfe, u8 wm,
> -				   enum vfe_line_id line_id, u8 enable);
> -	void (*enable_irq_pix_line)(struct vfe_device *vfe, u8 comp,
> -				    enum vfe_line_id line_id, u8 enable);
> -	void (*enable_irq_common)(struct vfe_device *vfe);
> -	void (*set_demux_cfg)(struct vfe_device *vfe, struct vfe_line *line);
> -	void (*set_scale_cfg)(struct vfe_device *vfe, struct vfe_line *line);
> -	void (*set_crop_cfg)(struct vfe_device *vfe, struct vfe_line *line);
> -	void (*set_clamp_cfg)(struct vfe_device *vfe);
> -	void (*set_qos)(struct vfe_device *vfe);
> -	void (*set_ds)(struct vfe_device *vfe);
> -	void (*set_cgc_override)(struct vfe_device *vfe, u8 wm, u8 enable);
> -	void (*set_camif_cfg)(struct vfe_device *vfe, struct vfe_line *line);
> -	void (*set_camif_cmd)(struct vfe_device *vfe, u8 enable);
> -	void (*set_module_cfg)(struct vfe_device *vfe, u8 enable);
> -	int (*camif_wait_for_stop)(struct vfe_device *vfe, struct device *dev);
> -	void (*isr_read)(struct vfe_device *vfe, u32 *value0, u32 *value1);
> +	void (*subdev_init)(struct device *dev, struct vfe_device *vfe);
> +	int (*vfe_disable)(struct vfe_line *line);
> +	int (*vfe_enable)(struct vfe_line *line);
> +	int (*vfe_halt)(struct vfe_device *vfe);
>   	void (*violation_read)(struct vfe_device *vfe);
> -	irqreturn_t (*isr)(int irq, void *dev);
>   };
>   
>   struct vfe_isr_ops {
> @@ -158,11 +138,14 @@ struct vfe_device {
>   	int stream_count;
>   	spinlock_t output_lock;
>   	enum vfe_line_id wm_output_map[MSM_VFE_IMAGE_MASTERS_NUM];
> -	struct vfe_line line[MSM_VFE_LINE_NUM];
> +	struct vfe_line line[VFE_LINE_NUM_MAX];
> +	u8 line_num;
>   	u32 reg_update;
>   	u8 was_streaming;
>   	const struct vfe_hw_ops *ops;
> +	const struct vfe_hw_ops_gen1 *ops_gen1;
>   	struct vfe_isr_ops isr_ops;
> +	struct camss_video_ops video_ops;
>   };
>   
>   struct resources;
> @@ -178,6 +161,38 @@ void msm_vfe_unregister_entities(struct vfe_device *vfe);
>   void msm_vfe_get_vfe_id(struct media_entity *entity, u8 *id);
>   void msm_vfe_get_vfe_line_id(struct media_entity *entity, enum vfe_line_id *id);
>   
> +
> +/*
> + * vfe_buf_add_pending - Add output buffer to list of pending
> + * @output: VFE output
> + * @buffer: Video buffer
> + */
> +void vfe_buf_add_pending(struct vfe_output *output, struct camss_buffer *buffer);
> +
> +struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output);
> +
> +/*
> + * vfe_disable - Disable streaming on VFE line
> + * @line: VFE line
> + *
> + * Return 0 on success or a negative error code otherwise
> + */
> +int vfe_disable(struct vfe_line *line);
> +
> +int vfe_flush_buffers(struct camss_video *vid, enum vb2_buffer_state state);
> +
> +/*
> + * vfe_isr_comp_done - Process composite image done interrupt
> + * @vfe: VFE Device
> + * @comp: Composite image id
> + */
> +void vfe_isr_comp_done(struct vfe_device *vfe, u8 comp);
> +
> +void vfe_isr_reset_ack(struct vfe_device *vfe);
> +int vfe_put_output(struct vfe_line *line);
> +int vfe_release_wm(struct vfe_device *vfe, u8 wm);
> +int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id);
> +
>   extern const struct vfe_hw_ops vfe_ops_4_1;
>   extern const struct vfe_hw_ops vfe_ops_4_7;
>   extern const struct vfe_hw_ops vfe_ops_4_8;
> diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
> index 5ac2dfc67c8b..6c6f1e59ccd8 100644
> --- a/drivers/media/platform/qcom/camss/camss.c
> +++ b/drivers/media/platform/qcom/camss/camss.c
> @@ -858,7 +858,7 @@ static int camss_register_entities(struct camss *camss)
>   
>   		for (i = 0; i < camss->ispif->line_num; i++)
>   			for (k = 0; k < camss->vfe_num; k++)
> -				for (j = 0; j < ARRAY_SIZE(camss->vfe[k].line); j++) {
> +				for (j = 0; j < camss->vfe[k].line_num; j++) {
>   					ret = media_create_pad_link(
>   						&camss->ispif->line[i].subdev.entity,
>   						MSM_ISPIF_PAD_SRC,
> @@ -877,7 +877,7 @@ static int camss_register_entities(struct camss *camss)
>   	} else {
>   		for (i = 0; i < camss->csid_num; i++)
>   			for (k = 0; k < camss->vfe_num; k++)
> -				for (j = 0; j < ARRAY_SIZE(camss->vfe[k].line); j++) {
> +				for (j = 0; j < camss->vfe[k].line_num; j++) {
>   					ret = media_create_pad_link(
>   						&camss->csid[i].subdev.entity,
>   						MSM_CSID_PAD_SRC,
> 

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ