Hi Yong,

Apologies for the late reply. Please find my (few) comments below.

On Tue, Oct 17, 2017 at 10:54:55PM -0500, Yong Zhi wrote:
> Add css pipeline and v4l code.
> 
> Signed-off-by: Yong Zhi <yong....@intel.com>
> ---
>  drivers/media/pci/intel/ipu3/ipu3-css.c | 1761 
> ++++++++++++++++++++++++++++++-
>  drivers/media/pci/intel/ipu3/ipu3-css.h |   89 ++
>  2 files changed, 1849 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/media/pci/intel/ipu3/ipu3-css.c 
> b/drivers/media/pci/intel/ipu3/ipu3-css.c
> index 6e615bf9378a..11f7ad3514c3 100644
> --- a/drivers/media/pci/intel/ipu3/ipu3-css.c
> +++ b/drivers/media/pci/intel/ipu3/ipu3-css.c
> @@ -13,9 +13,16 @@
>  
>  #include <linux/delay.h>
>  #include <linux/dma-mapping.h>
> +#include <linux/firmware.h>
> +#include <linux/gcd.h>
>  #include <linux/iopoll.h>
> +#include <linux/slab.h>
> +#include <linux/string.h>
> +#include <linux/swab.h>
> +
>  #include "ipu3-css.h"
>  #include "ipu3-css-fw.h"
> +#include "ipu3-css-params.h"
>  #include "ipu3-tables.h"
>  
>  /* IRQ configuration */
> @@ -24,6 +31,159 @@
>                                IMGU_IRQCTRL_IRQ_SW_PIN(0) | \
>                                IMGU_IRQCTRL_IRQ_SW_PIN(1))
>  
> +#define IPU3_CSS_FORMAT_BPP_DEN      50      /* Denominator */
> +
> +/* Some sane limits for resolutions */
> +#define IPU3_CSS_MIN_RES     32
> +#define IPU3_CSS_MAX_H               3136
> +#define IPU3_CSS_MAX_W               4224
> +
> +/* filter size from graph settings is fixed as 4 */
> +#define FILTER_SIZE             4
> +#define MIN_ENVELOPE            8
> +
> +/* Formats supported by IPU3 Camera Sub System */
> +static const struct ipu3_css_format ipu3_css_formats[] = {
> +     {
> +             .pixelformat = V4L2_PIX_FMT_NV12,
> +             .colorspace = V4L2_COLORSPACE_SRGB,
> +             .frame_format = IMGU_ABI_FRAME_FORMAT_NV12,
> +             .osys_format = IMGU_ABI_OSYS_FORMAT_NV12,
> +             .osys_tiling = IMGU_ABI_OSYS_TILING_NONE,
> +             .bytesperpixel_num = 1 * IPU3_CSS_FORMAT_BPP_DEN,
> +             .chroma_decim = 4,
> +             .width_align = IPU3_UAPI_ISP_VEC_ELEMS,
> +             .flags = IPU3_CSS_FORMAT_FL_OUT | IPU3_CSS_FORMAT_FL_VF,
> +     }, {
> +             /* Each 32 bytes contains 25 10-bit pixels */
> +             .pixelformat = V4L2_PIX_FMT_IPU3_SBGGR10,
> +             .colorspace = V4L2_COLORSPACE_RAW,
> +             .frame_format = IMGU_ABI_FRAME_FORMAT_RAW_PACKED,
> +             .bayer_order = IMGU_ABI_BAYER_ORDER_BGGR,
> +             .bit_depth = 10,
> +             .bytesperpixel_num = 64,
> +             .width_align = 2 * IPU3_UAPI_ISP_VEC_ELEMS,
> +             .flags = IPU3_CSS_FORMAT_FL_IN,
> +     }, {
> +             .pixelformat = V4L2_PIX_FMT_IPU3_SGBRG10,
> +             .colorspace = V4L2_COLORSPACE_RAW,
> +             .frame_format = IMGU_ABI_FRAME_FORMAT_RAW_PACKED,
> +             .bayer_order = IMGU_ABI_BAYER_ORDER_GBRG,
> +             .bit_depth = 10,
> +             .bytesperpixel_num = 64,
> +             .width_align = 2 * IPU3_UAPI_ISP_VEC_ELEMS,
> +             .flags = IPU3_CSS_FORMAT_FL_IN,
> +     }, {
> +             .pixelformat = V4L2_PIX_FMT_IPU3_SGRBG10,
> +             .colorspace = V4L2_COLORSPACE_RAW,
> +             .frame_format = IMGU_ABI_FRAME_FORMAT_RAW_PACKED,
> +             .bayer_order = IMGU_ABI_BAYER_ORDER_GRBG,
> +             .bit_depth = 10,
> +             .bytesperpixel_num = 64,
> +             .width_align = 2 * IPU3_UAPI_ISP_VEC_ELEMS,
> +             .flags = IPU3_CSS_FORMAT_FL_IN,
> +     }, {
> +             .pixelformat = V4L2_PIX_FMT_IPU3_SRGGB10,
> +             .colorspace = V4L2_COLORSPACE_RAW,
> +             .frame_format = IMGU_ABI_FRAME_FORMAT_RAW_PACKED,
> +             .bayer_order = IMGU_ABI_BAYER_ORDER_RGGB,
> +             .bit_depth = 10,
> +             .bytesperpixel_num = 64,
> +             .width_align = 2 * IPU3_UAPI_ISP_VEC_ELEMS,
> +             .flags = IPU3_CSS_FORMAT_FL_IN,
> +     },
> +};
> +
> +static const struct {
> +     enum imgu_abi_queue_id qid;
> +     size_t ptr_ofs;
> +} ipu3_css_queues[IPU3_CSS_QUEUES] = {
> +     [IPU3_CSS_QUEUE_IN] = {
> +             IMGU_ABI_QUEUE_C_ID,
> +             offsetof(struct imgu_abi_buffer, payload.frame.frame_data)
> +     },
> +     [IPU3_CSS_QUEUE_OUT] = {
> +             IMGU_ABI_QUEUE_D_ID,
> +             offsetof(struct imgu_abi_buffer, payload.frame.frame_data)
> +     },
> +     [IPU3_CSS_QUEUE_VF] = {
> +             IMGU_ABI_QUEUE_E_ID,
> +             offsetof(struct imgu_abi_buffer, payload.frame.frame_data)
> +     },
> +     [IPU3_CSS_QUEUE_STAT_3A] = {
> +             IMGU_ABI_QUEUE_F_ID,
> +             offsetof(struct imgu_abi_buffer, payload.s3a.data_ptr)
> +     },
> +     [IPU3_CSS_QUEUE_STAT_DVS] = {
> +             IMGU_ABI_QUEUE_G_ID,
> +             offsetof(struct imgu_abi_buffer, payload.skc_dvs_statistics)
> +     }
> +};
> +
> +/* Initialize queue based on given format, adjust format as needed */
> +static int ipu3_css_queue_init(struct ipu3_css_queue *queue,
> +                            struct v4l2_pix_format_mplane *fmt, u32 flags)
> +{
> +     struct v4l2_pix_format_mplane *const f = &queue->fmt.mpix;
> +     unsigned int i;
> +     u32 sizeimage;
> +
> +     INIT_LIST_HEAD(&queue->bufs);
> +
> +     queue->css_fmt = NULL;  /* Disable */
> +     if (!fmt)
> +             return 0;
> +
> +     for (i = 0; i < ARRAY_SIZE(ipu3_css_formats); i++) {
> +             if (!(ipu3_css_formats[i].flags & flags))
> +                     continue;
> +             queue->css_fmt = &ipu3_css_formats[i];
> +             if (ipu3_css_formats[i].pixelformat == fmt->pixelformat)
> +                     break;
> +     }
> +     if (!queue->css_fmt)
> +             return -EINVAL; /* Could not find any suitable format */
> +
> +     queue->fmt.mpix = *fmt;
> +
> +     f->width = ALIGN(clamp_t(u32, f->width,
> +                              IPU3_CSS_MIN_RES, IPU3_CSS_MAX_W), 2);
> +     f->height = ALIGN(clamp_t(u32, f->height,
> +                               IPU3_CSS_MIN_RES, IPU3_CSS_MAX_H), 2);
> +     queue->width_pad = ALIGN(f->width, queue->css_fmt->width_align);
> +     if (queue->css_fmt->frame_format != IMGU_ABI_FRAME_FORMAT_RAW_PACKED)
> +             f->plane_fmt[0].bytesperline = DIV_ROUND_UP(queue->width_pad *
> +                                     queue->css_fmt->bytesperpixel_num,
> +                                     IPU3_CSS_FORMAT_BPP_DEN);
> +     else
> +             /* For packed raw, alignment for bpl is by 50 to the width */
> +             f->plane_fmt[0].bytesperline =
> +                             DIV_ROUND_UP(f->width,
> +                                          IPU3_CSS_FORMAT_BPP_DEN) *
> +                                          queue->css_fmt->bytesperpixel_num;
> +
> +     sizeimage = f->height * f->plane_fmt[0].bytesperline;
> +     if (queue->css_fmt->chroma_decim)
> +             sizeimage += 2 * sizeimage / queue->css_fmt->chroma_decim;
> +
> +     f->plane_fmt[0].sizeimage = sizeimage;
> +     f->field = V4L2_FIELD_NONE;
> +     f->num_planes = 1;
> +     f->colorspace = queue->css_fmt->colorspace;
> +     f->flags = 0;
> +     f->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
> +     f->quantization = V4L2_QUANTIZATION_DEFAULT;
> +     f->xfer_func = V4L2_XFER_FUNC_DEFAULT;
> +     memset(f->reserved, 0, sizeof(f->reserved));
> +
> +     return 0;
> +}
> +
> +static bool ipu3_css_queue_enabled(struct ipu3_css_queue *q)
> +{
> +     return !!q->css_fmt;

No need for !!.

> +}
> +
>  /******************* css hw *******************/
>  
>  /* in the style of writesl() defined in include/asm-generic/io.h */
> @@ -477,6 +637,1605 @@ static void ipu3_css_hw_cleanup(struct ipu3_css *css)
>       usleep_range(200, 300);
>  }
>  
> +static void ipu3_css_pipeline_cleanup(struct ipu3_css *css)
> +{
> +     struct imgu_fw_info *bi = &css->fwp->binary_header[css->current_binary];
> +     int pipe = 0;
> +     int i;
> +
> +     if (css->current_binary < 0)
> +             return;
> +
> +     ipu3_css_pool_cleanup(css->dev, &css->pool.parameter_set_info);
> +     ipu3_css_pool_cleanup(css->dev, &css->pool.acc);
> +     ipu3_css_pool_cleanup(css->dev, &css->pool.gdc);
> +     ipu3_css_pool_cleanup(css->dev, &css->pool.obgrid);
> +     for (i = 0; i < IMGU_ABI_NUM_MEMORIES; i++)
> +             ipu3_css_pool_cleanup(css->dev,
> +                                   &css->pool.binary_params_p[i]);
> +
> +     for (i = 0; i < bi->info.isp.sp.iterator.num_stripes; i++)
> +             ipu3_css_dma_free(css->dev, &css->dvs_meta_data[pipe][i]);
> +}
> +
> +/*
> + * This function initializes various stages of the
> + * IPU3 CSS ISP pipeline
> + */
> +static int ipu3_css_pipeline_init(struct ipu3_css *css)
> +{
> +     static const unsigned int PIPE_ID = IPU3_CSS_PIPE_ID_VIDEO;
> +     static const int BYPC = 2;      /* Bytes per component */
> +     static const struct imgu_abi_buffer_sp buffer_sp_init = {
> +             .buf_src = {.queue_id = IMGU_ABI_QUEUE_EVENT_ID},
> +             .buf_type = IMGU_ABI_BUFFER_TYPE_INVALID,
> +     };
> +
> +     struct imgu_abi_isp_iterator_config *cfg_iter;
> +     struct imgu_abi_isp_ref_config *cfg_ref;
> +     struct imgu_abi_isp_dvs_config *cfg_dvs;
> +     struct imgu_abi_isp_tnr3_config *cfg_tnr;
> +     struct imgu_abi_isp_ref_dmem_state *cfg_ref_state;
> +     struct imgu_abi_isp_tnr3_dmem_state *cfg_tnr_state;
> +
> +     const int pipe = 0, stage = 0, thread = 0;
> +     unsigned int i, j;
> +
> +     const struct imgu_fw_info *bi =
> +         &css->fwp->binary_header[css->current_binary];
> +     const unsigned int stripes = bi->info.isp.sp.iterator.num_stripes;
> +
> +     struct imgu_fw_config_memory_offsets *cofs = (void *)css->fwp +
> +         bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_CONFIG];
> +     struct imgu_fw_state_memory_offsets *sofs = (void *)css->fwp +
> +         bi->blob.memory_offsets.offsets[IMGU_ABI_PARAM_CLASS_STATE];
> +
> +     struct imgu_abi_isp_stage *isp_stage;
> +     struct imgu_abi_sp_stage *sp_stage;
> +     struct imgu_abi_sp_group *sp_group;
> +
> +     const unsigned int bds_width_pad =
> +                             ALIGN(css->rect[IPU3_CSS_RECT_BDS].width,
> +                                   2 * IPU3_UAPI_ISP_VEC_ELEMS);
> +
> +     const enum imgu_abi_memories m0 = IMGU_ABI_MEM_ISP_DMEM0;
> +     enum imgu_abi_param_class cfg = IMGU_ABI_PARAM_CLASS_CONFIG;
> +     void *vaddr = css->binary_params_cs[cfg - 1][m0].vaddr;
> +
> +     if (css->current_binary == -1)
> +             return -EAGAIN;
> +
> +     /* Configure iterator */
> +
> +     cfg_iter = ipu3_css_fw_pipeline_params(css, cfg, m0,
> +                                            &cofs->dmem.iterator,
> +                                            sizeof(*cfg_iter), vaddr);
> +     if (!cfg_iter)
> +             goto bad_firmware;
> +
> +     cfg_iter->input_info.res.width =
> +         css->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.width;
> +     cfg_iter->input_info.res.height =
> +         css->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.height;
> +     cfg_iter->input_info.padded_width =
> +         css->queue[IPU3_CSS_QUEUE_IN].width_pad;
> +     cfg_iter->input_info.format =
> +         css->queue[IPU3_CSS_QUEUE_IN].css_fmt->frame_format;
> +     cfg_iter->input_info.raw_bit_depth =
> +         css->queue[IPU3_CSS_QUEUE_IN].css_fmt->bit_depth;
> +     cfg_iter->input_info.raw_bayer_order =
> +         css->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order;
> +     cfg_iter->input_info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
> +
> +     cfg_iter->internal_info.res.width =
> +                     css->rect[IPU3_CSS_RECT_BDS].width;
> +     cfg_iter->internal_info.res.height =
> +                     css->rect[IPU3_CSS_RECT_BDS].height;
> +     cfg_iter->internal_info.padded_width = bds_width_pad;
> +     cfg_iter->internal_info.format =
> +         css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
> +     cfg_iter->internal_info.raw_bit_depth =
> +         css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bit_depth;
> +     cfg_iter->internal_info.raw_bayer_order =
> +         css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bayer_order;
> +     cfg_iter->internal_info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
> +
> +     cfg_iter->output_info.res.width =
> +         css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
> +     cfg_iter->output_info.res.height =
> +         css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
> +     cfg_iter->output_info.padded_width =
> +         css->queue[IPU3_CSS_QUEUE_OUT].width_pad;
> +     cfg_iter->output_info.format =
> +         css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
> +     cfg_iter->output_info.raw_bit_depth =
> +         css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bit_depth;
> +     cfg_iter->output_info.raw_bayer_order =
> +         css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bayer_order;
> +     cfg_iter->output_info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
> +
> +     cfg_iter->vf_info.res.width =
> +         css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
> +     cfg_iter->vf_info.res.height =
> +         css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
> +     cfg_iter->vf_info.padded_width =
> +         css->queue[IPU3_CSS_QUEUE_VF].width_pad;
> +     cfg_iter->vf_info.format =
> +         css->queue[IPU3_CSS_QUEUE_VF].css_fmt->frame_format;
> +     cfg_iter->vf_info.raw_bit_depth =
> +         css->queue[IPU3_CSS_QUEUE_VF].css_fmt->bit_depth;
> +     cfg_iter->vf_info.raw_bayer_order =
> +         css->queue[IPU3_CSS_QUEUE_VF].css_fmt->bayer_order;
> +     cfg_iter->vf_info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
> +
> +     cfg_iter->dvs_envelope.width = css->rect[IPU3_CSS_RECT_ENVELOPE].width;
> +     cfg_iter->dvs_envelope.height =
> +             css->rect[IPU3_CSS_RECT_ENVELOPE].height;
> +
> +     /* Configure reference (delay) frames */
> +
> +     cfg_ref = ipu3_css_fw_pipeline_params(css, cfg, m0, &cofs->dmem.ref,
> +                                           sizeof(*cfg_ref), vaddr);
> +     if (!cfg_ref)
> +             goto bad_firmware;
> +
> +     cfg_ref->port_b.crop = 0;
> +     cfg_ref->port_b.elems = IMGU_ABI_ISP_DDR_WORD_BYTES / BYPC;
> +     cfg_ref->port_b.width  = css->aux_frames[IPU3_CSS_AUX_FRAME_REF].width;
> +     cfg_ref->port_b.stride =
> +         css->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperline;
> +     cfg_ref->width_a_over_b =
> +         IPU3_UAPI_ISP_VEC_ELEMS / cfg_ref->port_b.elems;
> +     cfg_ref->dvs_frame_delay = IPU3_CSS_AUX_FRAMES - 1;
> +     for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++) {
> +             cfg_ref->ref_frame_addr_y[i] =
> +                 css->aux_frames[IPU3_CSS_AUX_FRAME_REF].mem[i].daddr;
> +             cfg_ref->ref_frame_addr_c[i] =
> +                 css->aux_frames[IPU3_CSS_AUX_FRAME_REF].mem[i].daddr +
> +                 css->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperline *
> +                 css->aux_frames[IPU3_CSS_AUX_FRAME_REF].height;
> +     }
> +     for (; i < IMGU_ABI_FRAMES_REF; i++) {
> +             cfg_ref->ref_frame_addr_y[i] = 0;
> +             cfg_ref->ref_frame_addr_c[i] = 0;
> +     }
> +
> +     /* Configure DVS (digital video stabilization) */
> +
> +     cfg_dvs = ipu3_css_fw_pipeline_params(css, cfg, m0,
> +                                           &cofs->dmem.dvs, sizeof(*cfg_dvs),
> +                                           vaddr);
> +     if (!cfg_dvs)
> +             goto bad_firmware;
> +
> +     cfg_dvs->num_horizontal_blocks =
> +         ALIGN(DIV_ROUND_UP(css->rect[IPU3_CSS_RECT_GDC].width,
> +                            IMGU_DVS_BLOCK_W), 2);
> +     cfg_dvs->num_vertical_blocks =
> +         DIV_ROUND_UP(css->rect[IPU3_CSS_RECT_GDC].height,
> +                      IMGU_DVS_BLOCK_H);
> +
> +     if (cfg_dvs->num_horizontal_blocks * cfg_dvs->num_vertical_blocks < 0)
> +             return -EPROTO;
> +
> +     /* Configure TNR (temporal noise reduction) */
> +
> +     if (css->pipe_id == IPU3_CSS_PIPE_ID_VIDEO) {
> +             cfg_tnr = ipu3_css_fw_pipeline_params(css, cfg, m0,
> +                                                   &cofs->dmem.tnr3,
> +                                                   sizeof(*cfg_tnr),
> +                                                   vaddr);
> +             if (!cfg_tnr)
> +                     goto bad_firmware;
> +
> +             cfg_tnr->port_b.crop = 0;
> +             cfg_tnr->port_b.elems = IMGU_ABI_ISP_DDR_WORD_BYTES;
> +             cfg_tnr->port_b.width =
> +                 css->aux_frames[IPU3_CSS_AUX_FRAME_TNR].width;
> +             cfg_tnr->port_b.stride =
> +                 css->aux_frames[IPU3_CSS_AUX_FRAME_TNR].bytesperline;
> +             cfg_tnr->width_a_over_b =
> +                 IPU3_UAPI_ISP_VEC_ELEMS / cfg_tnr->port_b.elems;
> +             cfg_tnr->frame_height =
> +                 css->aux_frames[IPU3_CSS_AUX_FRAME_TNR].height;
> +             cfg_tnr->delay_frame = IPU3_CSS_AUX_FRAMES - 1;
> +             for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
> +                     cfg_tnr->frame_addr[i] =
> +                         css->aux_frames[IPU3_CSS_AUX_FRAME_TNR]
> +                         .mem[i].daddr;
> +             for (; i < IMGU_ABI_FRAMES_TNR; i++)
> +                     cfg_tnr->frame_addr[i] = 0;
> +     }
> +
> +     /* Configure ref dmem state parameters */
> +
> +     cfg = IMGU_ABI_PARAM_CLASS_STATE;
> +     vaddr = css->binary_params_cs[cfg - 1][m0].vaddr;
> +
> +     cfg_ref_state = ipu3_css_fw_pipeline_params(css, cfg, m0,
> +                                                 &sofs->dmem.ref,
> +                                                 sizeof(*cfg_ref_state),
> +                                                 vaddr);
> +     if (!cfg_ref_state)
> +             goto bad_firmware;
> +
> +     cfg_ref_state->ref_in_buf_idx = 0;
> +     cfg_ref_state->ref_out_buf_idx = 1;
> +
> +     /* Configure tnr dmem state parameters */
> +     if (css->pipe_id == IPU3_CSS_PIPE_ID_VIDEO) {
> +             cfg_tnr_state =
> +                     ipu3_css_fw_pipeline_params(css, cfg, m0,
> +                                                 &sofs->dmem.tnr3,
> +                                                 sizeof(*cfg_tnr_state),
> +                                                 vaddr);
> +             if (!cfg_tnr_state)
> +                     goto bad_firmware;
> +
> +             cfg_tnr_state->in_bufidx = 0;
> +             cfg_tnr_state->out_bufidx = 1;
> +             cfg_tnr_state->bypass_filter = 0;
> +             cfg_tnr_state->total_frame_counter = 0;
> +             for (i = 0; i < IMGU_ABI_BUF_SETS_TNR; i++)
> +                     cfg_tnr_state->buffer_frame_counter[i] = 0;
> +     }
> +
> +     /* Configure ISP stage */
> +
> +     isp_stage = css->xmem_isp_stage_ptrs[pipe][stage].vaddr;
> +     memset(isp_stage, 0, sizeof(*isp_stage));
> +     isp_stage->blob_info = bi->blob;
> +     isp_stage->binary_info = bi->info.isp.sp;
> +     strcpy(isp_stage->binary_name,
> +            (char *)css->fwp + bi->blob.prog_name_offset);
> +     isp_stage->mem_initializers = bi->info.isp.sp.mem_initializers;
> +     for (i = IMGU_ABI_PARAM_CLASS_CONFIG; i < IMGU_ABI_PARAM_CLASS_NUM; i++)
> +             for (j = 0; j < IMGU_ABI_NUM_MEMORIES; j++)
> +                     isp_stage->mem_initializers.params[i][j].address =
> +                         css->binary_params_cs[i - 1][j].daddr;
> +
> +     /* Configure SP stage */
> +
> +     sp_stage = css->xmem_sp_stage_ptrs[pipe][stage].vaddr;
> +     memset(sp_stage, 0, sizeof(*sp_stage));
> +
> +     sp_stage->frames.in.buf_attr = buffer_sp_init;
> +     for (i = 0; i < IMGU_ABI_BINARY_MAX_OUTPUT_PORTS; i++)
> +             sp_stage->frames.out[i].buf_attr = buffer_sp_init;
> +     sp_stage->frames.out_vf.buf_attr = buffer_sp_init;
> +     sp_stage->frames.s3a_buf = buffer_sp_init;
> +     sp_stage->frames.dvs_buf = buffer_sp_init;
> +     sp_stage->frames.lace_buf = buffer_sp_init;
> +
> +     sp_stage->stage_type = IMGU_ABI_STAGE_TYPE_ISP;
> +     sp_stage->num = stage;
> +     sp_stage->isp_online = 0;
> +     sp_stage->isp_copy_vf = 0;
> +     sp_stage->isp_copy_output = 0;
> +
> +     /* Enable VF output only when VF or PV queue requested by user */
> +
> +     sp_stage->enable.vf_output =
> +             (css->vf_output_en != IPU3_NODE_VF_DISABLED);
> +
> +     sp_stage->frames.effective_in_res.width =
> +             css->rect[IPU3_CSS_RECT_EFFECTIVE].width;
> +     sp_stage->frames.effective_in_res.height =
> +             css->rect[IPU3_CSS_RECT_EFFECTIVE].height;
> +     sp_stage->frames.in.info.res.width =
> +         css->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.width;
> +     sp_stage->frames.in.info.res.height =
> +         css->queue[IPU3_CSS_QUEUE_IN].fmt.mpix.height;
> +     sp_stage->frames.in.info.padded_width =
> +         css->queue[IPU3_CSS_QUEUE_IN].width_pad;
> +     sp_stage->frames.in.info.format =
> +         css->queue[IPU3_CSS_QUEUE_IN].css_fmt->frame_format;
> +     sp_stage->frames.in.info.raw_bit_depth =
> +         css->queue[IPU3_CSS_QUEUE_IN].css_fmt->bit_depth;
> +     sp_stage->frames.in.info.raw_bayer_order =
> +         css->queue[IPU3_CSS_QUEUE_IN].css_fmt->bayer_order;
> +     sp_stage->frames.in.info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
> +     sp_stage->frames.in.buf_attr.buf_src.queue_id = IMGU_ABI_QUEUE_C_ID;
> +     sp_stage->frames.in.buf_attr.buf_type =
> +         IMGU_ABI_BUFFER_TYPE_INPUT_FRAME;
> +
> +     sp_stage->frames.out[0].info.res.width =
> +         css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.width;
> +     sp_stage->frames.out[0].info.res.height =
> +         css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
> +     sp_stage->frames.out[0].info.padded_width =
> +         css->queue[IPU3_CSS_QUEUE_OUT].width_pad;
> +     sp_stage->frames.out[0].info.format =
> +         css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
> +     sp_stage->frames.out[0].info.raw_bit_depth =
> +         css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bit_depth;
> +     sp_stage->frames.out[0].info.raw_bayer_order =
> +         css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bayer_order;
> +     sp_stage->frames.out[0].info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
> +     sp_stage->frames.out[0].planes.nv.uv.offset =
> +         css->queue[IPU3_CSS_QUEUE_OUT].width_pad *
> +         css->queue[IPU3_CSS_QUEUE_OUT].fmt.mpix.height;
> +     sp_stage->frames.out[0].buf_attr.buf_src.queue_id = IMGU_ABI_QUEUE_D_ID;
> +     sp_stage->frames.out[0].buf_attr.buf_type =
> +         IMGU_ABI_BUFFER_TYPE_OUTPUT_FRAME;
> +
> +     sp_stage->frames.out[1].buf_attr.buf_src.queue_id =
> +         IMGU_ABI_QUEUE_EVENT_ID;
> +
> +     sp_stage->frames.internal_frame_info.res.width =
> +                                     css->rect[IPU3_CSS_RECT_BDS].width;
> +     sp_stage->frames.internal_frame_info.res.height =
> +                                     css->rect[IPU3_CSS_RECT_BDS].height;
> +     sp_stage->frames.internal_frame_info.padded_width = bds_width_pad;
> +
> +     sp_stage->frames.internal_frame_info.format =
> +         css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
> +     sp_stage->frames.internal_frame_info.raw_bit_depth =
> +         css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bit_depth;
> +     sp_stage->frames.internal_frame_info.raw_bayer_order =
> +         css->queue[IPU3_CSS_QUEUE_OUT].css_fmt->bayer_order;
> +     sp_stage->frames.internal_frame_info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
> +
> +     sp_stage->frames.out_vf.info.res.width =
> +         css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.width;
> +     sp_stage->frames.out_vf.info.res.height =
> +         css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
> +     sp_stage->frames.out_vf.info.padded_width =
> +         css->queue[IPU3_CSS_QUEUE_VF].width_pad;
> +     sp_stage->frames.out_vf.info.format =
> +         css->queue[IPU3_CSS_QUEUE_VF].css_fmt->frame_format;
> +     sp_stage->frames.out_vf.info.raw_bit_depth =
> +         css->queue[IPU3_CSS_QUEUE_VF].css_fmt->bit_depth;
> +     sp_stage->frames.out_vf.info.raw_bayer_order =
> +         css->queue[IPU3_CSS_QUEUE_VF].css_fmt->bayer_order;
> +     sp_stage->frames.out_vf.info.raw_type = IMGU_ABI_RAW_TYPE_BAYER;
> +     sp_stage->frames.out_vf.planes.yuv.u.offset =
> +         css->queue[IPU3_CSS_QUEUE_VF].width_pad *
> +         css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height;
> +     sp_stage->frames.out_vf.planes.yuv.v.offset =
> +         css->queue[IPU3_CSS_QUEUE_VF].width_pad *
> +         css->queue[IPU3_CSS_QUEUE_VF].fmt.mpix.height * 5 / 4;
> +     sp_stage->frames.out_vf.buf_attr.buf_src.queue_id = IMGU_ABI_QUEUE_E_ID;
> +     sp_stage->frames.out_vf.buf_attr.buf_type =
> +         IMGU_ABI_BUFFER_TYPE_VF_OUTPUT_FRAME;
> +
> +     sp_stage->frames.s3a_buf.buf_src.queue_id = IMGU_ABI_QUEUE_F_ID;
> +     sp_stage->frames.s3a_buf.buf_type = IMGU_ABI_BUFFER_TYPE_3A_STATISTICS;
> +
> +     sp_stage->frames.dvs_buf.buf_src.queue_id = IMGU_ABI_QUEUE_G_ID;
> +     sp_stage->frames.dvs_buf.buf_type = IMGU_ABI_BUFFER_TYPE_DIS_STATISTICS;
> +
> +     sp_stage->dvs_envelope.width = css->rect[IPU3_CSS_RECT_ENVELOPE].width;
> +     sp_stage->dvs_envelope.height =
> +             css->rect[IPU3_CSS_RECT_ENVELOPE].height;
> +
> +     sp_stage->isp_pipe_version =
> +                             bi->info.isp.sp.pipeline.isp_pipe_version;
> +     sp_stage->isp_deci_log_factor = clamp(
> +             max(fls(css->rect[IPU3_CSS_RECT_BDS].width /
> +                                     IMGU_MAX_BQ_GRID_WIDTH),
> +                 fls(css->rect[IPU3_CSS_RECT_BDS].height /
> +                                     IMGU_MAX_BQ_GRID_HEIGHT)) - 1, 3, 5);
> +     sp_stage->isp_vf_downscale_bits = 0;
> +     sp_stage->if_config_index = 255;
> +     sp_stage->sp_enable_xnr = 0;
> +     sp_stage->num_stripes = stripes;
> +     sp_stage->enable.s3a = 1;
> +     sp_stage->enable.dvs_stats = 1;
> +
> +     sp_stage->xmem_bin_addr = css->binary[css->current_binary].daddr;
> +     sp_stage->xmem_map_addr = css->sp_ddr_ptrs.daddr;
> +     sp_stage->isp_stage_addr = css->xmem_isp_stage_ptrs[pipe][stage].daddr;
> +
> +     /* Configure SP group */
> +
> +     sp_group = css->xmem_sp_group_ptrs.vaddr;
> +     memset(sp_group, 0, sizeof(*sp_group));
> +
> +     sp_group->pipe[thread].num_stages = 1;
> +     sp_group->pipe[thread].pipe_id = PIPE_ID;
> +     sp_group->pipe[thread].thread_id = thread;
> +     sp_group->pipe[thread].pipe_num = pipe;
> +     sp_group->pipe[thread].num_execs = -1;
> +     sp_group->pipe[thread].pipe_qos_config = -1;
> +     sp_group->pipe[thread].required_bds_factor = 0;
> +     sp_group->pipe[thread].dvs_frame_delay = IPU3_CSS_AUX_FRAMES - 1;
> +     sp_group->pipe[thread].inout_port_config =
> +         IMGU_ABI_PORT_CONFIG_TYPE_INPUT_HOST |
> +         IMGU_ABI_PORT_CONFIG_TYPE_OUTPUT_HOST;

Indentation. Most of this seems to have been fixed but some remains in this
patch at least. Could you address that for the next version, please?

> +     sp_group->pipe[thread].scaler_pp_lut = 0;
> +     sp_group->pipe[thread].shading.internal_frame_origin_x_bqs_on_sctbl = 0;
> +     sp_group->pipe[thread].shading.internal_frame_origin_y_bqs_on_sctbl = 0;
> +     sp_group->pipe[thread].sp_stage_addr[stage] =
> +         css->xmem_sp_stage_ptrs[pipe][stage].daddr;
> +     sp_group->pipe[thread].pipe_config =
> +         bi->info.isp.sp.enable.params ? (1 << thread) : 0;
> +     sp_group->pipe[thread].pipe_config |= IMGU_ABI_PIPE_CONFIG_ACQUIRE_ISP;
> +
> +     /* Allocate dvs statistics metadata */
> +
> +     for (i = 0; i < stripes; i++)
> +             if (ipu3_css_dma_alloc(css->dev, &css->dvs_meta_data[pipe][i],
> +                                    sizeof(struct imgu_abi_dvs_meta_data)))
> +                     goto out_of_memory;
> +
> +     /* Initialize parameter pools */
> +
> +     if (ipu3_css_pool_init(css->dev, &css->pool.parameter_set_info,
> +                            sizeof(struct imgu_abi_parameter_set_info)) ||
> +         ipu3_css_pool_init(css->dev, &css->pool.acc,
> +                            sizeof(struct ipu3_uapi_acc_param)) ||
> +         ipu3_css_pool_init(css->dev, &css->pool.gdc,
> +                            sizeof(struct ipu3_uapi_gdc_warp_param) *
> +                            3 * cfg_dvs->num_horizontal_blocks / 2 *
> +                            cfg_dvs->num_vertical_blocks) ||
> +         ipu3_css_pool_init(css->dev, &css->pool.obgrid,
> +                            ipu3_css_fw_obgrid_size(
> +                            &css->fwp->binary_header[css->current_binary])))
> +             goto out_of_memory;
> +
> +     for (i = 0; i < IMGU_ABI_NUM_MEMORIES; i++)
> +             if (ipu3_css_pool_init(css->dev, &css->pool.binary_params_p[i],
> +                                    bi->info.isp.sp.mem_initializers.params
> +                                    [IMGU_ABI_PARAM_CLASS_PARAM][i].size))
> +                     goto out_of_memory;
> +
> +     return 0;
> +
> +bad_firmware:
> +     ipu3_css_pipeline_cleanup(css);
> +     return -EPROTO;
> +
> +out_of_memory:
> +     ipu3_css_pipeline_cleanup(css);
> +     return -ENOMEM;
> +}
> +
> +static u8 ipu3_css_queue_pos(struct ipu3_css *css, int queue, int thread)
> +{
> +     static const unsigned int sp;
> +     void __iomem *const base = css->base;
> +     struct imgu_fw_info *bi = &css->fwp->binary_header[css->fw_sp[sp]];
> +     struct imgu_abi_queues __iomem *q = base + IMGU_REG_SP_DMEM_BASE(sp) +
> +         bi->info.sp.host_sp_queue;
> +
> +     return queue >= 0 ? readb(&q->host2sp_bufq_info[thread][queue].end) :
> +         readb(&q->host2sp_evtq_info.end);
> +}
> +
> +/* Sent data to sp using given buffer queue, or if queue < 0, event queue. */
> +static int ipu3_css_queue_data(struct ipu3_css *css,
> +                            int queue, int thread, u32 data)
> +{
> +     static const unsigned int sp;
> +     void __iomem *const base = css->base;
> +     struct imgu_fw_info *bi = &css->fwp->binary_header[css->fw_sp[sp]];
> +     struct imgu_abi_queues __iomem *q = base + IMGU_REG_SP_DMEM_BASE(sp) +
> +         bi->info.sp.host_sp_queue;
> +     u8 size, start, end, end2;
> +
> +     if (queue >= 0) {
> +             size = readb(&q->host2sp_bufq_info[thread][queue].size);
> +             start = readb(&q->host2sp_bufq_info[thread][queue].start);
> +             end = readb(&q->host2sp_bufq_info[thread][queue].end);
> +     } else {
> +             size = readb(&q->host2sp_evtq_info.size);
> +             start = readb(&q->host2sp_evtq_info.start);
> +             end = readb(&q->host2sp_evtq_info.end);
> +     }
> +
> +     if (size == 0)
> +             return -EIO;
> +
> +     end2 = (end + 1) % size;
> +     if (end2 == start)
> +             return -EBUSY;  /* Queue full */
> +
> +     if (queue >= 0) {
> +             writel(data, &q->host2sp_bufq[thread][queue][end]);
> +             writeb(end2, &q->host2sp_bufq_info[thread][queue].end);
> +     } else {
> +             writel(data, &q->host2sp_evtq[end]);
> +             writeb(end2, &q->host2sp_evtq_info.end);
> +     }
> +
> +     return 0;
> +}
> +
> +/* Receive data using given buffer queue, or if queue < 0, event queue. */
> +static int ipu3_css_dequeue_data(struct ipu3_css *css, int queue, u32 *data)
> +{
> +     static const unsigned int sp;
> +     void __iomem *const base = css->base;
> +     struct imgu_fw_info *bi = &css->fwp->binary_header[css->fw_sp[sp]];
> +     struct imgu_abi_queues __iomem *q = base + IMGU_REG_SP_DMEM_BASE(sp) +
> +         bi->info.sp.host_sp_queue;
> +     u8 size, start, end, start2;
> +
> +     if (queue >= 0) {
> +             size = readb(&q->sp2host_bufq_info[queue].size);
> +             start = readb(&q->sp2host_bufq_info[queue].start);
> +             end = readb(&q->sp2host_bufq_info[queue].end);
> +     } else {
> +             size = readb(&q->sp2host_evtq_info.size);
> +             start = readb(&q->sp2host_evtq_info.start);
> +             end = readb(&q->sp2host_evtq_info.end);
> +     }
> +
> +     if (size == 0)
> +             return -EIO;
> +
> +     if (end == start)
> +             return -EBUSY;  /* Queue empty */
> +
> +     start2 = (start + 1) % size;
> +
> +     if (queue >= 0) {
> +             *data = readl(&q->sp2host_bufq[queue][start]);
> +             writeb(start2, &q->sp2host_bufq_info[queue].start);
> +     } else {
> +             int r;
> +
> +             *data = readl(&q->sp2host_evtq[start]);
> +             writeb(start2, &q->sp2host_evtq_info.start);
> +
> +             /* Acknowledge events dequeued from event queue */
> +             r = ipu3_css_queue_data(css, queue, 0,
> +                                     IMGU_ABI_EVENT_EVENT_DEQUEUED);
> +             if (r < 0)
> +                     return r;
> +     }
> +
> +     return 0;
> +}
> +
> +/* Free binary-specific resources */
> +static void ipu3_css_binary_cleanup(struct ipu3_css *css)
> +{
> +     unsigned int i, j;
> +
> +     for (j = 0; j < IMGU_ABI_PARAM_CLASS_NUM - 1; j++)
> +             for (i = 0; i < IMGU_ABI_NUM_MEMORIES; i++)
> +                     ipu3_css_dma_free(css->dev,
> +                                       &css->binary_params_cs[j][i]);
> +
> +     j = IPU3_CSS_AUX_FRAME_REF;
> +     for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
> +             ipu3_css_dma_free(css->dev,
> +                               &css->aux_frames[j].mem[i]);
> +
> +     j = IPU3_CSS_AUX_FRAME_TNR;
> +     for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
> +             ipu3_css_dma_free(css->dev,
> +                               &css->aux_frames[j].mem[i]);
> +}
> +
> +/* allocate binary-specific resources */
> +static int ipu3_css_binary_setup(struct ipu3_css *css)
> +{
> +     struct imgu_fw_info *bi = &css->fwp->binary_header[css->current_binary];
> +     int i, j, sz;
> +     static const int BYPC = 2;      /* Bytes per component */
> +     unsigned int w, h;
> +
> +     /* Allocate parameter memory blocks for this binary */
> +     if (css->current_binary < 0)
> +             return -EINVAL;
> +
> +     for (j = IMGU_ABI_PARAM_CLASS_CONFIG; j < IMGU_ABI_PARAM_CLASS_NUM; j++)
> +             for (i = 0; i < IMGU_ABI_NUM_MEMORIES; i++) {
> +                     sz = bi->info.isp.sp.mem_initializers.params[j][i].size;
> +                     if (ipu3_css_dma_alloc(css->dev,
> +                                            &css->binary_params_cs[j - 1][i],
> +                                            sz))
> +                             goto out_of_memory;
> +             }
> +
> +     /* Allocate internal frame buffers */
> +
> +     /* Reference frames for DVS, FRAME_FORMAT_YUV420_16 */
> +     css->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperpixel = BYPC;
> +     css->aux_frames[IPU3_CSS_AUX_FRAME_REF].width =
> +         css->rect[IPU3_CSS_RECT_BDS].width;
> +     css->aux_frames[IPU3_CSS_AUX_FRAME_REF].height =
> +                             ALIGN(css->rect[IPU3_CSS_RECT_BDS].height,
> +                                   IMGU_DVS_BLOCK_H) + 2 * IMGU_GDC_BUF_Y;
> +     h = css->aux_frames[IPU3_CSS_AUX_FRAME_REF].height;
> +     w = ALIGN(css->rect[IPU3_CSS_RECT_BDS].width,
> +               2 * IPU3_UAPI_ISP_VEC_ELEMS) + 2 * IMGU_GDC_BUF_X;
> +     css->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperline =
> +             css->aux_frames[IPU3_CSS_AUX_FRAME_REF].bytesperpixel * w;
> +     sz = w * h * BYPC + (w / 2) * (h / 2) * BYPC * 2;
> +     for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
> +             if (ipu3_css_dma_alloc(css->dev,
> +                                    &css->aux_frames
> +                                     [IPU3_CSS_AUX_FRAME_REF].mem[i], sz))
> +                     goto out_of_memory;
> +
> +     /* TNR frames for temporal noise reduction, FRAME_FORMAT_YUV_LINE */
> +     css->aux_frames[IPU3_CSS_AUX_FRAME_TNR].bytesperpixel = 1;
> +     css->aux_frames[IPU3_CSS_AUX_FRAME_TNR].width =
> +                     roundup(css->rect[IPU3_CSS_RECT_GDC].width,
> +                             bi->info.isp.sp.block.block_width *
> +                             IPU3_UAPI_ISP_VEC_ELEMS);
> +     css->aux_frames[IPU3_CSS_AUX_FRAME_TNR].height =
> +                     roundup(css->rect[IPU3_CSS_RECT_GDC].height,
> +                             bi->info.isp.sp.block.output_block_height);
> +
> +     w = css->aux_frames[IPU3_CSS_AUX_FRAME_TNR].width;
> +     css->aux_frames[IPU3_CSS_AUX_FRAME_TNR].bytesperline = w;
> +     h = css->aux_frames[IPU3_CSS_AUX_FRAME_TNR].height;
> +     sz = w * ALIGN(h * 3 / 2 + 3, 2);       /* +3 for vf_pp prefetch */
> +
> +     for (i = 0; i < IPU3_CSS_AUX_FRAMES; i++)
> +             if (ipu3_css_dma_alloc(css->dev,
> +                                    &css->aux_frames
> +                                     [IPU3_CSS_AUX_FRAME_TNR].mem[i], sz))
> +                     goto out_of_memory;
> +
> +     return 0;
> +
> +out_of_memory:
> +     ipu3_css_binary_cleanup(css);
> +     return -ENOMEM;
> +}
> +
> +int ipu3_css_start_streaming(struct ipu3_css *css)
> +{
> +     u32 data;
> +     int r;
> +
> +     if (css->streaming)
> +             return -EPROTO;
> +
> +     r = ipu3_css_binary_setup(css);
> +     if (r < 0)
> +             return r;
> +
> +     r = ipu3_css_hw_init(css);
> +     if (r < 0)
> +             return r;
> +
> +     r = ipu3_css_hw_start(css);
> +     if (r < 0)
> +             goto fail;
> +
> +     r = ipu3_css_pipeline_init(css);
> +     if (r < 0)
> +             goto fail;
> +
> +     css->streaming = true;
> +     css->frame = 0;
> +
> +     /* Initialize parameters to default */
> +     r = ipu3_css_set_parameters(css, NULL, NULL, 0, NULL, 0);
> +     if (r < 0)
> +             goto fail;
> +
> +     while (!(r = ipu3_css_dequeue_data(css, IMGU_ABI_QUEUE_A_ID, &data)))
> +             ;
> +     if (r != -EBUSY)
> +             goto fail;
> +
> +     while (!(r = ipu3_css_dequeue_data(css, IMGU_ABI_QUEUE_B_ID, &data)))
> +             ;
> +     if (r != -EBUSY)
> +             goto fail;
> +
> +     r = ipu3_css_queue_data(css, IMGU_ABI_QUEUE_EVENT_ID, 0,
> +                             IMGU_ABI_EVENT_START_STREAM);
> +     if (r < 0)
> +             goto fail;
> +
> +     return 0;
> +
> +fail:
> +     css->streaming = false;
> +     ipu3_css_hw_cleanup(css);
> +     ipu3_css_pipeline_cleanup(css);
> +     ipu3_css_binary_cleanup(css);
> +
> +     return r;
> +}
> +
> +void ipu3_css_stop_streaming(struct ipu3_css *css)
> +{
> +     struct ipu3_css_buffer *b, *b0;
> +     int q, r;
> +
> +     r = ipu3_css_queue_data(css, IMGU_ABI_QUEUE_EVENT_ID, 0,
> +                             IMGU_ABI_EVENT_STOP_STREAM);
> +
> +     if (r < 0)
> +             dev_warn(css->dev, "failed on stop stream event\n");
> +
> +     if (!css->streaming)
> +             return;
> +
> +     ipu3_css_hw_cleanup(css);
> +
> +     ipu3_css_pipeline_cleanup(css);
> +
> +     for (q = 0; q < IPU3_CSS_QUEUES; q++)
> +             list_for_each_entry_safe(b, b0, &css->queue[q].bufs, list) {
> +                     b->state = IPU3_CSS_BUFFER_FAILED;
> +                     list_del(&b->list);
> +             }
> +
> +     ipu3_css_binary_cleanup(css);
> +
> +     css->streaming = false;
> +}
> +
> +bool ipu3_css_queue_empty(struct ipu3_css *css)
> +{
> +     int q;
> +
> +     for (q = 0; q < IPU3_CSS_QUEUES; q++)
> +             if (!list_empty(&css->queue[q].bufs))
> +                     return false;
> +     return true;
> +}
> +
> +bool ipu3_css_is_streaming(struct ipu3_css *css)
> +{
> +     return css->streaming;
> +}
> +
> +void ipu3_css_cleanup(struct ipu3_css *css)
> +{
> +     int p, q, i;
> +
> +     ipu3_css_stop_streaming(css);
> +     ipu3_css_binary_cleanup(css);
> +
> +     for (q = 0; q < IPU3_CSS_QUEUES; q++)
> +             for (i = 0; i < ARRAY_SIZE(css->abi_buffers[q]); i++)
> +                     ipu3_css_dma_free(css->dev, &css->abi_buffers[q][i]);
> +
> +     for (p = 0; p < IPU3_CSS_PIPE_ID_NUM; p++)
> +             for (i = 0; i < IMGU_ABI_MAX_STAGES; i++) {
> +                     ipu3_css_dma_free(css->dev,
> +                                       &css->xmem_sp_stage_ptrs[p][i]);
> +                     ipu3_css_dma_free(css->dev,
> +                                       &css->xmem_isp_stage_ptrs[p][i]);
> +             }
> +
> +     ipu3_css_dma_free(css->dev, &css->sp_ddr_ptrs);
> +     ipu3_css_dma_free(css->dev, &css->xmem_sp_group_ptrs);
> +
> +     ipu3_css_fw_cleanup(css);
> +}
> +
> +int ipu3_css_init(struct device *dev, struct ipu3_css *css,
> +               void __iomem *base, int length)
> +{
> +     int r, p, q, i;
> +     struct imgu_abi_sp_stage *sp_stage;
> +     /* Initialize main data structure */
> +
> +     css->dev = dev;
> +     css->base = base;
> +     css->iomem_length = length;
> +     css->current_binary = -1;
> +     css->pipe_id = IPU3_CSS_PIPE_ID_NUM;
> +
> +     for (q = 0; q < IPU3_CSS_QUEUES; q++) {
> +             r = ipu3_css_queue_init(&css->queue[q], NULL, 0);
> +             if (r)
> +                     return r;
> +     }
> +
> +     r = ipu3_css_fw_init(css);
> +     if (r)
> +             return r;
> +
> +     /* Allocate and map common structures with imgu hardware */
> +
> +     for (p = 0; p < IPU3_CSS_PIPE_ID_NUM; p++)
> +             for (i = 0; i < IMGU_ABI_MAX_STAGES; i++) {
> +                     if (ipu3_css_dma_alloc(dev,
> +                                            &css->xmem_sp_stage_ptrs[p][i],
> +                                            sizeof(*sp_stage)))
> +                             goto error_no_memory;
> +                     if (ipu3_css_dma_alloc(dev,
> +                                            &css->xmem_isp_stage_ptrs[p][i],
> +                                            sizeof(*sp_stage)))
> +                             goto error_no_memory;
> +             }
> +
> +     if (ipu3_css_dma_alloc(dev, &css->sp_ddr_ptrs,
> +                            ALIGN(sizeof(struct imgu_abi_ddr_address_map),
> +                                  IMGU_ABI_ISP_DDR_WORD_BYTES)))
> +             goto error_no_memory;
> +
> +     if (ipu3_css_dma_alloc(dev, &css->xmem_sp_group_ptrs,
> +                            sizeof(struct imgu_abi_sp_group)))
> +             goto error_no_memory;
> +
> +     for (q = 0; q < IPU3_CSS_QUEUES; q++)
> +             for (i = 0; i < ARRAY_SIZE(css->abi_buffers[q]); i++)
> +                     if (ipu3_css_dma_alloc(dev, &css->abi_buffers[q][i],
> +                                            sizeof(struct imgu_abi_buffer)))
> +                             goto error_no_memory;
> +
> +     return 0;
> +
> +error_no_memory:
> +     ipu3_css_cleanup(css);
> +
> +     return -ENOMEM;
> +}
> +
> +static u32 ipu3_css_adjust(u32 res, u32 align)
> +{
> +     if (res < IPU3_CSS_MIN_RES)
> +             res = IPU3_CSS_MIN_RES;
> +     res = roundclosest(res, align);
> +
> +     return res;
> +}
> +
> +/* Select a binary matching the required resolutions and formats */
> +static int ipu3_css_find_binary(struct ipu3_css *css,
> +                             struct ipu3_css_queue queue[IPU3_CSS_QUEUES],
> +                             struct v4l2_rect rects[IPU3_CSS_RECTS])
> +{
> +     const int binary_nr = css->fwp->file_header.binary_nr;
> +     unsigned int binary_mode = (css->pipe_id == IPU3_CSS_PIPE_ID_CAPTURE) ?
> +             IA_CSS_BINARY_MODE_PRIMARY : IA_CSS_BINARY_MODE_VIDEO;
> +     const char *name;
> +
> +     const struct v4l2_pix_format_mplane *in =
> +                     &queue[IPU3_CSS_QUEUE_IN].fmt.mpix;
> +     const struct v4l2_pix_format_mplane *out =
> +                     &queue[IPU3_CSS_QUEUE_OUT].fmt.mpix;
> +     const struct v4l2_pix_format_mplane *vf =
> +                     &queue[IPU3_CSS_QUEUE_VF].fmt.mpix;
> +
> +     int i, j;
> +     u32 stripe_w = 0;
> +     u32 stripe_h = 0;
> +
> +     if (!ipu3_css_queue_enabled(&queue[IPU3_CSS_QUEUE_IN]))
> +             return -EINVAL;
> +
> +     /* Find out the strip size boundary */
> +     for (i = 0; i < binary_nr; i++) {
> +             struct imgu_fw_info *bi = &css->fwp->binary_header[i];
> +
> +             u32 max_width = bi->info.isp.sp.output.max_width;
> +             u32 max_height = bi->info.isp.sp.output.max_height;
> +
> +             if (bi->info.isp.sp.iterator.num_stripes <= 1) {
> +                     stripe_w = stripe_w ?
> +                             min(stripe_w, max_width) : max_width;
> +                     stripe_h = stripe_h ?
> +                             min(stripe_h, max_height) : max_height;
> +             }
> +     }
> +
> +     for (i = 0; i < binary_nr; i++) {
> +             struct imgu_fw_info *bi = &css->fwp->binary_header[i];
> +             enum imgu_abi_frame_format q_fmt;
> +
> +             name = (void *)css->fwp + bi->blob.prog_name_offset;
> +
> +             /* Check that binary supports memory-to-memory processing */
> +             if (bi->info.isp.sp.input.source !=
> +                 IMGU_ABI_BINARY_INPUT_SOURCE_MEMORY)
> +                     continue;
> +
> +             /* Check that binary supports raw10 input */
> +             if (!bi->info.isp.sp.enable.input_feeder &&
> +                 !bi->info.isp.sp.enable.input_raw)
> +                     continue;
> +
> +             /* Check binary mode */
> +             if (bi->info.isp.sp.pipeline.mode != binary_mode)
> +                     continue;
> +
> +             /* Since input is RGGB bayer, need to process colors */
> +             if (bi->info.isp.sp.enable.luma_only)
> +                     continue;
> +
> +             if (in->width < bi->info.isp.sp.input.min_width ||
> +                 in->width > bi->info.isp.sp.input.max_width ||
> +                 in->height < bi->info.isp.sp.input.min_height ||
> +                 in->height > bi->info.isp.sp.input.max_height)
> +                     continue;
> +
> +             if (ipu3_css_queue_enabled(&queue[IPU3_CSS_QUEUE_OUT])) {
> +                     if (bi->info.isp.num_output_pins <= 0)
> +                             continue;
> +
> +                     q_fmt = queue[IPU3_CSS_QUEUE_OUT].css_fmt->frame_format;
> +
> +                     for (j = 0; j < bi->info.isp.num_output_formats; j++)
> +                             if (bi->info.isp.output_formats[j] == q_fmt)
> +                                     break;
> +                     if (j >= bi->info.isp.num_output_formats)
> +                             continue;
> +
> +                     if (out->width < bi->info.isp.sp.output.min_width ||
> +                         out->width > bi->info.isp.sp.output.max_width ||
> +                         out->height < bi->info.isp.sp.output.min_height ||
> +                         out->height > bi->info.isp.sp.output.max_height)
> +                             continue;
> +
> +                     if (out->width > bi->info.isp.sp.internal.max_width ||
> +                         out->height > bi->info.isp.sp.internal.max_height)
> +                             continue;
> +             }
> +
> +             if (ipu3_css_queue_enabled(&queue[IPU3_CSS_QUEUE_VF])) {
> +                     if (bi->info.isp.num_output_pins <= 1)
> +                             continue;
> +                     q_fmt = queue[IPU3_CSS_QUEUE_VF].css_fmt->frame_format;
> +                     for (j = 0; j < bi->info.isp.num_output_formats; j++)
> +                             if (bi->info.isp.output_formats[j] == q_fmt)
> +                                     break;
> +                     if (j >= bi->info.isp.num_output_formats)
> +                             continue;
> +
> +                     if (vf->width < bi->info.isp.sp.output.min_width ||
> +                         vf->width > bi->info.isp.sp.output.max_width ||
> +                         vf->height < bi->info.isp.sp.output.min_height ||
> +                         vf->height > bi->info.isp.sp.output.max_height)
> +                             continue;
> +             }
> +
> +             /* All checks passed, select the binary */
> +             dev_dbg(css->dev, "using binary %s\n", name);
> +             return i;
> +     }
> +
> +     /* Can not find suitable binary for these parameters */
> +     return -EINVAL;
> +}
> +
> +/*
> + * Check that there is a binary matching requirements. Parameters may be
> + * NULL indicating disabled input/output. Return negative if given
> + * parameters can not be supported or on error, zero or positive indicating
> + * found binary number. May modify the given parameters if not exact match
> + * is found.
> + */
> +int ipu3_css_fmt_try(struct ipu3_css *css,
> +                  struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES],
> +                  struct v4l2_rect *rects[IPU3_CSS_RECTS])
> +{
> +     static const u32 EFF_ALIGN_W = 2;
> +     static const u32 BDS_ALIGN_W = 4;
> +     static const u32 OUT_ALIGN_W = 8;
> +     static const u32 OUT_ALIGN_H = 4;
> +     static const u32 VF_ALIGN_W  = 2;
> +     static const char *qnames[IPU3_CSS_QUEUES] = {
> +             [IPU3_CSS_QUEUE_IN] = "in",
> +             [IPU3_CSS_QUEUE_PARAMS]    = "params",
> +             [IPU3_CSS_QUEUE_OUT] = "out",
> +             [IPU3_CSS_QUEUE_VF] = "vf",
> +             [IPU3_CSS_QUEUE_STAT_3A]   = "3a",
> +             [IPU3_CSS_QUEUE_STAT_DVS]  = "dvs",
> +             [IPU3_CSS_QUEUE_STAT_LACE] = "lace",
> +     };
> +     static const char *rnames[IPU3_CSS_RECTS] = {
> +             [IPU3_CSS_RECT_EFFECTIVE] = "effective resolution",
> +             [IPU3_CSS_RECT_BDS]       = "bayer-domain scaled resolution",
> +             [IPU3_CSS_RECT_ENVELOPE]  = "DVS envelope size",
> +             [IPU3_CSS_RECT_GDC]  = "GDC output res",
> +     };
> +     struct v4l2_rect r[IPU3_CSS_RECTS] = { };
> +     struct v4l2_rect *const eff = &r[IPU3_CSS_RECT_EFFECTIVE];
> +     struct v4l2_rect *const bds = &r[IPU3_CSS_RECT_BDS];
> +     struct v4l2_rect *const env = &r[IPU3_CSS_RECT_ENVELOPE];
> +     struct v4l2_rect *const gdc = &r[IPU3_CSS_RECT_GDC];
> +     struct ipu3_css_queue q[IPU3_CSS_QUEUES];
> +     struct v4l2_pix_format_mplane *const in =
> +                     &q[IPU3_CSS_QUEUE_IN].fmt.mpix;
> +     struct v4l2_pix_format_mplane *const out =
> +                     &q[IPU3_CSS_QUEUE_OUT].fmt.mpix;
> +     struct v4l2_pix_format_mplane *const vf =
> +                     &q[IPU3_CSS_QUEUE_VF].fmt.mpix;
> +     int binary, i, s;
> +
> +     /* Decide which pipe to use */
> +     if (css->vf_output_en == IPU3_NODE_PV_ENABLED)
> +             css->pipe_id = IPU3_CSS_PIPE_ID_CAPTURE;
> +     else if (css->vf_output_en == IPU3_NODE_VF_ENABLED)
> +             css->pipe_id = IPU3_CSS_PIPE_ID_VIDEO;
> +
> +     /* Adjust all formats, get statistics buffer sizes and formats */
> +     for (i = 0; i < IPU3_CSS_QUEUES; i++) {
> +             if (fmts[i])
> +                     dev_dbg(css->dev, "%s %s: (%i,%i) fmt 0x%x\n", __func__,
> +                             qnames[i], fmts[i]->width, fmts[i]->height,
> +                             fmts[i]->pixelformat);
> +             else
> +                     dev_dbg(css->dev, "%s %s: (not set)\n", __func__,
> +                             qnames[i]);
> +             if (ipu3_css_queue_init(&q[i], fmts[i],
> +                                     IPU3_CSS_QUEUE_TO_FLAGS(i))) {
> +                     dev_notice(css->dev, "can not initialize queue %s\n",
> +                                qnames[i]);
> +                     return -EINVAL;
> +             }
> +     }
> +     for (i = 0; i < IPU3_CSS_RECTS; i++) {
> +             if (rects[i]) {
> +                     dev_dbg(css->dev, "%s %s: (%i,%i)\n", __func__,
> +                             rnames[i], rects[i]->width, rects[i]->height);
> +                     r[i].width  = rects[i]->width;
> +                     r[i].height = rects[i]->height;
> +             } else {
> +                     dev_dbg(css->dev, "%s %s: (not set)\n", __func__,
> +                             rnames[i]);
> +             }
> +             /* For now, force known good resolutions */
> +             r[i].left = 0;
> +             r[i].top  = 0;
> +     }
> +
> +     /* Always require one input and vf only if out is also enabled */
> +     if (!ipu3_css_queue_enabled(&q[IPU3_CSS_QUEUE_IN]) ||
> +         (ipu3_css_queue_enabled(&q[IPU3_CSS_QUEUE_VF]) &&
> +         !ipu3_css_queue_enabled(&q[IPU3_CSS_QUEUE_OUT]))) {
> +             dev_dbg(css->dev, "required queues are disabled\n");
> +             return -EINVAL;
> +     }
> +
> +     if (!ipu3_css_queue_enabled(&q[IPU3_CSS_QUEUE_OUT])) {
> +             out->width = in->width;
> +             out->height = in->height;
> +     }
> +     if (eff->width <= 0 || eff->height <= 0) {
> +             eff->width = in->width;
> +             eff->height = in->height;
> +     }
> +     if (bds->width <= 0 || bds->height <= 0) {
> +             bds->width = out->width;
> +             bds->height = out->height;
> +     }
> +     if (gdc->width <= 0 || gdc->height <= 0) {
> +             gdc->width = out->width;
> +             gdc->height = out->height;
> +     }
> +
> +     in->width   = ipu3_css_adjust(in->width, 1);
> +     in->height  = ipu3_css_adjust(in->height, 1);
> +     eff->width  = ipu3_css_adjust(eff->width, EFF_ALIGN_W);
> +     eff->height = ipu3_css_adjust(eff->height, 1);
> +     bds->width  = ipu3_css_adjust(bds->width, BDS_ALIGN_W);
> +     bds->height = ipu3_css_adjust(bds->height, 1);
> +     gdc->width  = ipu3_css_adjust(gdc->width, OUT_ALIGN_W);
> +     gdc->height = ipu3_css_adjust(gdc->height, OUT_ALIGN_H);
> +     out->width  = ipu3_css_adjust(out->width, OUT_ALIGN_W);
> +     out->height = ipu3_css_adjust(out->height, OUT_ALIGN_H);
> +     vf->width   = ipu3_css_adjust(vf->width, VF_ALIGN_W);
> +     vf->height  = ipu3_css_adjust(vf->height, 1);
> +
> +     s = (bds->width - gdc->width) / 2 - FILTER_SIZE;
> +     env->width = s < MIN_ENVELOPE ? MIN_ENVELOPE : s;
> +     s = (bds->height - gdc->height) / 2 - FILTER_SIZE;
> +     env->height = s < MIN_ENVELOPE ? MIN_ENVELOPE : s;
> +
> +     binary = ipu3_css_find_binary(css, q, r);
> +     if (binary < 0) {
> +             dev_err(css->dev, "failed to find suitable binary\n");
> +             return -EINVAL;
> +     }
> +
> +     /* Final adjustment and set back the queried formats */
> +     for (i = 0; i < IPU3_CSS_QUEUES; i++) {
> +             if (fmts[i]) {
> +                     if (ipu3_css_queue_init(&q[i], &q[i].fmt.mpix,
> +                                             IPU3_CSS_QUEUE_TO_FLAGS(i))) {
> +                             dev_err(css->dev,
> +                                     "final resolution adjustment failed\n");
> +                             return -EINVAL;
> +                     }
> +                     *fmts[i] = q[i].fmt.mpix;
> +             }
> +     }
> +
> +     for (i = 0; i < IPU3_CSS_RECTS; i++)
> +             if (rects[i])
> +                     *rects[i] = r[i];
> +
> +     dev_dbg(css->dev,
> +             "in(%u,%u) if(%u,%u) ds(%u,%u) gdc(%u,%u) out(%u,%u) vf(%u,%u)",
> +              in->width, in->height, eff->width, eff->height,
> +              bds->width, bds->height, gdc->width, gdc->height,
> +              out->width, out->height, vf->width, vf->height);
> +
> +     return binary;
> +}
> +
> +int ipu3_css_fmt_set(struct ipu3_css *css,
> +                  struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES],
> +                  struct v4l2_rect *rects[IPU3_CSS_RECTS])
> +{
> +     struct v4l2_rect rect_data[IPU3_CSS_RECTS];
> +     struct v4l2_rect *all_rects[IPU3_CSS_RECTS];
> +     int i, r;
> +
> +     for (i = 0; i < IPU3_CSS_RECTS; i++) {
> +             if (rects[i])
> +                     rect_data[i] = *rects[i];
> +             else
> +                     memset(&rect_data[i], 0, sizeof(rect_data[i]));
> +             all_rects[i] = &rect_data[i];
> +     }
> +     r = ipu3_css_fmt_try(css, fmts, all_rects);
> +     if (r < 0)
> +             return r;
> +     css->current_binary = r;
> +
> +     for (i = 0; i < IPU3_CSS_QUEUES; i++)
> +             if (ipu3_css_queue_init(&css->queue[i], fmts[i],
> +                                     IPU3_CSS_QUEUE_TO_FLAGS(i)))
> +                     return -EINVAL;
> +     for (i = 0; i < IPU3_CSS_RECTS; i++) {
> +             css->rect[i] = rect_data[i];
> +             if (rects[i])
> +                     *rects[i] = rect_data[i];
> +     }
> +
> +     return 0;
> +}
> +
> +int ipu3_css_meta_fmt_set(struct v4l2_meta_format *fmt)
> +{
> +     switch (fmt->dataformat) {
> +     case V4L2_META_FMT_IPU3_PARAMS:
> +             fmt->buffersize = sizeof(struct ipu3_uapi_params);
> +             break;
> +     case V4L2_META_FMT_IPU3_STAT_3A:
> +             fmt->buffersize = sizeof(struct ipu3_uapi_stats_3a);
> +             break;
> +     case V4L2_META_FMT_IPU3_STAT_DVS:
> +             fmt->buffersize = sizeof(struct ipu3_uapi_stats_dvs);
> +             break;
> +     case V4L2_META_FMT_IPU3_STAT_LACE:
> +             fmt->buffersize = sizeof(struct ipu3_uapi_stats_lace);
> +             break;
> +     default:
> +             return -EINVAL;
> +     }
> +
> +     return 0;
> +}
> +
> +/*
> + * Queue given buffer to CSS. ipu3_css_buf_prepare() must have been first
> + * called for the buffer. May be called from interrupt context.
> + * Returns 0 on success, -EBUSY if the buffer queue is full, or some other
> + * code on error conditions.
> + */
> +int ipu3_css_buf_queue(struct ipu3_css *css, struct ipu3_css_buffer *b)
> +{
> +     static const int thread;
> +     struct imgu_abi_buffer *abi_buf;
> +     struct imgu_addr_t *buf_addr;
> +     u32 data;
> +     int r;
> +
> +     if (!css->streaming)
> +             return -EPROTO; /* CSS or buffer in wrong state */
> +
> +     if (b->queue >= IPU3_CSS_QUEUES || !ipu3_css_queues[b->queue].qid)
> +             return -EINVAL;
> +
> +     b->queue_pos = ipu3_css_queue_pos(
> +                             css, ipu3_css_queues[b->queue].qid, thread);
> +
> +     if (b->queue_pos >= ARRAY_SIZE(css->abi_buffers[b->queue]))
> +             return -EIO;
> +     abi_buf = css->abi_buffers[b->queue][b->queue_pos].vaddr;
> +
> +     /* Fill struct abi_buffer for firmware */
> +     memset(abi_buf, 0, sizeof(*abi_buf));
> +
> +     buf_addr = (void *)abi_buf + ipu3_css_queues[b->queue].ptr_ofs;
> +     *(imgu_addr_t *)buf_addr = b->daddr;
> +
> +     if (b->queue == IPU3_CSS_QUEUE_STAT_3A)
> +             abi_buf->payload.s3a.data.dmem.s3a_tbl = b->daddr;
> +
> +     if (b->queue == IPU3_CSS_QUEUE_OUT)
> +             abi_buf->payload.frame.padded_width =
> +                     css->queue[IPU3_CSS_QUEUE_OUT].width_pad;
> +
> +     if (b->queue == IPU3_CSS_QUEUE_VF)
> +             abi_buf->payload.frame.padded_width =
> +                     css->queue[IPU3_CSS_QUEUE_VF].width_pad;
> +
> +     list_add_tail(&b->list, &css->queue[b->queue].bufs);
> +     b->state = IPU3_CSS_BUFFER_QUEUED;
> +
> +     data = css->abi_buffers[b->queue][b->queue_pos].daddr;
> +     r = ipu3_css_queue_data(css, ipu3_css_queues[b->queue].qid,
> +                             thread, data);
> +     if (r < 0)
> +             goto queueing_failed;
> +
> +     data = IMGU_ABI_EVENT_BUFFER_ENQUEUED(thread,
> +                                           ipu3_css_queues[b->queue].qid);
> +     r = ipu3_css_queue_data(css, IMGU_ABI_QUEUE_EVENT_ID,
> +                             0, data);
> +     if (r < 0)
> +             goto queueing_failed;
> +
> +     dev_dbg(css->dev, "queued buffer %p to css queue %i\n", b, b->queue);
> +
> +     return 0;
> +
> +queueing_failed:
> +     b->state = (r == -EBUSY || r == -EAGAIN) ?
> +             IPU3_CSS_BUFFER_NEW : IPU3_CSS_BUFFER_FAILED;
> +     list_del(&b->list);
> +
> +     return r;
> +}
> +
> +/*
> + * Get next ready CSS buffer. Returns -EAGAIN in which case the function
> + * should be called again, or -EBUSY which means that there are no more
> + * buffers available. May be called from interrupt context.
> + */
> +struct ipu3_css_buffer *ipu3_css_buf_dequeue(struct ipu3_css *css)
> +{
> +     static const int thread;
> +     static const unsigned char evtype_to_queue[] = {
> +             [IMGU_ABI_EVTTYPE_INPUT_FRAME_DONE] = IPU3_CSS_QUEUE_IN,
> +             [IMGU_ABI_EVTTYPE_OUT_FRAME_DONE] = IPU3_CSS_QUEUE_OUT,
> +             [IMGU_ABI_EVTTYPE_VF_OUT_FRAME_DONE] = IPU3_CSS_QUEUE_VF,
> +             [IMGU_ABI_EVTTYPE_3A_STATS_DONE] = IPU3_CSS_QUEUE_STAT_3A,
> +             [IMGU_ABI_EVTTYPE_DIS_STATS_DONE] = IPU3_CSS_QUEUE_STAT_DVS,
> +             [IMGU_ABI_EVTTYPE_LACE_STATS_DONE] = IPU3_CSS_QUEUE_STAT_LACE,
> +     };
> +     struct ipu3_css_buffer *b = ERR_PTR(-EAGAIN);
> +     u32 event, daddr;
> +     int evtype, pipe, pipeid, queue, qid, r;
> +
> +     if (!css->streaming)
> +             return ERR_PTR(-EPROTO);
> +
> +     r = ipu3_css_dequeue_data(css, IMGU_ABI_QUEUE_EVENT_ID, &event);
> +     if (r < 0)
> +             return ERR_PTR(r);
> +
> +     evtype = (event & IMGU_ABI_EVTTYPE_EVENT_MASK) >>
> +         IMGU_ABI_EVTTYPE_EVENT_SHIFT;
> +
> +     switch (evtype) {
> +     case IMGU_ABI_EVTTYPE_OUT_FRAME_DONE:
> +     case IMGU_ABI_EVTTYPE_VF_OUT_FRAME_DONE:
> +     case IMGU_ABI_EVTTYPE_3A_STATS_DONE:
> +     case IMGU_ABI_EVTTYPE_DIS_STATS_DONE:
> +     case IMGU_ABI_EVTTYPE_INPUT_FRAME_DONE:
> +     case IMGU_ABI_EVTTYPE_LACE_STATS_DONE:
> +             pipe = (event & IMGU_ABI_EVTTYPE_PIPE_MASK) >>
> +                 IMGU_ABI_EVTTYPE_PIPE_SHIFT;
> +             pipeid = (event & IMGU_ABI_EVTTYPE_PIPEID_MASK) >>
> +                 IMGU_ABI_EVTTYPE_PIPEID_SHIFT;
> +             queue = evtype_to_queue[evtype];
> +             qid = ipu3_css_queues[queue].qid;
> +
> +             if (qid >= IMGU_ABI_QUEUE_NUM) {
> +                     dev_err(css->dev, "Invalid qid: %i\n", qid);
> +                     return ERR_PTR(-EIO);
> +             }
> +
> +             dev_dbg(css->dev,
> +                     "event: buffer done 0x%x queue %i pipe %i pipeid %i\n",
> +                     event, queue, pipe, pipeid);
> +
> +             r = ipu3_css_dequeue_data(css, qid, &daddr);
> +             if (r < 0) {
> +                     dev_err(css->dev, "failed to dequeue buffer\n");
> +                     /* Force real error, not -EBUSY */
> +                     return ERR_PTR(-EIO);
> +             }
> +
> +             r = ipu3_css_queue_data(css, IMGU_ABI_QUEUE_EVENT_ID, thread,
> +                                     IMGU_ABI_EVENT_BUFFER_DEQUEUED(qid));
> +             if (r < 0) {
> +                     dev_err(css->dev, "failed to queue event\n");
> +                     return ERR_PTR(-EIO);
> +             }
> +
> +             if (list_empty(&css->queue[queue].bufs)) {
> +                     dev_err(css->dev, "event on empty queue\n");
> +                     return ERR_PTR(-EIO);
> +             }
> +             b = list_first_entry(&css->queue[queue].bufs,
> +                                  struct ipu3_css_buffer, list);
> +             if (queue != b->queue ||
> +                 daddr != css->abi_buffers[b->queue][b->queue_pos].daddr) {
> +                     dev_err(css->dev, "dequeued bad buffer 0x%x\n", daddr);
> +                     return ERR_PTR(-EIO);
> +             }
> +             b->state = IPU3_CSS_BUFFER_DONE;
> +             list_del(&b->list);
> +             break;
> +     case IMGU_ABI_EVTTYPE_PIPELINE_DONE:
> +             dev_dbg(css->dev, "event: pipeline done 0x%x for frame %ld\n",
> +                     event, css->frame);
> +
> +             if (css->frame == LONG_MAX)
> +                     css->frame = 0;
> +             else
> +                     css->frame++;
> +             break;
> +     case IMGU_ABI_EVTTYPE_TIMER:
> +             r = ipu3_css_dequeue_data(css, IMGU_ABI_QUEUE_EVENT_ID, &event);
> +             if (r < 0)
> +                     return ERR_PTR(r);
> +
> +             if ((event & IMGU_ABI_EVTTYPE_EVENT_MASK) >>
> +                 IMGU_ABI_EVTTYPE_EVENT_SHIFT == IMGU_ABI_EVTTYPE_TIMER)
> +                     dev_dbg(css->dev, "event: timer\n");
> +             else
> +                     dev_warn(css->dev, "half of timer event missing\n");
> +             break;
> +     case IMGU_ABI_EVTTYPE_FW_WARNING:
> +             dev_warn(css->dev, "event: firmware warning 0x%x\n", event);
> +             break;
> +     case IMGU_ABI_EVTTYPE_FW_ASSERT:
> +             dev_err(css->dev,
> +                     "event: firmware assert 0x%x module_id %i line_no %i\n",
> +                     event,
> +                     (event & IMGU_ABI_EVTTYPE_MODULEID_MASK) >>
> +                     IMGU_ABI_EVTTYPE_MODULEID_SHIFT,
> +                     swab16((event & IMGU_ABI_EVTTYPE_LINENO_MASK) >>
> +                            IMGU_ABI_EVTTYPE_LINENO_SHIFT));
> +             break;
> +     default:
> +             dev_warn(css->dev, "received unknown event 0x%x\n", event);
> +     }
> +
> +     return b;
> +}
> +
> +/*
> + * Get a new set of parameters from pool and initialize them based on
> + * the parameters params, gdc, and obgrid. Any of these may be NULL,
> + * in which case the previously set parameters are used.
> + * If parameters haven't been set previously, initialize from scratch.
> + *
> + * Return index to css->parameter_set_info which has the newly created
> + * parameters or negative value on error.
> + */
> +int ipu3_css_set_parameters(struct ipu3_css *css,
> +                         struct ipu3_uapi_params *set_params,
> +                         struct ipu3_uapi_gdc_warp_param *set_gdc,
> +                         unsigned int gdc_bytes,
> +                         struct ipu3_uapi_obgrid_param *set_obgrid,
> +                         unsigned int obgrid_bytes)
> +{
> +     static const unsigned int queue_id = IMGU_ABI_QUEUE_A_ID;
> +     const int stage = 0, thread = 0;
> +     const struct imgu_fw_info *bi;
> +     int obgrid_size;
> +     unsigned int stripes;
> +     struct ipu3_uapi_flags *use = set_params ? &set_params->use : NULL;
> +
> +     /* Destination buffers which are filled here */
> +     struct imgu_abi_parameter_set_info *param_set;
> +     struct ipu3_uapi_acc_param *acc = NULL;
> +     struct ipu3_uapi_gdc_warp_param *gdc = NULL;
> +     struct ipu3_uapi_obgrid_param *obgrid = NULL;
> +     const struct ipu3_css_map *map;
> +     void *vmem0 = NULL;
> +     void *dmem0 = NULL;
> +
> +     enum imgu_abi_memories m;
> +     int r = -EBUSY;
> +     int s;
> +
> +     if (!css->streaming)
> +             return -EPROTO;
> +
> +     bi = &css->fwp->binary_header[css->current_binary];
> +     obgrid_size = ipu3_css_fw_obgrid_size(bi);
> +     stripes = bi->info.isp.sp.iterator.num_stripes ? : 1;
> +
> +     /*
> +      * Check that we can get a new parameter_set_info from the pool.
> +      * If this succeeds, then all of the other pool_get() calls below
> +      * should also succeed.
> +      */
> +     if (ipu3_css_pool_get(&css->pool.parameter_set_info, css->frame) < 0)
> +             goto fail_no_put;

The size of the pool is always four. If there were four parameter buffers
queued, this would fails, wouldn't it? And that would lead to a failure in
queueing the buffer, too, right?

How about associating a kernel-only buffer with each parameter buffer?

> +     param_set = ipu3_css_pool_last(&css->pool.parameter_set_info, 0)->vaddr;
> +
> +     /* Get a new acc only if new parameters given, or none yet */
> +     if (set_params || !ipu3_css_pool_last(&css->pool.acc, 0)->vaddr) {
> +             if (ipu3_css_pool_get(&css->pool.acc, css->frame) < 0)
> +                     goto fail;
> +             acc = ipu3_css_pool_last(&css->pool.acc, 0)->vaddr;
> +     }
> +
> +     /* Get new VMEM0 only if needed, or none yet */
> +     m = IMGU_ABI_MEM_ISP_VMEM0;
> +     if (!ipu3_css_pool_last(&css->pool.binary_params_p[m], 0)->vaddr ||
> +         (set_params && (set_params->use.lin_vmem_params ||
> +                         set_params->use.tnr3_vmem_params ||
> +                         set_params->use.xnr3_vmem_params))) {
> +             if (ipu3_css_pool_get(&css->pool.binary_params_p[m],
> +                                   css->frame) < 0)
> +                     goto fail;
> +             vmem0 = ipu3_css_pool_last(&css->pool.binary_params_p[m], 0)
> +                 ->vaddr;
> +     }
> +
> +     /* Get new DMEM0 only if needed, or none yet */
> +     m = IMGU_ABI_MEM_ISP_DMEM0;
> +     if (!ipu3_css_pool_last(&css->pool.binary_params_p[m], 0)->vaddr ||
> +         (set_params && (set_params->use.tnr3_dmem_params ||
> +                         set_params->use.xnr3_dmem_params))) {
> +             if (ipu3_css_pool_get(&css->pool.binary_params_p[m],
> +                                   css->frame) < 0)
> +                     goto fail;
> +             dmem0 = ipu3_css_pool_last(&css->pool.binary_params_p[m], 0)
> +                 ->vaddr;
> +     }
> +
> +     /* Configure acc parameter cluster */
> +     if (acc) {
> +             map = ipu3_css_pool_last(&css->pool.acc, 1);
> +             r = ipu3_css_cfg_acc(css, use, acc, map->vaddr, set_params ?
> +                                  &set_params->acc_param : NULL);
> +             if (r < 0)
> +                     goto fail;
> +     }
> +
> +     /* Configure late binding parameters */
> +     if (vmem0) {
> +             m = IMGU_ABI_MEM_ISP_VMEM0;
> +             map = ipu3_css_pool_last(&css->pool.binary_params_p[m], 1);
> +             r = ipu3_css_cfg_vmem0(css, use, vmem0, map->vaddr, set_params);
> +             if (r < 0)
> +                     goto fail;
> +     }
> +
> +     if (dmem0) {
> +             m = IMGU_ABI_MEM_ISP_DMEM0;
> +             map = ipu3_css_pool_last(&css->pool.binary_params_p[m], 1);
> +             r = ipu3_css_cfg_dmem0(css, use, dmem0, map->vaddr, set_params);
> +             if (r < 0)
> +                     goto fail;
> +     }
> +
> +     /* Get a new gdc only if a new gdc is given, or none yet */
> +     if (bi->info.isp.sp.enable.dvs_6axis) {
> +             unsigned int a = IPU3_CSS_AUX_FRAME_REF;
> +             unsigned int g = IPU3_CSS_RECT_GDC;
> +
> +             map = ipu3_css_pool_last(&css->pool.gdc, 0);
> +
> +             if (set_params && !set_params->use.gdc)
> +                     set_gdc = NULL;
> +             if (set_gdc || !map->vaddr) {
> +                     if (ipu3_css_pool_get(&css->pool.gdc, css->frame) < 0)
> +
> +                             goto fail;
> +                     map = ipu3_css_pool_last(&css->pool.gdc, 0);
> +                     gdc =  map->vaddr;
> +                     ipu3_css_cfg_gdc_table(gdc,
> +                                            css->aux_frames[a].bytesperline /
> +                                            css->aux_frames[a].bytesperpixel,
> +                                            css->aux_frames[a].height,
> +                                            css->rect[g].width,
> +                                            css->rect[g].height);
> +             }
> +     }
> +
> +     /* Get a new obgrid only if a new obgrid is given, or none yet */
> +     if (set_params && !set_params->use.obgrid)
> +             set_obgrid = NULL;
> +     if (set_obgrid && obgrid_bytes < obgrid_size / stripes)
> +             goto fail;
> +     if (set_obgrid || (set_params && set_params->use.obgrid_param) ||
> +         !ipu3_css_pool_last(&css->pool.obgrid, 0)->vaddr) {
> +             if (ipu3_css_pool_get(&css->pool.obgrid, css->frame) < 0)
> +                     goto fail;
> +             map = ipu3_css_pool_last(&css->pool.obgrid, 0);
> +             obgrid = map->vaddr;
> +
> +             /* Configure optical black level grid (obgrid) */
> +             if (set_obgrid) {
> +                     for (s = 0; s < stripes; s++)
> +                             memcpy((void *)obgrid +
> +                                     (obgrid_size / stripes) * s, set_obgrid,
> +                                     obgrid_size / stripes);
> +
> +             } else if (set_params && set_params->use.obgrid_param) {
> +                     for (s = 0; s < obgrid_size / sizeof(*obgrid); s++)
> +                             obgrid[s] = set_params->obgrid_param;
> +             } else {
> +                     memset(obgrid, 0, obgrid_size);
> +             }
> +     }
> +
> +     /* Configure parameter set info, queued to `queue_id' */
> +
> +     memset(param_set, 0, sizeof(*param_set));
> +
> +     param_set->mem_map.acc_cluster_params_for_sp =
> +         ipu3_css_pool_last(&css->pool.acc, 0)->daddr;
> +
> +     param_set->mem_map.dvs_6axis_params_y =
> +         ipu3_css_pool_last(&css->pool.gdc, 0)->daddr;
> +
> +     for (s = 0; s < stripes; s++)
> +             param_set->mem_map.obgrid_tbl[s] =
> +                 ipu3_css_pool_last(&css->pool.obgrid, 0)->daddr +
> +                 (obgrid_size / stripes) * s;
> +
> +     for (m = 0; m < IMGU_ABI_NUM_MEMORIES; m++)
> +             param_set->mem_map.isp_mem_param[stage][m] =
> +                 ipu3_css_pool_last(&css->pool.binary_params_p[m], 0)
> +                 ->daddr;
> +
> +     /* Then queue the new parameter buffer */
> +     map = ipu3_css_pool_last(&css->pool.parameter_set_info, 0);
> +     r = ipu3_css_queue_data(css, queue_id, thread, map->daddr);
> +     if (r < 0)
> +             goto fail;
> +
> +     r = ipu3_css_queue_data(css, IMGU_ABI_QUEUE_EVENT_ID, 0,
> +                             IMGU_ABI_EVENT_BUFFER_ENQUEUED(thread,
> +                                                            queue_id));
> +     if (r < 0)
> +             goto fail_no_put;
> +
> +     /* Finally dequeue all old parameter buffers */
> +
> +     do {
> +             u32 daddr;
> +
> +             r = ipu3_css_dequeue_data(css, queue_id, &daddr);
> +             if (r == -EBUSY)
> +                     break;
> +             if (r)
> +                     goto fail_no_put;
> +             r = ipu3_css_queue_data(css, IMGU_ABI_QUEUE_EVENT_ID, thread,
> +                                     IMGU_ABI_EVENT_BUFFER_DEQUEUED
> +                                     (queue_id));
> +             if (r < 0) {
> +                     dev_err(css->dev, "failed to queue parameter event\n");
> +                     goto fail_no_put;
> +             }
> +     } while (1);
> +
> +     return 0;
> +
> +fail:
> +     /*
> +      * A failure, most likely the parameter queue was full.
> +      * Return error but continue streaming. User can try submitting new
> +      * parameters again later.
> +      */
> +
> +     ipu3_css_pool_put(&css->pool.parameter_set_info);
> +     if (acc)
> +             ipu3_css_pool_put(&css->pool.acc);
> +     if (gdc)
> +             ipu3_css_pool_put(&css->pool.gdc);
> +     if (obgrid)
> +             ipu3_css_pool_put(&css->pool.obgrid);
> +     if (vmem0)
> +             ipu3_css_pool_put(
> +                     &css->pool.binary_params_p[IMGU_ABI_MEM_ISP_VMEM0]);
> +     if (dmem0)
> +             ipu3_css_pool_put(
> +                     &css->pool.binary_params_p[IMGU_ABI_MEM_ISP_DMEM0]);
> +
> +fail_no_put:
> +     return r;
> +}
>  
>  void ipu3_css_irq_ack(struct ipu3_css *css)
>  {
> @@ -501,7 +2260,7 @@ void ipu3_css_irq_ack(struct ipu3_css *css)
>                                       bi->info.sp.output + 4 + 4 * i);
>  
>                       dev_dbg(css->dev, "%s: swirq %i cnt %i val 0x%x\n",
> -                              __func__, i, cnt, val);
> +                             __func__, i, cnt, val);
>               }
>       }
>  
> diff --git a/drivers/media/pci/intel/ipu3/ipu3-css.h 
> b/drivers/media/pci/intel/ipu3/ipu3-css.h
> index 5b8e92d47f5d..43627df9910d 100644
> --- a/drivers/media/pci/intel/ipu3/ipu3-css.h
> +++ b/drivers/media/pci/intel/ipu3/ipu3-css.h
> @@ -16,6 +16,8 @@
>  
>  #include <linux/videodev2.h>
>  #include <linux/types.h>
> +#include <media/v4l2-ctrls.h>
> +#include <media/videobuf2-core.h>
>  #include "ipu3-abi.h"
>  #include "ipu3-css-pool.h"
>  
> @@ -39,6 +41,12 @@
>  #define IPU3_CSS_QUEUE_STAT_LACE     6
>  #define IPU3_CSS_QUEUES                      7
>  
> +#define IPU3_CSS_RECT_EFFECTIVE              0       /* Effective resolution 
> */
> +#define IPU3_CSS_RECT_BDS            1       /* Resolution after BDS */
> +#define IPU3_CSS_RECT_ENVELOPE               2       /* DVS envelope size */
> +#define IPU3_CSS_RECT_GDC            3       /* gdc output res */
> +#define IPU3_CSS_RECTS                       4       /* number of rects */
> +
>  #define IA_CSS_BINARY_MODE_PRIMARY   2
>  #define IA_CSS_BINARY_MODE_VIDEO     3
>  
> @@ -56,6 +64,33 @@ enum ipu3_css_pipe_id {
>       IPU3_CSS_PIPE_ID_NUM
>  };
>  
> +struct ipu3_css_resolution {
> +     u32 w;
> +     u32 h;
> +};
> +
> +enum ipu3_css_vf_status {
> +     IPU3_NODE_VF_ENABLED,
> +     IPU3_NODE_PV_ENABLED,
> +     IPU3_NODE_VF_DISABLED
> +};
> +
> +enum ipu3_css_buffer_state {
> +     IPU3_CSS_BUFFER_NEW,    /* Not yet queued */
> +     IPU3_CSS_BUFFER_QUEUED, /* Queued, waiting to be filled */
> +     IPU3_CSS_BUFFER_DONE,   /* Finished processing, removed from queue */
> +     IPU3_CSS_BUFFER_FAILED, /* Was not processed, removed from queue */
> +};
> +
> +struct ipu3_css_buffer {
> +     /* Private fields: user doesn't touch */
> +     dma_addr_t daddr;
> +     unsigned int queue;
> +     enum ipu3_css_buffer_state state;
> +     struct list_head list;
> +     u8 queue_pos;
> +};
> +
>  struct ipu3_css_format {
>       u32 pixelformat;
>       enum v4l2_colorspace colorspace;
> @@ -126,11 +161,65 @@ struct ipu3_css {
>  
>       struct ipu3_css_queue queue[IPU3_CSS_QUEUES];
>       struct v4l2_rect rect[IPU3_CSS_RECTS];
> +     struct ipu3_css_map abi_buffers[IPU3_CSS_QUEUES]
> +                                 [IMGU_ABI_HOST2SP_BUFQ_SIZE];
> +
> +     struct {
> +             struct ipu3_css_pool parameter_set_info;
> +             struct ipu3_css_pool acc;
> +             struct ipu3_css_pool gdc;
> +             struct ipu3_css_pool obgrid;
> +             /* PARAM_CLASS_PARAM parameters for binding while streaming */
> +             struct ipu3_css_pool binary_params_p[IMGU_ABI_NUM_MEMORIES];
> +     } pool;
> +
> +     enum ipu3_css_vf_status vf_output_en;
>  };
>  
> +/******************* css v4l *******************/
> +int ipu3_css_init(struct device *dev, struct ipu3_css *css,
> +               void __iomem *base, int length);
> +void ipu3_css_cleanup(struct ipu3_css *css);
> +int ipu3_css_fmt_try(struct ipu3_css *css,
> +                  struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES],
> +                  struct v4l2_rect *rects[IPU3_CSS_RECTS]);
> +int ipu3_css_fmt_set(struct ipu3_css *css,
> +                  struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES],
> +                  struct v4l2_rect *rects[IPU3_CSS_RECTS]);
> +int ipu3_css_meta_fmt_set(struct v4l2_meta_format *fmt);
> +int ipu3_css_buf_queue(struct ipu3_css *css, struct ipu3_css_buffer *b);
> +struct ipu3_css_buffer *ipu3_css_buf_dequeue(struct ipu3_css *css);
> +int ipu3_css_start_streaming(struct ipu3_css *css);
> +void ipu3_css_stop_streaming(struct ipu3_css *css);
> +bool ipu3_css_queue_empty(struct ipu3_css *css);
> +bool ipu3_css_is_streaming(struct ipu3_css *css);
> +
>  /******************* css hw *******************/
>  int ipu3_css_set_powerup(struct device *dev, void __iomem *base);
>  int ipu3_css_set_powerdown(struct device *dev, void __iomem *base);
>  void ipu3_css_irq_ack(struct ipu3_css *css);
>  
> +/******************* set parameters ************/
> +int ipu3_css_set_parameters(struct ipu3_css *css,
> +             struct ipu3_uapi_params *set_params,
> +             struct ipu3_uapi_gdc_warp_param *set_gdc,
> +             unsigned int gdc_bytes,
> +             struct ipu3_uapi_obgrid_param *set_obgrid,
> +             unsigned int obgrid_bytes);
> +
> +/******************* css misc *******************/
> +static inline enum ipu3_css_buffer_state
> +ipu3_css_buf_state(struct ipu3_css_buffer *b)
> +{
> +     return b->state;
> +}
> +
> +/* Initialize given buffer. May be called several times. */
> +static inline void ipu3_css_buf_init(struct ipu3_css_buffer *b,
> +                                  unsigned int queue, dma_addr_t daddr)
> +{
> +     b->state = IPU3_CSS_BUFFER_NEW;
> +     b->queue = queue;
> +     b->daddr = daddr;
> +}
>  #endif

-- 
Kind regards,

Sakari Ailus
e-mail: sakari.ai...@iki.fi

Reply via email to