Re: [PATCH v2 01/01] media: gscaler: Add new driver for generic scaler

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

 



Hi Pawel,

Thanks for the review comments.,
I will try to release the v3 patch in a day or two with your comments
addressed ...

please find my review comments inline...


On Wed, Jul 11, 2012 at 11:22 PM, Pawel Osciak <pawel@xxxxxxxxxx> wrote:
> Hi Shaik,
> Thanks for the patches. Please find my comments inline.
> Please also make sure you run checkpatch.

I will make sure this...

>
> On Thu, Jul 5, 2012 at 3:27 AM, Shaik Ameer Basha
> <shaik.ameer@xxxxxxxxxxx> wrote:
>> This patch add support for gscaler (generic scaler) device which is a
>> new device for scaling and color space conversion on EXYNOS5 SoCs.
>>
>> This device supports the followings as key feature.
>>  1) Input image format
>>    - RGB888/565, YUV422 1P/2P, YUV420 2P/3P, TILE
>>  2) Output image format
>>    - RGB888/565, YUV422 1P/2P, YUV420 2P/3P, YUV444
>>  3) Input rotation
>>    - 0/90/180/270 degree, X/Y Flip
>>  4) Scale ratio
>>    - 1/16 scale down to 8 scale up
>>  5) CSC
>>    - RGB to YUV / YUV to RGB
>>  6) Size
>>    - 2048 x 2048 for tile or rotation
>>    - 4800 x 3344 other case
>>
>> Signed-off-by: Hynwoong Kim <khw0178.kim@xxxxxxxxxxx>
>> Signed-off-by: Sungchun Kang <sungchun.kang@xxxxxxxxxxx>
>> Signed-off-by: Shaik Ameer Basha <shaik.ameer@xxxxxxxxxxx>
>> ---
>>  drivers/media/video/Kconfig               |   10 +
>>  drivers/media/video/Makefile              |    1 +
>>  drivers/media/video/exynos/Kconfig        |   11 +
>>  drivers/media/video/exynos/Makefile       |    1 +
>>  drivers/media/video/exynos/gsc/Kconfig    |    7 +
>>  drivers/media/video/exynos/gsc/Makefile   |    3 +
>>  drivers/media/video/exynos/gsc/gsc-core.c | 1304 +++++++++++++++++++++++++++++
>>  drivers/media/video/exynos/gsc/gsc-core.h |  652 ++++++++++++++
>>  drivers/media/video/exynos/gsc/gsc-m2m.c  |  751 +++++++++++++++++
>>  drivers/media/video/exynos/gsc/gsc-regs.c |  579 +++++++++++++
>>  drivers/media/video/exynos/gsc/gsc-regs.h |  211 +++++
>>  include/linux/videodev2.h                 |    2 +
>>  12 files changed, 3532 insertions(+), 0 deletions(-)
>>  create mode 100644 drivers/media/video/exynos/Kconfig
>>  create mode 100644 drivers/media/video/exynos/Makefile
>>  create mode 100644 drivers/media/video/exynos/gsc/Kconfig
>>  create mode 100644 drivers/media/video/exynos/gsc/Makefile
>>  create mode 100644 drivers/media/video/exynos/gsc/gsc-core.c
>>  create mode 100644 drivers/media/video/exynos/gsc/gsc-core.h
>>  create mode 100644 drivers/media/video/exynos/gsc/gsc-m2m.c
>>  create mode 100644 drivers/media/video/exynos/gsc/gsc-regs.c
>>  create mode 100644 drivers/media/video/exynos/gsc/gsc-regs.h
>>
>> diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
>> index 99937c9..0ff1abf 100644
>> --- a/drivers/media/video/Kconfig
>> +++ b/drivers/media/video/Kconfig
>> @@ -1153,6 +1153,7 @@ config VIDEO_ATMEL_ISI
>>
>>  source "drivers/media/video/s5p-fimc/Kconfig"
>>  source "drivers/media/video/s5p-tv/Kconfig"
>> +source "drivers/media/video/exynos/Kconfig"
>
> I believe we'd prefer to have it under exynos-gscaler directory and
> not create general platform directories.
>

OK. I will create "exynos-gsc" folder.

>>
>>  endif # V4L_PLATFORM_DRIVERS
>>  endif # VIDEO_CAPTURE_DRIVERS
>> @@ -1215,4 +1216,13 @@ config VIDEO_MX2_EMMAPRP
>>             memory to memory. Operations include resizing and format
>>             conversion.
>>
>> +config VIDEO_SAMSUNG_GSCALER
>> +        tristate "Samsung Exynos GSC driver"
>> +        depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P
>> +        select VIDEOBUF2_DMA_CONTIG
>> +        select V4L2_MEM2MEM_DEV
>> +        select DMA_SHARED_BUFFER
>> +        help
>> +            This is v4l2 based g-scaler driver for EXYNOS5
>> +
>>  endif # V4L_MEM2MEM_DRIVERS
>> diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
>> index d209de0..4389f3e 100644
>> --- a/drivers/media/video/Makefile
>> +++ b/drivers/media/video/Makefile
>> @@ -192,6 +192,7 @@ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC)        += s5p-fimc/
>>  obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG)   += s5p-jpeg/
>>  obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC)    += s5p-mfc/
>>  obj-$(CONFIG_VIDEO_SAMSUNG_S5P_TV)     += s5p-tv/
>> +obj-$(CONFIG_VIDEO_EXYNOS)              += exynos/
>>
>>  obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D)    += s5p-g2d/
>>
>> diff --git a/drivers/media/video/exynos/Kconfig b/drivers/media/video/exynos/Kconfig
>> new file mode 100644
>> index 0000000..f5836a2
>> --- /dev/null
>> +++ b/drivers/media/video/exynos/Kconfig
>> @@ -0,0 +1,11 @@
>> +config VIDEO_EXYNOS
>> +       bool "Exynos Multimedia Devices"
>> +       depends on ARCH_EXYNOS5
>> +       select VIDEO_FIXED_MINOR_RANGES
>> +       select VIDEOBUF2_DMA_CONTIG
>> +       help
>> +         This is a representative exynos multimedia device.
>> +
>> +if VIDEO_EXYNOS
>> +       source "drivers/media/video/exynos/gsc/Kconfig"
>> +endif
>
> Looks like you have two different Kconfigs and Makefiles for the same
> thing. Please don't create an exynos/gsc directories, just exynos-gsc
> and put everything in there. Don't create any Kconfigs, just add the
> entry to the drivers/media/video/Kconfig and only have a Makefile in
> exynos-gsc. s5p-g2d is a good example.
>
>> diff --git a/drivers/media/video/exynos/Makefile b/drivers/media/video/exynos/Makefile
>> new file mode 100644
>> index 0000000..1666724
>> --- /dev/null
>> +++ b/drivers/media/video/exynos/Makefile
>> @@ -0,0 +1 @@
>> +obj-$(CONFIG_VIDEO_EXYNOS_GSCALER)      += gsc/
>> diff --git a/drivers/media/video/exynos/gsc/Kconfig b/drivers/media/video/exynos/gsc/Kconfig
>> new file mode 100644
>> index 0000000..9036078
>> --- /dev/null
>> +++ b/drivers/media/video/exynos/gsc/Kconfig
>> @@ -0,0 +1,7 @@
>> +config VIDEO_EXYNOS_GSCALER
>> +       bool "Exynos G-Scaler driver"
>> +       depends on VIDEO_EXYNOS
>> +       select MEDIA_EXYNOS
>> +       select V4L2_MEM2MEM_DEV
>> +       help
>> +         This is a v4l2 driver for exynos G-Scaler device.
>> diff --git a/drivers/media/video/exynos/gsc/Makefile b/drivers/media/video/exynos/gsc/Makefile
>> new file mode 100644
>> index 0000000..d3f66e4
>> --- /dev/null
>> +++ b/drivers/media/video/exynos/gsc/Makefile
>> @@ -0,0 +1,3 @@
>> +gsc-objs := gsc-core.o gsc-m2m.o gsc-regs.o
>> +
>> +obj-$(CONFIG_VIDEO_SAMSUNG_GSCALER)    += gsc.o
>> diff --git a/drivers/media/video/exynos/gsc/gsc-core.c b/drivers/media/video/exynos/gsc/gsc-core.c
>> new file mode 100644
>> index 0000000..06bd24f
>> --- /dev/null
>> +++ b/drivers/media/video/exynos/gsc/gsc-core.c
>> @@ -0,0 +1,1304 @@
>> +/* linux/drivers/media/video/exynos/gsc/gsc-core.c
>
> No need for this line.

OK. I will remove that.

>
>> + *
>> + * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd.
>> + *             http://www.samsung.com
>> + *
>> + * Samsung EXYNOS5 SoC series G-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/module.h>
>> +#include <linux/kernel.h>
>> +#include <linux/version.h>
>> +#include <linux/types.h>
>> +#include <linux/errno.h>
>> +#include <linux/bug.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/workqueue.h>
>> +#include <linux/device.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/list.h>
>> +#include <linux/io.h>
>> +#include <linux/slab.h>
>> +#include <linux/clk.h>
>> +#include <media/v4l2-ioctl.h>
>> +#include <linux/of.h>
>> +#include "gsc-core.h"
>> +
>> +#define GSC_CLOCK_GATE_NAME    "gscl"
>> +
>> +int gsc_dbg;
>> +module_param(gsc_dbg, int, 0644);
>> +
>> +
>> +static struct gsc_fmt gsc_formats[] = {
>> +       {
>> +               .name           = "RGB565",
>> +               .pixelformat    = V4L2_PIX_FMT_RGB565X,
>> +               .depth          = { 16 },
>> +               .color          = GSC_RGB,
>> +               .num_planes     = 1,
>> +               .num_comp       = 1,
>> +       }, {
>> +               .name           = "XRGB-8-8-8-8, 32 bpp",
>> +               .pixelformat    = V4L2_PIX_FMT_RGB32,
>> +               .depth          = { 32 },
>> +               .color          = GSC_RGB,
>> +               .num_planes     = 1,
>> +               .num_comp       = 1,
>> +       }, {
>> +               .name           = "YUV 4:2:2 packed, YCbYCr",
>> +               .pixelformat    = V4L2_PIX_FMT_YUYV,
>> +               .depth          = { 16 },
>> +               .color          = GSC_YUV422,
>> +               .yorder         = GSC_LSB_Y,
>> +               .corder         = GSC_CBCR,
>> +               .num_planes     = 1,
>> +               .num_comp       = 1,
>> +               .mbus_code      = V4L2_MBUS_FMT_YUYV8_2X8,
>> +       }, {
>> +               .name           = "YUV 4:2:2 packed, CbYCrY",
>> +               .pixelformat    = V4L2_PIX_FMT_UYVY,
>> +               .depth          = { 16 },
>> +               .color          = GSC_YUV422,
>> +               .yorder         = GSC_LSB_C,
>> +               .corder         = GSC_CBCR,
>> +               .num_planes     = 1,
>> +               .num_comp       = 1,
>> +               .mbus_code      = V4L2_MBUS_FMT_UYVY8_2X8,
>> +       }, {
>> +               .name           = "YUV 4:2:2 packed, CrYCbY",
>> +               .pixelformat    = V4L2_PIX_FMT_VYUY,
>> +               .depth          = { 16 },
>> +               .color          = GSC_YUV422,
>> +               .yorder         = GSC_LSB_C,
>> +               .corder         = GSC_CRCB,
>> +               .num_planes     = 1,
>> +               .num_comp       = 1,
>> +               .mbus_code      = V4L2_MBUS_FMT_VYUY8_2X8,
>> +       }, {
>> +               .name           = "YUV 4:2:2 packed, YCrYCb",
>> +               .pixelformat    = V4L2_PIX_FMT_YVYU,
>> +               .depth          = { 16 },
>> +               .color          = GSC_YUV422,
>> +               .yorder         = GSC_LSB_Y,
>> +               .corder         = GSC_CRCB,
>> +               .num_planes     = 1,
>> +               .num_comp       = 1,
>> +               .mbus_code      = V4L2_MBUS_FMT_YVYU8_2X8,
>> +       }, {
>> +               .name           = "YUV 4:4:4 planar, YCbYCr",
>> +               .pixelformat    = V4L2_PIX_FMT_YUV32,
>> +               .depth          = { 32 },
>> +               .color          = GSC_YUV444,
>> +               .yorder         = GSC_LSB_Y,
>> +               .corder         = GSC_CBCR,
>> +               .num_planes     = 1,
>> +               .num_comp       = 1,
>> +       }, {
>> +               .name           = "YUV 4:2:2 planar, Y/Cb/Cr",
>> +               .pixelformat    = V4L2_PIX_FMT_YUV422P,
>> +               .depth          = { 16 },
>> +               .color          = GSC_YUV422,
>> +               .yorder         = GSC_LSB_Y,
>> +               .corder         = GSC_CBCR,
>> +               .num_planes     = 1,
>> +               .num_comp       = 3,
>> +       }, {
>> +               .name           = "YUV 4:2:2 planar, Y/CbCr",
>> +               .pixelformat    = V4L2_PIX_FMT_NV16,
>> +               .depth          = { 16 },
>> +               .color          = GSC_YUV422,
>> +               .yorder         = GSC_LSB_Y,
>> +               .corder         = GSC_CBCR,
>> +               .num_planes     = 1,
>> +               .num_comp       = 2,
>> +       }, {
>> +               .name           = "YUV 4:2:2 planar, Y/CrCb",
>> +               .pixelformat    = V4L2_PIX_FMT_NV61,
>> +               .depth          = { 16 },
>> +               .color          = GSC_YUV422,
>> +               .yorder         = GSC_LSB_Y,
>> +               .corder         = GSC_CRCB,
>> +               .num_planes     = 1,
>> +               .num_comp       = 2,
>> +       }, {
>> +               .name           = "YUV 4:2:0 planar, YCbCr",
>> +               .pixelformat    = V4L2_PIX_FMT_YUV420,
>> +               .depth          = { 12 },
>> +               .color          = GSC_YUV420,
>> +               .yorder         = GSC_LSB_Y,
>> +               .corder         = GSC_CBCR,
>> +               .num_planes     = 1,
>> +               .num_comp       = 3,
>> +       }, {
>> +               .name           = "YUV 4:2:0 planar, YCbCr",
>
> Same name as above, should be YCrCb?

Ah... I will change that.

>
>> +               .pixelformat    = V4L2_PIX_FMT_YVU420,
>> +               .depth          = { 12 },
>> +               .color          = GSC_YUV420,
>
> Is this a copy-paste bug or should be the same as above?

".color" remains same, the VU order is taken care under ".corder" field

>
>> +               .yorder         = GSC_LSB_Y,
>> +               .corder         = GSC_CRCB,
>> +               .num_planes     = 1,
>> +               .num_comp       = 3,
>> +
>> +       }, {
>> +               .name           = "YUV 4:2:0 planar, Y/CbCr",
>> +               .pixelformat    = V4L2_PIX_FMT_NV12,
>> +               .depth          = { 12 },
>> +               .color          = GSC_YUV420,
>> +               .yorder         = GSC_LSB_Y,
>> +               .corder         = GSC_CBCR,
>> +               .num_planes     = 1,
>> +               .num_comp       = 2,
>> +       }, {
>> +               .name           = "YUV 4:2:0 planar, Y/CrCb",
>> +               .pixelformat    = V4L2_PIX_FMT_NV21,
>> +               .depth          = { 12 },
>> +               .color          = GSC_YUV420,
>> +               .yorder         = GSC_LSB_Y,
>> +               .corder         = GSC_CRCB,
>> +               .num_planes     = 1,
>> +               .num_comp       = 2,
>> +       }, {
>> +               .name           = "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr",
>> +               .pixelformat    = V4L2_PIX_FMT_NV12M,
>> +               .depth          = { 8, 4 },
>> +               .color          = GSC_YUV420,
>> +               .yorder         = GSC_LSB_Y,
>> +               .corder         = GSC_CBCR,
>> +               .num_planes     = 2,
>> +               .num_comp       = 2,
>> +       }, {
>> +               .name           = "YUV 4:2:0 non-contiguous 3-planar, Y/Cb/Cr",
>> +               .pixelformat    = V4L2_PIX_FMT_YUV420M,
>> +               .depth          = { 8, 2, 2 },
>> +               .color          = GSC_YUV420,
>> +               .yorder         = GSC_LSB_Y,
>> +               .corder         = GSC_CBCR,
>> +               .num_planes     = 3,
>> +               .num_comp       = 3,
>> +       }, {
>> +               .name           = "YUV 4:2:0 non-contiguous 3-planar, Y/Cr/Cb",
>
> YUV -> YVU?

Its same.. YUV. as you can see, the plane order is changed in the name (Y/Cr/Cb)

>
>> +               .pixelformat    = V4L2_PIX_FMT_YVU420M,
>> +               .depth          = { 8, 2, 2 },
>> +               .color          = GSC_YUV420,
>> +               .yorder         = GSC_LSB_Y,
>> +               .corder         = GSC_CRCB,
>> +               .num_planes     = 3,
>> +               .num_comp       = 3,
>> +       }, {
>> +               .name           =
>> +                       "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr, tiled",
>> +               .pixelformat    = V4L2_PIX_FMT_NV12MT_16X16,
>> +               .depth          = { 8, 4 },
>> +               .color          = GSC_YUV420,
>> +               .yorder         = GSC_LSB_Y,
>> +               .corder         = GSC_CBCR,
>> +               .num_planes     = 2,
>> +               .num_comp       = 2,
>> +       },
>> +};
>> +
>> +struct gsc_fmt *get_format(int index)
>> +{
>
> if (index >= ARRAY_SIZE(gsc_formats))
>          return NULL;
>

Ok. I will change that.

>> +       return &gsc_formats[index];
>> +}
>> +
>> +struct gsc_fmt *find_fmt(u32 *pixelformat, u32 *mbus_code, int index)
>> +{
>> +       struct gsc_fmt *fmt, *def_fmt = NULL;
>> +       unsigned int i;
>> +
>> +       if (index >= ARRAY_SIZE(gsc_formats))
>> +               return NULL;
>> +
>> +       for (i = 0; i < ARRAY_SIZE(gsc_formats); ++i) {
>> +               fmt = 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 gsc_set_frame_size(struct gsc_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 gsc_cal_prescaler_ratio(struct gsc_variant *var, u32 src, u32 dst,
>> +                                                               u32 *ratio)
>> +{
>> +       if ((dst > src) || (dst >= src / var->poly_sc_down_max)) {
>> +               *ratio = 1;
>> +               return 0;
>> +       }
>> +
>> +       if ((src / var->poly_sc_down_max / var->pre_sc_down_max) > dst) {
>> +               gsc_err("scale ratio exceeded maximun scale down ratio(1/16)");
>> +               return -EINVAL;
>> +       }
>> +
>> +       *ratio = (dst > (src / 8)) ? 2 : 4;
>> +
>> +       return 0;
>> +}
>> +
>> +void gsc_get_prescaler_shfactor(u32 hratio, u32 vratio, u32 *sh)
>> +{
>> +       if (hratio == 4 && vratio == 4)
>> +               *sh = 4;
>> +       else if ((hratio == 4 && vratio == 2) ||
>> +                (hratio == 2 && vratio == 4))
>> +               *sh = 3;
>> +       else if ((hratio == 4 && vratio == 1) ||
>> +                (hratio == 1 && vratio == 4) ||
>> +                (hratio == 2 && vratio == 2))
>> +               *sh = 2;
>> +       else if (hratio == 1 && vratio == 1)
>> +               *sh = 0;
>> +       else
>> +               *sh = 1;
>> +}
>> +
>> +void gsc_check_src_scale_info(struct gsc_variant *var,
>> +                               struct gsc_frame *s_frame, u32 *wratio,
>> +                                u32 tx, u32 ty, u32 *hratio)
>> +{
>> +       int remainder = 0, walign, halign;
>> +
>> +       if (is_yuv420(s_frame->fmt->color)) {
>> +               walign = GSC_SC_ALIGN_4;
>> +               halign = GSC_SC_ALIGN_4;
>> +       } else if (is_yuv422(s_frame->fmt->color)) {
>> +               walign = GSC_SC_ALIGN_4;
>> +               halign = GSC_SC_ALIGN_2;
>> +       } else {
>> +               walign = GSC_SC_ALIGN_2;
>> +               halign = GSC_SC_ALIGN_2;
>> +       }
>> +
>> +       remainder = s_frame->crop.width % (*wratio * walign);
>> +       if (remainder) {
>> +               s_frame->crop.width -= remainder;
>> +               gsc_cal_prescaler_ratio(var, s_frame->crop.width, tx, wratio);
>> +               gsc_info("cropped src width size is recalculated from %d to %d",
>> +                       s_frame->crop.width + remainder, s_frame->crop.width);
>> +       }
>> +
>> +       remainder = s_frame->crop.height % (*hratio * halign);
>> +       if (remainder) {
>> +               s_frame->crop.height -= remainder;
>> +               gsc_cal_prescaler_ratio(var, s_frame->crop.height, ty, hratio);
>> +               gsc_info("cropped src height size is recalculated from %d to %d",
>> +                       s_frame->crop.height + remainder, s_frame->crop.height);
>> +       }
>> +}
>> +
>> +int gsc_enum_fmt_mplane(struct v4l2_fmtdesc *f)
>> +{
>> +       struct gsc_fmt *fmt;
>> +
>> +       fmt = find_fmt(NULL, NULL, f->index);
>> +       if (!fmt)
>> +               return -EINVAL;
>> +
>> +       strncpy(f->description, fmt->name, sizeof(f->description) - 1);
>> +       f->pixelformat = fmt->pixelformat;
>> +
>> +       return 0;
>> +}
>> +
>> +u32 get_plane_size(struct gsc_frame *frame, unsigned int plane)
>> +{
>> +       if (!frame || plane >= frame->fmt->num_planes) {
>> +               gsc_err("Invalid argument");
>> +               return 0;
>> +       }
>> +
>> +       return frame->payload[plane];
>> +}
>> +
>> +u32 get_plane_info(struct gsc_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 {
>> +               gsc_err("Plane address is wrong");
>> +               return -EINVAL;
>> +       }
>> +}
>> +
>> +void gsc_set_prefbuf(struct gsc_dev *gsc, struct gsc_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];
>> +               }
>> +       }
>> +       gsc_dbg("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 gsc_try_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f)
>> +{
>> +       struct gsc_dev *gsc = ctx->gsc_dev;
>> +       struct gsc_variant *variant = gsc->variant;
>> +       struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
>> +       struct gsc_fmt *fmt;
>> +       u32 max_w, max_h, mod_x, mod_y;
>> +       u32 min_w, min_h, tmp_w, tmp_h;
>> +       int i;
>> +
>> +       gsc_dbg("user put w: %d, h: %d", pix_mp->width, pix_mp->height);
>> +
>> +       fmt = find_fmt(&pix_mp->pixelformat, NULL, 0);
>> +       if (!fmt) {
>> +               gsc_err("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) {
>> +               gsc_err("Not supported field order(%d)\n", pix_mp->field);
>> +               return -EINVAL;
>> +       }
>> +
>> +       max_w = variant->pix_max->target_rot_dis_w;
>> +       max_h = variant->pix_max->target_rot_dis_h;
>> +       if (V4L2_TYPE_IS_OUTPUT(f->type)) {
>> +               mod_x = ffs(variant->pix_align->org_w) - 1;
>> +               if (is_yuv420(fmt->color))
>> +                       mod_y = ffs(variant->pix_align->org_h) - 1;
>> +               else
>> +                       mod_y = ffs(variant->pix_align->org_h) - 2;
>> +               min_w = variant->pix_min->org_w;
>> +               min_h = variant->pix_min->org_h;
>> +       } else {
>> +               mod_x = ffs(variant->pix_align->org_w) - 1;
>> +               if (is_yuv420(fmt->color))
>> +                       mod_y = ffs(variant->pix_align->org_h) - 1;
>> +               else
>> +                       mod_y = ffs(variant->pix_align->org_h) - 2;
>> +               min_w = variant->pix_min->target_rot_dis_w;
>> +               min_h = variant->pix_min->target_rot_dis_h;
>> +       }
>
> Looks to me like only the last 2 lines in both branches are different,
> so the first 5 could be abstracted out.

Ok. I will change that.

>
>> +       gsc_dbg("mod_x: %d, mod_y: %d, max_w: %d, max_h = %d",
>> +            mod_x, mod_y, 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_x,
>> +               &pix_mp->height, min_h, max_h, mod_y, 0);
>> +       if (tmp_w != pix_mp->width || tmp_h != pix_mp->height)
>> +               gsc_info("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;
>> +
>> +       if (ctx->gsc_ctrls.csc_eq_mode->val)
>> +               ctx->gsc_ctrls.csc_eq->val =
>> +                       (pix_mp->width >= 1280) ? 1 : 0;
>> +       if (ctx->gsc_ctrls.csc_eq->val) /* HD */
>> +               pix_mp->colorspace = V4L2_COLORSPACE_REC709;
>> +       else    /* SD */
>> +               pix_mp->colorspace = V4L2_COLORSPACE_SMPTE170M;
>> +
>> +
>> +       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;
>> +
>> +               gsc_dbg("[%d]: bpl: %d, sizeimage: %d",
>> +                   i, bpl, pix_mp->plane_fmt[i].sizeimage);
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +int gsc_g_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f)
>> +{
>> +       struct gsc_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_JPEG;
>
> I don't know the right answer, but why JPEG not SRGB?

Gscaler supports RGB Types
RGB601 (SD, 16 ~ 235)
RGB601 (SD, 0 ~ 255)
RGB709 (HD, 16 ~ 235)
RGB709 (HD, 0 ~ 255)

so i will change this field to either V4L2_COLORSPACE_REC709 or
V4L2_COLORSPACE_SMPTE170M as default.
Is it fine ???

>
>> +       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 gsc_check_crop_change(u32 tmp_w, u32 tmp_h, u32 *w, u32 *h)
>> +{
>> +       if (tmp_w != *w || tmp_h != *h) {
>> +               gsc_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 gsc_g_crop(struct gsc_ctx *ctx, struct v4l2_crop *cr)
>> +{
>> +       struct gsc_frame *frame;
>> +
>> +       frame = ctx_get_frame(ctx, cr->type);
>> +       if (IS_ERR(frame))
>> +               return PTR_ERR(frame);
>> +
>> +       cr->c = frame->crop;
>> +
>> +       return 0;
>> +}
>> +
>> +int gsc_try_crop(struct gsc_ctx *ctx, struct v4l2_crop *cr)
>> +{
>> +       struct gsc_frame *f;
>> +       struct gsc_dev *gsc = ctx->gsc_dev;
>> +       struct gsc_variant *variant = gsc->variant;
>> +       u32 mod_x = 0, mod_y = 0, tmp_w, tmp_h;
>> +       u32 min_w, min_h, max_w, max_h;
>> +
>> +       if (cr->c.top < 0 || cr->c.left < 0) {
>> +               gsc_err("doesn't support negative values for top & left\n");
>> +               return -EINVAL;
>> +       }
>> +       gsc_dbg("user put w: %d, h: %d", cr->c.width, cr->c.height);
>> +
>> +       if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
>> +               f = &ctx->d_frame;
>> +       else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
>> +               f = &ctx->s_frame;
>> +       else
>> +               return -EINVAL;
>> +
>> +       max_w = f->f_width;
>> +       max_h = f->f_height;
>> +       tmp_w = cr->c.width;
>> +       tmp_h = cr->c.height;
>> +
>> +       if (V4L2_TYPE_IS_OUTPUT(cr->type)) {
>> +               if ((is_yuv422(f->fmt->color) && f->fmt->num_comp == 1) ||
>> +                   is_rgb(f->fmt->color))
>> +                       min_w = 32;
>> +               else
>> +                       min_w = 64;
>> +               if ((is_yuv422(f->fmt->color) && f->fmt->num_comp == 3) ||
>> +                   is_yuv420(f->fmt->color))
>> +                       min_h = 32;
>> +               else
>> +                       min_h = 16;
>> +       } else {
>> +               if (is_yuv420(f->fmt->color) || is_yuv422(f->fmt->color))
>> +                       mod_x = ffs(variant->pix_align->target_w) - 1;
>> +               if (is_yuv420(f->fmt->color))
>> +                       mod_y = ffs(variant->pix_align->target_h) - 1;
>> +               if (ctx->gsc_ctrls.rotate->val == 90 ||
>> +                   ctx->gsc_ctrls.rotate->val == 270) {
>> +                       max_w = f->f_height;
>> +                       max_h = f->f_width;
>> +                       min_w = variant->pix_min->target_rot_en_w;
>> +                       min_h = variant->pix_min->target_rot_en_h;
>> +                       tmp_w = cr->c.height;
>> +                       tmp_h = cr->c.width;
>> +               } else {
>> +                       min_w = variant->pix_min->target_rot_dis_w;
>> +                       min_h = variant->pix_min->target_rot_dis_h;
>> +               }
>> +       }
>> +       gsc_dbg("mod_x: %d, mod_y: %d, min_w: %d, min_h = %d",
>> +                                       mod_x, mod_y, min_w, min_h);
>> +       gsc_dbg("tmp_w : %d, tmp_h : %d", tmp_w, tmp_h);
>> +
>> +       v4l_bound_align_image(&tmp_w, min_w, max_w, mod_x,
>> +                             &tmp_h, min_h, max_h, mod_y, 0);
>> +
>> +       if (!V4L2_TYPE_IS_OUTPUT(cr->type) &&
>> +           (ctx->gsc_ctrls.rotate->val == 90 ||
>> +           ctx->gsc_ctrls.rotate->val == 270)) {
>> +               gsc_check_crop_change(tmp_h, tmp_w, &cr->c.width,
>> +                                                       &cr->c.height);
>> +       } else {
>> +               gsc_check_crop_change(tmp_w, tmp_h, &cr->c.width,
>> +                                                       &cr->c.height);
>> +       }
>
> No need for braces.
>

Ok. I will change this.

>> +
>> +       /* 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_yuv420(f->fmt->color) || is_yuv422(f->fmt->color))
>> +               if (cr->c.left % 2)
>> +                       cr->c.left -= 1;
>> +
>> +       gsc_dbg("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 gsc_check_scaler_ratio(struct gsc_variant *var, int sw, int sh, int dw,
>> +                          int dh, int rot, int out_path)
>> +{
>> +       int tmp_w, tmp_h, sc_down_max;
>> +       sc_down_max =
>> +               (out_path == GSC_DMA) ? var->sc_down_max : var->local_sc_down;
>> +
>> +       if (rot == 90 || rot == 270) {
>> +               tmp_w = dh;
>> +               tmp_h = dw;
>> +       } else {
>> +               tmp_w = dw;
>> +               tmp_h = dh;
>> +       }
>> +
>> +       if ((sw / tmp_w) > sc_down_max ||
>> +           (sh / tmp_h) > sc_down_max ||
>> +           (tmp_w / sw) > var->sc_up_max ||
>> +           (tmp_h / sh) > var->sc_up_max)
>> +               return -EINVAL;
>> +
>> +       return 0;
>> +}
>> +
>> +int gsc_set_scaler_info(struct gsc_ctx *ctx)
>> +{
>> +       struct gsc_scaler *sc = &ctx->scaler;
>> +       struct gsc_frame *s_frame = &ctx->s_frame;
>> +       struct gsc_frame *d_frame = &ctx->d_frame;
>> +       struct gsc_variant *variant = ctx->gsc_dev->variant;
>> +       int tx, ty;
>> +       int ret;
>> +
>> +       ret = gsc_check_scaler_ratio(variant, s_frame->crop.width,
>> +               s_frame->crop.height, d_frame->crop.width, d_frame->crop.height,
>> +               ctx->gsc_ctrls.rotate->val, ctx->out_path);
>> +       if (ret) {
>> +               gsc_err("out of scaler range");
>> +               return ret;
>> +       }
>> +
>> +       if (ctx->gsc_ctrls.rotate->val == 90 ||
>> +           ctx->gsc_ctrls.rotate->val == 270) {
>> +               ty = d_frame->crop.width;
>> +               tx = d_frame->crop.height;
>> +       } else {
>> +               tx = d_frame->crop.width;
>> +               ty = d_frame->crop.height;
>> +       }
>> +
>> +       ret = gsc_cal_prescaler_ratio(variant, s_frame->crop.width,
>> +                                     tx, &sc->pre_hratio);
>> +       if (ret) {
>> +               gsc_err("Horizontal scale ratio is out of range");
>> +               return ret;
>> +       }
>> +
>> +       ret = gsc_cal_prescaler_ratio(variant, s_frame->crop.height,
>> +                                     ty, &sc->pre_vratio);
>> +       if (ret) {
>> +               gsc_err("Vertical scale ratio is out of range");
>> +               return ret;
>> +       }
>> +
>> +       gsc_check_src_scale_info(variant, s_frame, &sc->pre_hratio,
>> +                                tx, ty, &sc->pre_vratio);
>> +
>> +       gsc_get_prescaler_shfactor(sc->pre_hratio, sc->pre_vratio,
>> +                                  &sc->pre_shfactor);
>> +
>> +       sc->main_hratio = (s_frame->crop.width << 16) / tx;
>> +       sc->main_vratio = (s_frame->crop.height << 16) / ty;
>> +
>
> Would be nice to ensure tx and ty were not zeros, unless it's done somewhere
> else.
>

Ok. I will check for zero parameters.

>> +       gsc_dbg("scaler input/output size : sx = %d, sy = %d, tx = %d, ty = %d",
>> +                       s_frame->crop.width, s_frame->crop.height, tx, ty);
>> +       gsc_dbg("scaler ratio info : pre_shfactor : %d, pre_h : %d",
>> +                       sc->pre_shfactor, sc->pre_hratio);
>> +       gsc_dbg("pre_v :%d, main_h : %ld, main_v : %ld",
>> +                       sc->pre_vratio, sc->main_hratio, sc->main_vratio);
>> +
>> +       return 0;
>> +}
>> +
>> +
>> +/*
>> + * V4L2 controls handling
>> + */
>> +static int gsc_s_ctrl(struct v4l2_ctrl *ctrl)
>> +{
>> +       struct gsc_ctx *ctx = ctrl_to_ctx(ctrl);
>> +
>> +       switch (ctrl->id) {
>> +       case V4L2_CID_HFLIP:
>> +               user_to_drv(ctx->gsc_ctrls.hflip, ctrl->val);
>> +               break;
>> +
>> +       case V4L2_CID_VFLIP:
>> +               user_to_drv(ctx->gsc_ctrls.vflip, ctrl->val);
>> +               break;
>> +
>> +       case V4L2_CID_ROTATE:
>> +               user_to_drv(ctx->gsc_ctrls.rotate, ctrl->val);
>> +               break;
>> +
>> +       default:
>> +               break;
>> +       }
>> +
>> +       if (gsc_m2m_opened(ctx->gsc_dev))
>> +               gsc_ctx_state_lock_set(GSC_PARAMS, ctx);
>> +
>> +       return 0;
>> +}
>> +
>> +const struct v4l2_ctrl_ops gsc_ctrl_ops = {
>> +       .s_ctrl = gsc_s_ctrl,
>> +};
>> +
>> +static const struct v4l2_ctrl_config gsc_custom_ctrl[] = {
>> +       {
>> +               .ops = &gsc_ctrl_ops,
>> +               .id = V4L2_CID_GLOBAL_ALPHA,
>> +               .name = "Set RGB alpha",
>> +               .type = V4L2_CTRL_TYPE_INTEGER,
>> +               .flags = V4L2_CTRL_FLAG_SLIDER,
>> +               .max = 255,
>> +               .step = 1,
>> +               .def = 0,
>> +       }, {
>> +               .ops = &gsc_ctrl_ops,
>> +               .id = V4L2_CID_CACHEABLE,
>> +               .name = "Set cacheable",
>> +               .type = V4L2_CTRL_TYPE_BOOLEAN,
>> +               .flags = V4L2_CTRL_FLAG_SLIDER,
>> +               .max = 1,
>> +               .def = true,
>> +       }, {
>> +               .ops = &gsc_ctrl_ops,
>> +               .id = V4L2_CID_TV_LAYER_BLEND_ENABLE,
>> +               .name = "Enable layer alpha blending",
>> +               .type = V4L2_CTRL_TYPE_BOOLEAN,
>> +               .flags = V4L2_CTRL_FLAG_SLIDER,
>> +       }, {
>> +               .ops = &gsc_ctrl_ops,
>> +               .id = V4L2_CID_TV_LAYER_BLEND_ALPHA,
>> +               .name = "Set alpha for layer blending",
>> +               .type = V4L2_CTRL_TYPE_INTEGER,
>> +               .flags = V4L2_CTRL_FLAG_SLIDER,
>> +               .min = 0,
>> +               .max = 255,
>> +               .step = 1,
>> +       }, {
>> +               .ops = &gsc_ctrl_ops,
>> +               .id = V4L2_CID_TV_PIXEL_BLEND_ENABLE,
>> +               .name = "Enable pixel alpha blending",
>> +               .type = V4L2_CTRL_TYPE_BOOLEAN,
>> +               .flags = V4L2_CTRL_FLAG_SLIDER,
>> +       }, {
>> +               .ops = &gsc_ctrl_ops,
>> +               .id = V4L2_CID_TV_CHROMA_ENABLE,
>> +               .name = "Enable chromakey",
>> +               .type = V4L2_CTRL_TYPE_BOOLEAN,
>> +               .flags = V4L2_CTRL_FLAG_SLIDER,
>> +       }, {
>> +               .ops = &gsc_ctrl_ops,
>> +               .id = V4L2_CID_TV_CHROMA_VALUE,
>> +               .name = "Set chromakey value",
>> +               .type = V4L2_CTRL_TYPE_INTEGER,
>> +               .flags = V4L2_CTRL_FLAG_SLIDER,
>> +               .min = 0,
>> +               .max = 255,
>> +               .step = 1,
>> +       }, {
>> +               .ops = &gsc_ctrl_ops,
>> +               .id = V4L2_CID_CSC_EQ_MODE,
>> +               .name = "Set CSC equation mode",
>> +               .type = V4L2_CTRL_TYPE_BOOLEAN,
>> +               .flags = V4L2_CTRL_FLAG_SLIDER,
>> +               .max = DEFAULT_CSC_EQ,
>> +               .def = DEFAULT_CSC_EQ,
>> +       }, {
>> +               .ops = &gsc_ctrl_ops,
>> +               .id = V4L2_CID_CSC_EQ,
>> +               .name = "Set CSC equation",
>> +               .type = V4L2_CTRL_TYPE_INTEGER,
>> +               .flags = V4L2_CTRL_FLAG_SLIDER,
>> +               .step = 1,
>> +               .max = 8,
>> +               .def = V4L2_COLORSPACE_REC709,
>> +       }, {
>> +               .ops = &gsc_ctrl_ops,
>> +               .id = V4L2_CID_CSC_RANGE,
>> +               .name = "Set CSC range",
>> +               .type = V4L2_CTRL_TYPE_BOOLEAN,
>> +               .flags = V4L2_CTRL_FLAG_SLIDER,
>> +               .max = DEFAULT_CSC_RANGE,
>> +               .def = DEFAULT_CSC_RANGE,
>> +       },
>> +};
>> +
>> +int gsc_ctrls_create(struct gsc_ctx *ctx)
>> +{
>> +       if (ctx->ctrls_rdy) {
>> +               gsc_err("Control handler of this context was created already");
>> +               return 0;
>> +       }
>> +
>> +       v4l2_ctrl_handler_init(&ctx->ctrl_handler, GSC_MAX_CTRL_NUM);
>> +
>> +       ctx->gsc_ctrls.rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler,
>> +                               &gsc_ctrl_ops, V4L2_CID_ROTATE, 0, 270, 90, 0);
>> +       ctx->gsc_ctrls.hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
>> +                               &gsc_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
>> +       ctx->gsc_ctrls.vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
>> +                               &gsc_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
>> +
>> +
>> +       ctx->gsc_ctrls.global_alpha = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
>> +                                       &gsc_custom_ctrl[0], NULL);
>> +       ctx->gsc_ctrls.layer_blend_en = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
>> +                                       &gsc_custom_ctrl[2], NULL);
>> +       ctx->gsc_ctrls.layer_alpha = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
>> +                                       &gsc_custom_ctrl[3], NULL);
>> +       ctx->gsc_ctrls.pixel_blend_en = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
>> +                                       &gsc_custom_ctrl[4], NULL);
>> +       ctx->gsc_ctrls.chroma_en = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
>> +                                       &gsc_custom_ctrl[5], NULL);
>> +       ctx->gsc_ctrls.chroma_val = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
>> +                                       &gsc_custom_ctrl[6], NULL);
>> +
>> +/* for CSC equation */
>> +       ctx->gsc_ctrls.csc_eq_mode = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
>> +                                       &gsc_custom_ctrl[7], NULL);
>> +       ctx->gsc_ctrls.csc_eq = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
>> +                                       &gsc_custom_ctrl[8], NULL);
>> +       ctx->gsc_ctrls.csc_range = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
>> +                                       &gsc_custom_ctrl[9], NULL);
>> +
>> +       ctx->ctrls_rdy = ctx->ctrl_handler.error == 0;
>> +
>> +
>> +       if (ctx->ctrl_handler.error) {
>> +               int err = ctx->ctrl_handler.error;
>> +               v4l2_ctrl_handler_free(&ctx->ctrl_handler);
>> +               gsc_err("Failed to gscaler control hander create");
>> +               return err;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +void gsc_ctrls_delete(struct gsc_ctx *ctx)
>> +{
>> +       if (ctx->ctrls_rdy) {
>> +               v4l2_ctrl_handler_free(&ctx->ctrl_handler);
>> +               ctx->ctrls_rdy = false;
>> +       }
>> +}
>> +
>> +/* The color format (num_comp, num_planes) must be already configured. */
>> +int gsc_prepare_addr(struct gsc_ctx *ctx, struct vb2_buffer *vb,
>> +                       struct gsc_frame *frame, struct gsc_addr *addr)
>> +{
>> +       int ret = 0;
>> +       u32 pix_size;
>> +
>> +       if (IS_ERR(vb) || IS_ERR(frame)) {
>
> Can vb pointer really contain ERRors? I think you should use !vb here.
>

sorry. i will change this.

>> +               gsc_err("Invalid argument");
>> +               return -EINVAL;
>> +       }
>> +
>> +       pix_size = frame->f_width * frame->f_height;
>> +
>> +       gsc_dbg("num_planes= %d, num_comp= %d, pix_size= %d",
>> +               frame->fmt->num_planes, frame->fmt->num_comp, pix_size);
>> +
>> +       addr->y = vb2_dma_contig_plane_dma_addr(vb, 0);
>> +
>> +       if (frame->fmt->num_planes == 1) {
>> +               switch (frame->fmt->num_comp) {
>> +               case 1:
>> +                       addr->cb = 0;
>> +                       addr->cr = 0;
>> +                       break;
>> +               case 2:
>> +                       /* decompose Y into Y/Cb */
>> +                       addr->cb = (dma_addr_t)(addr->y + pix_size);
>> +                       addr->cr = 0;
>> +                       break;
>> +               case 3:
>> +                       addr->cb = (dma_addr_t)(addr->y + pix_size);
>> +                       addr->cr = (dma_addr_t)(addr->cb + (pix_size >> 2));
>
> No need to distinguish between 420 and 422?

Yes. I will update the code.

>
>> +                       break;
>> +               default:
>> +                       gsc_err("Invalid the number of color planes");
>> +                       return -EINVAL;
>> +               }
>> +       } else {
>> +               if (frame->fmt->num_planes >= 2)
>> +                       addr->cb = vb2_dma_contig_plane_dma_addr(vb, 1);
>> +
>> +               if (frame->fmt->num_planes == 3)
>> +                       addr->cr = vb2_dma_contig_plane_dma_addr(vb, 2);
>> +       }
>> +
>> +       if (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420) {
>
> What about other YVU formats?

Ok. I will update the code.

>
>> +               u32 t_cb = addr->cb;
>> +               addr->cb = addr->cr;
>> +               addr->cr = t_cb;
>> +       }
>> +
>> +       gsc_dbg("ADDR: y= 0x%X  cb= 0x%X cr= 0x%X ret= %d",
>> +               addr->y, addr->cb, addr->cr, ret);
>> +
>> +       return ret;
>> +}
>> +
>> +static irqreturn_t gsc_irq_handler(int irq, void *priv)
>> +{
>> +       struct gsc_dev *gsc = priv;
>> +       int gsc_irq;
>> +
>> +       gsc_irq = gsc_hw_get_irq_status(gsc);
>> +       gsc_hw_clear_irq(gsc, gsc_irq);
>> +
>> +       if (gsc_irq == GSC_OR_IRQ) {
>> +               gsc_err("Local path input over-run interrupt has occurred!\n");
>> +               return IRQ_HANDLED;
>> +       }
>> +
>> +       spin_lock(&gsc->slock);
>> +
>> +       if (test_and_clear_bit(ST_M2M_RUN, &gsc->state)) {
>> +               struct vb2_buffer *src_vb, *dst_vb;
>> +               struct gsc_ctx *ctx =
>> +                       v4l2_m2m_get_curr_priv(gsc->m2m.m2m_dev);
>> +
>> +               if (!ctx || !ctx->m2m_ctx)
>> +                       goto isr_unlock;
>> +
>> +               src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
>> +               dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
>> +               if (src_vb && dst_vb) {
>> +                       v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
>> +                       v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
>> +
>> +                       if (test_and_clear_bit(ST_STOP_REQ, &gsc->state))
>> +                               wake_up(&gsc->irq_queue);
>> +                       else
>> +                               v4l2_m2m_job_finish(gsc->m2m.m2m_dev,
>> +                                                       ctx->m2m_ctx);
>
> Why not job_finish before wake_up if we are shutting down?

yes. you are right.. i will update the code.


>
>> +                       /* wake_up job_abort, stop_streaming */
>> +                       spin_lock(&ctx->slock);
>> +                       if (ctx->state & GSC_CTX_STOP_REQ) {
>> +                               ctx->state &= ~GSC_CTX_STOP_REQ;
>> +                               wake_up(&gsc->irq_queue);
>> +                       }
>> +                       spin_unlock(&ctx->slock);
>> +               }
>> +       }
>> +
>> +isr_unlock:
>> +       spin_unlock(&gsc->slock);
>> +       return IRQ_HANDLED;
>> +}
>> +
>> +static int gsc_runtime_suspend(struct device *dev)
>> +{
>> +       struct platform_device *pdev = to_platform_device(dev);
>> +       struct gsc_dev *gsc = (struct gsc_dev *)platform_get_drvdata(pdev);
>> +
>> +       if (gsc_m2m_opened(gsc))
>> +               gsc->m2m.ctx = NULL;
>> +
>> +       clk_disable(gsc->clock);
>> +       clear_bit(ST_PWR_ON, &gsc->state);
>> +
>> +       return 0;
>> +}
>> +
>> +static int gsc_runtime_resume(struct device *dev)
>> +{
>> +       struct platform_device *pdev = to_platform_device(dev);
>> +       struct gsc_dev *gsc = (struct gsc_dev *)platform_get_drvdata(pdev);
>> +       int ret;
>> +
>> +       ret = clk_enable(gsc->clock);
>> +       if (ret)
>> +               return ret;
>> +
>> +       set_bit(ST_PWR_ON, &gsc->state);
>> +       return 0;
>> +}
>> +
>> +static inline void *gsc_get_drv_data(struct platform_device *pdev);
>> +
>> +static int gsc_probe(struct platform_device *pdev)
>> +{
>> +       struct gsc_dev *gsc;
>> +       struct resource *res;
>> +       struct gsc_driverdata *drv_data;
>> +
>> +       int ret = 0;
>> +
>> +       dev_dbg(&pdev->dev, "%s():\n", __func__);
>> +       drv_data = (struct gsc_driverdata *)
>> +                               gsc_get_drv_data(pdev);
>> +
>> +       if (pdev->dev.of_node) {
>> +               pdev->id = of_alias_get_id(pdev->dev.of_node, "gsc");
>> +               if (pdev->id < 0)
>> +                       dev_err(&pdev->dev,
>> +                               "failed to get alias id, errno %d\n", ret);
>> +       }
>> +
>> +       if (pdev->id >= drv_data->num_entities) {
>> +               dev_err(&pdev->dev, "Invalid platform device id: %d\n",
>> +                       pdev->id);
>> +               return -EINVAL;
>> +       }
>> +
>> +       gsc = devm_kzalloc(&pdev->dev, sizeof(struct gsc_dev), GFP_KERNEL);
>> +       if (!gsc)
>> +               return -ENOMEM;
>> +
>> +       gsc->id = pdev->id;
>> +       gsc->variant = drv_data->variant[gsc->id];
>> +       gsc->pdev = pdev;
>> +       gsc->pdata = pdev->dev.platform_data;
>> +
>> +       init_waitqueue_head(&gsc->irq_queue);
>> +       spin_lock_init(&gsc->slock);
>> +       mutex_init(&gsc->lock);
>> +
>> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +       gsc->regs = devm_request_and_ioremap(&pdev->dev, res);
>> +       if (!gsc->regs) {
>> +               dev_err(&pdev->dev, "failed to map registers\n");
>> +               return -ENOENT;
>> +       }
>> +
>> +       /* Get Gscaler clock */
>> +       gsc->clock = clk_get(&gsc->pdev->dev, GSC_CLOCK_GATE_NAME);
>> +       if (IS_ERR(gsc->clock)) {
>> +               gsc_err("failed to get gscaler.%d clock", gsc->id);
>> +               return -ENXIO;
>> +       }
>> +       clk_put(gsc->clock);
>> +
>> +       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
>> +       if (!res) {
>> +               dev_err(&pdev->dev, "failed to get IRQ resource\n");
>> +               return -ENXIO;
>> +       }
>> +       gsc->irq = res->start;
>> +
>> +       ret = devm_request_irq(&pdev->dev, gsc->irq, gsc_irq_handler, 0,
>> +                                                       pdev->name, gsc);
>> +       if (ret) {
>> +               dev_err(&pdev->dev, "failed to install irq (%d)\n", ret);
>> +               return ret;
>> +       }
>> +
>> +       gsc->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
>> +       if (IS_ERR(gsc->alloc_ctx)) {
>> +               ret = PTR_ERR(gsc->alloc_ctx);
>> +               goto err_irq;
>> +       }
>> +
>> +       platform_set_drvdata(pdev, gsc);
>> +
>> +       ret = gsc_register_m2m_device(gsc);
>> +       if (ret)
>> +               goto err_irq;
>> +
>> +       gsc_runtime_resume(&pdev->dev);
>> +       pm_runtime_enable(&pdev->dev);
>> +
>> +       gsc_info("gsc-%d registered successfully", gsc->id);
>> +       return 0;
>> +
>
> I think you are missing additional error path here with
> platform_release_resource()s
> that you might have acquired with platform_get_resource().
>

platform_get_resource() is getting some references from
platform_device. I don't think we need to explicitly release these
resources..
Is there anything i am missing?? i mean any API's ???

>> +err_irq:
>> +       free_irq(gsc->irq, gsc);
>> +
>> +       return ret;
>> +}
>> +
>> +static int __devexit gsc_remove(struct platform_device *pdev)
>> +{
>> +       struct gsc_dev *gsc =
>> +               (struct gsc_dev *)platform_get_drvdata(pdev);
>> +
>> +       free_irq(gsc->irq, gsc);
>> +
>> +       gsc_unregister_m2m_device(gsc);
>> +
>> +       vb2_dma_contig_cleanup_ctx(gsc->alloc_ctx);
>> +       pm_runtime_disable(&pdev->dev);
>> +
>> +       iounmap(gsc->regs);
>> +       release_resource(gsc->regs_res);
>> +       kfree(gsc->regs_res);
>> +       kfree(gsc);
>> +
>> +       dev_info(&pdev->dev, "%s driver unloaded\n", pdev->name);
>> +       return 0;
>> +}
>> +
>> +static int gsc_suspend(struct device *dev)
>> +{
>> +       struct platform_device *pdev;
>> +       struct gsc_dev *gsc;
>> +       int ret = 0;
>> +
>> +       pdev = to_platform_device(dev);
>> +       gsc = (struct gsc_dev *)platform_get_drvdata(pdev);
>> +
>> +       if (gsc_m2m_run(gsc)) {
>> +               set_bit(ST_STOP_REQ, &gsc->state);
>> +               ret = wait_event_timeout(gsc->irq_queue,
>> +                               !test_bit(ST_STOP_REQ, &gsc->state),
>> +                               GSC_SHUTDOWN_TIMEOUT);
>> +               if (ret == 0)
>> +                       dev_err(&gsc->pdev->dev, "wait timeout : %s\n",
>> +                               __func__);
>> +       }
>> +
>> +       pm_runtime_put_sync(dev);
>> +
>> +       return ret;
>> +}
>> +
>> +static int gsc_resume(struct device *dev)
>> +{
>> +       struct gsc_dev *gsc;
>> +       struct gsc_ctx *ctx;
>> +
>> +       gsc = dev_get_drvdata(dev);
>> +
>> +       pm_runtime_get_sync(dev);
>> +       if (gsc_m2m_opened(gsc)) {
>> +               ctx = v4l2_m2m_get_curr_priv(gsc->m2m.m2m_dev);
>> +               if (ctx != NULL) {
>> +                       gsc->m2m.ctx = NULL;
>> +                       v4l2_m2m_job_finish(gsc->m2m.m2m_dev, ctx->m2m_ctx);
>> +               }
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static const struct dev_pm_ops gsc_pm_ops = {
>> +       .suspend                = gsc_suspend,
>> +       .resume                 = gsc_resume,
>> +       .runtime_suspend        = gsc_runtime_suspend,
>> +       .runtime_resume         = gsc_runtime_resume,
>> +};
>> +
>> +struct gsc_pix_max gsc_v_100_max = {
>> +       .org_scaler_bypass_w    = 8192,
>> +       .org_scaler_bypass_h    = 8192,
>> +       .org_scaler_input_w     = 4800,
>> +       .org_scaler_input_h     = 3344,
>> +       .real_rot_dis_w         = 4800,
>> +       .real_rot_dis_h         = 3344,
>> +       .real_rot_en_w          = 2047,
>> +       .real_rot_en_h          = 2047,
>> +       .target_rot_dis_w       = 4800,
>> +       .target_rot_dis_h       = 3344,
>> +       .target_rot_en_w        = 2016,
>> +       .target_rot_en_h        = 2016,
>> +};
>> +
>> +struct gsc_pix_min gsc_v_100_min = {
>> +       .org_w                  = 64,
>> +       .org_h                  = 32,
>> +       .real_w                 = 64,
>> +       .real_h                 = 32,
>> +       .target_rot_dis_w       = 64,
>> +       .target_rot_dis_h       = 32,
>> +       .target_rot_en_w        = 32,
>> +       .target_rot_en_h        = 16,
>> +};
>> +
>> +struct gsc_pix_align gsc_v_100_align = {
>> +       .org_h                  = 16,
>> +       .org_w                  = 16, /* yuv420 : 16, others : 8 */
>> +       .offset_h               = 2,  /* yuv420/422 : 2, others : 1 */
>> +       .real_w                 = 16, /* yuv420/422 : 4~16, others : 2~8 */
>> +       .real_h                 = 16, /* yuv420 : 4~16, others : 1 */
>> +       .target_w               = 2,  /* yuv420/422 : 2, others : 1 */
>> +       .target_h               = 2,  /* yuv420 : 2, others : 1 */
>> +};
>> +
>> +struct gsc_variant gsc_v_100_variant = {
>> +       .pix_max                = &gsc_v_100_max,
>> +       .pix_min                = &gsc_v_100_min,
>> +       .pix_align              = &gsc_v_100_align,
>> +       .in_buf_cnt             = 8,
>> +       .out_buf_cnt            = 16,
>> +       .sc_up_max              = 8,
>> +       .sc_down_max            = 16,
>> +       .poly_sc_down_max       = 4,
>> +       .pre_sc_down_max        = 4,
>> +       .local_sc_down          = 2,
>> +};
>
> static structs?
>

Ok. I will change this.

>> +
>> +static struct gsc_driverdata gsc_v_100_drvdata = {
>> +       .variant = {
>> +               [0] = &gsc_v_100_variant,
>> +               [1] = &gsc_v_100_variant,
>> +               [2] = &gsc_v_100_variant,
>> +               [3] = &gsc_v_100_variant,
>> +       },
>> +       .num_entities = 4,
>> +       .lclk_frequency = 266000000UL,
>> +};
>> +
>> +static struct platform_device_id gsc_driver_ids[] = {
>> +       {
>> +               .name           = "exynos-gsc",
>> +               .driver_data    = (unsigned long)&gsc_v_100_drvdata,
>> +       },
>> +       {},
>> +};
>> +MODULE_DEVICE_TABLE(platform, gsc_driver_ids);
>> +
>> +#ifdef CONFIG_OF
>> +static const struct of_device_id exynos_gsc_match[] = {
>> +       { .compatible = "samsung,exynos-gsc",
>> +       .data = &gsc_v_100_drvdata, },
>> +       {},
>> +};
>> +MODULE_DEVICE_TABLE(of, exynos_gsc_match);
>> +#else
>> +#define exynos_gsc_match NULL
>> +#endif
>> +
>> +static inline void *gsc_get_drv_data(struct platform_device *pdev)
>> +{
>> +#ifdef CONFIG_OF
>> +       if (pdev->dev.of_node) {
>> +               const struct of_device_id *match;
>> +       match = of_match_node(exynos_gsc_match, pdev->dev.of_node);
>> +       return (struct gsc_driverdata *) match->data;
>> +       }
>> +#endif
>> +       return (struct gsc_driverdata *)
>> +                       platform_get_device_id(pdev)->driver_data;
>> +}
>> +
>> +static struct platform_driver gsc_driver = {
>> +       .probe          = gsc_probe,
>> +       .remove = __devexit_p(gsc_remove),
>> +       .id_table       = gsc_driver_ids,
>> +       .driver = {
>> +               .name   = GSC_MODULE_NAME,
>> +               .owner  = THIS_MODULE,
>> +               .pm     = &gsc_pm_ops,
>> +               .of_match_table = exynos_gsc_match,
>> +       }
>> +};
>> +
>> +static int __init gsc_init(void)
>> +{
>> +       int ret = platform_driver_register(&gsc_driver);
>> +       if (ret)
>> +               gsc_err("platform_driver_register failed: %d\n", ret);
>> +       return ret;
>> +}
>> +
>> +static void __exit gsc_exit(void)
>> +{
>> +       platform_driver_unregister(&gsc_driver);
>> +}
>> +
>> +module_init(gsc_init);
>> +module_exit(gsc_exit);
>> +
>> +MODULE_AUTHOR("Hyunwong Kim <khw0178.kim@xxxxxxxxxxx>");
>> +MODULE_DESCRIPTION("Samsung EXYNOS5 Soc series G-Scaler driver");
>> +MODULE_LICENSE("GPL");
>> diff --git a/drivers/media/video/exynos/gsc/gsc-core.h b/drivers/media/video/exynos/gsc/gsc-core.h
>> new file mode 100644
>> index 0000000..3a236ec
>> --- /dev/null
>> +++ b/drivers/media/video/exynos/gsc/gsc-core.h
>> @@ -0,0 +1,652 @@
>> +/* linux/drivers/media/video/exynos/gsc/gsc-core.h
>> + *
>> + * Copyright (c) 2011 Samsung Electronics Co., Ltd.
>> + *             http://www.samsung.com
>> + *
>> + * header file for Samsung EXYNOS5 SoC series G-scaler driver
>> +
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#ifndef GSC_CORE_H_
>> +#define GSC_CORE_H_
>> +
>> +#include <linux/delay.h>
>> +#include <linux/sched.h>
>> +#include <linux/spinlock.h>
>> +#include <linux/types.h>
>> +#include <linux/videodev2.h>
>> +#include <linux/io.h>
>> +#include <linux/pm_runtime.h>
>> +#include <media/videobuf2-core.h>
>> +#include <media/v4l2-ctrls.h>
>> +#include <media/v4l2-device.h>
>> +#include <media/v4l2-mem2mem.h>
>> +#include <media/v4l2-mediabus.h>
>> +#define CONFIG_VB2_GSC_DMA_CONTIG      1
>> +#include <media/videobuf2-dma-contig.h>
>> +#include "gsc-regs.h"
>> +extern int gsc_dbg;
>> +
>> +#define GSC_MODULE_NAME                        "exynos-gsc"
>> +
>> +#define gsc_info(fmt, args...)                                         \
>> +       do {                                                            \
>> +               if (gsc_dbg >= 6)                                       \
>> +                       pr_info("[INFO]%s:%d: "fmt "\n",                \
>> +                               __func__, __LINE__, ##args);            \
>> +       } while (0)
>> +
>> +#define gsc_err(fmt, args...)                                          \
>> +       do {                                                            \
>> +               if (gsc_dbg >= 3)                                       \
>> +                       pr_err("[ERROR]%s:%d: "fmt "\n",                \
>> +                               __func__, __LINE__, ##args);            \
>> +       } while (0)
>> +
>> +#define gsc_warn(fmt, args...)                                         \
>> +       do {                                                            \
>> +               if (gsc_dbg >= 4)                                       \
>> +                       pr_warn("[WARN]%s:%d: "fmt "\n",                \
>> +                               __func__, __LINE__, ##args);            \
>> +       } while (0)
>> +
>> +#define gsc_dbg(fmt, args...)                                          \
>> +       do {                                                            \
>> +               if (gsc_dbg >= 7)                                       \
>> +                       pr_debug("[DEBUG]%s:%d: "fmt "\n",              \
>> +                               __func__, __LINE__, ##args);            \
>> +       } while (0)
>> +
>> +#define GSC_MAX_CLOCKS                 3
>
> never used
>

Ok. i will remove all the unused code...

>> +#define GSC_SHUTDOWN_TIMEOUT           ((100*HZ)/1000)
>> +#define GSC_MAX_DEVS                   4
>> +#define WORKQUEUE_NAME_SIZE            32
>
> never used
>
>> +#define FIMD_NAME_SIZE                 32
>
> ditto
>
>> +#define GSC_M2M_BUF_NUM                        0
>> +#define GSC_OUT_BUF_MAX                        2
>
> ditto
>
>> +#define GSC_MAX_CTRL_NUM               10
>> +#define GSC_OUT_MAX_MASK_NUM           7
>
> ditto
>
>> +#define GSC_SC_ALIGN_4                 4
>> +#define GSC_SC_ALIGN_2                 2
>
>> +#define GSC_OUT_DEF_SRC                        15
>> +#define GSC_OUT_DEF_DST                        7
>> +#define DEFAULT_GSC_SINK_WIDTH         800
>> +#define DEFAULT_GSC_SINK_HEIGHT                480
>> +#define DEFAULT_GSC_SOURCE_WIDTH       800
>> +#define DEFAULT_GSC_SOURCE_HEIGHT      480
>
> ditto for all 6 above.
>
>> +#define DEFAULT_CSC_EQ                 1
>> +#define DEFAULT_CSC_RANGE              1
>> +
>> +#define GSC_LAST_DEV_ID                        3
>> +#define GSC_PAD_SINK                   0
>> +#define GSC_PAD_SOURCE                 1
>> +#define GSC_PADS_NUM                   2
>
> ditto for all 4 above.
>
>> +
>> +#define        GSC_PARAMS                      (1 << 0)
>> +#define        GSC_SRC_FMT                     (1 << 1)
>> +#define        GSC_DST_FMT                     (1 << 2)
>> +#define        GSC_CTX_M2M                     (1 << 3)
>> +#define        GSC_CTX_OUTPUT                  (1 << 4)
>> +#define        GSC_CTX_START                   (1 << 5)
>> +#define        GSC_CTX_STOP_REQ                (1 << 6)
>> +#define        GSC_CTX_CAP                     (1 << 10)
>
>> +#define MAX_MDEV                       2
>
> ditto
>
>> +
>> +#define V4L2_CID_CACHEABLE                     (V4L2_CID_LASTP1 + 1)
>> +#define V4L2_CID_TV_LAYER_BLEND_ENABLE         (V4L2_CID_LASTP1 + 2)
>> +#define V4L2_CID_TV_LAYER_BLEND_ALPHA          (V4L2_CID_LASTP1 + 3)
>> +#define V4L2_CID_TV_PIXEL_BLEND_ENABLE         (V4L2_CID_LASTP1 + 4)
>> +#define V4L2_CID_TV_CHROMA_ENABLE              (V4L2_CID_LASTP1 + 5)
>> +#define V4L2_CID_TV_CHROMA_VALUE               (V4L2_CID_LASTP1 + 6)
>> +/* for color space conversion equation selection */
>> +#define V4L2_CID_CSC_EQ_MODE                   (V4L2_CID_LASTP1 + 8)
>> +#define V4L2_CID_CSC_EQ                                (V4L2_CID_LASTP1 + 9)
>> +#define V4L2_CID_CSC_RANGE                     (V4L2_CID_LASTP1 + 10)
>> +#define V4L2_CID_GLOBAL_ALPHA                  (V4L2_CID_LASTP1 + 11)
>> +
>> +enum gsc_dev_flags {
>> +       /* for global */
>> +       ST_PWR_ON,
>> +       ST_STOP_REQ,
>> +       /* for m2m node */
>> +       ST_M2M_OPEN,
>> +       ST_M2M_RUN,
>> +};
>> +
>> +enum gsc_irq {
>> +       GSC_OR_IRQ = 17,
>> +       GSC_DONE_IRQ = 16,
>> +};
>> +
>> +/**
>> + * enum gsc_datapath - the path of data used for gscaler
>> + * @GSC_CAMERA: from camera
>> + * @GSC_DMA: from/to DMA
>> + * @GSC_LOCAL: to local path
>> + * @GSC_WRITEBACK: from FIMD
>> + */
>> +enum gsc_datapath {
>> +       GSC_CAMERA = 0x1,
>> +       GSC_DMA,
>> +       GSC_MIXER,
>> +       GSC_FIMD,
>> +       GSC_WRITEBACK,
>> +};
>> +
>> +enum gsc_color_fmt {
>> +       GSC_RGB = 0x1,
>> +       GSC_YUV420 = 0x2,
>> +       GSC_YUV422 = 0x4,
>> +       GSC_YUV444 = 0x8,
>> +};
>> +
>> +enum gsc_yuv_fmt {
>> +       GSC_LSB_Y = 0x10,
>> +       GSC_LSB_C,
>> +       GSC_CBCR = 0x20,
>> +       GSC_CRCB,
>> +};
>> +
>> +#define fh_to_ctx(__fh) container_of(__fh, struct gsc_ctx, fh)
>> +#define is_rgb(x) (!!((x) & 0x1))
>> +#define is_yuv420(x) (!!((x) & 0x2))
>> +#define is_yuv422(x) (!!((x) & 0x4))
>> +#define gsc_m2m_run(dev) test_bit(ST_M2M_RUN, &(dev)->state)
>> +#define gsc_m2m_opened(dev) test_bit(ST_M2M_OPEN, &(dev)->state)
>> +
>> +#define ctrl_to_ctx(__ctrl) \
>> +       container_of((__ctrl)->handler, struct gsc_ctx, ctrl_handler)
>> +/**
>> + * struct gsc_fmt - the driver's internal color format data
>> + * @mbus_code: Media Bus pixel code, -1 if not applicable
>> + * @name: format description
>> + * @pixelformat: the fourcc code for this format, 0 if not applicable
>> + * @yorder: Y/C order
>> + * @corder: Chrominance order control
>> + * @num_planes: number of physically non-contiguous data planes
>> + * @nr_comp: number of physically contiguous data planes
>> + * @depth: per plane driver's private 'number of bits per pixel'
>> + * @flags: flags indicating which operation mode format applies to
>> + */
>> +struct gsc_fmt {
>> +       enum v4l2_mbus_pixelcode mbus_code;
>> +       char    *name;
>> +       u32     pixelformat;
>> +       u32     color;
>> +       u32     yorder;
>> +       u32     corder;
>> +       u16     num_planes;
>> +       u16     num_comp;
>> +       u8      depth[VIDEO_MAX_PLANES];
>> +       u32     flags;
>> +};
>> +
>> +/**
>> + * struct gsc_input_buf - the driver's video buffer
>> + * @vb:        videobuf2 buffer
>> + * @list : linked list structure for buffer queue
>> + * @idx : index of G-Scaler input buffer
>> + */
>> +struct gsc_input_buf {
>> +       struct vb2_buffer       vb;
>> +       struct list_head        list;
>> +       int                     idx;
>> +};
>> +
>> +/**
>> + * struct gsc_addr - the G-Scaler physical address set
>> + * @y:  luminance plane address
>> + * @cb:         Cb plane address
>> + * @cr:         Cr plane address
>> + */
>> +struct gsc_addr {
>> +       dma_addr_t      y;
>> +       dma_addr_t      cb;
>> +       dma_addr_t      cr;
>> +};
>> +
>> +/* struct gsc_ctrls - the G-Scaler control set
>> + * @rotate: rotation degree
>> + * @hflip: horizontal flip
>> + * @vflip: vertical flip
>> + * @global_alpha: the alpha value of current frame
>> + * @layer_blend_en: enable mixer layer alpha blending
>> + * @layer_alpha: set alpha value for mixer layer
>> + * @pixel_blend_en: enable mixer pixel alpha blending
>> + * @chroma_en: enable chromakey
>> + * @chroma_val:        set value for chromakey
>> + * @csc_eq_mode: mode to select csc equation of current frame
>> + * @csc_eq: csc equation of current frame
>> + * @csc_range: csc range of current frame
>> + */
>> +struct gsc_ctrls {
>> +       struct v4l2_ctrl        *rotate;
>> +       struct v4l2_ctrl        *hflip;
>> +       struct v4l2_ctrl        *vflip;
>> +       struct v4l2_ctrl        *global_alpha;
>> +       struct v4l2_ctrl        *layer_blend_en;
>> +       struct v4l2_ctrl        *layer_alpha;
>> +       struct v4l2_ctrl        *pixel_blend_en;
>> +       struct v4l2_ctrl        *chroma_en;
>> +       struct v4l2_ctrl        *chroma_val;
>> +       struct v4l2_ctrl        *csc_eq_mode;
>> +       struct v4l2_ctrl        *csc_eq;
>> +       struct v4l2_ctrl        *csc_range;
>> +};
>
> Can you do this? Keep the pointer to the v4l2_ctrl struct passed to s_ctrl
> after it returns?

Yes. I think we can keep the reference.. but updating the values are
not valid... which i was doing in the user_to_drv() funciton.
I will change that..

>
>> +
>> +/**
>> + * struct gsc_scaler - the configuration data for G-Scaler inetrnal scaler
>> + * @pre_shfactor:      pre sclaer shift factor
>> + * @pre_hratio:                horizontal ratio of the prescaler
>> + * @pre_vratio:                vertical ratio of the prescaler
>> + * @main_hratio:       the main scaler's horizontal ratio
>> + * @main_vratio:       the main scaler's vertical ratio
>> + */
>> +struct gsc_scaler {
>> +       u32     pre_shfactor;
>> +       u32     pre_hratio;
>> +       u32     pre_vratio;
>> +       unsigned long main_hratio;
>> +       unsigned long main_vratio;
>> +};
>> +
>> +struct gsc_dev;
>> +
>> +struct gsc_ctx;
>> +
>> +/**
>> + * struct gsc_frame - source/target frame properties
>> + * @f_width:   SRC : SRCIMG_WIDTH, DST : OUTPUTDMA_WHOLE_IMG_WIDTH
>> + * @f_height:  SRC : SRCIMG_HEIGHT, DST : OUTPUTDMA_WHOLE_IMG_HEIGHT
>> + * @crop:      cropped(source)/scaled(destination) size
>> + * @payload:   image size in bytes (w x h x bpp)
>> + * @addr:      image frame buffer physical addresses
>> + * @fmt:       G-scaler color format pointer
>> + * @alph:      frame's alpha value
>> + */
>> +struct gsc_frame {
>> +       u32     f_width;
>> +       u32     f_height;
>> +       struct v4l2_rect        crop;
>> +       unsigned long payload[VIDEO_MAX_PLANES];
>> +       struct gsc_addr         addr;
>> +       struct gsc_fmt          *fmt;
>> +       u8      alpha;
>> +};
>> +
>> +/**
>> + * struct gsc_m2m_device - v4l2 memory-to-memory device data
>> + * @vfd: the video device node for v4l2 m2m mode
>> + * @m2m_dev: v4l2 memory-to-memory device data
>> + * @ctx: hardware context data
>> + * @refcnt: the reference counter
>> + */
>> +struct gsc_m2m_device {
>> +       struct video_device     *vfd;
>> +       struct v4l2_m2m_dev     *m2m_dev;
>> +       struct gsc_ctx          *ctx;
>> +       int                     refcnt;
>> +};
>> +
>> +/**
>> + *  struct gsc_pix_max - image pixel size limits in various IP configurations
>> + *
>> + *  @org_scaler_bypass_w: max pixel width when the scaler is disabled
>> + *  @org_scaler_bypass_h: max pixel height when the scaler is disabled
>> + *  @org_scaler_input_w: max pixel width when the scaler is enabled
>> + *  @org_scaler_input_h: max pixel height when the scaler is enabled
>> + *  @real_rot_dis_w: max pixel src cropped height with the rotator is off
>> + *  @real_rot_dis_h: max pixel src croppped width with the rotator is off
>> + *  @real_rot_en_w: max pixel src cropped width with the rotator is on
>> + *  @real_rot_en_h: max pixel src cropped height with the rotator is on
>> + *  @target_rot_dis_w: max pixel dst scaled width with the rotator is off
>> + *  @target_rot_dis_h: max pixel dst scaled height with the rotator is off
>> + *  @target_rot_en_w: max pixel dst scaled width with the rotator is on
>> + *  @target_rot_en_h: max pixel dst scaled height with the rotator is on
>> + */
>> +struct gsc_pix_max {
>> +       u16 org_scaler_bypass_w;
>> +       u16 org_scaler_bypass_h;
>> +       u16 org_scaler_input_w;
>> +       u16 org_scaler_input_h;
>> +       u16 real_rot_dis_w;
>> +       u16 real_rot_dis_h;
>> +       u16 real_rot_en_w;
>> +       u16 real_rot_en_h;
>> +       u16 target_rot_dis_w;
>> +       u16 target_rot_dis_h;
>> +       u16 target_rot_en_w;
>> +       u16 target_rot_en_h;
>> +};
>> +
>> +/**
>> + *  struct gsc_pix_min - image pixel size limits in various IP configurations
>> + *
>> + *  @org_w: minimum source pixel width
>> + *  @org_h: minimum source pixel height
>> + *  @real_w: minimum input crop pixel width
>> + *  @real_h: minimum input crop pixel height
>> + *  @target_rot_dis_w: minimum output scaled pixel height when rotator is off
>> + *  @target_rot_dis_h: minimum output scaled pixel height when rotator is off
>> + *  @target_rot_en_w: minimum output scaled pixel height when rotator is on
>> + *  @target_rot_en_h: minimum output scaled pixel height when rotator is on
>> + */
>> +struct gsc_pix_min {
>> +       u16 org_w;
>> +       u16 org_h;
>> +       u16 real_w;
>> +       u16 real_h;
>> +       u16 target_rot_dis_w;
>> +       u16 target_rot_dis_h;
>> +       u16 target_rot_en_w;
>> +       u16 target_rot_en_h;
>> +};
>> +
>> +struct gsc_pix_align {
>> +       u16 org_h;
>> +       u16 org_w;
>> +       u16 offset_h;
>> +       u16 real_w;
>> +       u16 real_h;
>> +       u16 target_w;
>> +       u16 target_h;
>> +};
>> +
>> +/**
>> + * struct gsc_variant - G-Scaler variant information
>> + */
>> +struct gsc_variant {
>> +       struct gsc_pix_max *pix_max;
>> +       struct gsc_pix_min *pix_min;
>> +       struct gsc_pix_align *pix_align;
>> +       u16             in_buf_cnt;
>> +       u16             out_buf_cnt;
>> +       u16             sc_up_max;
>> +       u16             sc_down_max;
>> +       u16             poly_sc_down_max;
>> +       u16             pre_sc_down_max;
>> +       u16             local_sc_down;
>> +};
>> +
>> +/**
>> + * struct gsc_driverdata - per device type driver data for init time.
>> + *
>> + * @variant: the variant information for this driver.
>> + * @lclk_frequency: g-scaler clock frequency
>> + * @num_entities: the number of g-scalers
>> + */
>> +struct gsc_driverdata {
>> +       struct gsc_variant *variant[GSC_MAX_DEVS];
>> +       unsigned long   lclk_frequency;
>> +       int             num_entities;
>> +};
>> +
>> +struct gsc_vb2 {
>> +       const struct vb2_mem_ops *ops;
>> +       void *(*init)(struct gsc_dev *gsc);
>> +       void (*cleanup)(void *alloc_ctx);
>> +
>> +       void (*resume)(void *alloc_ctx);
>> +       void (*suspend)(void *alloc_ctx);
>> +
>> +       int (*cache_flush)(struct vb2_buffer *vb, u32 num_planes);
>> +       void (*set_cacheable)(void *alloc_ctx, bool cacheable);
>> +       void (*set_sharable)(void *alloc_ctx, bool sharable);
>> +};
>
> I don't see anything from here being used apart from resume/suspend.
> Am I missing something?
>
>> +
>> +/**
>> + * struct gsc_dev - abstraction for G-Scaler entity
>> + * @slock:     the spinlock protecting this data structure
>> + * @lock:      the mutex protecting this data structure
>> + * @pdev:      pointer to the G-Scaler platform device
>> + * @variant:   the IP variant information
>> + * @id:                g_scaler device index (0..GSC_MAX_DEVS)
>> + * @regs:      the mapped hardware registers
>> + * @regs_res:  the resource claimed for IO registers
>> + * @irq:       G-scaler interrupt number
>> + * @irq_queue: interrupt handler waitqueue
>> + * @m2m:       memory-to-memory V4L2 device information
>> + * @out:       memory-to-local V4L2 output device information
>> + * @state:     flags used to synchronize m2m and capture mode operation
>> + * @alloc_ctx: videobuf2 memory allocator context
>> + * @vb2:       videobuf2 memory allocator call-back functions
>> + * @mdev:      pointer to exynos media device
>> + * @pipeline:  pointer to subdevs that are connected with gscaler
>> + */
>> +struct gsc_dev {
>> +       spinlock_t                      slock;
>> +       struct mutex                    lock;
>> +       struct platform_device          *pdev;
>> +       struct gsc_variant              *variant;
>> +       u16                             id;
>> +       struct clk                      *clock;
>> +       void __iomem                    *regs;
>> +       struct resource                 *regs_res;
>> +       int                             irq;
>> +       wait_queue_head_t               irq_queue;
>> +       struct gsc_m2m_device           m2m;
>> +       struct exynos_platform_gscaler  *pdata;
>> +       unsigned long                   state;
>> +       struct vb2_alloc_ctx            *alloc_ctx;
>> +       const struct gsc_vb2            *vb2;
>> +};
>> +
>> +/**
>> + * gsc_ctx - the device context data
>> + * @slock:             spinlock protecting this data structure
>> + * @s_frame:           source frame properties
>> + * @d_frame:           destination frame properties
>> + * @in_path:           input mode (DMA or camera)
>> + * @out_path:          output mode (DMA or FIFO)
>> + * @scaler:            image scaler properties
>> + * @flags:             additional flags for image conversion
>> + * @state:             flags to keep track of user configuration
>> + * @gsc_dev:           the g-scaler device this context applies to
>> + * @m2m_ctx:           memory-to-memory device context
>> + * @fh:                 v4l2 file handle
>> + * @ctrl_handler:       v4l2 controls handler
>> + * @ctrls_rdy:          true if the control handler is initialized
>> + * @gsc_ctrls          G-Scaler control set
>> + * @m2m_ctx:           memory-to-memory device context
>> + */
>> +struct gsc_ctx {
>> +       spinlock_t              slock;
>> +       struct gsc_frame        s_frame;
>> +       struct gsc_frame        d_frame;
>> +       enum gsc_datapath       in_path;
>> +       enum gsc_datapath       out_path;
>> +       struct gsc_scaler       scaler;
>> +       u32                     flags;
>> +       u32                     state;
>> +       struct gsc_dev          *gsc_dev;
>> +       struct v4l2_m2m_ctx     *m2m_ctx;
>> +       struct v4l2_fh          fh;
>> +       struct v4l2_ctrl_handler ctrl_handler;
>> +       struct gsc_ctrls        gsc_ctrls;
>> +       bool                    ctrls_rdy;
>> +};
>> +
>> +void gsc_set_prefbuf(struct gsc_dev *gsc, struct gsc_frame frm);
>> +void gsc_clk_release(struct gsc_dev *gsc);
>
> no such function
>
>> +int gsc_register_m2m_device(struct gsc_dev *gsc);
>> +void gsc_unregister_m2m_device(struct gsc_dev *gsc);
>> +
>> +u32 get_plane_size(struct gsc_frame *fr, unsigned int plane);
>> +char gsc_total_fmts(void);
>
> no such function
>
>> +struct gsc_fmt *get_format(int index);
>> +struct gsc_fmt *find_fmt(u32 *pixelformat, u32 *mbus_code, int index);
>> +int gsc_enum_fmt_mplane(struct v4l2_fmtdesc *f);
>> +int gsc_try_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f);
>> +void gsc_set_frame_size(struct gsc_frame *frame, int width, int height);
>> +int gsc_g_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f);
>> +void gsc_check_crop_change(u32 tmp_w, u32 tmp_h, u32 *w, u32 *h);
>> +int gsc_g_crop(struct gsc_ctx *ctx, struct v4l2_crop *cr);
>> +int gsc_try_crop(struct gsc_ctx *ctx, struct v4l2_crop *cr);
>> +int gsc_cal_prescaler_ratio(struct gsc_variant *var, u32 src, u32 dst,
>> +                                                       u32 *ratio);
>> +void gsc_get_prescaler_shfactor(u32 hratio, u32 vratio, u32 *sh);
>> +void gsc_check_src_scale_info(struct gsc_variant *var,
>> +                               struct gsc_frame *s_frame,
>> +                               u32 *wratio, u32 tx, u32 ty, u32 *hratio);
>> +int gsc_check_scaler_ratio(struct gsc_variant *var, int sw, int sh, int dw,
>> +                          int dh, int rot, int out_path);
>> +int gsc_set_scaler_info(struct gsc_ctx *ctx);
>> +int gsc_ctrls_create(struct gsc_ctx *ctx);
>> +void gsc_ctrls_delete(struct gsc_ctx *ctx);
>> +int gsc_out_hw_set(struct gsc_ctx *ctx);
>> +int gsc_out_set_in_addr(struct gsc_dev *gsc, struct gsc_ctx *ctx,
>> +                  struct gsc_input_buf *buf, int index);
>
> Above two don't exist.
>
>> +int gsc_prepare_addr(struct gsc_ctx *ctx, struct vb2_buffer *vb,
>> +                    struct gsc_frame *frame, struct gsc_addr *addr);
>> +int gsc_out_link_validate(const struct media_pad *source,
>> +                         const struct media_pad *sink);
>> +int gsc_pipeline_s_stream(struct gsc_dev *gsc, bool on);
>
> Ditto for above two.
>
>> +
>> +static inline void gsc_ctx_state_lock_set(u32 state, struct gsc_ctx *ctx)
>> +{
>> +       unsigned long flags;
>> +
>> +       spin_lock_irqsave(&ctx->slock, flags);
>> +       ctx->state |= state;
>> +       spin_unlock_irqrestore(&ctx->slock, flags);
>> +}
>> +
>> +static inline void gsc_ctx_state_lock_clear(u32 state, struct gsc_ctx *ctx)
>> +{
>> +       unsigned long flags;
>> +
>> +       spin_lock_irqsave(&ctx->slock, flags);
>> +       ctx->state &= ~state;
>> +       spin_unlock_irqrestore(&ctx->slock, flags);
>> +}
>> +
>> +static inline int get_win_num(struct gsc_dev *dev)
>> +{
>> +       return (dev->id == 3) ? 2 : dev->id;
>> +}
>
> unused
>
>> +static inline int is_tiled(struct gsc_fmt *fmt)
>> +{
>> +       return fmt->pixelformat == V4L2_PIX_FMT_NV12MT_16X16;
>> +}
>> +
>> +static inline int is_output(enum v4l2_buf_type type)
>> +{
>> +       return (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ||
>> +               type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ? 1 : 0;
>> +}
>
> never used
>
>> +
>> +static inline void gsc_hw_enable_control(struct gsc_dev *dev, bool on)
>> +{
>> +       u32 cfg = readl(dev->regs + GSC_ENABLE);
>> +
>> +       if (on)
>> +               cfg |= GSC_ENABLE_ON;
>> +       else
>> +               cfg &= ~GSC_ENABLE_ON;
>> +
>> +       writel(cfg, dev->regs + GSC_ENABLE);
>> +}
>> +
>> +static inline int gsc_hw_get_irq_status(struct gsc_dev *dev)
>> +{
>> +       u32 cfg = readl(dev->regs + GSC_IRQ);
>> +       if (cfg & (1 << GSC_OR_IRQ))
>> +               return GSC_OR_IRQ;
>> +       else
>> +               return GSC_DONE_IRQ;
>> +
>> +}
>> +
>> +static inline void gsc_hw_clear_irq(struct gsc_dev *dev, int irq)
>> +{
>> +       u32 cfg = readl(dev->regs + GSC_IRQ);
>> +       if (irq == GSC_OR_IRQ)
>> +               cfg |= GSC_IRQ_STATUS_OR_IRQ;
>> +       else if (irq == GSC_DONE_IRQ)
>> +               cfg |= GSC_IRQ_STATUS_OR_FRM_DONE;
>> +       writel(cfg, dev->regs + GSC_IRQ);
>> +}
>> +
>> +static inline void gsc_lock(struct vb2_queue *vq)
>> +{
>> +       struct gsc_ctx *ctx = vb2_get_drv_priv(vq);
>> +       mutex_lock(&ctx->gsc_dev->lock);
>> +}
>> +
>> +static inline void gsc_unlock(struct vb2_queue *vq)
>> +{
>> +       struct gsc_ctx *ctx = vb2_get_drv_priv(vq);
>> +       mutex_unlock(&ctx->gsc_dev->lock);
>> +}
>> +
>> +static inline bool gsc_ctx_state_is_set(u32 mask, struct gsc_ctx *ctx)
>> +{
>> +       unsigned long flags;
>> +       bool ret;
>> +
>> +       spin_lock_irqsave(&ctx->slock, flags);
>> +       ret = (ctx->state & mask) == mask;
>> +       spin_unlock_irqrestore(&ctx->slock, flags);
>> +       return ret;
>> +}
>> +
>> +static inline struct gsc_frame *ctx_get_frame(struct gsc_ctx *ctx,
>> +                                             enum v4l2_buf_type type)
>> +{
>> +       struct gsc_frame *frame;
>> +
>> +       if (V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == type) {
>> +               frame = &ctx->s_frame;
>> +       } else if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type) {
>> +               frame = &ctx->d_frame;
>> +       } else {
>> +               gsc_err("Wrong buffer/video queue type (%d)", type);
>> +               return ERR_PTR(-EINVAL);
>> +       }
>> +
>> +       return frame;
>> +}
>> +
>> +static inline void user_to_drv(struct v4l2_ctrl *ctrl, s32 value)
>> +{
>> +       ctrl->cur.val = ctrl->val = value;
>> +}
>
> This is fishy. Can you store the pointer to the control after s_ctrl returns?
>

Sorry.. i read the documentation... we can store the pointer but we
should not update values explicitly...
I will change this implementation.

>> +
>> +void gsc_hw_set_sw_reset(struct gsc_dev *dev);
>> +void gsc_hw_set_one_frm_mode(struct gsc_dev *dev, bool mask);
>
> Both never used.
>
>> +void gsc_hw_set_frm_done_irq_mask(struct gsc_dev *dev, bool mask);
>> +void gsc_hw_set_overflow_irq_mask(struct gsc_dev *dev, bool mask);
>
> Never used.
>
>> +void gsc_hw_set_gsc_irq_enable(struct gsc_dev *dev, bool mask);
>
>> +void gsc_hw_set_input_buf_mask_all(struct gsc_dev *dev);
>> +void gsc_hw_set_output_buf_mask_all(struct gsc_dev *dev);
>
> both never used
>
>> +void gsc_hw_set_input_buf_masking(struct gsc_dev *dev, u32 shift, bool enable);
>> +void gsc_hw_set_output_buf_masking(struct gsc_dev *dev, u32 shift, bool enable);
>> +void gsc_hw_set_input_addr(struct gsc_dev *dev, struct gsc_addr *addr,
>> +                                                       int index);
>> +void gsc_hw_set_output_addr(struct gsc_dev *dev, struct gsc_addr *addr,
>> +                                                       int index);
>> +void gsc_hw_set_input_path(struct gsc_ctx *ctx);
>> +void gsc_hw_set_in_size(struct gsc_ctx *ctx);
>> +void gsc_hw_set_in_image_rgb(struct gsc_ctx *ctx);
>> +void gsc_hw_set_in_image_format(struct gsc_ctx *ctx);
>> +void gsc_hw_set_output_path(struct gsc_ctx *ctx);
>> +void gsc_hw_set_out_size(struct gsc_ctx *ctx);
>> +void gsc_hw_set_out_image_rgb(struct gsc_ctx *ctx);
>> +void gsc_hw_set_out_image_format(struct gsc_ctx *ctx);
>> +void gsc_hw_set_prescaler(struct gsc_ctx *ctx);
>> +void gsc_hw_set_mainscaler(struct gsc_ctx *ctx);
>> +void gsc_hw_set_rotation(struct gsc_ctx *ctx);
>> +void gsc_hw_set_global_alpha(struct gsc_ctx *ctx);
>> +void gsc_hw_set_sfr_update(struct gsc_ctx *ctx);
>> +
>> +int gsc_hw_get_input_buf_mask_status(struct gsc_dev *dev);
>> +int gsc_hw_get_done_input_buf_index(struct gsc_dev *dev);
>> +int gsc_hw_get_nr_unmask_bits(struct gsc_dev *dev);
>> +int gsc_wait_reset(struct gsc_dev *dev);
>
> Above 4 never used.
>
>> +int gsc_wait_operating(struct gsc_dev *dev);
>> +int gsc_wait_stop(struct gsc_dev *dev);
>
> Never used.
>
>> +
>> +#endif /* GSC_CORE_H_ */
>> diff --git a/drivers/media/video/exynos/gsc/gsc-m2m.c b/drivers/media/video/exynos/gsc/gsc-m2m.c
>> new file mode 100644
>> index 0000000..ead59a0
>> --- /dev/null
>> +++ b/drivers/media/video/exynos/gsc/gsc-m2m.c
>> @@ -0,0 +1,751 @@
>> +/* linux/drivers/media/video/exynos/gsc/gsc-m2m.c
>> + *
>> + * Copyright (c) 2011 Samsung Electronics Co., Ltd.
>> + *             http://www.samsung.com
>> + *
>> + * Samsung EXYNOS5 SoC series G-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/module.h>
>> +#include <linux/kernel.h>
>> +#include <linux/version.h>
>> +#include <linux/types.h>
>> +#include <linux/errno.h>
>> +#include <linux/bug.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/workqueue.h>
>> +#include <linux/device.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/list.h>
>> +#include <linux/io.h>
>> +#include <linux/slab.h>
>> +#include <linux/clk.h>
>> +#include <media/v4l2-ioctl.h>
>> +
>> +#include "gsc-core.h"
>> +
>> +static int gsc_ctx_stop_req(struct gsc_ctx *ctx)
>> +{
>> +       struct gsc_ctx *curr_ctx;
>> +       struct gsc_dev *gsc = ctx->gsc_dev;
>> +       int ret = 0;
>> +
>> +       curr_ctx = v4l2_m2m_get_curr_priv(gsc->m2m.m2m_dev);
>> +       if (!gsc_m2m_run(gsc) || (curr_ctx != ctx))
>> +               return 0;
>> +       ctx->state |= GSC_CTX_STOP_REQ;
>> +       ret = wait_event_timeout(gsc->irq_queue,
>> +                       !gsc_ctx_state_is_set(GSC_CTX_STOP_REQ, ctx),
>> +                       GSC_SHUTDOWN_TIMEOUT);
>> +       if (!ret)
>> +               ret = -EBUSY;
>> +
>> +       return ret;
>> +}
>> +
>> +static int gsc_m2m_start_streaming(struct vb2_queue *q, unsigned int count)
>> +{
>> +       struct gsc_ctx *ctx = q->drv_priv;
>> +       int ret;
>> +
>> +       ret = pm_runtime_get_sync(&ctx->gsc_dev->pdev->dev);
>> +       return ret > 0 ? 0 : ret;
>> +}
>> +
>> +static int gsc_m2m_stop_streaming(struct vb2_queue *q)
>> +{
>> +       struct gsc_ctx *ctx = q->drv_priv;
>> +       struct gsc_dev *gsc = ctx->gsc_dev;
>> +       int ret;
>> +
>> +       ret = gsc_ctx_stop_req(ctx);
>> +       /* FIXME: need to add v4l2_m2m_job_finish(fail) if ret is timeout */
>
> Can we fix this?

Ok. I will fix this and all others...

>
>> +       if (ret < 0)
>> +               dev_err(&gsc->pdev->dev, "wait timeout : %s\n", __func__);
>> +
>> +       pm_runtime_put(&ctx->gsc_dev->pdev->dev);
>> +
>> +       return 0;
>> +}
>> +
>> +static void gsc_m2m_job_abort(void *priv)
>> +{
>> +       struct gsc_ctx *ctx = priv;
>> +       struct gsc_dev *gsc = ctx->gsc_dev;
>> +       int ret;
>> +
>> +       ret = gsc_ctx_stop_req(ctx);
>> +       /* FIXME: need to add v4l2_m2m_job_finish(fail) if ret is timeout */
>
> Can we fix this?
>
>> +       if (ret < 0)
>> +               dev_err(&gsc->pdev->dev, "wait timeout : %s\n", __func__);
>> +}
>> +
>> +int gsc_fill_addr(struct gsc_ctx *ctx)
>> +{
>> +       struct gsc_frame *s_frame, *d_frame;
>> +       struct vb2_buffer *vb = NULL;
>> +       int ret = 0;
>> +
>> +       s_frame = &ctx->s_frame;
>> +       d_frame = &ctx->d_frame;
>> +
>> +       vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
>> +       ret = gsc_prepare_addr(ctx, vb, s_frame, &s_frame->addr);
>> +       if (ret)
>> +               return ret;
>> +
>> +       vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
>> +       ret = gsc_prepare_addr(ctx, vb, d_frame, &d_frame->addr);
>> +
>> +       return ret;
>> +}
>> +
>> +static void gsc_m2m_device_run(void *priv)
>> +{
>> +       struct gsc_ctx *ctx = priv;
>> +       struct gsc_dev *gsc;
>> +       unsigned long flags;
>> +       u32 ret;
>> +       bool is_set = false;
>> +
>> +       if (WARN(!ctx, "null hardware context\n"))
>> +               return;
>> +
>> +       gsc = ctx->gsc_dev;
>> +
>> +       spin_lock_irqsave(&ctx->slock, flags);
>> +       /* Reconfigure hardware if the context has changed. */
>> +       if (gsc->m2m.ctx != ctx) {
>> +               gsc_dbg("gsc->m2m.ctx = 0x%p, current_ctx = 0x%p",
>> +                         gsc->m2m.ctx, ctx);
>> +               ctx->state |= GSC_PARAMS;
>> +               gsc->m2m.ctx = ctx;
>> +       }
>> +
>> +       is_set = (ctx->state & GSC_CTX_STOP_REQ) ? 1 : 0;
>> +       ctx->state &= ~GSC_CTX_STOP_REQ;
>> +       if (is_set) {
>> +               wake_up(&gsc->irq_queue);
>> +               goto put_device;
>> +       }
>> +
>> +       ret = gsc_fill_addr(ctx);
>> +       if (ret) {
>> +               gsc_err("Wrong address");
>> +               goto put_device;
>> +       }
>> +
>> +       gsc_set_prefbuf(gsc, ctx->s_frame);
>> +       gsc_hw_set_input_addr(gsc, &ctx->s_frame.addr, GSC_M2M_BUF_NUM);
>> +       gsc_hw_set_output_addr(gsc, &ctx->d_frame.addr, GSC_M2M_BUF_NUM);
>> +
>> +       if (ctx->state & GSC_PARAMS) {
>> +               gsc_hw_set_input_buf_masking(gsc, GSC_M2M_BUF_NUM, false);
>> +               gsc_hw_set_output_buf_masking(gsc, GSC_M2M_BUF_NUM, false);
>> +               gsc_hw_set_frm_done_irq_mask(gsc, false);
>> +               gsc_hw_set_gsc_irq_enable(gsc, true);
>> +
>> +               if (gsc_set_scaler_info(ctx)) {
>> +                       gsc_err("Scaler setup error");
>> +                       goto put_device;
>> +               }
>> +
>> +               gsc_hw_set_input_path(ctx);
>> +               gsc_hw_set_in_size(ctx);
>> +               gsc_hw_set_in_image_format(ctx);
>> +
>> +               gsc_hw_set_output_path(ctx);
>> +               gsc_hw_set_out_size(ctx);
>> +               gsc_hw_set_out_image_format(ctx);
>> +
>> +               gsc_hw_set_prescaler(ctx);
>> +               gsc_hw_set_mainscaler(ctx);
>> +               gsc_hw_set_rotation(ctx);
>> +               gsc_hw_set_global_alpha(ctx);
>> +       }
>> +       /* When you update SFRs in the middle of operating
>> +       gsc_hw_set_sfr_update(ctx);
>> +       */
>
> Leftover?
>
>> +
>> +       ctx->state &= ~GSC_PARAMS;
>> +
>> +       if (!test_and_set_bit(ST_M2M_RUN, &gsc->state)) {
>> +               /* One frame mode sequence
>> +                GSCALER_ON on -> GSCALER_OP_STATUS is operating ->
>> +                GSCALER_ON off */
>> +               gsc_hw_enable_control(gsc, true);
>> +               ret = gsc_wait_operating(gsc);
>> +               if (ret < 0) {
>> +                       gsc_err("gscaler wait operating timeout");
>> +                       goto put_device;
>> +               }
>> +               gsc_hw_enable_control(gsc, false);
>> +       }
>> +
>> +       spin_unlock_irqrestore(&ctx->slock, flags);
>> +       return;
>> +
>> +put_device:
>> +       ctx->state &= ~GSC_PARAMS;
>> +       spin_unlock_irqrestore(&ctx->slock, flags);
>> +}
>> +
>> +static int gsc_m2m_queue_setup(struct vb2_queue *vq,
>> +                       const struct v4l2_format *fmt,
>> +                       unsigned int *num_buffers, unsigned int *num_planes,
>> +                       unsigned int sizes[], void *allocators[])
>> +{
>> +       struct gsc_ctx *ctx = vb2_get_drv_priv(vq);
>> +       struct gsc_frame *frame;
>> +       int i;
>> +
>> +       frame = ctx_get_frame(ctx, vq->type);
>> +       if (IS_ERR(frame))
>> +               return PTR_ERR(frame);
>> +
>> +       if (!frame->fmt)
>> +               return -EINVAL;
>> +
>> +       *num_planes = frame->fmt->num_planes;
>> +       for (i = 0; i < frame->fmt->num_planes; i++) {
>> +               sizes[i] = get_plane_size(frame, i);
>> +               allocators[i] = ctx->gsc_dev->alloc_ctx;
>> +       }
>> +       return 0;
>> +}
>> +
>> +static int gsc_m2m_buf_prepare(struct vb2_buffer *vb)
>> +{
>> +       struct gsc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
>> +       struct gsc_frame *frame;
>> +       int i;
>> +
>> +       frame = ctx_get_frame(ctx, vb->vb2_queue->type);
>> +       if (IS_ERR(frame))
>> +               return PTR_ERR(frame);
>> +
>> +       if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
>> +               for (i = 0; i < frame->fmt->num_planes; i++)
>> +                       vb2_set_plane_payload(vb, i, frame->payload[i]);
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static void gsc_m2m_buf_queue(struct vb2_buffer *vb)
>> +{
>> +       struct gsc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
>> +
>> +       gsc_dbg("ctx: %p, ctx->state: 0x%x", ctx, ctx->state);
>> +
>> +       if (ctx->m2m_ctx)
>> +               v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
>> +}
>> +
>> +struct vb2_ops gsc_m2m_qops = {
>> +       .queue_setup     = gsc_m2m_queue_setup,
>> +       .buf_prepare     = gsc_m2m_buf_prepare,
>> +       .buf_queue       = gsc_m2m_buf_queue,
>> +       .wait_prepare    = gsc_unlock,
>> +       .wait_finish     = gsc_lock,
>> +       .stop_streaming  = gsc_m2m_stop_streaming,
>> +       .start_streaming = gsc_m2m_start_streaming,
>> +};
>> +
>> +static int gsc_m2m_querycap(struct file *file, void *fh,
>> +                          struct v4l2_capability *cap)
>> +{
>> +       struct gsc_ctx *ctx = fh_to_ctx(fh);
>> +       struct gsc_dev *gsc = ctx->gsc_dev;
>> +
>> +       strncpy(cap->driver, gsc->pdev->name, sizeof(cap->driver) - 1);
>> +       strncpy(cap->card, gsc->pdev->name, sizeof(cap->card) - 1);
>> +       cap->bus_info[0] = 0;
>> +       cap->capabilities = V4L2_CAP_STREAMING |
>> +               V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
>> +
>> +       return 0;
>> +}
>> +
>> +static int gsc_m2m_enum_fmt_mplane(struct file *file, void *priv,
>> +                               struct v4l2_fmtdesc *f)
>> +{
>> +       return gsc_enum_fmt_mplane(f);
>> +}
>> +
>> +static int gsc_m2m_g_fmt_mplane(struct file *file, void *fh,
>> +                            struct v4l2_format *f)
>> +{
>> +       struct gsc_ctx *ctx = fh_to_ctx(fh);
>> +
>> +       return gsc_g_fmt_mplane(ctx, f);
>> +}
>> +
>> +static int gsc_m2m_try_fmt_mplane(struct file *file, void *fh,
>> +                                 struct v4l2_format *f)
>> +{
>> +       struct gsc_ctx *ctx = fh_to_ctx(fh);
>> +
>> +       return gsc_try_fmt_mplane(ctx, f);
>> +}
>> +
>> +static int gsc_m2m_s_fmt_mplane(struct file *file, void *fh,
>> +                                struct v4l2_format *f)
>> +{
>> +       struct gsc_ctx *ctx = fh_to_ctx(fh);
>> +       struct vb2_queue *vq;
>> +       struct gsc_frame *frame;
>> +       struct v4l2_pix_format_mplane *pix;
>> +       int i, ret = 0;
>> +
>> +       ret = gsc_m2m_try_fmt_mplane(file, fh, f);
>> +       if (ret)
>> +               return ret;
>> +
>> +       vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
>> +
>> +       if (vb2_is_streaming(vq)) {
>> +               gsc_err("queue (%d) busy", f->type);
>> +               return -EBUSY;
>> +       }
>> +
>> +       if (V4L2_TYPE_IS_OUTPUT(f->type))
>> +               frame = &ctx->s_frame;
>> +       else
>> +               frame = &ctx->d_frame;
>> +
>> +       pix = &f->fmt.pix_mp;
>> +       frame->fmt = find_fmt(&pix->pixelformat, NULL, 0);
>> +       if (!frame->fmt)
>> +               return -EINVAL;
>> +
>> +       for (i = 0; i < frame->fmt->num_planes; i++)
>> +               frame->payload[i] = pix->plane_fmt[i].sizeimage;
>> +
>> +       gsc_set_frame_size(frame, pix->width, pix->height);
>> +
>> +       if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
>> +               gsc_ctx_state_lock_set(GSC_PARAMS | GSC_DST_FMT, ctx);
>> +       else
>> +               gsc_ctx_state_lock_set(GSC_PARAMS | GSC_SRC_FMT, ctx);
>> +
>> +       gsc_dbg("f_w: %d, f_h: %d", frame->f_width, frame->f_height);
>> +
>> +       return 0;
>> +}
>> +
>> +static int gsc_m2m_reqbufs(struct file *file, void *fh,
>> +                         struct v4l2_requestbuffers *reqbufs)
>> +{
>> +       struct gsc_ctx *ctx = fh_to_ctx(fh);
>> +       struct gsc_dev *gsc = ctx->gsc_dev;
>> +       struct gsc_frame *frame;
>> +       u32 max_cnt;
>> +
>> +       max_cnt = (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ?
>> +               gsc->variant->in_buf_cnt : gsc->variant->out_buf_cnt;
>> +       if (reqbufs->count > max_cnt)
>> +               return -EINVAL;
>
> Needs braces.

Ok. I will fix.

>
>> +       else if (reqbufs->count == 0) {
>> +               if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
>> +                       gsc_ctx_state_lock_clear(GSC_SRC_FMT, ctx);
>> +               else
>> +                       gsc_ctx_state_lock_clear(GSC_DST_FMT, ctx);
>> +       }
>> +
>> +       frame = ctx_get_frame(ctx, reqbufs->type);
>> +
>> +       return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
>> +}
>> +
>> +static int gsc_m2m_querybuf(struct file *file, void *fh,
>> +                                       struct v4l2_buffer *buf)
>> +{
>> +       struct gsc_ctx *ctx = fh_to_ctx(fh);
>> +       return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
>> +}
>> +
>> +static int gsc_m2m_qbuf(struct file *file, void *fh,
>> +                         struct v4l2_buffer *buf)
>> +{
>> +       struct gsc_ctx *ctx = fh_to_ctx(fh);
>> +       return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
>> +}
>> +
>> +static int gsc_m2m_dqbuf(struct file *file, void *fh,
>> +                          struct v4l2_buffer *buf)
>> +{
>> +       struct gsc_ctx *ctx = fh_to_ctx(fh);
>> +       return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
>> +}
>> +
>> +static int gsc_m2m_streamon(struct file *file, void *fh,
>> +                          enum v4l2_buf_type type)
>> +{
>> +       struct gsc_ctx *ctx = fh_to_ctx(fh);
>> +
>> +       /* The source and target color format need to be set */
>> +       if (V4L2_TYPE_IS_OUTPUT(type)) {
>> +               if (!gsc_ctx_state_is_set(GSC_SRC_FMT, ctx))
>> +                       return -EINVAL;
>> +       } else if (!gsc_ctx_state_is_set(GSC_DST_FMT, ctx)) {
>> +               return -EINVAL;
>> +       }
>> +
>> +       return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
>> +}
>> +
>> +static int gsc_m2m_streamoff(struct file *file, void *fh,
>> +                           enum v4l2_buf_type type)
>> +{
>> +       struct gsc_ctx *ctx = fh_to_ctx(fh);
>> +       return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
>> +}
>> +
>> +/* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */
>> +static int is_rectangle_enclosed(struct v4l2_rect *a, struct v4l2_rect *b)
>> +{
>> +       if (a->left < b->left || a->top < b->top)
>> +               return 0;
>> +
>> +       if (a->left + a->width > b->left + b->width)
>> +               return 0;
>> +
>> +       if (a->top + a->height > b->top + b->height)
>> +               return 0;
>> +
>> +       return 1;
>> +}
>> +
>> +static int gsc_m2m_g_selection(struct file *file, void *fh,
>> +                       struct v4l2_selection *s)
>> +{
>> +       struct gsc_frame *frame;
>> +       struct gsc_ctx *ctx = fh_to_ctx(fh);
>> +
>> +       if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
>> +           (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE))
>> +               return -EINVAL;
>> +
>> +       frame = ctx_get_frame(ctx, s->type);
>> +       if (IS_ERR(frame))
>> +               return PTR_ERR(frame);
>> +
>> +       switch (s->target) {
>> +       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
>> +       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
>> +       case V4L2_SEL_TGT_CROP_BOUNDS:
>> +       case V4L2_SEL_TGT_CROP_DEFAULT:
>> +               s->r.left = 0;
>> +               s->r.top = 0;
>> +               s->r.width = frame->f_width;
>> +               s->r.height = frame->f_height;
>> +               return 0;
>> +
>> +       case V4L2_SEL_TGT_COMPOSE_ACTIVE:
>> +       case V4L2_SEL_TGT_CROP_ACTIVE:
>> +               s->r.left = frame->crop.left;
>> +               s->r.top = frame->crop.top;
>> +               s->r.width = frame->crop.width;
>> +               s->r.height = frame->crop.height;
>> +               return 0;
>> +       }
>> +
>> +       return -EINVAL;
>> +}
>> +
>> +static int gsc_m2m_s_selection(struct file *file, void *fh,
>> +                       struct v4l2_selection *s)
>> +{
>> +       struct gsc_frame *frame;
>> +       struct gsc_ctx *ctx = fh_to_ctx(fh);
>> +       struct v4l2_crop cr;
>> +       struct gsc_variant *variant = ctx->gsc_dev->variant;
>> +       int ret;
>> +
>> +       cr.type = s->type;
>> +       cr.c = s->r;
>> +
>> +       if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
>> +           (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE))
>> +               return -EINVAL;
>> +
>> +       ret = gsc_try_crop(ctx, &cr);
>> +       if (ret)
>> +               return ret;
>> +
>> +       if (s->flags & V4L2_SEL_FLAG_LE &&
>> +           !is_rectangle_enclosed(&cr.c, &s->r))
>> +               return -ERANGE;
>> +
>> +       if (s->flags & V4L2_SEL_FLAG_GE &&
>> +           !is_rectangle_enclosed(&s->r, &cr.c))
>> +               return -ERANGE;
>> +
>> +       s->r = cr.c;
>> +
>> +       switch (s->target) {
>> +       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
>> +       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
>> +       case V4L2_SEL_TGT_COMPOSE_ACTIVE:
>> +               frame = &ctx->s_frame;
>> +               break;
>> +
>> +       case V4L2_SEL_TGT_CROP_BOUNDS:
>> +       case V4L2_SEL_TGT_CROP_ACTIVE:
>> +       case V4L2_SEL_TGT_CROP_DEFAULT:
>> +               frame = &ctx->d_frame;
>> +               break;
>> +
>> +       default:
>> +               return -EINVAL;
>> +       }
>> +
>> +       /* Check to see if scaling ratio is within supported range */
>> +       if (gsc_ctx_state_is_set(GSC_DST_FMT | GSC_SRC_FMT, ctx)) {
>> +               if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
>> +                       ret = gsc_check_scaler_ratio(variant, cr.c.width,
>> +                               cr.c.height, ctx->d_frame.crop.width,
>> +                               ctx->d_frame.crop.height,
>> +                               ctx->gsc_ctrls.rotate->val, ctx->out_path);
>> +               } else {
>> +                       ret = gsc_check_scaler_ratio(variant,
>> +                               ctx->s_frame.crop.width,
>> +                               ctx->s_frame.crop.height, cr.c.width,
>> +                               cr.c.height, ctx->gsc_ctrls.rotate->val,
>> +                               ctx->out_path);
>> +               }
>> +
>> +               if (ret) {
>> +                       gsc_err("Out of scaler range");
>> +                       return -EINVAL;
>> +               }
>> +       }
>> +
>> +       frame->crop = cr.c;
>> +
>> +       gsc_ctx_state_lock_set(GSC_PARAMS, ctx);
>> +       return 0;
>> +}
>> +
>> +static const struct v4l2_ioctl_ops gsc_m2m_ioctl_ops = {
>> +       .vidioc_querycap                = gsc_m2m_querycap,
>> +
>> +       .vidioc_enum_fmt_vid_cap_mplane = gsc_m2m_enum_fmt_mplane,
>> +       .vidioc_enum_fmt_vid_out_mplane = gsc_m2m_enum_fmt_mplane,
>> +
>> +       .vidioc_g_fmt_vid_cap_mplane    = gsc_m2m_g_fmt_mplane,
>> +       .vidioc_g_fmt_vid_out_mplane    = gsc_m2m_g_fmt_mplane,
>> +
>> +       .vidioc_try_fmt_vid_cap_mplane  = gsc_m2m_try_fmt_mplane,
>> +       .vidioc_try_fmt_vid_out_mplane  = gsc_m2m_try_fmt_mplane,
>> +
>> +       .vidioc_s_fmt_vid_cap_mplane    = gsc_m2m_s_fmt_mplane,
>> +       .vidioc_s_fmt_vid_out_mplane    = gsc_m2m_s_fmt_mplane,
>> +
>> +       .vidioc_reqbufs                 = gsc_m2m_reqbufs,
>> +       .vidioc_querybuf                = gsc_m2m_querybuf,
>> +
>> +       .vidioc_qbuf                    = gsc_m2m_qbuf,
>> +       .vidioc_dqbuf                   = gsc_m2m_dqbuf,
>> +
>> +       .vidioc_streamon                = gsc_m2m_streamon,
>> +       .vidioc_streamoff               = gsc_m2m_streamoff,
>> +
>> +       .vidioc_g_selection             = gsc_m2m_g_selection,
>> +       .vidioc_s_selection             = gsc_m2m_s_selection
>> +
>> +};
>> +
>> +static int queue_init(void *priv, struct vb2_queue *src_vq,
>> +                     struct vb2_queue *dst_vq)
>> +{
>> +       struct gsc_ctx *ctx = priv;
>> +       int ret;
>> +
>> +       memset(src_vq, 0, sizeof(*src_vq));
>> +       src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
>> +       src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
>> +       src_vq->drv_priv = ctx;
>> +       src_vq->ops = &gsc_m2m_qops;
>> +       src_vq->mem_ops = &vb2_dma_contig_memops;
>> +       src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
>> +
>> +       ret = vb2_queue_init(src_vq);
>> +       if (ret)
>> +               return ret;
>> +
>> +       memset(dst_vq, 0, sizeof(*dst_vq));
>> +       dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
>> +       dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
>> +       dst_vq->drv_priv = ctx;
>> +       dst_vq->ops = &gsc_m2m_qops;
>> +       dst_vq->mem_ops = &vb2_dma_contig_memops;
>> +       dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
>> +
>> +       return vb2_queue_init(dst_vq);
>> +}
>> +
>> +static int gsc_m2m_open(struct file *file)
>> +{
>> +       struct gsc_dev *gsc = video_drvdata(file);
>> +       struct gsc_ctx *ctx = NULL;
>> +       int ret;
>> +
>> +       gsc_dbg("pid: %d, state: 0x%lx", task_pid_nr(current), gsc->state);
>> +
>> +       ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
>> +       if (!ctx)
>> +               return -ENOMEM;
>> +
>> +       v4l2_fh_init(&ctx->fh, gsc->m2m.vfd);
>> +       ret = gsc_ctrls_create(ctx);
>> +       if (ret)
>> +               goto error_fh;
>> +
>> +       /* Use separate control handler per file handle */
>> +       ctx->fh.ctrl_handler = &ctx->ctrl_handler;
>> +       file->private_data = &ctx->fh;
>> +       v4l2_fh_add(&ctx->fh);
>> +
>> +       ctx->gsc_dev = gsc;
>> +       /* Default color format */
>> +       ctx->s_frame.fmt = get_format(0);
>> +       ctx->d_frame.fmt = get_format(0);
>> +       /* Setup the device context for mem2mem mode. */
>> +       ctx->state |= GSC_CTX_M2M;
>> +       ctx->flags = 0;
>> +       ctx->in_path = GSC_DMA;
>> +       ctx->out_path = GSC_DMA;
>> +       spin_lock_init(&ctx->slock);
>> +
>> +       ctx->m2m_ctx = v4l2_m2m_ctx_init(gsc->m2m.m2m_dev, ctx, queue_init);
>> +       if (IS_ERR(ctx->m2m_ctx)) {
>> +               gsc_err("Failed to initialize m2m context");
>> +               ret = PTR_ERR(ctx->m2m_ctx);
>> +               goto error_fh;
>> +       }
>> +
>> +       if (gsc->m2m.refcnt++ == 0)
>> +               set_bit(ST_M2M_OPEN, &gsc->state);
>> +
>> +       gsc_dbg("gsc m2m driver is opened, ctx(0x%p)", ctx);
>> +       return 0;
>> +
>> +error_fh:
>
> No need to ctrls_delete somewhere here as well?
>

Ok. I will fix.

>> +       v4l2_fh_del(&ctx->fh);
>> +       v4l2_fh_exit(&ctx->fh);
>> +       kfree(ctx);
>> +       return ret;
>> +}
>> +
>> +static int gsc_m2m_release(struct file *file)
>> +{
>> +       struct gsc_ctx *ctx = fh_to_ctx(file->private_data);
>> +       struct gsc_dev *gsc = ctx->gsc_dev;
>> +
>> +       gsc_dbg("pid: %d, state: 0x%lx, refcnt= %d",
>> +               task_pid_nr(current), gsc->state, gsc->m2m.refcnt);
>> +
>> +       v4l2_m2m_ctx_release(ctx->m2m_ctx);
>> +       gsc_ctrls_delete(ctx);
>> +       v4l2_fh_del(&ctx->fh);
>> +       v4l2_fh_exit(&ctx->fh);
>> +
>> +       if (--gsc->m2m.refcnt <= 0)
>> +               clear_bit(ST_M2M_OPEN, &gsc->state);
>> +       kfree(ctx);
>> +       return 0;
>> +}
>> +
>> +static unsigned int gsc_m2m_poll(struct file *file,
>> +                                    struct poll_table_struct *wait)
>> +{
>> +       struct gsc_ctx *ctx = fh_to_ctx(file->private_data);
>> +
>> +       return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
>> +}
>> +
>> +static int gsc_m2m_mmap(struct file *file, struct vm_area_struct *vma)
>> +{
>> +       struct gsc_ctx *ctx = fh_to_ctx(file->private_data);
>> +
>> +       return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
>> +}
>> +static const struct v4l2_file_operations gsc_m2m_fops = {
>> +       .owner          = THIS_MODULE,
>> +       .open           = gsc_m2m_open,
>> +       .release        = gsc_m2m_release,
>> +       .poll           = gsc_m2m_poll,
>> +       .unlocked_ioctl = video_ioctl2,
>> +       .mmap           = gsc_m2m_mmap,
>> +};
>> +
>> +static struct v4l2_m2m_ops gsc_m2m_ops = {
>> +       .device_run     = gsc_m2m_device_run,
>> +       .job_abort      = gsc_m2m_job_abort,
>> +};
>> +
>> +int gsc_register_m2m_device(struct gsc_dev *gsc)
>> +{
>> +       struct video_device *vfd;
>> +       struct platform_device *pdev;
>> +       int ret = 0;
>> +
>> +       if (!gsc)
>> +               return -ENODEV;
>> +
>> +       pdev = gsc->pdev;
>> +
>> +       vfd = video_device_alloc();
>> +       if (!vfd) {
>> +               dev_err(&pdev->dev, "Failed to allocate video device\n");
>> +               return -ENOMEM;
>> +       }
>> +
>> +       vfd->fops       = &gsc_m2m_fops;
>> +       vfd->ioctl_ops  = &gsc_m2m_ioctl_ops;
>> +       vfd->release    = video_device_release;
>> +       vfd->lock       = &gsc->lock;
>> +       snprintf(vfd->name, sizeof(vfd->name), "%s.%d:m2m",
>> +                                       GSC_MODULE_NAME, gsc->id);
>> +
>> +       video_set_drvdata(vfd, gsc);
>> +
>> +       gsc->m2m.vfd = vfd;
>> +       gsc->m2m.m2m_dev = v4l2_m2m_init(&gsc_m2m_ops);
>> +       if (IS_ERR(gsc->m2m.m2m_dev)) {
>> +               dev_err(&pdev->dev, "failed to initialize v4l2-m2m device\n");
>> +               ret = PTR_ERR(gsc->m2m.m2m_dev);
>> +               goto err_m2m_r1;
>> +       }
>> +
>> +       ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
>> +       if (ret) {
>> +               dev_err(&pdev->dev,
>> +                        "%s(): failed to register video device\n", __func__);
>> +               goto err_m2m_r2;
>> +       }
>> +
>> +       gsc_dbg("gsc m2m driver registered as /dev/video%d", vfd->num);
>> +
>> +       return 0;
>> +
>> +err_m2m_r2:
>> +       v4l2_m2m_release(gsc->m2m.m2m_dev);
>> +err_m2m_r1:
>> +       video_device_release(gsc->m2m.vfd);
>> +
>> +       return ret;
>> +}
>> +
>> +void gsc_unregister_m2m_device(struct gsc_dev *gsc)
>> +{
>> +       if (gsc)
>> +               v4l2_m2m_release(gsc->m2m.m2m_dev);
>> +}
>> diff --git a/drivers/media/video/exynos/gsc/gsc-regs.c b/drivers/media/video/exynos/gsc/gsc-regs.c
>> new file mode 100644
>> index 0000000..7c5cce2
>> --- /dev/null
>> +++ b/drivers/media/video/exynos/gsc/gsc-regs.c
>> @@ -0,0 +1,579 @@
>> +/* linux/drivers/media/video/exynos/gsc/gsc-regs.c
>> + *
>> + * Copyright (c) 2011 Samsung Electronics Co., Ltd.
>> + *             http://www.samsung.com
>> + *
>> + * Samsung EXYNOS5 SoC series G-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/io.h>
>> +#include <linux/delay.h>
>> +#include <mach/map.h>
>> +#include "gsc-core.h"
>> +
>> +void gsc_hw_set_sw_reset(struct gsc_dev *dev)
>> +{
>> +       u32 cfg = 0;
>> +
>> +       cfg |= GSC_SW_RESET_SRESET;
>> +       writel(cfg, dev->regs + GSC_SW_RESET);
>> +}
>> +
>> +int gsc_wait_reset(struct gsc_dev *dev)
>> +{
>> +       unsigned long timeo = jiffies + 10; /* timeout of 50ms */
>> +       u32 cfg;
>> +
>> +       while (time_before(jiffies, timeo)) {
>> +               cfg = readl(dev->regs + GSC_SW_RESET);
>> +               if (!cfg)
>> +                       return 0;
>> +               usleep_range(10, 20);
>> +       }
>> +       gsc_dbg("wait time : %d ms", jiffies_to_msecs(jiffies - timeo + 20));
>> +
>> +       return -EBUSY;
>> +}
>> +
>> +int gsc_wait_operating(struct gsc_dev *dev)
>> +{
>> +       unsigned long timeo = jiffies + 10; /* timeout of 50ms */
>> +       u32 cfg;
>> +
>> +       while (time_before(jiffies, timeo)) {
>> +               cfg = readl(dev->regs + GSC_ENABLE);
>> +               if ((cfg & GSC_ENABLE_OP_STATUS) == GSC_ENABLE_OP_STATUS)
>> +                       return 0;
>> +               usleep_range(10, 20);
>> +       }
>> +       gsc_dbg("wait time : %d ms", jiffies_to_msecs(jiffies - timeo + 20));
>> +
>> +       return -EBUSY;
>> +}
>> +
>> +int gsc_wait_stop(struct gsc_dev *dev)
>> +{
>> +       unsigned long timeo = jiffies + 10; /* timeout of 50ms */
>> +       u32 cfg;
>> +
>> +       while (time_before(jiffies, timeo)) {
>> +               cfg = readl(dev->regs + GSC_ENABLE);
>> +               if (!(cfg & GSC_ENABLE_OP_STATUS))
>> +                       return 0;
>> +               usleep_range(10, 20);
>> +       }
>> +       gsc_dbg("wait time : %d ms", jiffies_to_msecs(jiffies - timeo + 20));
>> +
>> +       return -EBUSY;
>> +}
>> +
>> +
>> +void gsc_hw_set_one_frm_mode(struct gsc_dev *dev, bool mask)
>> +{
>> +       u32 cfg;
>> +
>> +       cfg = readl(dev->regs + GSC_ENABLE);
>> +       if (mask)
>> +               cfg |= GSC_ENABLE_ON_CLEAR;
>> +       else
>> +               cfg &= ~GSC_ENABLE_ON_CLEAR;
>> +       writel(cfg, dev->regs + GSC_ENABLE);
>> +}
>> +
>> +int gsc_hw_get_input_buf_mask_status(struct gsc_dev *dev)
>> +{
>> +       u32 cfg, status, bits = 0;
>> +
>> +       cfg = readl(dev->regs + GSC_IN_BASE_ADDR_Y_MASK);
>> +       status = cfg & GSC_IN_BASE_ADDR_MASK;
>> +       while (status) {
>> +               status = status & (status - 1);
>> +               bits++;
>> +       }
>> +       return bits;
>> +}
>> +
>> +int gsc_hw_get_done_input_buf_index(struct gsc_dev *dev)
>> +{
>> +       u32 cfg, curr_index, i;
>> +
>> +       cfg = readl(dev->regs + GSC_IN_BASE_ADDR_Y_MASK);
>> +       curr_index = GSC_IN_CURR_GET_INDEX(cfg);
>> +       for (i = curr_index; i > 1; i--) {
>> +               if (cfg ^ (1 << (i - 2)))
>> +                       return i - 2;
>> +       }
>> +
>> +       for (i = dev->variant->in_buf_cnt; i > curr_index; i--) {
>> +               if (cfg ^ (1 << (i - 1)))
>> +                       return i - 1;
>> +       }
>> +
>> +       return curr_index - 1;
>> +}
>> +
>> +void gsc_hw_set_frm_done_irq_mask(struct gsc_dev *dev, bool mask)
>> +{
>> +       u32 cfg;
>> +
>> +       cfg = readl(dev->regs + GSC_IRQ);
>> +       if (mask)
>> +               cfg |= GSC_IRQ_FRMDONE_MASK;
>> +       else
>> +               cfg &= ~GSC_IRQ_FRMDONE_MASK;
>> +       writel(cfg, dev->regs + GSC_IRQ);
>> +}
>> +
>> +void gsc_hw_set_overflow_irq_mask(struct gsc_dev *dev, bool mask)
>> +{
>> +       u32 cfg;
>> +
>> +       cfg = readl(dev->regs + GSC_IRQ);
>> +       if (mask)
>> +               cfg |= GSC_IRQ_OR_MASK;
>> +       else
>> +               cfg &= ~GSC_IRQ_OR_MASK;
>> +       writel(cfg, dev->regs + GSC_IRQ);
>> +}
>> +
>> +void gsc_hw_set_gsc_irq_enable(struct gsc_dev *dev, bool mask)
>> +{
>> +       u32 cfg;
>> +
>> +       cfg = readl(dev->regs + GSC_IRQ);
>> +       if (mask)
>> +               cfg |= GSC_IRQ_ENABLE;
>> +       else
>> +               cfg &= ~GSC_IRQ_ENABLE;
>> +       writel(cfg, dev->regs + GSC_IRQ);
>> +}
>> +
>> +void gsc_hw_set_input_buf_mask_all(struct gsc_dev *dev)
>> +{
>> +       u32 cfg;
>> +
>> +       cfg = readl(dev->regs + GSC_IN_BASE_ADDR_Y_MASK);
>> +       cfg |= GSC_IN_BASE_ADDR_MASK;
>> +       cfg |= GSC_IN_BASE_ADDR_PINGPONG(dev->variant->in_buf_cnt);
>> +
>> +       writel(cfg, dev->regs + GSC_IN_BASE_ADDR_Y_MASK);
>> +       writel(cfg, dev->regs + GSC_IN_BASE_ADDR_CB_MASK);
>> +       writel(cfg, dev->regs + GSC_IN_BASE_ADDR_CR_MASK);
>> +}
>> +
>> +void gsc_hw_set_output_buf_mask_all(struct gsc_dev *dev)
>> +{
>> +       u32 cfg;
>> +
>> +       cfg = readl(dev->regs + GSC_OUT_BASE_ADDR_Y_MASK);
>> +       cfg |= GSC_OUT_BASE_ADDR_MASK;
>> +       cfg |= GSC_OUT_BASE_ADDR_PINGPONG(dev->variant->out_buf_cnt);
>> +
>> +       writel(cfg, dev->regs + GSC_OUT_BASE_ADDR_Y_MASK);
>> +       writel(cfg, dev->regs + GSC_OUT_BASE_ADDR_CB_MASK);
>> +       writel(cfg, dev->regs + GSC_OUT_BASE_ADDR_CR_MASK);
>> +}
>> +
>> +void gsc_hw_set_input_buf_masking(struct gsc_dev *dev, u32 shift,
>> +                               bool enable)
>> +{
>> +       u32 cfg = readl(dev->regs + GSC_IN_BASE_ADDR_Y_MASK);
>> +       u32 mask = 1 << shift;
>> +
>> +       cfg &= (~mask);
>> +       cfg |= enable << shift;
>> +
>> +       writel(cfg, dev->regs + GSC_IN_BASE_ADDR_Y_MASK);
>> +       writel(cfg, dev->regs + GSC_IN_BASE_ADDR_CB_MASK);
>> +       writel(cfg, dev->regs + GSC_IN_BASE_ADDR_CR_MASK);
>> +}
>> +
>> +void gsc_hw_set_output_buf_masking(struct gsc_dev *dev, u32 shift,
>> +                               bool enable)
>> +{
>> +       u32 cfg = readl(dev->regs + GSC_OUT_BASE_ADDR_Y_MASK);
>> +       u32 mask = 1 << shift;
>> +
>> +       cfg &= (~mask);
>> +       cfg |= enable << shift;
>> +
>> +       writel(cfg, dev->regs + GSC_OUT_BASE_ADDR_Y_MASK);
>> +       writel(cfg, dev->regs + GSC_OUT_BASE_ADDR_CB_MASK);
>> +       writel(cfg, dev->regs + GSC_OUT_BASE_ADDR_CR_MASK);
>> +}
>> +
>> +int gsc_hw_get_nr_unmask_bits(struct gsc_dev *dev)
>> +{
>> +       u32 bits = 0;
>> +       u32 mask_bits = readl(dev->regs + GSC_OUT_BASE_ADDR_Y_MASK);
>> +       mask_bits &= GSC_OUT_BASE_ADDR_MASK;
>> +
>> +       while (mask_bits) {
>> +               mask_bits = mask_bits & (mask_bits - 1);
>
> mask_bits &=
>
>> +               bits++;
>> +       }
>> +       bits = 16 - bits;
>> +
>> +       return bits;
>> +}
>> +
>> +void gsc_hw_set_input_addr(struct gsc_dev *dev, struct gsc_addr *addr,
>> +                               int index)
>> +{
>> +       gsc_dbg("src_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X", index,
>> +               addr->y, addr->cb, addr->cr);
>> +       writel(addr->y, dev->regs + GSC_IN_BASE_ADDR_Y(index));
>> +       writel(addr->cb, dev->regs + GSC_IN_BASE_ADDR_CB(index));
>> +       writel(addr->cr, dev->regs + GSC_IN_BASE_ADDR_CR(index));
>> +
>> +}
>> +
>> +void gsc_hw_set_output_addr(struct gsc_dev *dev,
>> +                            struct gsc_addr *addr, int index)
>> +{
>> +       gsc_dbg("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X",
>> +                       index, addr->y, addr->cb, addr->cr);
>> +       writel(addr->y, dev->regs + GSC_OUT_BASE_ADDR_Y(index));
>> +       writel(addr->cb, dev->regs + GSC_OUT_BASE_ADDR_CB(index));
>> +       writel(addr->cr, dev->regs + GSC_OUT_BASE_ADDR_CR(index));
>> +}
>> +
>> +void gsc_hw_set_input_path(struct gsc_ctx *ctx)
>> +{
>> +       struct gsc_dev *dev = ctx->gsc_dev;
>> +
>> +       u32 cfg = readl(dev->regs + GSC_IN_CON);
>> +       cfg &= ~(GSC_IN_PATH_MASK | GSC_IN_LOCAL_SEL_MASK);
>> +
>> +       if (ctx->in_path == GSC_DMA)
>> +               cfg |= GSC_IN_PATH_MEMORY;
>> +
>> +       writel(cfg, dev->regs + GSC_IN_CON);
>> +}
>> +
>> +void gsc_hw_set_in_size(struct gsc_ctx *ctx)
>> +{
>> +       struct gsc_dev *dev = ctx->gsc_dev;
>> +       struct gsc_frame *frame = &ctx->s_frame;
>> +       u32 cfg;
>> +
>> +       /* Set input pixel offset */
>> +       cfg = GSC_SRCIMG_OFFSET_X(frame->crop.left);
>> +       cfg |= GSC_SRCIMG_OFFSET_Y(frame->crop.top);
>> +       writel(cfg, dev->regs + GSC_SRCIMG_OFFSET);
>> +
>> +       /* Set input original size */
>> +       cfg = GSC_SRCIMG_WIDTH(frame->f_width);
>> +       cfg |= GSC_SRCIMG_HEIGHT(frame->f_height);
>> +       writel(cfg, dev->regs + GSC_SRCIMG_SIZE);
>> +
>> +       /* Set input cropped size */
>> +       cfg = GSC_CROPPED_WIDTH(frame->crop.width);
>> +       cfg |= GSC_CROPPED_HEIGHT(frame->crop.height);
>> +       writel(cfg, dev->regs + GSC_CROPPED_SIZE);
>> +}
>> +
>> +void gsc_hw_set_in_image_rgb(struct gsc_ctx *ctx)
>> +{
>> +       struct gsc_dev *dev = ctx->gsc_dev;
>> +       struct gsc_frame *frame = &ctx->s_frame;
>> +       u32 cfg;
>> +
>> +       cfg = readl(dev->regs + GSC_IN_CON);
>> +       if (ctx->gsc_ctrls.csc_eq->val) {
>> +               if (ctx->gsc_ctrls.csc_range->val)
>> +                       cfg |= GSC_IN_RGB_HD_WIDE;
>> +               else
>> +                       cfg |= GSC_IN_RGB_HD_NARROW;
>> +       } else {
>> +               if (ctx->gsc_ctrls.csc_range->val)
>> +                       cfg |= GSC_IN_RGB_SD_WIDE;
>> +               else
>> +                       cfg |= GSC_IN_RGB_SD_NARROW;
>> +       }
>> +
>> +       if (frame->fmt->pixelformat == V4L2_PIX_FMT_RGB565X)
>> +               cfg |= GSC_IN_RGB565;
>> +       else if (frame->fmt->pixelformat == V4L2_PIX_FMT_RGB32)
>> +               cfg |= GSC_IN_XRGB8888;
>> +
>> +       writel(cfg, dev->regs + GSC_IN_CON);
>> +}
>> +
>> +void gsc_hw_set_in_image_format(struct gsc_ctx *ctx)
>> +{
>> +       struct gsc_dev *dev = ctx->gsc_dev;
>> +       struct gsc_frame *frame = &ctx->s_frame;
>> +       u32 i, depth = 0;
>> +       u32 cfg;
>> +
>> +       cfg = readl(dev->regs + GSC_IN_CON);
>> +       cfg &= ~(GSC_IN_RGB_TYPE_MASK | GSC_IN_YUV422_1P_ORDER_MASK |
>> +                GSC_IN_CHROMA_ORDER_MASK | GSC_IN_FORMAT_MASK |
>> +                GSC_IN_TILE_TYPE_MASK | GSC_IN_TILE_MODE);
>> +       writel(cfg, dev->regs + GSC_IN_CON);
>> +
>> +       if (is_rgb(frame->fmt->color)) {
>> +               gsc_hw_set_in_image_rgb(ctx);
>> +               return;
>> +       }
>> +       for (i = 0; i < frame->fmt->num_planes; i++)
>> +               depth += frame->fmt->depth[i];
>> +
>> +       switch (frame->fmt->num_comp) {
>> +       case 1:
>> +               cfg |= GSC_IN_YUV422_1P;
>> +               if (frame->fmt->yorder == GSC_LSB_Y)
>> +                       cfg |= GSC_IN_YUV422_1P_ORDER_LSB_Y;
>> +               else
>> +                       cfg |= GSC_IN_YUV422_1P_OEDER_LSB_C;
>> +               if (frame->fmt->corder == GSC_CBCR)
>> +                       cfg |= GSC_IN_CHROMA_ORDER_CBCR;
>> +               else
>> +                       cfg |= GSC_IN_CHROMA_ORDER_CRCB;
>> +               break;
>> +       case 2:
>> +               if (depth == 12)
>> +                       cfg |= GSC_IN_YUV420_2P;
>> +               else
>> +                       cfg |= GSC_IN_YUV422_2P;
>> +               if (frame->fmt->corder == GSC_CBCR)
>> +                       cfg |= GSC_IN_CHROMA_ORDER_CBCR;
>> +               else
>> +                       cfg |= GSC_IN_CHROMA_ORDER_CRCB;
>> +               break;
>> +       case 3:
>> +               if (depth == 12)
>> +                       cfg |= GSC_IN_YUV420_3P;
>> +               else
>> +                       cfg |= GSC_IN_YUV422_3P;
>> +               break;
>> +       };
>> +
>> +       if (is_tiled(frame->fmt))
>> +               cfg |= GSC_IN_TILE_C_16x8 | GSC_IN_TILE_MODE;
>> +
>> +       writel(cfg, dev->regs + GSC_IN_CON);
>> +}
>> +
>> +void gsc_hw_set_output_path(struct gsc_ctx *ctx)
>> +{
>> +       struct gsc_dev *dev = ctx->gsc_dev;
>> +
>> +       u32 cfg = readl(dev->regs + GSC_OUT_CON);
>> +       cfg &= ~GSC_OUT_PATH_MASK;
>> +
>> +       if (ctx->out_path == GSC_DMA)
>> +               cfg |= GSC_OUT_PATH_MEMORY;
>> +       else
>> +               cfg |= GSC_OUT_PATH_LOCAL;
>> +
>> +       writel(cfg, dev->regs + GSC_OUT_CON);
>> +}
>> +
>> +void gsc_hw_set_out_size(struct gsc_ctx *ctx)
>> +{
>> +       struct gsc_dev *dev = ctx->gsc_dev;
>> +       struct gsc_frame *frame = &ctx->d_frame;
>> +       u32 cfg;
>> +
>> +       /* Set output original size */
>> +       if (ctx->out_path == GSC_DMA) {
>> +               cfg = GSC_DSTIMG_OFFSET_X(frame->crop.left);
>> +               cfg |= GSC_DSTIMG_OFFSET_Y(frame->crop.top);
>> +               writel(cfg, dev->regs + GSC_DSTIMG_OFFSET);
>> +
>> +               cfg = GSC_DSTIMG_WIDTH(frame->f_width);
>> +               cfg |= GSC_DSTIMG_HEIGHT(frame->f_height);
>> +               writel(cfg, dev->regs + GSC_DSTIMG_SIZE);
>> +       }
>> +
>> +       /* Set output scaled size */
>> +       if (ctx->gsc_ctrls.rotate->val == 90 ||
>> +           ctx->gsc_ctrls.rotate->val == 270) {
>> +               cfg = GSC_SCALED_WIDTH(frame->crop.height);
>> +               cfg |= GSC_SCALED_HEIGHT(frame->crop.width);
>> +       } else {
>> +               cfg = GSC_SCALED_WIDTH(frame->crop.width);
>> +               cfg |= GSC_SCALED_HEIGHT(frame->crop.height);
>> +       }
>> +       writel(cfg, dev->regs + GSC_SCALED_SIZE);
>> +}
>> +
>> +void gsc_hw_set_out_image_rgb(struct gsc_ctx *ctx)
>> +{
>> +       struct gsc_dev *dev = ctx->gsc_dev;
>> +       struct gsc_frame *frame = &ctx->d_frame;
>> +       u32 cfg;
>> +
>> +       cfg = readl(dev->regs + GSC_OUT_CON);
>> +       if (ctx->gsc_ctrls.csc_eq->val) {
>> +               if (ctx->gsc_ctrls.csc_range->val)
>> +                       cfg |= GSC_OUT_RGB_HD_WIDE;
>> +               else
>> +                       cfg |= GSC_OUT_RGB_HD_NARROW;
>> +       } else {
>> +               if (ctx->gsc_ctrls.csc_range->val)
>> +                       cfg |= GSC_OUT_RGB_SD_WIDE;
>> +               else
>> +                       cfg |= GSC_OUT_RGB_SD_NARROW;
>> +       }
>> +
>> +       if (frame->fmt->pixelformat == V4L2_PIX_FMT_RGB565X)
>> +               cfg |= GSC_OUT_RGB565;
>> +       else if (frame->fmt->pixelformat == V4L2_PIX_FMT_RGB32)
>> +               cfg |= GSC_OUT_XRGB8888;
>> +
>> +       writel(cfg, dev->regs + GSC_OUT_CON);
>> +}
>> +
>> +void gsc_hw_set_out_image_format(struct gsc_ctx *ctx)
>> +{
>> +       struct gsc_dev *dev = ctx->gsc_dev;
>> +       struct gsc_frame *frame = &ctx->d_frame;
>> +       u32 i, depth = 0;
>> +       u32 cfg;
>> +
>> +       cfg = readl(dev->regs + GSC_OUT_CON);
>> +       cfg &= ~(GSC_OUT_RGB_TYPE_MASK | GSC_OUT_YUV422_1P_ORDER_MASK |
>> +                GSC_OUT_CHROMA_ORDER_MASK | GSC_OUT_FORMAT_MASK |
>> +                GSC_OUT_TILE_TYPE_MASK | GSC_OUT_TILE_MODE);
>> +       writel(cfg, dev->regs + GSC_OUT_CON);
>> +
>> +       if (is_rgb(frame->fmt->color)) {
>> +               gsc_hw_set_out_image_rgb(ctx);
>> +               return;
>> +       }
>> +
>> +       if (ctx->out_path != GSC_DMA) {
>> +               cfg |= GSC_OUT_YUV444;
>> +               goto end_set;
>> +       }
>> +
>> +       for (i = 0; i < frame->fmt->num_planes; i++)
>> +               depth += frame->fmt->depth[i];
>> +
>> +       switch (frame->fmt->num_comp) {
>> +       case 1:
>> +               cfg |= GSC_OUT_YUV422_1P;
>> +               if (frame->fmt->yorder == GSC_LSB_Y)
>> +                       cfg |= GSC_OUT_YUV422_1P_ORDER_LSB_Y;
>> +               else
>> +                       cfg |= GSC_OUT_YUV422_1P_OEDER_LSB_C;
>> +               if (frame->fmt->corder == GSC_CBCR)
>> +                       cfg |= GSC_OUT_CHROMA_ORDER_CBCR;
>> +               else
>> +                       cfg |= GSC_OUT_CHROMA_ORDER_CRCB;
>> +               break;
>> +       case 2:
>> +               if (depth == 12)
>> +                       cfg |= GSC_OUT_YUV420_2P;
>> +               else
>> +                       cfg |= GSC_OUT_YUV422_2P;
>> +               if (frame->fmt->corder == GSC_CBCR)
>> +                       cfg |= GSC_OUT_CHROMA_ORDER_CBCR;
>> +               else
>> +                       cfg |= GSC_OUT_CHROMA_ORDER_CRCB;
>> +               break;
>> +       case 3:
>> +               cfg |= GSC_OUT_YUV420_3P;
>> +               break;
>> +       };
>> +
>> +       if (is_tiled(frame->fmt))
>> +               cfg |= GSC_OUT_TILE_C_16x8 | GSC_OUT_TILE_MODE;
>> +
>> +end_set:
>> +       writel(cfg, dev->regs + GSC_OUT_CON);
>> +}
>> +
>> +void gsc_hw_set_prescaler(struct gsc_ctx *ctx)
>> +{
>> +       struct gsc_dev *dev = ctx->gsc_dev;
>> +       struct gsc_scaler *sc = &ctx->scaler;
>> +       u32 cfg;
>> +
>> +       cfg = GSC_PRESC_SHFACTOR(sc->pre_shfactor);
>> +       cfg |= GSC_PRESC_H_RATIO(sc->pre_hratio);
>> +       cfg |= GSC_PRESC_V_RATIO(sc->pre_vratio);
>> +       writel(cfg, dev->regs + GSC_PRE_SCALE_RATIO);
>> +}
>> +
>> +void gsc_hw_set_mainscaler(struct gsc_ctx *ctx)
>> +{
>> +       struct gsc_dev *dev = ctx->gsc_dev;
>> +       struct gsc_scaler *sc = &ctx->scaler;
>> +       u32 cfg;
>> +
>> +       cfg = GSC_MAIN_H_RATIO_VALUE(sc->main_hratio);
>> +       writel(cfg, dev->regs + GSC_MAIN_H_RATIO);
>> +
>> +       cfg = GSC_MAIN_V_RATIO_VALUE(sc->main_vratio);
>> +       writel(cfg, dev->regs + GSC_MAIN_V_RATIO);
>> +}
>> +
>> +void gsc_hw_set_rotation(struct gsc_ctx *ctx)
>> +{
>> +       struct gsc_dev *dev = ctx->gsc_dev;
>> +       u32 cfg;
>> +
>> +       cfg = readl(dev->regs + GSC_IN_CON);
>> +       cfg &= ~GSC_IN_ROT_MASK;
>> +
>> +       switch (ctx->gsc_ctrls.rotate->val) {
>> +       case 270:
>> +               cfg |= GSC_IN_ROT_270;
>> +               break;
>> +       case 180:
>> +               cfg |= GSC_IN_ROT_180;
>> +               break;
>> +       case 90:
>> +               if (ctx->gsc_ctrls.hflip->val)
>> +                       cfg |= GSC_IN_ROT_90_XFLIP;
>> +               else if (ctx->gsc_ctrls.vflip->val)
>> +                       cfg |= GSC_IN_ROT_90_YFLIP;
>> +               else
>> +                       cfg |= GSC_IN_ROT_90;
>> +               break;
>> +       case 0:
>> +               if (ctx->gsc_ctrls.hflip->val)
>> +                       cfg |= GSC_IN_ROT_XFLIP;
>> +               else if (ctx->gsc_ctrls.vflip->val)
>> +                       cfg |= GSC_IN_ROT_YFLIP;
>> +       }
>> +
>> +       writel(cfg, dev->regs + GSC_IN_CON);
>> +}
>> +
>> +void gsc_hw_set_global_alpha(struct gsc_ctx *ctx)
>> +{
>> +       struct gsc_dev *dev = ctx->gsc_dev;
>> +       struct gsc_frame *frame = &ctx->d_frame;
>> +       u32 cfg;
>> +
>> +       if (!is_rgb(frame->fmt->color)) {
>> +               gsc_dbg("Not a RGB format");
>> +               return;
>> +       }
>> +
>> +       cfg = readl(dev->regs + GSC_OUT_CON);
>> +       cfg &= ~GSC_OUT_GLOBAL_ALPHA_MASK;
>> +
>> +       cfg |= GSC_OUT_GLOBAL_ALPHA(ctx->gsc_ctrls.global_alpha->val);
>> +       writel(cfg, dev->regs + GSC_OUT_CON);
>> +}
>> +
>> +void gsc_hw_set_sfr_update(struct gsc_ctx *ctx)
>> +{
>> +       struct gsc_dev *dev = ctx->gsc_dev;
>> +       u32 cfg;
>> +
>> +       cfg = readl(dev->regs + GSC_ENABLE);
>> +       cfg |= GSC_ENABLE_SFR_UPDATE;
>> +       writel(cfg, dev->regs + GSC_ENABLE);
>> +}
>> diff --git a/drivers/media/video/exynos/gsc/gsc-regs.h b/drivers/media/video/exynos/gsc/gsc-regs.h
>> new file mode 100644
>> index 0000000..50ddabe
>> --- /dev/null
>> +++ b/drivers/media/video/exynos/gsc/gsc-regs.h
>> @@ -0,0 +1,211 @@
>> +/* linux/drivers/media/video/exynos/gsc/regs-gsc.h
>> + *
>> + * Copyright (c) 2011 Samsung Electronics Co., Ltd.
>> + *             http://www.samsung.com
>> + *
>> + * Register definition file for Samsung G-Scaler driver
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#ifndef REGS_GSC_H_
>> +#define REGS_GSC_H_
>> +
>> +/* G-Scaler enable */
>> +#define GSC_ENABLE                     0x00
>> +#define GSC_ENABLE_ON_CLEAR            (1 << 4)
>> +#define GSC_ENABLE_QOS_ENABLE          (1 << 3)
>> +#define GSC_ENABLE_OP_STATUS           (1 << 2)
>> +#define GSC_ENABLE_SFR_UPDATE          (1 << 1)
>> +#define GSC_ENABLE_ON                  (1 << 0)
>> +
>> +/* G-Scaler S/W reset */
>> +#define GSC_SW_RESET                   0x04
>> +#define GSC_SW_RESET_SRESET            (1 << 0)
>> +
>> +/* G-Scaler IRQ */
>> +#define GSC_IRQ                                0x08
>> +#define GSC_IRQ_STATUS_OR_IRQ          (1 << 17)
>> +#define GSC_IRQ_STATUS_OR_FRM_DONE     (1 << 16)
>> +#define GSC_IRQ_OR_MASK                        (1 << 2)
>> +#define GSC_IRQ_FRMDONE_MASK           (1 << 1)
>> +#define GSC_IRQ_ENABLE                 (1 << 0)
>> +
>> +/* G-Scaler input control */
>> +#define GSC_IN_CON                     0x10
>> +#define GSC_IN_ROT_MASK                        (7 << 16)
>> +#define GSC_IN_ROT_270                 (7 << 16)
>> +#define GSC_IN_ROT_90_YFLIP            (6 << 16)
>> +#define GSC_IN_ROT_90_XFLIP            (5 << 16)
>> +#define GSC_IN_ROT_90                  (4 << 16)
>> +#define GSC_IN_ROT_180                 (3 << 16)
>> +#define GSC_IN_ROT_YFLIP               (2 << 16)
>> +#define GSC_IN_ROT_XFLIP               (1 << 16)
>> +#define GSC_IN_RGB_TYPE_MASK           (3 << 14)
>> +#define GSC_IN_RGB_HD_WIDE             (3 << 14)
>> +#define GSC_IN_RGB_HD_NARROW           (2 << 14)
>> +#define GSC_IN_RGB_SD_WIDE             (1 << 14)
>> +#define GSC_IN_RGB_SD_NARROW           (0 << 14)
>> +#define GSC_IN_YUV422_1P_ORDER_MASK    (1 << 13)
>> +#define GSC_IN_YUV422_1P_ORDER_LSB_Y   (0 << 13)
>> +#define GSC_IN_YUV422_1P_OEDER_LSB_C   (1 << 13)
>> +#define GSC_IN_CHROMA_ORDER_MASK       (1 << 12)
>> +#define GSC_IN_CHROMA_ORDER_CBCR       (0 << 12)
>> +#define GSC_IN_CHROMA_ORDER_CRCB       (1 << 12)
>> +#define GSC_IN_FORMAT_MASK             (7 << 8)
>> +#define GSC_IN_XRGB8888                        (0 << 8)
>> +#define GSC_IN_RGB565                  (1 << 8)
>> +#define GSC_IN_YUV420_2P               (2 << 8)
>> +#define GSC_IN_YUV420_3P               (3 << 8)
>> +#define GSC_IN_YUV422_1P               (4 << 8)
>> +#define GSC_IN_YUV422_2P               (5 << 8)
>> +#define GSC_IN_YUV422_3P               (6 << 8)
>> +#define GSC_IN_TILE_TYPE_MASK          (1 << 4)
>> +#define GSC_IN_TILE_C_16x8             (0 << 4)
>> +#define GSC_IN_TILE_C_16x16            (1 << 4)
>> +#define GSC_IN_TILE_MODE               (1 << 3)
>> +#define GSC_IN_LOCAL_SEL_MASK          (3 << 1)
>> +#define GSC_IN_LOCAL_FIMD_WB           (2 << 1)
>> +#define GSC_IN_LOCAL_CAM1              (1 << 1)
>> +#define GSC_IN_LOCAL_CAM0              (0 << 1)
>> +#define GSC_IN_PATH_MASK               (1 << 0)
>> +#define GSC_IN_PATH_LOCAL              (1 << 0)
>> +#define GSC_IN_PATH_MEMORY             (0 << 0)
>> +
>> +/* G-Scaler source image size */
>> +#define GSC_SRCIMG_SIZE                        0x14
>> +#define GSC_SRCIMG_HEIGHT_MASK         (0x1fff << 16)
>> +#define GSC_SRCIMG_HEIGHT(x)           ((x) << 16)
>> +#define GSC_SRCIMG_WIDTH_MASK          (0x1fff << 0)
>> +#define GSC_SRCIMG_WIDTH(x)            ((x) << 0)
>> +
>> +/* G-Scaler source image offset */
>> +#define GSC_SRCIMG_OFFSET              0x18
>> +#define GSC_SRCIMG_OFFSET_Y_MASK       (0x1fff << 16)
>> +#define GSC_SRCIMG_OFFSET_Y(x)         ((x) << 16)
>> +#define GSC_SRCIMG_OFFSET_X_MASK       (0x1fff << 0)
>> +#define GSC_SRCIMG_OFFSET_X(x)         ((x) << 0)
>> +
>> +/* G-Scaler cropped source image size */
>> +#define GSC_CROPPED_SIZE               0x1c
>> +#define GSC_CROPPED_HEIGHT_MASK                (0x1fff << 16)
>> +#define GSC_CROPPED_HEIGHT(x)          ((x) << 16)
>> +#define GSC_CROPPED_WIDTH_MASK         (0x1fff << 0)
>> +#define GSC_CROPPED_WIDTH(x)           ((x) << 0)
>> +
>> +/* G-Scaler output control */
>> +#define GSC_OUT_CON                    0x20
>> +#define GSC_OUT_GLOBAL_ALPHA_MASK      (0xff << 24)
>> +#define GSC_OUT_GLOBAL_ALPHA(x)                ((x) << 24)
>> +#define GSC_OUT_RGB_TYPE_MASK          (3 << 10)
>> +#define GSC_OUT_RGB_HD_NARROW          (3 << 10)
>> +#define GSC_OUT_RGB_HD_WIDE            (2 << 10)
>> +#define GSC_OUT_RGB_SD_NARROW          (1 << 10)
>> +#define GSC_OUT_RGB_SD_WIDE            (0 << 10)
>> +#define GSC_OUT_YUV422_1P_ORDER_MASK   (1 << 9)
>> +#define GSC_OUT_YUV422_1P_ORDER_LSB_Y  (0 << 9)
>> +#define GSC_OUT_YUV422_1P_OEDER_LSB_C  (1 << 9)
>> +#define GSC_OUT_CHROMA_ORDER_MASK      (1 << 8)
>> +#define GSC_OUT_CHROMA_ORDER_CBCR      (0 << 8)
>> +#define GSC_OUT_CHROMA_ORDER_CRCB      (1 << 8)
>> +#define GSC_OUT_FORMAT_MASK            (7 << 4)
>> +#define GSC_OUT_XRGB8888               (0 << 4)
>> +#define GSC_OUT_RGB565                 (1 << 4)
>> +#define GSC_OUT_YUV420_2P              (2 << 4)
>> +#define GSC_OUT_YUV420_3P              (3 << 4)
>> +#define GSC_OUT_YUV422_1P              (4 << 4)
>> +#define GSC_OUT_YUV422_2P              (5 << 4)
>> +#define GSC_OUT_YUV444                 (7 << 4)
>> +#define GSC_OUT_TILE_TYPE_MASK         (1 << 2)
>> +#define GSC_OUT_TILE_C_16x8            (0 << 2)
>> +#define GSC_OUT_TILE_C_16x16           (1 << 2)
>> +#define GSC_OUT_TILE_MODE              (1 << 1)
>> +#define GSC_OUT_PATH_MASK              (1 << 0)
>> +#define GSC_OUT_PATH_LOCAL             (1 << 0)
>> +#define GSC_OUT_PATH_MEMORY            (0 << 0)
>> +
>> +/* G-Scaler scaled destination image size */
>> +#define GSC_SCALED_SIZE                        0x24
>> +#define GSC_SCALED_HEIGHT_MASK         (0x1fff << 16)
>> +#define GSC_SCALED_HEIGHT(x)           ((x) << 16)
>> +#define GSC_SCALED_WIDTH_MASK          (0x1fff << 0)
>> +#define GSC_SCALED_WIDTH(x)            ((x) << 0)
>> +
>> +/* G-Scaler pre scale ratio */
>> +#define GSC_PRE_SCALE_RATIO            0x28
>> +#define GSC_PRESC_SHFACTOR_MASK                (7 << 28)
>> +#define GSC_PRESC_SHFACTOR(x)          ((x) << 28)
>> +#define GSC_PRESC_V_RATIO_MASK         (7 << 16)
>> +#define GSC_PRESC_V_RATIO(x)           ((x) << 16)
>> +#define GSC_PRESC_H_RATIO_MASK         (7 << 0)
>> +#define GSC_PRESC_H_RATIO(x)           ((x) << 0)
>> +
>> +/* G-Scaler main scale horizontal ratio */
>> +#define GSC_MAIN_H_RATIO               0x2c
>> +#define GSC_MAIN_H_RATIO_MASK          (0xfffff << 0)
>> +#define GSC_MAIN_H_RATIO_VALUE(x)      ((x) << 0)
>> +
>> +/* G-Scaler main scale vertical ratio */
>> +#define GSC_MAIN_V_RATIO               0x30
>> +#define GSC_MAIN_V_RATIO_MASK          (0xfffff << 0)
>> +#define GSC_MAIN_V_RATIO_VALUE(x)      ((x) << 0)
>> +
>> +/* G-Scaler destination image size */
>> +#define GSC_DSTIMG_SIZE                        0x40
>> +#define GSC_DSTIMG_HEIGHT_MASK         (0x1fff << 16)
>> +#define GSC_DSTIMG_HEIGHT(x)           ((x) << 16)
>> +#define GSC_DSTIMG_WIDTH_MASK          (0x1fff << 0)
>> +#define GSC_DSTIMG_WIDTH(x)            ((x) << 0)
>> +
>> +/* G-Scaler destination image offset */
>> +#define GSC_DSTIMG_OFFSET              0x44
>> +#define GSC_DSTIMG_OFFSET_Y_MASK       (0x1fff << 16)
>> +#define GSC_DSTIMG_OFFSET_Y(x)         ((x) << 16)
>> +#define GSC_DSTIMG_OFFSET_X_MASK       (0x1fff << 0)
>> +#define GSC_DSTIMG_OFFSET_X(x)         ((x) << 0)
>> +
>> +/* G-Scaler input y address mask */
>> +#define GSC_IN_BASE_ADDR_Y_MASK                0x4c
>> +/* G-Scaler input y base address */
>> +#define GSC_IN_BASE_ADDR_Y(n)          (0x50 + (n) * 0x4)
>> +
>> +/* G-Scaler input cb address mask */
>> +#define GSC_IN_BASE_ADDR_CB_MASK       0x7c
>> +/* G-Scaler input cb base address */
>> +#define GSC_IN_BASE_ADDR_CB(n)         (0x80 + (n) * 0x4)
>> +
>> +/* G-Scaler input cr address mask */
>> +#define GSC_IN_BASE_ADDR_CR_MASK       0xac
>> +/* G-Scaler input cr base address */
>> +#define GSC_IN_BASE_ADDR_CR(n)         (0xb0 + (n) * 0x4)
>> +
>> +/* G-Scaler input address mask */
>> +#define GSC_IN_CURR_ADDR_INDEX         (0xf << 12)
>> +#define GSC_IN_CURR_GET_INDEX(x)       ((x) >> 12)
>> +#define GSC_IN_BASE_ADDR_PINGPONG(x)   ((x) << 8)
>> +#define GSC_IN_BASE_ADDR_MASK          (0xff << 0)
>> +
>> +/* G-Scaler output y address mask */
>> +#define GSC_OUT_BASE_ADDR_Y_MASK       0x10c
>> +/* G-Scaler output y base address */
>> +#define GSC_OUT_BASE_ADDR_Y(n)         (0x110 + (n) * 0x4)
>> +
>> +/* G-Scaler output cb address mask */
>> +#define GSC_OUT_BASE_ADDR_CB_MASK      0x15c
>> +/* G-Scaler output cb base address */
>> +#define GSC_OUT_BASE_ADDR_CB(n)                (0x160 + (n) * 0x4)
>> +
>> +/* G-Scaler output cr address mask */
>> +#define GSC_OUT_BASE_ADDR_CR_MASK      0x1ac
>> +/* G-Scaler output cr base address */
>> +#define GSC_OUT_BASE_ADDR_CR(n)                (0x1b0 + (n) * 0x4)
>> +
>> +/* G-Scaler output address mask */
>> +#define GSC_OUT_CURR_ADDR_INDEX                (0xf << 24)
>> +#define GSC_OUT_CURR_GET_INDEX(x)      ((x) >> 24)
>> +#define GSC_OUT_BASE_ADDR_PINGPONG(x)  ((x) << 16)
>> +#define GSC_OUT_BASE_ADDR_MASK         (0xffff << 0)
>
> Some of the defines in this file are not used like those above.
>

