Re: [PATCH v5 06/22] media: camss: Refactor VFE HW version support
From: Robert Foss
Date: Mon Feb 22 2021 - 05:47:50 EST
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,
> >