Re: [PATCH v5 06/22] media: camss: Refactor VFE HW version support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

I agree, I'll change it to vfe->vfe_num. Maybe some future copy-paste
bugs can be avoided that way.

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

Ack, thanks for finding this.

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



[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux