On 08/19/2013 12:58 PM, Shaik Ameer Basha wrote:
> This patch adds the core functionality for the M-Scaler driver.

Some more comments below...

> 
> Signed-off-by: Shaik Ameer Basha <shaik.am...@samsung.com>
> ---
>  drivers/media/platform/exynos-mscl/mscl-core.c | 1312 
> ++++++++++++++++++++++++
>  drivers/media/platform/exynos-mscl/mscl-core.h |  549 ++++++++++
>  2 files changed, 1861 insertions(+)
>  create mode 100644 drivers/media/platform/exynos-mscl/mscl-core.c
>  create mode 100644 drivers/media/platform/exynos-mscl/mscl-core.h
> 
> diff --git a/drivers/media/platform/exynos-mscl/mscl-core.c 
> b/drivers/media/platform/exynos-mscl/mscl-core.c
> new file mode 100644
> index 0000000..4a3a851
> --- /dev/null
> +++ b/drivers/media/platform/exynos-mscl/mscl-core.c
> @@ -0,0 +1,1312 @@
> +/*
> + * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd.
> + *           http://www.samsung.com
> + *
> + * Samsung EXYNOS5 SoC series M-Scaler driver
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published
> + * by the Free Software Foundation, either version 2 of the License,
> + * or (at your option) any later version.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/of_platform.h>
> +#include <linux/pm_runtime.h>
> +
> +#ifdef CONFIG_EXYNOS_IOMMU
> +#include <asm/dma-iommu.h>
> +#endif
> +
> +#include "mscl-core.h"
> +
> +#define MSCL_CLOCK_GATE_NAME "mscl"
> +
> +static const struct mscl_fmt mscl_formats[] = {
> +     {
> +             .name           = "YUV 4:2:0 non-contig. 2p, Y/CbCr",
> +             .pixelformat    = V4L2_PIX_FMT_NV12M,
> +             .depth          = { 8, 4 },
> +             .color          = MSCL_YUV420,
> +             .corder         = MSCL_CBCR,
> +             .num_planes     = 2,
> +             .num_comp       = 2,
> +             .mscl_color     = MSCL_YUV420_2P_Y_UV,
> +             .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +
> +     }, {
> +             .name           = "YUV 4:2:0 contig. 2p, Y/CbCr",
> +             .pixelformat    = V4L2_PIX_FMT_NV12,
> +             .depth          = { 12 },
> +             .color          = MSCL_YUV420,
> +             .corder         = MSCL_CBCR,
> +             .num_planes     = 1,
> +             .num_comp       = 2,
> +             .mscl_color     = MSCL_YUV420_2P_Y_UV,
> +             .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +     }, {
> +             .name           = "YUV 4:2:0 n.c. 2p, Y/CbCr tiled",
> +             .pixelformat    = V4L2_PIX_FMT_NV12MT_16X16,
> +             .depth          = { 8, 4 },
> +             .color          = MSCL_YUV420,
> +             .corder         = MSCL_CBCR,
> +             .num_planes     = 2,
> +             .num_comp       = 2,
> +             .mscl_color     = MSCL_YUV420_2P_Y_UV,
> +             .mscl_color_fmt_type = (MSCL_FMT_SRC),
> +             .is_tiled       = true,
> +     }, {
> +             .name           = "YUV 4:2:2 contig. 2p, Y/CbCr",
> +             .pixelformat    = V4L2_PIX_FMT_NV16,
> +             .depth          = { 16 },
> +             .color          = MSCL_YUV422,
> +             .corder         = MSCL_CBCR,
> +             .num_planes     = 1,
> +             .num_comp       = 2,
> +             .mscl_color     = MSCL_YUV422_2P_Y_UV,
> +             .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +     }, {
> +             .name           = "YUV 4:4:4 contig. 2p, Y/CbCr",
> +             .pixelformat    = V4L2_PIX_FMT_NV24,
> +             .depth          = { 24 },
> +             .color          = MSCL_YUV444,
> +             .corder         = MSCL_CBCR,
> +             .num_planes     = 1,
> +             .num_comp       = 2,
> +             .mscl_color     = MSCL_YUV444_2P_Y_UV,
> +             .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +     }, {
> +             .name           = "RGB565",
> +             .pixelformat    = V4L2_PIX_FMT_RGB565X,
> +             .depth          = { 16 },
> +             .color          = MSCL_RGB,
> +             .num_planes     = 1,
> +             .num_comp       = 1,
> +             .mscl_color     = MSCL_RGB565,
> +             .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +     }, {
> +             .name           = "XRGB-1555, 16 bpp",
> +             .pixelformat    = V4L2_PIX_FMT_RGB555,
> +             .depth          = { 16 },
> +             .color          = MSCL_RGB,
> +             .num_planes     = 1,
> +             .num_comp       = 1,
> +             .mscl_color     = MSCL_ARGB1555,
> +             .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +     }, {
> +             .name           = "XRGB-8888, 32 bpp",
> +             .pixelformat    = V4L2_PIX_FMT_RGB32,
> +             .depth          = { 32 },
> +             .color          = MSCL_RGB,
> +             .num_planes     = 1,
> +             .num_comp       = 1,
> +             .mscl_color     = MSCL_ARGB8888,
> +             .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +     }, {
> +             .name           = "YUV 4:2:2 packed, YCrYCb",
> +             .pixelformat    = V4L2_PIX_FMT_YVYU,
> +             .depth          = { 16 },
> +             .color          = MSCL_YUV422,
> +             .corder         = MSCL_CRCB,
> +             .num_planes     = 1,
> +             .num_comp       = 1,
> +             .mbus_code      = V4L2_MBUS_FMT_YVYU8_2X8,
> +             .mscl_color     = MSCL_YUV422_1P_YVYU,
> +             .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +     }, {
> +             .name           = "YUV 4:2:2 packed, YCbYCr",
> +             .pixelformat    = V4L2_PIX_FMT_YUYV,
> +             .depth          = { 16 },
> +             .color          = MSCL_YUV422,
> +             .corder         = MSCL_CBCR,
> +             .num_planes     = 1,
> +             .num_comp       = 1,
> +             .mbus_code      = V4L2_MBUS_FMT_YUYV8_2X8,
> +             .mscl_color     = MSCL_YUV422_1P_YUYV,
> +             .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +     }, {
> +             .name           = "YUV 4:2:2 packed, CbYCrY",
> +             .pixelformat    = V4L2_PIX_FMT_UYVY,
> +             .depth          = { 16 },
> +             .color          = MSCL_YUV422,
> +             .corder         = MSCL_CBCR,
> +             .num_planes     = 1,
> +             .num_comp       = 1,
> +             .mbus_code      = V4L2_MBUS_FMT_UYVY8_2X8,
> +             .mscl_color     = MSCL_YUV422_1P_UYVY,
> +             .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +     }, {
> +             .name           = "XRGB-4444, 16 bpp",
> +             .pixelformat    = V4L2_PIX_FMT_RGB444,
> +             .depth          = { 16 },
> +             .color          = MSCL_RGB,
> +             .num_planes     = 1,
> +             .num_comp       = 1,
> +             .mscl_color     = MSCL_ARGB4444,
> +             .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +     }, {
> +             .name           = "YUV 4:2:0 non-contig. 2p, Y/CrCb",
> +             .pixelformat    = V4L2_PIX_FMT_NV21M,
> +             .depth          = { 8, 4 },
> +             .color          = MSCL_YUV420,
> +             .corder         = MSCL_CRCB,
> +             .num_planes     = 2,
> +             .num_comp       = 2,
> +             .mscl_color     = MSCL_YUV420_2P_Y_VU,
> +             .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +     }, {
> +             .name           = "YUV 4:2:0 contig. 2p, Y/CrCb",
> +             .pixelformat    = V4L2_PIX_FMT_NV21,
> +             .depth          = { 12 },
> +             .color          = MSCL_YUV420,
> +             .corder         = MSCL_CRCB,
> +             .num_planes     = 1,
> +             .num_comp       = 2,
> +             .mscl_color     = MSCL_YUV420_2P_Y_VU,
> +             .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +     }, {
> +             .name           = "YUV 4:2:2 contig. 2p, Y/CrCb",
> +             .pixelformat    = V4L2_PIX_FMT_NV61,
> +             .depth          = { 16 },
> +             .color          = MSCL_YUV422,
> +             .corder         = MSCL_CRCB,
> +             .num_planes     = 1,
> +             .num_comp       = 2,
> +             .mscl_color     = MSCL_YUV422_2P_Y_VU,
> +             .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +     }, {
> +             .name           = "YUV 4:4:4 contig. 2p, Y/CrCb",
> +             .pixelformat    = V4L2_PIX_FMT_NV42,
> +             .depth          = { 24 },
> +             .color          = MSCL_YUV444,
> +             .corder         = MSCL_CRCB,
> +             .num_planes     = 1,
> +             .num_comp       = 2,
> +             .mscl_color     = MSCL_YUV444_2P_Y_VU,
> +             .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +     }, {
> +             .name           = "YUV 4:2:0 contig. 3p, YCbCr",
> +             .pixelformat    = V4L2_PIX_FMT_YUV420,
> +             .depth          = { 12 },
> +             .color          = MSCL_YUV420,
> +             .corder         = MSCL_CBCR,
> +             .num_planes     = 1,
> +             .num_comp       = 3,
> +             .mscl_color     = MSCL_YUV420_3P_Y_U_V,
> +             .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +     }, {
> +             .name           = "YUV 4:2:0 contig. 3p, YCrCb",
> +             .pixelformat    = V4L2_PIX_FMT_YVU420,
> +             .depth          = { 12 },
> +             .color          = MSCL_YUV420,
> +             .corder         = MSCL_CRCB,
> +             .num_planes     = 1,
> +             .num_comp       = 3,
> +             .mscl_color     = MSCL_YUV420_3P_Y_U_V,
> +             .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +     }, {
> +             .name           = "YUV 4:2:0 non-contig. 3p, Y/Cb/Cr",
> +             .pixelformat    = V4L2_PIX_FMT_YUV420M,
> +             .depth          = { 8, 2, 2 },
> +             .color          = MSCL_YUV420,
> +             .corder         = MSCL_CBCR,
> +             .num_planes     = 3,
> +             .num_comp       = 3,
> +             .mscl_color     = MSCL_YUV420_3P_Y_U_V,
> +             .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +     }, {
> +             .name           = "YUV 4:2:0 non-contig. 3p, Y/Cr/Cb",
> +             .pixelformat    = V4L2_PIX_FMT_YVU420M,
> +             .depth          = { 8, 2, 2 },
> +             .color          = MSCL_YUV420,
> +             .corder         = MSCL_CRCB,
> +             .num_planes     = 3,
> +             .num_comp       = 3,
> +             .mscl_color     = MSCL_YUV420_3P_Y_U_V,
> +             .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +     }, {
> +             .name           = "YUV 4:2:2 contig. 3p, Y/Cb/Cr",
> +             .pixelformat    = V4L2_PIX_FMT_YUV422P,
> +             .depth          = { 16 },
> +             .color          = MSCL_YUV422,
> +             .corder         = MSCL_CBCR,
> +             .num_planes     = 1,
> +             .num_comp       = 3,
> +             .mscl_color     = MSCL_YUV422_3P_Y_U_V,
> +             .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
> +     },
> +
> +     /* [TBD] support pixel formats, corresponds to these mscl_color formats
> +      * MSCL_L8A8, MSCL_RGBA8888, MSCL_L8 etc
> +      */
> +};
> +
> +const struct mscl_fmt *mscl_get_format(int index)
> +{
> +     if (index >= ARRAY_SIZE(mscl_formats))
> +             return NULL;
> +
> +     return (struct mscl_fmt *)&mscl_formats[index];
> +}
> +
> +const struct mscl_fmt *mscl_find_fmt(u32 *pixelformat,
> +                             u32 *mbus_code, u32 index)
> +{
> +     const struct mscl_fmt *fmt, *def_fmt = NULL;
> +     unsigned int i;
> +
> +     if (index >= ARRAY_SIZE(mscl_formats))
> +             return NULL;
> +
> +     for (i = 0; i < ARRAY_SIZE(mscl_formats); ++i) {
> +             fmt = mscl_get_format(i);
> +             if (pixelformat && fmt->pixelformat == *pixelformat)
> +                     return fmt;
> +             if (mbus_code && fmt->mbus_code == *mbus_code)
> +                     return fmt;
> +             if (index == i)
> +                     def_fmt = fmt;
> +     }
> +
> +     return def_fmt;
> +}
> +
> +void mscl_set_frame_size(struct mscl_frame *frame, int width, int height)
> +{
> +     frame->f_width  = width;
> +     frame->f_height = height;
> +     frame->crop.width = width;
> +     frame->crop.height = height;
> +     frame->crop.left = 0;
> +     frame->crop.top = 0;
> +}
> +
> +int mscl_enum_fmt_mplane(struct v4l2_fmtdesc *f)
> +{
> +     const struct mscl_fmt *fmt;
> +
> +     fmt = mscl_find_fmt(NULL, NULL, f->index);
> +     if (!fmt)
> +             return -EINVAL;
> +
> +     /* input supports all mscl_formats but all mscl_formats are not
> +      * supported for output. don't return the unsupported formats for output
> +      */
> +     if (!(V4L2_TYPE_IS_OUTPUT(f->type) &&
> +             (fmt->mscl_color_fmt_type & MSCL_FMT_SRC)))
> +             return -EINVAL;

Confusing layout. It's better to align it like this:

        if (!(V4L2_TYPE_IS_OUTPUT(f->type) &&
            (fmt->mscl_color_fmt_type & MSCL_FMT_SRC)))
                return -EINVAL;

> +
> +     strlcpy(f->description, fmt->name, sizeof(f->description));
> +     f->pixelformat = fmt->pixelformat;
> +
> +     return 0;
> +}
> +
> +static u32 get_plane_info(struct mscl_frame *frm, u32 addr, u32 *index)
> +{
> +     if (frm->addr.y == addr) {
> +             *index = 0;
> +             return frm->addr.y;
> +     } else if (frm->addr.cb == addr) {
> +             *index = 1;
> +             return frm->addr.cb;
> +     } else if (frm->addr.cr == addr) {
> +             *index = 2;
> +             return frm->addr.cr;
> +     } else {
> +             pr_debug("Plane address is wrong");
> +             return -EINVAL;
> +     }

Since all the statement blocks above end with a 'return' the 'else' keyword.
isn't necessary.

So just do:

        if (frm->addr.y == addr) {
                *index = 0;
                return frm->addr.y;
        }
        if (frm->addr.cb == addr) {
                *index = 1;
                return frm->addr.cb;
        }
        if (frm->addr.cr == addr) {
                *index = 2;
                return frm->addr.cr;
        }
        pr_debug("Plane address is wrong");
        return -EINVAL;


> +}
> +
> +void mscl_set_prefbuf(struct mscl_dev *mscl, struct mscl_frame *frm)
> +{
> +     u32 f_chk_addr, f_chk_len, s_chk_addr, s_chk_len;
> +     f_chk_addr = f_chk_len = s_chk_addr = s_chk_len = 0;
> +
> +     f_chk_addr = frm->addr.y;
> +     f_chk_len = frm->payload[0];
> +     if (frm->fmt->num_planes == 2) {
> +             s_chk_addr = frm->addr.cb;
> +             s_chk_len = frm->payload[1];
> +     } else if (frm->fmt->num_planes == 3) {
> +             u32 low_addr, low_plane, mid_addr, mid_plane;
> +             u32 high_addr, high_plane;
> +             u32 t_min, t_max;
> +
> +             t_min = min3(frm->addr.y, frm->addr.cb, frm->addr.cr);
> +             low_addr = get_plane_info(frm, t_min, &low_plane);
> +             t_max = max3(frm->addr.y, frm->addr.cb, frm->addr.cr);
> +             high_addr = get_plane_info(frm, t_max, &high_plane);
> +
> +             mid_plane = 3 - (low_plane + high_plane);
> +             if (mid_plane == 0)
> +                     mid_addr = frm->addr.y;
> +             else if (mid_plane == 1)
> +                     mid_addr = frm->addr.cb;
> +             else if (mid_plane == 2)
> +                     mid_addr = frm->addr.cr;
> +             else
> +                     return;
> +
> +             f_chk_addr = low_addr;
> +             if (mid_addr + frm->payload[mid_plane] - low_addr >
> +                 high_addr + frm->payload[high_plane] - mid_addr) {
> +                     f_chk_len = frm->payload[low_plane];
> +                     s_chk_addr = mid_addr;
> +                     s_chk_len = high_addr +
> +                                     frm->payload[high_plane] - mid_addr;
> +             } else {
> +                     f_chk_len = mid_addr +
> +                                     frm->payload[mid_plane] - low_addr;
> +                     s_chk_addr = high_addr;
> +                     s_chk_len = frm->payload[high_plane];
> +             }
> +     }
> +     dev_dbg(&mscl->pdev->dev,
> +             "f_addr = 0x%08x, f_len = %d, s_addr = 0x%08x, s_len = %d\n",
> +             f_chk_addr, f_chk_len, s_chk_addr, s_chk_len);
> +}
> +
> +int mscl_try_fmt_mplane(struct mscl_ctx *ctx, struct v4l2_format *f)
> +{
> +     struct mscl_dev *mscl = ctx->mscl_dev;
> +     struct device *dev = &mscl->pdev->dev;
> +     struct mscl_variant *variant = mscl->variant;
> +     struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
> +     const struct mscl_fmt *fmt;
> +     u32 max_w, max_h, mod_w = 0, mod_h = 0;
> +     u32 min_w, min_h, tmp_w, tmp_h;
> +     int i;
> +     struct mscl_frm_limit *frm_limit;
> +
> +     dev_dbg(dev, "user put w: %d, h: %d",
> +                     pix_mp->width, pix_mp->height);
> +
> +     fmt = mscl_find_fmt(&pix_mp->pixelformat, NULL, 0);
> +     if (!fmt) {
> +             dev_dbg(dev, "pixelformat format (0x%X) invalid\n",
> +                                             pix_mp->pixelformat);
> +             return -EINVAL;
> +     }
> +
> +     if (pix_mp->field == V4L2_FIELD_ANY)
> +             pix_mp->field = V4L2_FIELD_NONE;
> +     else if (pix_mp->field != V4L2_FIELD_NONE) {
> +             dev_dbg(dev, "Not supported field order(%d)\n", pix_mp->field);
> +             return -EINVAL;

Don't return an error, just always map field to FIELD_NONE.

> +     }
> +
> +     if (V4L2_TYPE_IS_OUTPUT(f->type))
> +             frm_limit = variant->pix_out;
> +     else
> +             frm_limit = variant->pix_in;
> +
> +     max_w = frm_limit->max_w;
> +     max_h = frm_limit->max_h;
> +     min_w = frm_limit->min_w;
> +     min_h = frm_limit->min_h;
> +
> +     /* Span has to be even number for YCbCr422-2p or YCbCr420 format */
> +     if (is_yuv422_2p(fmt) || is_yuv420(fmt))
> +             mod_w = 1;
> +
> +     dev_dbg(dev, "mod_w: %d, mod_h: %d, max_w: %d, max_h = %d",
> +                     mod_w, mod_h, max_w, max_h);
> +
> +     /* To check if image size is modified to adjust parameter against
> +        hardware abilities */
> +     tmp_w = pix_mp->width;
> +     tmp_h = pix_mp->height;
> +
> +     v4l_bound_align_image(&pix_mp->width, min_w, max_w, mod_w,
> +             &pix_mp->height, min_h, max_h, mod_h, 0);
> +     if (tmp_w != pix_mp->width || tmp_h != pix_mp->height)
> +             dev_info(dev,
> +                      "Image size has been modified from %dx%d to %dx%d",
> +                      tmp_w, tmp_h, pix_mp->width, pix_mp->height);
> +
> +     pix_mp->num_planes = fmt->num_planes;
> +
> +     /* nothing mentioned about the colorspace in m2m-scaler
> +      * default value is set to V4L2_COLORSPACE_REC709
> +      */
> +     pix_mp->colorspace = V4L2_COLORSPACE_REC709;
> +
> +     for (i = 0; i < pix_mp->num_planes; ++i) {
> +             int bpl = (pix_mp->width * fmt->depth[i]) >> 3;
> +             pix_mp->plane_fmt[i].bytesperline = bpl;
> +             pix_mp->plane_fmt[i].sizeimage = bpl * pix_mp->height;
> +
> +             dev_dbg(dev, "[%d]: bpl: %d, sizeimage: %d",
> +                             i, bpl, pix_mp->plane_fmt[i].sizeimage);
> +     }
> +
> +     return 0;
> +}
> +
> +int mscl_g_fmt_mplane(struct mscl_ctx *ctx, struct v4l2_format *f)
> +{
> +     struct mscl_frame *frame;
> +     struct v4l2_pix_format_mplane *pix_mp;
> +     int i;
> +
> +     frame = ctx_get_frame(ctx, f->type);
> +     if (IS_ERR(frame))
> +             return PTR_ERR(frame);
> +
> +     pix_mp = &f->fmt.pix_mp;
> +
> +     pix_mp->width           = frame->f_width;
> +     pix_mp->height          = frame->f_height;
> +     pix_mp->field           = V4L2_FIELD_NONE;
> +     pix_mp->pixelformat     = frame->fmt->pixelformat;
> +     pix_mp->colorspace      = V4L2_COLORSPACE_REC709;
> +     pix_mp->num_planes      = frame->fmt->num_planes;
> +
> +     for (i = 0; i < pix_mp->num_planes; ++i) {
> +             pix_mp->plane_fmt[i].bytesperline = (frame->f_width *
> +                     frame->fmt->depth[i]) / 8;
> +             pix_mp->plane_fmt[i].sizeimage =
> +                      pix_mp->plane_fmt[i].bytesperline * frame->f_height;
> +     }
> +
> +     return 0;
> +}
> +
> +void mscl_check_crop_change(u32 tmp_w, u32 tmp_h, u32 *w, u32 *h)
> +{
> +     if (tmp_w != *w || tmp_h != *h) {
> +             pr_info("Cropped size has been modified from %dx%d to %dx%d",
> +                                                     *w, *h, tmp_w, tmp_h);
> +             *w = tmp_w;
> +             *h = tmp_h;
> +     }
> +}
> +
> +int mscl_g_crop(struct mscl_ctx *ctx, struct v4l2_crop *cr)
> +{
> +     struct mscl_frame *frame;
> +
> +     frame = ctx_get_frame(ctx, cr->type);
> +     if (IS_ERR(frame))
> +             return PTR_ERR(frame);
> +
> +     cr->c = frame->crop;
> +
> +     return 0;
> +}
> +
> +int mscl_try_crop(struct mscl_ctx *ctx, struct v4l2_crop *cr)
> +{
> +     struct mscl_frame *f;
> +     const struct mscl_fmt *fmt;
> +     struct mscl_dev *mscl = ctx->mscl_dev;
> +     struct device *dev = &mscl->pdev->dev;
> +     struct mscl_variant *variant = mscl->variant;
> +     u32 mod_w = 0, mod_h = 0, tmp_w, tmp_h;
> +     u32 min_w, min_h, max_w, max_h;
> +     struct mscl_frm_limit *frm_limit;
> +
> +     if (cr->c.top < 0 || cr->c.left < 0) {
> +             dev_dbg(dev, "doesn't support negative values\n");
> +             return -EINVAL;
> +     }
> +     dev_dbg(dev, "user requested width: %d, height: %d",
> +                                     cr->c.width, cr->c.height);
> +
> +     f = ctx_get_frame(ctx, cr->type);
> +     if (IS_ERR(f))
> +             return PTR_ERR(f);
> +
> +     fmt = f->fmt;
> +     tmp_w = cr->c.width;
> +     tmp_h = cr->c.height;
> +
> +     if (V4L2_TYPE_IS_OUTPUT(cr->type))
> +             frm_limit = variant->pix_out;
> +     else
> +             frm_limit = variant->pix_in;
> +
> +     max_w = f->f_width;
> +     max_h = f->f_height;
> +     min_w = frm_limit->min_w;
> +     min_h = frm_limit->min_h;
> +
> +     if (V4L2_TYPE_IS_OUTPUT(cr->type)) {
> +             if (is_yuv420(fmt)) {
> +                     mod_w = ffs(variant->pix_align->dst_w_420) - 1;
> +                     mod_h = ffs(variant->pix_align->dst_h_420) - 1;
> +             } else if (is_yuv422(fmt)) {
> +                     mod_w = ffs(variant->pix_align->dst_w_422) - 1;
> +             }
> +     } else {
> +             if (is_yuv420(fmt)) {
> +                     mod_w = ffs(variant->pix_align->src_w_420) - 1;
> +                     mod_h = ffs(variant->pix_align->src_h_420) - 1;
> +             } else if (is_yuv422(fmt)) {
> +                     mod_w = ffs(variant->pix_align->src_w_422) - 1;
> +             }
> +
> +             if (ctx->ctrls_mscl.rotate->val == 90 ||
> +                 ctx->ctrls_mscl.rotate->val == 270) {
> +                     max_w = f->f_height;
> +                     max_h = f->f_width;
> +                     tmp_w = cr->c.height;
> +                     tmp_h = cr->c.width;
> +             }
> +     }
> +
> +     dev_dbg(dev, "mod_x: %d, mod_y: %d, min_w: %d, min_h = %d",
> +                                     mod_w, mod_h, min_w, min_h);
> +     dev_dbg(dev, "tmp_w : %d, tmp_h : %d", tmp_w, tmp_h);
> +
> +     v4l_bound_align_image(&tmp_w, min_w, max_w, mod_w,
> +                           &tmp_h, min_h, max_h, mod_h, 0);
> +
> +     if (!V4L2_TYPE_IS_OUTPUT(cr->type) &&
> +             (ctx->ctrls_mscl.rotate->val == 90 ||
> +              ctx->ctrls_mscl.rotate->val == 270))
> +             mscl_check_crop_change(tmp_h, tmp_w,
> +                                     &cr->c.width, &cr->c.height);
> +     else
> +             mscl_check_crop_change(tmp_w, tmp_h,
> +                                     &cr->c.width, &cr->c.height);
> +
> +     /* adjust left/top if cropping rectangle is out of bounds */
> +     /* Need to add code to algin left value with 2's multiple */
> +     if (cr->c.left + tmp_w > max_w)
> +             cr->c.left = max_w - tmp_w;
> +     if (cr->c.top + tmp_h > max_h)
> +             cr->c.top = max_h - tmp_h;
> +
> +     if (is_yuv422_1p(fmt) && (cr->c.left & 1))
> +             cr->c.left -= 1;
> +
> +     dev_dbg(dev, "Aligned l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
> +         cr->c.left, cr->c.top, cr->c.width, cr->c.height, max_w, max_h);
> +
> +     return 0;
> +}
> +
> +int mscl_check_scaler_ratio(struct mscl_variant *var, int sw, int sh, int dw,
> +                        int dh, int rot)
> +{
> +     if ((dw == 0) || (dh == 0))
> +             return -EINVAL;
> +
> +     if (rot == 90 || rot == 270)
> +             swap(dh, dw);
> +
> +     pr_debug("sw: %d, sh: %d, dw: %d, dh: %d\n", sw, sh, dw, dh);
> +
> +     if ((sw/dw) > var->scl_down_max || (sh/dh) > var->scl_down_max ||
> +         (dw/sw) > var->scl_up_max   || (dh/sh) > var->scl_up_max)
> +             return -EINVAL;
> +
> +     return 0;
> +}
> +
> +int mscl_set_scaler_info(struct mscl_ctx *ctx)
> +{
> +     struct mscl_scaler *sc = &ctx->scaler;
> +     struct mscl_frame *s_frame = &ctx->s_frame;
> +     struct mscl_frame *d_frame = &ctx->d_frame;
> +     struct mscl_variant *variant = ctx->mscl_dev->variant;
> +     struct device *dev = &ctx->mscl_dev->pdev->dev;
> +     int src_w, src_h, ret;
> +
> +     ret = mscl_check_scaler_ratio(variant,
> +                             s_frame->crop.width, s_frame->crop.height,
> +                             d_frame->crop.width, d_frame->crop.height,
> +                             ctx->ctrls_mscl.rotate->val);
> +     if (ret) {
> +             dev_dbg(dev, "out of scaler range\n");
> +             return ret;
> +     }
> +
> +     if (ctx->ctrls_mscl.rotate->val == 90 ||
> +             ctx->ctrls_mscl.rotate->val == 270) {
> +             src_w = s_frame->crop.height;
> +             src_h = s_frame->crop.width;
> +     } else {
> +             src_w = s_frame->crop.width;
> +             src_h = s_frame->crop.height;
> +     }
> +
> +     sc->hratio = (src_w << 16) / d_frame->crop.width;
> +     sc->vratio = (src_h << 16) / d_frame->crop.height;
> +
> +     dev_dbg(dev, "scaler settings::\n"
> +              "sx = %d, sy = %d, sw = %d, sh = %d\n"
> +              "dx = %d, dy = %d, dw = %d, dh = %d\n"
> +              "h-ratio : %d, v-ratio: %d\n",
> +              s_frame->crop.left, s_frame->crop.top,
> +              s_frame->crop.width, s_frame->crop.height,
> +              d_frame->crop.left, d_frame->crop.top,
> +              d_frame->crop.width, s_frame->crop.height,
> +              sc->hratio, sc->vratio);
> +
> +     return 0;
> +}
> +
> +static int __mscl_s_ctrl(struct mscl_ctx *ctx, struct v4l2_ctrl *ctrl)
> +{
> +     struct mscl_dev *mscl = ctx->mscl_dev;
> +     struct mscl_variant *variant = mscl->variant;
> +     unsigned int flags = MSCL_DST_FMT | MSCL_SRC_FMT;
> +     int ret = 0;
> +
> +     if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
> +             return 0;

Why would you want to do this check?

> +
> +     switch (ctrl->id) {
> +     case V4L2_CID_HFLIP:
> +             ctx->hflip = ctrl->val;
> +             break;
> +
> +     case V4L2_CID_VFLIP:
> +             ctx->vflip = ctrl->val;
> +             break;
> +
> +     case V4L2_CID_ROTATE:
> +             if ((ctx->state & flags) == flags) {
> +                     ret = mscl_check_scaler_ratio(variant,
> +                                     ctx->s_frame.crop.width,
> +                                     ctx->s_frame.crop.height,
> +                                     ctx->d_frame.crop.width,
> +                                     ctx->d_frame.crop.height,
> +                                     ctx->ctrls_mscl.rotate->val);
> +
> +                     if (ret)
> +                             return -EINVAL;
> +             }

I think it would be good if the try_ctrl op is implemented so you can call
VIDIOC_EXT_TRY_CTRLS in the application to check if the ROTATE control can be
set.

> +
> +             ctx->rotation = ctrl->val;
> +             break;
> +
> +     case V4L2_CID_ALPHA_COMPONENT:
> +             ctx->d_frame.alpha = ctrl->val;
> +             break;
> +     }
> +
> +     ctx->state |= MSCL_PARAMS;
> +     return 0;
> +}
> +
> +static int mscl_s_ctrl(struct v4l2_ctrl *ctrl)
> +{
> +     struct mscl_ctx *ctx = ctrl_to_ctx(ctrl);
> +     unsigned long flags;
> +     int ret;
> +
> +     spin_lock_irqsave(&ctx->mscl_dev->slock, flags);
> +     ret = __mscl_s_ctrl(ctx, ctrl);
> +     spin_unlock_irqrestore(&ctx->mscl_dev->slock, flags);
> +
> +     return ret;
> +}
> +
> +static const struct v4l2_ctrl_ops mscl_ctrl_ops = {
> +     .s_ctrl = mscl_s_ctrl,
> +};

Thanks for the patches!

Regards,

        Hans
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to