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, > >