I will remove the unused code...

>> +
>> +#endif /* REGS_GSC_H_ */
>> diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
>> index f79d0cc..5b4a33b 100644
>> --- a/include/linux/videodev2.h
>> +++ b/include/linux/videodev2.h
>> @@ -360,9 +360,11 @@ struct v4l2_pix_format {
>>  /* two non contiguous planes - one Y, one Cr + Cb interleaved  */
>>  #define V4L2_PIX_FMT_NV12M   v4l2_fourcc('N', 'M', '1', '2') /* 12  Y/CbCr 4:2:0  */
>>  #define V4L2_PIX_FMT_NV12MT  v4l2_fourcc('T', 'M', '1', '2') /* 12  Y/CbCr 4:2:0 64x32 macroblocks */
>
> Already defined in videodev2.h
>
>> +#define V4L2_PIX_FMT_NV12MT_16X16 v4l2_fourcc('V', 'M', '1', '2') /* 12  Y/CbCr 4:2:0 16x16 macroblocks */
>>
>>  /* three non contiguous planes - Y, Cb, Cr */
>>  #define V4L2_PIX_FMT_YUV420M v4l2_fourcc('Y', 'M', '1', '2') /* 12  YUV420 planar */
>> +#define V4L2_PIX_FMT_YVU420M v4l2_fourcc('Y', 'V', 'U', 'M') /* 12  YVU420 planar */
>>
>>  /* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */
>>  #define V4L2_PIX_FMT_SBGGR8  v4l2_fourcc('B', 'A', '8', '1') /*  8  BGBG.. GRGR.. */
>
> Some of those formats are defined in videodev2.h. For those that are not,
> you should add them there instead.
>
>> --
>> 1.7.0.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-media" in
>> the body of a message to majordomo@xxxxxxxxxxxxxxx
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
>
>
> --
> Best regards,
> Pawel Osciak


Regards,
Shaik Ameer Basha
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux