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 \
 
 
 
 #include "camss.h"
 #include "camss-vfe.h"
+#include "camss-vfe-gen1.h"
 
 #define VFE_0_HW_VERSION               0x000
 
                        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)
 {
        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;
        return IRQ_HANDLED;
 }
 
-const struct vfe_hw_ops vfe_ops_4_1 = {
-       .hw_version_read = vfe_hw_version_read,
+static 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,
 };
 
 
 #include "camss.h"
 #include "camss-vfe.h"
+#include "camss-vfe-gen1.h"
+
 
 #define VFE_0_HW_VERSION               0x000
 
        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;
                         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);
 }
        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),
 
 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_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();
 }
 
        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;
        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;
        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;
 
        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)
        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
        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++)
+       for (i = VFE_LINE_RDI0; i < vfe->line_num; i++)
                if (value0 & VFE_0_IRQ_STATUS_0_line_n_REG_UPDATE(i))
                        vfe->isr_ops.reg_update(vfe, i);
 
        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,
+static 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,
 };
 
--- /dev/null
+// 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_num; i++)
+               if (value0 & VFE_0_IRQ_STATUS_0_line_n_REG_UPDATE(i))
+                       vfe->isr_ops.reg_update(vfe, i);
+
+       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);
+}
+
+static 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,
+};
 
--- /dev/null
+// 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;
+
+       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 halt ack
+ * @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;
+}
+
+#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,
+};
 
--- /dev/null
+/* 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
+ */
+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;
+}
+
+/*
+ * 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 */
 
 
 #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
 
        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;
                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;
        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;
        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;
 
        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);
        }
 }
 
-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;
        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
 static int vfe_set_clock_rates(struct vfe_device *vfe)
 {
        struct device *dev = vfe->camss->dev;
-       u64 pixel_clock[MSM_VFE_LINE_NUM];
+       u64 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)
                        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;
 
  */
 static int vfe_check_clock_rates(struct vfe_device *vfe)
 {
-       u64 pixel_clock[MSM_VFE_LINE_NUM];
+       u64 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)
                        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;
 
        } 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);
        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
  *
  * 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);
        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");
        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;
        default:
                return -EINVAL;
        }
+       vfe->ops->subdev_init(dev, vfe);
 
        /* Memory */
 
        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;
        .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
        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;
                        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) {
        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;
 
 
 #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,
        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;
 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 {
        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;
 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;
 
 
                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++) {
                                        struct v4l2_subdev *ispif = &camss->ispif->line[i].subdev;
                                        struct v4l2_subdev *vfe = &camss->vfe[k].line[j].subdev;
 
        } 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++) {
                                        struct v4l2_subdev *csid = &camss->csid[i].subdev;
                                        struct v4l2_subdev *vfe = &camss->vfe[k].line[j].subdev;