media: platform: rename exynos-gsc/ to samsung/exynos-gsc/
authorMauro Carvalho Chehab <mchehab@kernel.org>
Sun, 13 Mar 2022 10:18:16 +0000 (11:18 +0100)
committerMauro Carvalho Chehab <mchehab@kernel.org>
Fri, 18 Mar 2022 04:56:51 +0000 (05:56 +0100)
As the end goal is to have platform drivers split by vendor,
rename exynos-gsc/ to samsung/exynos-gsc/.

Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
16 files changed:
drivers/media/platform/Kconfig
drivers/media/platform/Makefile
drivers/media/platform/exynos-gsc/Kconfig [deleted file]
drivers/media/platform/exynos-gsc/Makefile [deleted file]
drivers/media/platform/exynos-gsc/gsc-core.c [deleted file]
drivers/media/platform/exynos-gsc/gsc-core.h [deleted file]
drivers/media/platform/exynos-gsc/gsc-m2m.c [deleted file]
drivers/media/platform/exynos-gsc/gsc-regs.c [deleted file]
drivers/media/platform/exynos-gsc/gsc-regs.h [deleted file]
drivers/media/platform/samsung/exynos-gsc/Kconfig [new file with mode: 0644]
drivers/media/platform/samsung/exynos-gsc/Makefile [new file with mode: 0644]
drivers/media/platform/samsung/exynos-gsc/gsc-core.c [new file with mode: 0644]
drivers/media/platform/samsung/exynos-gsc/gsc-core.h [new file with mode: 0644]
drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c [new file with mode: 0644]
drivers/media/platform/samsung/exynos-gsc/gsc-regs.c [new file with mode: 0644]
drivers/media/platform/samsung/exynos-gsc/gsc-regs.h [new file with mode: 0644]

index 8654961..48210ad 100644 (file)
@@ -74,7 +74,6 @@ source "drivers/media/platform/atmel/Kconfig"
 source "drivers/media/platform/cadence/Kconfig"
 source "drivers/media/platform/chips-media/Kconfig"
 source "drivers/media/platform/davinci/Kconfig"
-source "drivers/media/platform/exynos-gsc/Kconfig"
 source "drivers/media/platform/intel/Kconfig"
 source "drivers/media/platform/marvell/Kconfig"
 source "drivers/media/platform/mediatek/mtk-jpeg/Kconfig"
@@ -92,6 +91,7 @@ source "drivers/media/platform/s3c-camif/Kconfig"
 source "drivers/media/platform/s5p-g2d/Kconfig"
 source "drivers/media/platform/s5p-jpeg/Kconfig"
 source "drivers/media/platform/s5p-mfc/Kconfig"
+source "drivers/media/platform/samsung/exynos-gsc/Kconfig"
 source "drivers/media/platform/samsung/exynos4-is/Kconfig"
 source "drivers/media/platform/sti/Kconfig"
 source "drivers/media/platform/stm32/Kconfig"
index 3457866..354796d 100644 (file)
@@ -14,7 +14,6 @@ obj-y += atmel/
 obj-y += cadence/
 obj-y += chips-media/
 obj-y += davinci/
-obj-y += exynos-gsc/
 obj-y += intel/
 obj-y += marvell/
 obj-y += mediatek/mtk-jpeg/
@@ -34,6 +33,7 @@ obj-y += s3c-camif/
 obj-y += s5p-g2d/
 obj-y += s5p-jpeg/
 obj-y += s5p-mfc/
+obj-y += samsung/exynos-gsc/
 obj-y += samsung/exynos4-is/
 obj-y += sti/bdisp/
 obj-y += sti/c8sectpfe/
diff --git a/drivers/media/platform/exynos-gsc/Kconfig b/drivers/media/platform/exynos-gsc/Kconfig
deleted file mode 100644 (file)
index f9bdffe..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config VIDEO_SAMSUNG_EXYNOS_GSC
-       tristate "Samsung Exynos G-Scaler driver"
-       depends on V4L_MEM2MEM_DRIVERS
-       depends on VIDEO_DEV && VIDEO_V4L2
-       depends on ARCH_EXYNOS || COMPILE_TEST
-       select VIDEOBUF2_DMA_CONTIG
-       select V4L2_MEM2MEM_DEV
-       help
-         This is a v4l2 driver for Samsung EXYNOS5 SoC G-Scaler.
diff --git a/drivers/media/platform/exynos-gsc/Makefile b/drivers/media/platform/exynos-gsc/Makefile
deleted file mode 100644 (file)
index bcefbad..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-exynos-gsc-objs := gsc-core.o gsc-m2m.o gsc-regs.o
-
-obj-$(CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC) += exynos-gsc.o
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
deleted file mode 100644 (file)
index e3559b0..0000000
+++ /dev/null
@@ -1,1327 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com
- *
- * Samsung EXYNOS5 SoC series G-Scaler driver
- */
-
-#include <linux/module.h>
-#include <linux/kernel.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 <linux/of.h>
-#include <linux/of_device.h>
-#include <media/v4l2-ioctl.h>
-
-#include "gsc-core.h"
-
-static const struct gsc_fmt gsc_formats[] = {
-       {
-               .pixelformat    = V4L2_PIX_FMT_RGB565X,
-               .depth          = { 16 },
-               .color          = GSC_RGB,
-               .num_planes     = 1,
-               .num_comp       = 1,
-       }, {
-               .pixelformat    = V4L2_PIX_FMT_BGR32,
-               .depth          = { 32 },
-               .color          = GSC_RGB,
-               .num_planes     = 1,
-               .num_comp       = 1,
-       }, {
-               .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      = MEDIA_BUS_FMT_YUYV8_2X8,
-       }, {
-               .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      = MEDIA_BUS_FMT_UYVY8_2X8,
-       }, {
-               .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      = MEDIA_BUS_FMT_VYUY8_2X8,
-       }, {
-               .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      = MEDIA_BUS_FMT_YVYU8_2X8,
-       }, {
-               .pixelformat    = V4L2_PIX_FMT_YUV32,
-               .depth          = { 32 },
-               .color          = GSC_YUV444,
-               .yorder         = GSC_LSB_Y,
-               .corder         = GSC_CBCR,
-               .num_planes     = 1,
-               .num_comp       = 1,
-       }, {
-               .pixelformat    = V4L2_PIX_FMT_YUV422P,
-               .depth          = { 16 },
-               .color          = GSC_YUV422,
-               .yorder         = GSC_LSB_Y,
-               .corder         = GSC_CBCR,
-               .num_planes     = 1,
-               .num_comp       = 3,
-       }, {
-               .pixelformat    = V4L2_PIX_FMT_NV16,
-               .depth          = { 16 },
-               .color          = GSC_YUV422,
-               .yorder         = GSC_LSB_Y,
-               .corder         = GSC_CBCR,
-               .num_planes     = 1,
-               .num_comp       = 2,
-       }, {
-               .pixelformat    = V4L2_PIX_FMT_NV16M,
-               .depth          = { 8, 8 },
-               .color          = GSC_YUV422,
-               .yorder         = GSC_LSB_Y,
-               .corder         = GSC_CBCR,
-               .num_planes     = 2,
-               .num_comp       = 2,
-       }, {
-               .pixelformat    = V4L2_PIX_FMT_NV61,
-               .depth          = { 16 },
-               .color          = GSC_YUV422,
-               .yorder         = GSC_LSB_Y,
-               .corder         = GSC_CRCB,
-               .num_planes     = 1,
-               .num_comp       = 2,
-       }, {
-               .pixelformat    = V4L2_PIX_FMT_NV61M,
-               .depth          = { 8, 8 },
-               .color          = GSC_YUV422,
-               .yorder         = GSC_LSB_Y,
-               .corder         = GSC_CRCB,
-               .num_planes     = 2,
-               .num_comp       = 2,
-       }, {
-               .pixelformat    = V4L2_PIX_FMT_YUV420,
-               .depth          = { 12 },
-               .color          = GSC_YUV420,
-               .yorder         = GSC_LSB_Y,
-               .corder         = GSC_CBCR,
-               .num_planes     = 1,
-               .num_comp       = 3,
-       }, {
-               .pixelformat    = V4L2_PIX_FMT_YVU420,
-               .depth          = { 12 },
-               .color          = GSC_YUV420,
-               .yorder         = GSC_LSB_Y,
-               .corder         = GSC_CRCB,
-               .num_planes     = 1,
-               .num_comp       = 3,
-
-       }, {
-               .pixelformat    = V4L2_PIX_FMT_NV12,
-               .depth          = { 12 },
-               .color          = GSC_YUV420,
-               .yorder         = GSC_LSB_Y,
-               .corder         = GSC_CBCR,
-               .num_planes     = 1,
-               .num_comp       = 2,
-       }, {
-               .pixelformat    = V4L2_PIX_FMT_NV21,
-               .depth          = { 12 },
-               .color          = GSC_YUV420,
-               .yorder         = GSC_LSB_Y,
-               .corder         = GSC_CRCB,
-               .num_planes     = 1,
-               .num_comp       = 2,
-       }, {
-               .pixelformat    = V4L2_PIX_FMT_NV21M,
-               .depth          = { 8, 4 },
-               .color          = GSC_YUV420,
-               .yorder         = GSC_LSB_Y,
-               .corder         = GSC_CRCB,
-               .num_planes     = 2,
-               .num_comp       = 2,
-       }, {
-               .pixelformat    = V4L2_PIX_FMT_NV12M,
-               .depth          = { 8, 4 },
-               .color          = GSC_YUV420,
-               .yorder         = GSC_LSB_Y,
-               .corder         = GSC_CBCR,
-               .num_planes     = 2,
-               .num_comp       = 2,
-       }, {
-               .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,
-       }, {
-               .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,
-       }, {
-               .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,
-       }
-};
-
-const struct gsc_fmt *get_format(int index)
-{
-       if (index >= ARRAY_SIZE(gsc_formats))
-               return NULL;
-
-       return (struct gsc_fmt *)&gsc_formats[index];
-}
-
-const struct gsc_fmt *find_fmt(u32 *pixelformat, u32 *mbus_code, u32 index)
-{
-       const 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) {
-               pr_err("Exceeded maximum downscaling 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);
-               pr_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);
-               pr_info("cropped src height size is recalculated from %d to %d",
-                       s_frame->crop.height + remainder, s_frame->crop.height);
-       }
-}
-
-int gsc_enum_fmt(struct v4l2_fmtdesc *f)
-{
-       const struct gsc_fmt *fmt;
-
-       fmt = find_fmt(NULL, NULL, f->index);
-       if (!fmt)
-               return -EINVAL;
-
-       f->pixelformat = fmt->pixelformat;
-
-       return 0;
-}
-
-static int get_plane_info(struct gsc_frame *frm, u32 addr, u32 *index, u32 *ret_addr)
-{
-       if (frm->addr.y == addr) {
-               *index = 0;
-               *ret_addr = frm->addr.y;
-       } else if (frm->addr.cb == addr) {
-               *index = 1;
-               *ret_addr = frm->addr.cb;
-       } else if (frm->addr.cr == addr) {
-               *index = 2;
-               *ret_addr = frm->addr.cr;
-       } else {
-               pr_err("Plane address is wrong");
-               return -EINVAL;
-       }
-       return 0;
-}
-
-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);
-               if (get_plane_info(frm, t_min, &low_plane, &low_addr))
-                       return;
-               t_max = max3(frm->addr.y, frm->addr.cb, frm->addr.cr);
-               if (get_plane_info(frm, t_max, &high_plane, &high_addr))
-                       return;
-
-               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];
-               }
-       }
-       pr_debug("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;
-       const struct gsc_fmt *fmt;
-       u32 max_w, max_h, mod_x, mod_y;
-       u32 min_w, min_h, tmp_w, tmp_h;
-       int i;
-
-       pr_debug("user put w: %d, h: %d", pix_mp->width, pix_mp->height);
-
-       fmt = find_fmt(&pix_mp->pixelformat, NULL, 0);
-       if (!fmt) {
-               pr_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) {
-               pr_debug("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;
-
-       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;
-
-       if (V4L2_TYPE_IS_OUTPUT(f->type)) {
-               min_w = variant->pix_min->org_w;
-               min_h = variant->pix_min->org_h;
-       } else {
-               min_w = variant->pix_min->target_rot_dis_w;
-               min_h = variant->pix_min->target_rot_dis_h;
-               pix_mp->colorspace = ctx->out_colorspace;
-       }
-
-       pr_debug("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)
-               pr_debug("Image size has been modified from %dx%d to %dx%d\n",
-                        tmp_w, tmp_h, pix_mp->width, pix_mp->height);
-
-       pix_mp->num_planes = fmt->num_planes;
-
-       if (V4L2_TYPE_IS_OUTPUT(f->type))
-               ctx->out_colorspace = pix_mp->colorspace;
-
-       for (i = 0; i < pix_mp->num_planes; ++i) {
-               struct v4l2_plane_pix_format *plane_fmt = &pix_mp->plane_fmt[i];
-               u32 bpl = plane_fmt->bytesperline;
-
-               if (fmt->num_comp == 1 && /* Packed */
-                   (bpl == 0 || (bpl * 8 / fmt->depth[i]) < pix_mp->width))
-                       bpl = pix_mp->width * fmt->depth[i] / 8;
-
-               if (fmt->num_comp > 1 && /* Planar */
-                   (bpl == 0 || bpl < pix_mp->width))
-                       bpl = pix_mp->width;
-
-               if (i != 0 && fmt->num_comp == 3)
-                       bpl /= 2;
-
-               plane_fmt->bytesperline = bpl;
-               plane_fmt->sizeimage = max(pix_mp->width * pix_mp->height *
-                                          fmt->depth[i] / 8,
-                                          plane_fmt->sizeimage);
-               pr_debug("[%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->num_planes      = frame->fmt->num_planes;
-       pix_mp->colorspace = ctx->out_colorspace;
-
-       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) {
-               pr_info("Cropped size has been modified from %dx%d to %dx%d",
-                                                       *w, *h, tmp_w, tmp_h);
-               *w = tmp_w;
-               *h = tmp_h;
-       }
-}
-
-int gsc_try_selection(struct gsc_ctx *ctx, struct v4l2_selection *s)
-{
-       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 (s->r.top < 0 || s->r.left < 0) {
-               pr_err("doesn't support negative values for top & left\n");
-               return -EINVAL;
-       }
-       pr_debug("user put w: %d, h: %d", s->r.width, s->r.height);
-
-       if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               f = &ctx->d_frame;
-       else if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
-               f = &ctx->s_frame;
-       else
-               return -EINVAL;
-
-       max_w = f->f_width;
-       max_h = f->f_height;
-       tmp_w = s->r.width;
-       tmp_h = s->r.height;
-
-       if (V4L2_TYPE_IS_OUTPUT(s->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 = s->r.height;
-                       tmp_h = s->r.width;
-               } else {
-                       min_w = variant->pix_min->target_rot_dis_w;
-                       min_h = variant->pix_min->target_rot_dis_h;
-               }
-       }
-       pr_debug("mod_x: %d, mod_y: %d, min_w: %d, min_h = %d",
-                                       mod_x, mod_y, min_w, min_h);
-       pr_debug("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_CAPTURE(s->type) &&
-           (ctx->gsc_ctrls.rotate->val == 90 ||
-            ctx->gsc_ctrls.rotate->val == 270))
-               gsc_check_crop_change(tmp_h, tmp_w,
-                                       &s->r.width, &s->r.height);
-       else
-               gsc_check_crop_change(tmp_w, tmp_h,
-                                       &s->r.width, &s->r.height);
-
-
-       /* adjust left/top if cropping rectangle is out of bounds */
-       /* Need to add code to algin left value with 2's multiple */
-       if (s->r.left + tmp_w > max_w)
-               s->r.left = max_w - tmp_w;
-       if (s->r.top + tmp_h > max_h)
-               s->r.top = max_h - tmp_h;
-
-       if ((is_yuv420(f->fmt->color) || is_yuv422(f->fmt->color)) &&
-           s->r.left & 1)
-               s->r.left -= 1;
-
-       pr_debug("Aligned l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
-                s->r.left, s->r.top, s->r.width, s->r.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;
-
-       if (out_path == GSC_DMA)
-               sc_down_max = var->sc_down_max;
-       else
-               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;
-       struct device *dev = &ctx->gsc_dev->pdev->dev;
-       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) {
-               pr_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;
-       }
-
-       if (tx <= 0 || ty <= 0) {
-               dev_err(dev, "Invalid target size: %dx%d", tx, ty);
-               return -EINVAL;
-       }
-
-       ret = gsc_cal_prescaler_ratio(variant, s_frame->crop.width,
-                                     tx, &sc->pre_hratio);
-       if (ret) {
-               pr_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) {
-               pr_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;
-
-       pr_debug("scaler input/output size : sx = %d, sy = %d, tx = %d, ty = %d",
-                       s_frame->crop.width, s_frame->crop.height, tx, ty);
-       pr_debug("scaler ratio info : pre_shfactor : %d, pre_h : %d",
-                       sc->pre_shfactor, sc->pre_hratio);
-       pr_debug("pre_v :%d, main_h : %d, main_v : %d",
-                       sc->pre_vratio, sc->main_hratio, sc->main_vratio);
-
-       return 0;
-}
-
-static int __gsc_s_ctrl(struct gsc_ctx *ctx, struct v4l2_ctrl *ctrl)
-{
-       struct gsc_dev *gsc = ctx->gsc_dev;
-       struct gsc_variant *variant = gsc->variant;
-       unsigned int flags = GSC_DST_FMT | GSC_SRC_FMT;
-       int ret = 0;
-
-       if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
-               return 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_HFLIP:
-               ctx->hflip = ctrl->val;
-               break;
-
-       case V4L2_CID_VFLIP:
-               ctx->vflip = ctrl->val;
-               break;
-
-       case V4L2_CID_ROTATE:
-               if ((ctx->state & flags) == flags) {
-                       ret = gsc_check_scaler_ratio(variant,
-                                       ctx->s_frame.crop.width,
-                                       ctx->s_frame.crop.height,
-                                       ctx->d_frame.crop.width,
-                                       ctx->d_frame.crop.height,
-                                       ctx->gsc_ctrls.rotate->val,
-                                       ctx->out_path);
-
-                       if (ret)
-                               return -EINVAL;
-               }
-
-               ctx->rotation = ctrl->val;
-               break;
-
-       case V4L2_CID_ALPHA_COMPONENT:
-               ctx->d_frame.alpha = ctrl->val;
-               break;
-       }
-
-       ctx->state |= GSC_PARAMS;
-       return 0;
-}
-
-static int gsc_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct gsc_ctx *ctx = ctrl_to_ctx(ctrl);
-       unsigned long flags;
-       int ret;
-
-       spin_lock_irqsave(&ctx->gsc_dev->slock, flags);
-       ret = __gsc_s_ctrl(ctx, ctrl);
-       spin_unlock_irqrestore(&ctx->gsc_dev->slock, flags);
-
-       return ret;
-}
-
-static const struct v4l2_ctrl_ops gsc_ctrl_ops = {
-       .s_ctrl = gsc_s_ctrl,
-};
-
-int gsc_ctrls_create(struct gsc_ctx *ctx)
-{
-       if (ctx->ctrls_rdy) {
-               pr_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_std(&ctx->ctrl_handler,
-                       &gsc_ctrl_ops, V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 0);
-
-       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);
-               pr_err("Failed to create G-Scaler control handlers");
-               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 ((vb == NULL) || (frame == NULL))
-               return -EINVAL;
-
-       pix_size = frame->f_width * frame->f_height;
-
-       pr_debug("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:
-                       /* decompose Y into Y/Cb/Cr */
-                       addr->cb = (dma_addr_t)(addr->y + pix_size);
-                       if (GSC_YUV420 == frame->fmt->color)
-                               addr->cr = (dma_addr_t)(addr->cb
-                                               + (pix_size >> 2));
-                       else /* 422 */
-                               addr->cr = (dma_addr_t)(addr->cb
-                                               + (pix_size >> 1));
-                       break;
-               default:
-                       pr_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_VYUY) ||
-               (frame->fmt->pixelformat == V4L2_PIX_FMT_YVYU) ||
-               (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420) ||
-               (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420M))
-               swap(addr->cb, addr->cr);
-
-       pr_debug("ADDR: y= %pad  cb= %pad cr= %pad 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;
-       struct gsc_ctx *ctx;
-       int gsc_irq;
-
-       gsc_irq = gsc_hw_get_irq_status(gsc);
-       gsc_hw_clear_irq(gsc, gsc_irq);
-
-       if (gsc_irq == GSC_IRQ_OVERRUN) {
-               pr_err("Local path input over-run interrupt has occurred!\n");
-               return IRQ_HANDLED;
-       }
-
-       spin_lock(&gsc->slock);
-
-       if (test_and_clear_bit(ST_M2M_PEND, &gsc->state)) {
-
-               gsc_hw_enable_control(gsc, false);
-
-               if (test_and_clear_bit(ST_M2M_SUSPENDING, &gsc->state)) {
-                       set_bit(ST_M2M_SUSPENDED, &gsc->state);
-                       wake_up(&gsc->irq_queue);
-                       goto isr_unlock;
-               }
-               ctx = v4l2_m2m_get_curr_priv(gsc->m2m.m2m_dev);
-
-               if (!ctx || !ctx->m2m_ctx)
-                       goto isr_unlock;
-
-               spin_unlock(&gsc->slock);
-               gsc_m2m_job_finish(ctx, VB2_BUF_STATE_DONE);
-
-               /* wake_up job_abort, stop_streaming */
-               if (ctx->state & GSC_CTX_STOP_REQ) {
-                       ctx->state &= ~GSC_CTX_STOP_REQ;
-                       wake_up(&gsc->irq_queue);
-               }
-               return IRQ_HANDLED;
-       }
-
-isr_unlock:
-       spin_unlock(&gsc->slock);
-       return IRQ_HANDLED;
-}
-
-static 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,
-};
-
-static struct gsc_pix_max gsc_v_5250_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          = 2016,
-       .real_rot_en_h          = 2016,
-       .target_rot_dis_w       = 4800,
-       .target_rot_dis_h       = 3344,
-       .target_rot_en_w        = 2016,
-       .target_rot_en_h        = 2016,
-};
-
-static struct gsc_pix_max gsc_v_5420_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          = 2048,
-       .real_rot_en_h          = 2048,
-       .target_rot_dis_w       = 4800,
-       .target_rot_dis_h       = 3344,
-       .target_rot_en_w        = 2016,
-       .target_rot_en_h        = 2016,
-};
-
-static struct gsc_pix_max gsc_v_5433_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,
-};
-
-static 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,
-};
-
-static 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 */
-};
-
-static 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             = 32,
-       .out_buf_cnt            = 32,
-       .sc_up_max              = 8,
-       .sc_down_max            = 16,
-       .poly_sc_down_max       = 4,
-       .pre_sc_down_max        = 4,
-       .local_sc_down          = 2,
-};
-
-static struct gsc_variant gsc_v_5250_variant = {
-       .pix_max                = &gsc_v_5250_max,
-       .pix_min                = &gsc_v_100_min,
-       .pix_align              = &gsc_v_100_align,
-       .in_buf_cnt             = 32,
-       .out_buf_cnt            = 32,
-       .sc_up_max              = 8,
-       .sc_down_max            = 16,
-       .poly_sc_down_max       = 4,
-       .pre_sc_down_max        = 4,
-       .local_sc_down          = 2,
-};
-
-static struct gsc_variant gsc_v_5420_variant = {
-       .pix_max                = &gsc_v_5420_max,
-       .pix_min                = &gsc_v_100_min,
-       .pix_align              = &gsc_v_100_align,
-       .in_buf_cnt             = 32,
-       .out_buf_cnt            = 32,
-       .sc_up_max              = 8,
-       .sc_down_max            = 16,
-       .poly_sc_down_max       = 4,
-       .pre_sc_down_max        = 4,
-       .local_sc_down          = 2,
-};
-
-static struct gsc_variant gsc_v_5433_variant = {
-       .pix_max                = &gsc_v_5433_max,
-       .pix_min                = &gsc_v_100_min,
-       .pix_align              = &gsc_v_100_align,
-       .in_buf_cnt             = 32,
-       .out_buf_cnt            = 32,
-       .sc_up_max              = 8,
-       .sc_down_max            = 16,
-       .poly_sc_down_max       = 4,
-       .pre_sc_down_max        = 4,
-       .local_sc_down          = 2,
-};
-
-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,
-       .clk_names = { "gscl" },
-       .num_clocks = 1,
-};
-
-static struct gsc_driverdata gsc_v_5250_drvdata = {
-       .variant = {
-               [0] = &gsc_v_5250_variant,
-               [1] = &gsc_v_5250_variant,
-               [2] = &gsc_v_5250_variant,
-               [3] = &gsc_v_5250_variant,
-       },
-       .num_entities = 4,
-       .clk_names = { "gscl" },
-       .num_clocks = 1,
-};
-
-static struct gsc_driverdata gsc_v_5420_drvdata = {
-       .variant = {
-               [0] = &gsc_v_5420_variant,
-               [1] = &gsc_v_5420_variant,
-       },
-       .num_entities = 2,
-       .clk_names = { "gscl" },
-       .num_clocks = 1,
-};
-
-static struct gsc_driverdata gsc_5433_drvdata = {
-       .variant = {
-               [0] = &gsc_v_5433_variant,
-               [1] = &gsc_v_5433_variant,
-               [2] = &gsc_v_5433_variant,
-       },
-       .num_entities = 3,
-       .clk_names = { "pclk", "aclk", "aclk_xiu", "aclk_gsclbend" },
-       .num_clocks = 4,
-};
-
-static const struct of_device_id exynos_gsc_match[] = {
-       {
-               .compatible = "samsung,exynos5250-gsc",
-               .data = &gsc_v_5250_drvdata,
-       },
-       {
-               .compatible = "samsung,exynos5420-gsc",
-               .data = &gsc_v_5420_drvdata,
-       },
-       {
-               .compatible = "samsung,exynos5433-gsc",
-               .data = &gsc_5433_drvdata,
-       },
-       {
-               .compatible = "samsung,exynos5-gsc",
-               .data = &gsc_v_100_drvdata,
-       },
-       {},
-};
-MODULE_DEVICE_TABLE(of, exynos_gsc_match);
-
-static int gsc_probe(struct platform_device *pdev)
-{
-       struct gsc_dev *gsc;
-       struct device *dev = &pdev->dev;
-       const struct gsc_driverdata *drv_data = of_device_get_match_data(dev);
-       int irq;
-       int ret;
-       int i;
-
-       gsc = devm_kzalloc(dev, sizeof(struct gsc_dev), GFP_KERNEL);
-       if (!gsc)
-               return -ENOMEM;
-
-       ret = of_alias_get_id(pdev->dev.of_node, "gsc");
-       if (ret < 0)
-               return ret;
-
-       if (drv_data == &gsc_v_100_drvdata)
-               dev_info(dev, "compatible 'exynos5-gsc' is deprecated\n");
-
-       gsc->id = ret;
-       if (gsc->id >= drv_data->num_entities) {
-               dev_err(dev, "Invalid platform device id: %d\n", gsc->id);
-               return -EINVAL;
-       }
-
-       gsc->num_clocks = drv_data->num_clocks;
-       gsc->variant = drv_data->variant[gsc->id];
-       gsc->pdev = pdev;
-
-       init_waitqueue_head(&gsc->irq_queue);
-       spin_lock_init(&gsc->slock);
-       mutex_init(&gsc->lock);
-
-       gsc->regs = devm_platform_ioremap_resource(pdev, 0);
-       if (IS_ERR(gsc->regs))
-               return PTR_ERR(gsc->regs);
-
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
-               return irq;
-
-       for (i = 0; i < gsc->num_clocks; i++) {
-               gsc->clock[i] = devm_clk_get(dev, drv_data->clk_names[i]);
-               if (IS_ERR(gsc->clock[i])) {
-                       dev_err(dev, "failed to get clock: %s\n",
-                               drv_data->clk_names[i]);
-                       return PTR_ERR(gsc->clock[i]);
-               }
-       }
-
-       for (i = 0; i < gsc->num_clocks; i++) {
-               ret = clk_prepare_enable(gsc->clock[i]);
-               if (ret) {
-                       dev_err(dev, "clock prepare failed for clock: %s\n",
-                               drv_data->clk_names[i]);
-                       while (--i >= 0)
-                               clk_disable_unprepare(gsc->clock[i]);
-                       return ret;
-               }
-       }
-
-       ret = devm_request_irq(dev, irq, gsc_irq_handler,
-                              0, pdev->name, gsc);
-       if (ret) {
-               dev_err(dev, "failed to install irq (%d)\n", ret);
-               goto err_clk;
-       }
-
-       ret = v4l2_device_register(dev, &gsc->v4l2_dev);
-       if (ret)
-               goto err_clk;
-
-       ret = gsc_register_m2m_device(gsc);
-       if (ret)
-               goto err_v4l2;
-
-       platform_set_drvdata(pdev, gsc);
-
-       gsc_hw_set_sw_reset(gsc);
-       gsc_wait_reset(gsc);
-
-       vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32));
-
-       dev_dbg(dev, "gsc-%d registered successfully\n", gsc->id);
-
-       pm_runtime_set_active(dev);
-       pm_runtime_enable(dev);
-
-       return 0;
-
-err_v4l2:
-       v4l2_device_unregister(&gsc->v4l2_dev);
-err_clk:
-       for (i = gsc->num_clocks - 1; i >= 0; i--)
-               clk_disable_unprepare(gsc->clock[i]);
-       return ret;
-}
-
-static int gsc_remove(struct platform_device *pdev)
-{
-       struct gsc_dev *gsc = platform_get_drvdata(pdev);
-       int i;
-
-       gsc_unregister_m2m_device(gsc);
-       v4l2_device_unregister(&gsc->v4l2_dev);
-
-       vb2_dma_contig_clear_max_seg_size(&pdev->dev);
-
-       pm_runtime_disable(&pdev->dev);
-
-       if (!pm_runtime_status_suspended(&pdev->dev))
-               for (i = 0; i < gsc->num_clocks; i++)
-                       clk_disable_unprepare(gsc->clock[i]);
-
-       pm_runtime_set_suspended(&pdev->dev);
-
-       dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int gsc_m2m_suspend(struct gsc_dev *gsc)
-{
-       unsigned long flags;
-       int timeout;
-
-       spin_lock_irqsave(&gsc->slock, flags);
-       if (!gsc_m2m_pending(gsc)) {
-               spin_unlock_irqrestore(&gsc->slock, flags);
-               return 0;
-       }
-       clear_bit(ST_M2M_SUSPENDED, &gsc->state);
-       set_bit(ST_M2M_SUSPENDING, &gsc->state);
-       spin_unlock_irqrestore(&gsc->slock, flags);
-
-       timeout = wait_event_timeout(gsc->irq_queue,
-                            test_bit(ST_M2M_SUSPENDED, &gsc->state),
-                            GSC_SHUTDOWN_TIMEOUT);
-
-       clear_bit(ST_M2M_SUSPENDING, &gsc->state);
-       return timeout == 0 ? -EAGAIN : 0;
-}
-
-static void gsc_m2m_resume(struct gsc_dev *gsc)
-{
-       struct gsc_ctx *ctx;
-       unsigned long flags;
-
-       spin_lock_irqsave(&gsc->slock, flags);
-       /* Clear for full H/W setup in first run after resume */
-       ctx = gsc->m2m.ctx;
-       gsc->m2m.ctx = NULL;
-       spin_unlock_irqrestore(&gsc->slock, flags);
-
-       if (test_and_clear_bit(ST_M2M_SUSPENDED, &gsc->state))
-               gsc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
-}
-
-static int gsc_runtime_resume(struct device *dev)
-{
-       struct gsc_dev *gsc = dev_get_drvdata(dev);
-       int ret = 0;
-       int i;
-
-       pr_debug("gsc%d: state: 0x%lx\n", gsc->id, gsc->state);
-
-       for (i = 0; i < gsc->num_clocks; i++) {
-               ret = clk_prepare_enable(gsc->clock[i]);
-               if (ret) {
-                       while (--i >= 0)
-                               clk_disable_unprepare(gsc->clock[i]);
-                       return ret;
-               }
-       }
-
-       gsc_hw_set_sw_reset(gsc);
-       gsc_wait_reset(gsc);
-       gsc_m2m_resume(gsc);
-
-       return 0;
-}
-
-static int gsc_runtime_suspend(struct device *dev)
-{
-       struct gsc_dev *gsc = dev_get_drvdata(dev);
-       int ret = 0;
-       int i;
-
-       ret = gsc_m2m_suspend(gsc);
-       if (ret)
-               return ret;
-
-       for (i = gsc->num_clocks - 1; i >= 0; i--)
-               clk_disable_unprepare(gsc->clock[i]);
-
-       pr_debug("gsc%d: state: 0x%lx\n", gsc->id, gsc->state);
-       return ret;
-}
-#endif
-
-static const struct dev_pm_ops gsc_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
-                               pm_runtime_force_resume)
-       SET_RUNTIME_PM_OPS(gsc_runtime_suspend, gsc_runtime_resume, NULL)
-};
-
-static struct platform_driver gsc_driver = {
-       .probe          = gsc_probe,
-       .remove         = gsc_remove,
-       .driver = {
-               .name   = GSC_MODULE_NAME,
-               .pm     = &gsc_pm_ops,
-               .of_match_table = exynos_gsc_match,
-       }
-};
-
-module_platform_driver(gsc_driver);
-
-MODULE_AUTHOR("Hyunwong Kim <khw0178.kim@samsung.com>");
-MODULE_DESCRIPTION("Samsung EXYNOS5 Soc series G-Scaler driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.h b/drivers/media/platform/exynos-gsc/gsc-core.h
deleted file mode 100644 (file)
index e894e85..0000000
+++ /dev/null
@@ -1,521 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com
- *
- * header file for Samsung EXYNOS5 SoC series G-Scaler driver
-
- */
-
-#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-v4l2.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-mem2mem.h>
-#include <media/v4l2-mediabus.h>
-#include <media/videobuf2-dma-contig.h>
-
-#include "gsc-regs.h"
-
-#define CONFIG_VB2_GSC_DMA_CONTIG      1
-#define GSC_MODULE_NAME                        "exynos-gsc"
-
-#define GSC_SHUTDOWN_TIMEOUT           ((100*HZ)/1000)
-#define GSC_MAX_DEVS                   4
-#define GSC_MAX_CLOCKS                 4
-#define GSC_M2M_BUF_NUM                        0
-#define GSC_MAX_CTRL_NUM               10
-#define GSC_SC_ALIGN_4                 4
-#define GSC_SC_ALIGN_2                 2
-#define DEFAULT_CSC_EQ                 1
-#define DEFAULT_CSC_RANGE              1
-
-#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_STOP_REQ               (1 << 6)
-#define        GSC_CTX_ABORT                   (1 << 7)
-
-enum gsc_dev_flags {
-       /* for m2m node */
-       ST_M2M_OPEN,
-       ST_M2M_RUN,
-       ST_M2M_PEND,
-       ST_M2M_SUSPENDED,
-       ST_M2M_SUSPENDING,
-};
-
-enum gsc_irq {
-       GSC_IRQ_DONE,
-       GSC_IRQ_OVERRUN
-};
-
-/**
- * enum gsc_datapath - the path of data used for G-Scaler
- * @GSC_CAMERA: from camera
- * @GSC_DMA: from/to DMA
- * @GSC_WRITEBACK: from FIMD
- */
-enum gsc_datapath {
-       GSC_CAMERA = 0x1,
-       GSC_DMA,
-       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_active(dev)    test_bit(ST_M2M_RUN, &(dev)->state)
-#define gsc_m2m_pending(dev)   test_bit(ST_M2M_PEND, &(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
- * @pixelformat: the fourcc code for this format, 0 if not applicable
- * @color: color encoding
- * @yorder: Y/C order
- * @corder: Chrominance order control
- * @num_planes: number of physically non-contiguous data planes
- * @num_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 {
-       u32 mbus_code;
-       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_v4l2_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
- */
-struct gsc_ctrls {
-       struct v4l2_ctrl *rotate;
-       struct v4l2_ctrl *hflip;
-       struct v4l2_ctrl *vflip;
-       struct v4l2_ctrl *global_alpha;
-};
-
-/**
- * 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;
-       u32 main_hratio;
-       u32 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
- * @colorspace: value indicating v4l2_colorspace
- * @alpha:     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;
-       const struct gsc_fmt *fmt;
-       u32 colorspace;
-       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.
- * @num_entities: the number of g-scalers
- * @clk_names: clock names
- * @num_clocks: the number of clocks in @clk_names
- * @num_entities: the number of g-scalers
- */
-struct gsc_driverdata {
-       struct gsc_variant *variant[GSC_MAX_DEVS];
-       const char      *clk_names[GSC_MAX_CLOCKS];
-       int             num_clocks;
-       int             num_entities;
-};
-
-/**
- * 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)
- * @num_clocks:        number of clocks required for G-Scaler operation
- * @clock:     clocks required for G-Scaler operation
- * @regs:      the mapped hardware registers
- * @irq_queue: interrupt handler waitqueue
- * @m2m:       memory-to-memory V4L2 device information
- * @state:     flags used to synchronize m2m and capture mode operation
- * @vdev:      video device for G-Scaler instance
- * @v4l2_dev:  v4l2_device for G-Scaler instance
- */
-struct gsc_dev {
-       spinlock_t                      slock;
-       struct mutex                    lock;
-       struct platform_device          *pdev;
-       struct gsc_variant              *variant;
-       u16                             id;
-       int                             num_clocks;
-       struct clk                      *clock[GSC_MAX_CLOCKS];
-       void __iomem                    *regs;
-       wait_queue_head_t               irq_queue;
-       struct gsc_m2m_device           m2m;
-       unsigned long                   state;
-       struct video_device             vdev;
-       struct v4l2_device              v4l2_dev;
-};
-
-/**
- * struct gsc_ctx - the device context data
- * @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
- * @rotation:          rotation
- * @hflip:             horizontal flip
- * @vflip:             vertical flip
- * @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
- * @gsc_ctrls:         G-Scaler control set
- * @ctrls_rdy:          true if the control handler is initialized
- * @out_colorspace:     the colorspace of the OUTPUT queue
- */
-struct gsc_ctx {
-       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;
-       int                     rotation;
-       unsigned int            hflip:1;
-       unsigned int            vflip:1;
-       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;
-       enum v4l2_colorspace out_colorspace;
-};
-
-void gsc_set_prefbuf(struct gsc_dev *gsc, struct gsc_frame *frm);
-int gsc_register_m2m_device(struct gsc_dev *gsc);
-void gsc_unregister_m2m_device(struct gsc_dev *gsc);
-void gsc_m2m_job_finish(struct gsc_ctx *ctx, int vb_state);
-
-u32 get_plane_size(struct gsc_frame *fr, unsigned int plane);
-const struct gsc_fmt *get_format(int index);
-const struct gsc_fmt *find_fmt(u32 *pixelformat, u32 *mbus_code, u32 index);
-int gsc_enum_fmt(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_try_selection(struct gsc_ctx *ctx, struct v4l2_selection *s);
-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_prepare_addr(struct gsc_ctx *ctx, struct vb2_buffer *vb,
-                    struct gsc_frame *frame, struct gsc_addr *addr);
-
-static inline void gsc_ctx_state_lock_set(u32 state, struct gsc_ctx *ctx)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&ctx->gsc_dev->slock, flags);
-       ctx->state |= state;
-       spin_unlock_irqrestore(&ctx->gsc_dev->slock, flags);
-}
-
-static inline void gsc_ctx_state_lock_clear(u32 state, struct gsc_ctx *ctx)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&ctx->gsc_dev->slock, flags);
-       ctx->state &= ~state;
-       spin_unlock_irqrestore(&ctx->gsc_dev->slock, flags);
-}
-
-static inline int is_tiled(const struct gsc_fmt *fmt)
-{
-       return fmt->pixelformat == V4L2_PIX_FMT_NV12MT_16X16;
-}
-
-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 & GSC_IRQ_STATUS_OR_IRQ)
-               return GSC_IRQ_OVERRUN;
-       else
-               return GSC_IRQ_DONE;
-
-}
-
-static inline void gsc_hw_clear_irq(struct gsc_dev *dev, int irq)
-{
-       u32 cfg = readl(dev->regs + GSC_IRQ);
-       if (irq == GSC_IRQ_OVERRUN)
-               cfg |= GSC_IRQ_STATUS_OR_IRQ;
-       else if (irq == GSC_IRQ_DONE)
-               cfg |= GSC_IRQ_STATUS_FRM_DONE_IRQ;
-       writel(cfg, dev->regs + GSC_IRQ);
-}
-
-static inline bool gsc_ctx_state_is_set(u32 mask, struct gsc_ctx *ctx)
-{
-       unsigned long flags;
-       bool ret;
-
-       spin_lock_irqsave(&ctx->gsc_dev->slock, flags);
-       ret = (ctx->state & mask) == mask;
-       spin_unlock_irqrestore(&ctx->gsc_dev->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 {
-               pr_err("Wrong buffer/video queue type (%d)", type);
-               return ERR_PTR(-EINVAL);
-       }
-
-       return frame;
-}
-
-void gsc_hw_set_sw_reset(struct gsc_dev *dev);
-int gsc_wait_reset(struct gsc_dev *dev);
-
-void gsc_hw_set_frm_done_irq_mask(struct gsc_dev *dev, bool mask);
-void gsc_hw_set_gsc_irq_enable(struct gsc_dev *dev, bool mask);
-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);
-
-#endif /* GSC_CORE_H_ */
diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c
deleted file mode 100644 (file)
index f1cf847..0000000
+++ /dev/null
@@ -1,794 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com
- *
- * Samsung EXYNOS5 SoC series G-Scaler driver
- */
-
-#include <linux/module.h>
-#include <linux/kernel.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_m2m_ctx_stop_req(struct gsc_ctx *ctx)
-{
-       struct gsc_ctx *curr_ctx;
-       struct gsc_dev *gsc = ctx->gsc_dev;
-       int ret;
-
-       curr_ctx = v4l2_m2m_get_curr_priv(gsc->m2m.m2m_dev);
-       if (!gsc_m2m_pending(gsc) || (curr_ctx != ctx))
-               return 0;
-
-       gsc_ctx_state_lock_set(GSC_CTX_STOP_REQ, ctx);
-       ret = wait_event_timeout(gsc->irq_queue,
-                       !gsc_ctx_state_is_set(GSC_CTX_STOP_REQ, ctx),
-                       GSC_SHUTDOWN_TIMEOUT);
-
-       return ret == 0 ? -ETIMEDOUT : ret;
-}
-
-static void __gsc_m2m_job_abort(struct gsc_ctx *ctx)
-{
-       int ret;
-
-       ret = gsc_m2m_ctx_stop_req(ctx);
-       if ((ret == -ETIMEDOUT) || (ctx->state & GSC_CTX_ABORT)) {
-               gsc_ctx_state_lock_clear(GSC_CTX_STOP_REQ | GSC_CTX_ABORT, ctx);
-               gsc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
-       }
-}
-
-static int gsc_m2m_start_streaming(struct vb2_queue *q, unsigned int count)
-{
-       struct gsc_ctx *ctx = q->drv_priv;
-
-       return pm_runtime_resume_and_get(&ctx->gsc_dev->pdev->dev);
-}
-
-static void __gsc_m2m_cleanup_queue(struct gsc_ctx *ctx)
-{
-       struct vb2_v4l2_buffer *src_vb, *dst_vb;
-
-       while (v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) > 0) {
-               src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
-               v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR);
-       }
-
-       while (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) > 0) {
-               dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
-               v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR);
-       }
-}
-
-static void gsc_m2m_stop_streaming(struct vb2_queue *q)
-{
-       struct gsc_ctx *ctx = q->drv_priv;
-
-       __gsc_m2m_job_abort(ctx);
-
-       __gsc_m2m_cleanup_queue(ctx);
-
-       pm_runtime_put(&ctx->gsc_dev->pdev->dev);
-}
-
-void gsc_m2m_job_finish(struct gsc_ctx *ctx, int vb_state)
-{
-       struct vb2_v4l2_buffer *src_vb, *dst_vb;
-
-       if (!ctx || !ctx->m2m_ctx)
-               return;
-
-       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) {
-               dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp;
-               dst_vb->timecode = src_vb->timecode;
-               dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
-               dst_vb->flags |=
-                       src_vb->flags
-                       & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
-
-               v4l2_m2m_buf_done(src_vb, vb_state);
-               v4l2_m2m_buf_done(dst_vb, vb_state);
-
-               v4l2_m2m_job_finish(ctx->gsc_dev->m2m.m2m_dev,
-                                   ctx->m2m_ctx);
-       }
-}
-
-static void gsc_m2m_job_abort(void *priv)
-{
-       __gsc_m2m_job_abort((struct gsc_ctx *)priv);
-}
-
-static int gsc_get_bufs(struct gsc_ctx *ctx)
-{
-       struct gsc_frame *s_frame, *d_frame;
-       struct vb2_v4l2_buffer *src_vb, *dst_vb;
-       int ret;
-
-       s_frame = &ctx->s_frame;
-       d_frame = &ctx->d_frame;
-
-       src_vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
-       ret = gsc_prepare_addr(ctx, &src_vb->vb2_buf, s_frame, &s_frame->addr);
-       if (ret)
-               return ret;
-
-       dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
-       ret = gsc_prepare_addr(ctx, &dst_vb->vb2_buf, d_frame, &d_frame->addr);
-       if (ret)
-               return ret;
-
-       dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp;
-
-       return 0;
-}
-
-static void gsc_m2m_device_run(void *priv)
-{
-       struct gsc_ctx *ctx = priv;
-       struct gsc_dev *gsc;
-       unsigned long flags;
-       int ret;
-       bool is_set = false;
-
-       if (WARN(!ctx, "null hardware context\n"))
-               return;
-
-       gsc = ctx->gsc_dev;
-       spin_lock_irqsave(&gsc->slock, flags);
-
-       set_bit(ST_M2M_PEND, &gsc->state);
-
-       /* Reconfigure hardware if the context has changed. */
-       if (gsc->m2m.ctx != ctx) {
-               pr_debug("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;
-       if (is_set) {
-               ctx->state &= ~GSC_CTX_STOP_REQ;
-               ctx->state |= GSC_CTX_ABORT;
-               wake_up(&gsc->irq_queue);
-               goto put_device;
-       }
-
-       ret = gsc_get_bufs(ctx);
-       if (ret) {
-               pr_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)) {
-                       pr_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);
-       }
-
-       /* update shadow registers */
-       gsc_hw_set_sfr_update(ctx);
-
-       ctx->state &= ~GSC_PARAMS;
-       gsc_hw_enable_control(gsc, true);
-
-       spin_unlock_irqrestore(&gsc->slock, flags);
-       return;
-
-put_device:
-       ctx->state &= ~GSC_PARAMS;
-       spin_unlock_irqrestore(&gsc->slock, flags);
-}
-
-static int gsc_m2m_queue_setup(struct vb2_queue *vq,
-                       unsigned int *num_buffers, unsigned int *num_planes,
-                       unsigned int sizes[], struct device *alloc_devs[])
-{
-       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] = frame->payload[i];
-       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_CAPTURE(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 vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
-       struct gsc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-
-       pr_debug("ctx: %p, ctx->state: 0x%x", ctx, ctx->state);
-
-       if (ctx->m2m_ctx)
-               v4l2_m2m_buf_queue(ctx->m2m_ctx, vbuf);
-}
-
-static const 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    = vb2_ops_wait_prepare,
-       .wait_finish     = vb2_ops_wait_finish,
-       .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;
-
-       strscpy(cap->driver, GSC_MODULE_NAME, sizeof(cap->driver));
-       strscpy(cap->card, GSC_MODULE_NAME " gscaler", sizeof(cap->card));
-       snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
-                dev_name(&gsc->pdev->dev));
-       return 0;
-}
-
-static int gsc_m2m_enum_fmt(struct file *file, void *priv,
-                           struct v4l2_fmtdesc *f)
-{
-       return gsc_enum_fmt(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)) {
-               pr_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);
-       frame->colorspace = pix->colorspace;
-       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);
-
-       pr_debug("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;
-       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;
-
-       return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
-}
-
-static int gsc_m2m_expbuf(struct file *file, void *fh,
-                               struct v4l2_exportbuffer *eb)
-{
-       struct gsc_ctx *ctx = fh_to_ctx(fh);
-       return v4l2_m2m_expbuf(file, ctx->m2m_ctx, eb);
-}
-
-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) &&
-           (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
-               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:
-       case V4L2_SEL_TGT_CROP:
-               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 gsc_variant *variant = ctx->gsc_dev->variant;
-       struct v4l2_selection sel = *s;
-       int ret;
-
-       if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
-           (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
-               return -EINVAL;
-
-       ret = gsc_try_selection(ctx, &sel);
-       if (ret)
-               return ret;
-
-       if (s->flags & V4L2_SEL_FLAG_LE &&
-           !is_rectangle_enclosed(&sel.r, &s->r))
-               return -ERANGE;
-
-       if (s->flags & V4L2_SEL_FLAG_GE &&
-           !is_rectangle_enclosed(&s->r, &sel.r))
-               return -ERANGE;
-
-       s->r = sel.r;
-
-       switch (s->target) {
-       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
-       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
-       case V4L2_SEL_TGT_COMPOSE:
-               frame = &ctx->s_frame;
-               break;
-
-       case V4L2_SEL_TGT_CROP_BOUNDS:
-       case V4L2_SEL_TGT_CROP:
-       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, sel.r.width,
-                               sel.r.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, sel.r.width,
-                               sel.r.height, ctx->gsc_ctrls.rotate->val,
-                               ctx->out_path);
-               }
-
-               if (ret) {
-                       pr_err("Out of scaler range");
-                       return -EINVAL;
-               }
-       }
-
-       frame->crop = sel.r;
-
-       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        = gsc_m2m_enum_fmt,
-       .vidioc_enum_fmt_vid_out        = gsc_m2m_enum_fmt,
-       .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_expbuf                  = gsc_m2m_expbuf,
-       .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 | VB2_DMABUF;
-       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);
-       src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
-       src_vq->lock = &ctx->gsc_dev->lock;
-       src_vq->dev = &ctx->gsc_dev->pdev->dev;
-
-       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 | VB2_DMABUF;
-       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);
-       dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
-       dst_vq->lock = &ctx->gsc_dev->lock;
-       dst_vq->dev = &ctx->gsc_dev->pdev->dev;
-
-       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;
-
-       pr_debug("pid: %d, state: 0x%lx", task_pid_nr(current), gsc->state);
-
-       if (mutex_lock_interruptible(&gsc->lock))
-               return -ERESTARTSYS;
-
-       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
-       if (!ctx) {
-               ret = -ENOMEM;
-               goto unlock;
-       }
-
-       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;
-
-       ctx->m2m_ctx = v4l2_m2m_ctx_init(gsc->m2m.m2m_dev, ctx, queue_init);
-       if (IS_ERR(ctx->m2m_ctx)) {
-               pr_err("Failed to initialize m2m context");
-               ret = PTR_ERR(ctx->m2m_ctx);
-               goto error_ctrls;
-       }
-
-       if (gsc->m2m.refcnt++ == 0)
-               set_bit(ST_M2M_OPEN, &gsc->state);
-
-       pr_debug("gsc m2m driver is opened, ctx(0x%p)", ctx);
-
-       mutex_unlock(&gsc->lock);
-       return 0;
-
-error_ctrls:
-       gsc_ctrls_delete(ctx);
-       v4l2_fh_del(&ctx->fh);
-error_fh:
-       v4l2_fh_exit(&ctx->fh);
-       kfree(ctx);
-unlock:
-       mutex_unlock(&gsc->lock);
-       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;
-
-       pr_debug("pid: %d, state: 0x%lx, refcnt= %d",
-               task_pid_nr(current), gsc->state, gsc->m2m.refcnt);
-
-       mutex_lock(&gsc->lock);
-
-       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);
-
-       mutex_unlock(&gsc->lock);
-       return 0;
-}
-
-static __poll_t gsc_m2m_poll(struct file *file,
-                                       struct poll_table_struct *wait)
-{
-       struct gsc_ctx *ctx = fh_to_ctx(file->private_data);
-       struct gsc_dev *gsc = ctx->gsc_dev;
-       __poll_t ret;
-
-       if (mutex_lock_interruptible(&gsc->lock))
-               return EPOLLERR;
-
-       ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
-       mutex_unlock(&gsc->lock);
-
-       return ret;
-}
-
-static int gsc_m2m_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct gsc_ctx *ctx = fh_to_ctx(file->private_data);
-       struct gsc_dev *gsc = ctx->gsc_dev;
-       int ret;
-
-       if (mutex_lock_interruptible(&gsc->lock))
-               return -ERESTARTSYS;
-
-       ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
-       mutex_unlock(&gsc->lock);
-
-       return ret;
-}
-
-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 const 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 platform_device *pdev;
-       int ret;
-
-       if (!gsc)
-               return -ENODEV;
-
-       pdev = gsc->pdev;
-
-       gsc->vdev.fops          = &gsc_m2m_fops;
-       gsc->vdev.ioctl_ops     = &gsc_m2m_ioctl_ops;
-       gsc->vdev.release       = video_device_release_empty;
-       gsc->vdev.lock          = &gsc->lock;
-       gsc->vdev.vfl_dir       = VFL_DIR_M2M;
-       gsc->vdev.v4l2_dev      = &gsc->v4l2_dev;
-       gsc->vdev.device_caps   = V4L2_CAP_STREAMING |
-                                 V4L2_CAP_VIDEO_M2M_MPLANE;
-       snprintf(gsc->vdev.name, sizeof(gsc->vdev.name), "%s.%d:m2m",
-                                       GSC_MODULE_NAME, gsc->id);
-
-       video_set_drvdata(&gsc->vdev, gsc);
-
-       gsc->m2m.vfd = &gsc->vdev;
-       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");
-               return PTR_ERR(gsc->m2m.m2m_dev);
-       }
-
-       ret = video_register_device(&gsc->vdev, VFL_TYPE_VIDEO, -1);
-       if (ret) {
-               dev_err(&pdev->dev,
-                        "%s(): failed to register video device\n", __func__);
-               goto err_m2m_release;
-       }
-
-       pr_debug("gsc m2m driver registered as /dev/video%d", gsc->vdev.num);
-       return 0;
-
-err_m2m_release:
-       v4l2_m2m_release(gsc->m2m.m2m_dev);
-
-       return ret;
-}
-
-void gsc_unregister_m2m_device(struct gsc_dev *gsc)
-{
-       if (gsc) {
-               v4l2_m2m_release(gsc->m2m.m2m_dev);
-               video_unregister_device(&gsc->vdev);
-       }
-}
diff --git a/drivers/media/platform/exynos-gsc/gsc-regs.c b/drivers/media/platform/exynos-gsc/gsc-regs.c
deleted file mode 100644 (file)
index 995a1f0..0000000
+++ /dev/null
@@ -1,426 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com
- *
- * Samsung EXYNOS5 SoC series G-Scaler driver
- */
-
-#include <linux/io.h>
-#include <linux/delay.h>
-
-#include "gsc-core.h"
-
-void gsc_hw_set_sw_reset(struct gsc_dev *dev)
-{
-       writel(GSC_SW_RESET_SRESET, dev->regs + GSC_SW_RESET);
-}
-
-int gsc_wait_reset(struct gsc_dev *dev)
-{
-       unsigned long end = jiffies + msecs_to_jiffies(50);
-       u32 cfg;
-
-       while (time_before(jiffies, end)) {
-               cfg = readl(dev->regs + GSC_SW_RESET);
-               if (!cfg)
-                       return 0;
-               usleep_range(10, 20);
-       }
-
-       return -EBUSY;
-}
-
-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_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_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);
-}
-
-void gsc_hw_set_input_addr(struct gsc_dev *dev, struct gsc_addr *addr,
-                               int index)
-{
-       pr_debug("src_buf[%d]: %pad, cb: %pad, cr: %pad", 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)
-{
-       pr_debug("dst_buf[%d]: %pad, cb: %pad, cr: %pad",
-                       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 (frame->colorspace == V4L2_COLORSPACE_REC709)
-               cfg |= GSC_IN_RGB_HD_WIDE;
-       else
-               cfg |= GSC_IN_RGB_SD_WIDE;
-
-       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 (frame->colorspace == V4L2_COLORSPACE_REC709)
-               cfg |= GSC_OUT_RGB_HD_WIDE;
-       else
-               cfg |= GSC_OUT_RGB_SD_WIDE;
-
-       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)) {
-               pr_debug("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/platform/exynos-gsc/gsc-regs.h b/drivers/media/platform/exynos-gsc/gsc-regs.h
deleted file mode 100644 (file)
index d4f7ead..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com
- *
- * Register definition file for Samsung G-Scaler driver
- */
-
-#ifndef REGS_GSC_H_
-#define REGS_GSC_H_
-
-/* G-Scaler enable */
-#define GSC_ENABLE                     0x00
-#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_FRM_DONE_IRQ    (1 << 16)
-#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_NARROW           (3 << 14)
-#define GSC_IN_RGB_HD_WIDE             (2 << 14)
-#define GSC_IN_RGB_SD_NARROW           (1 << 14)
-#define GSC_IN_RGB_SD_WIDE             (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_MODE               (1 << 3)
-#define GSC_IN_LOCAL_SEL_MASK          (3 << 1)
-#define GSC_IN_PATH_MASK               (1 << 0)
-#define GSC_IN_PATH_MEMORY             (0 << 0)
-
-/* G-Scaler source image size */
-#define GSC_SRCIMG_SIZE                        0x14
-#define GSC_SRCIMG_HEIGHT(x)           ((x) << 16)
-#define GSC_SRCIMG_WIDTH(x)            ((x) << 0)
-
-/* G-Scaler source image offset */
-#define GSC_SRCIMG_OFFSET              0x18
-#define GSC_SRCIMG_OFFSET_Y(x)         ((x) << 16)
-#define GSC_SRCIMG_OFFSET_X(x)         ((x) << 0)
-
-/* G-Scaler cropped source image size */
-#define GSC_CROPPED_SIZE               0x1c
-#define GSC_CROPPED_HEIGHT(x)          ((x) << 16)
-#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_WIDE            (3 << 10)
-#define GSC_OUT_RGB_HD_NARROW          (2 << 10)
-#define GSC_OUT_RGB_SD_WIDE            (1 << 10)
-#define GSC_OUT_RGB_SD_NARROW          (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_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(x)           ((x) << 16)
-#define GSC_SCALED_WIDTH(x)            ((x) << 0)
-
-/* G-Scaler pre scale ratio */
-#define GSC_PRE_SCALE_RATIO            0x28
-#define GSC_PRESC_SHFACTOR(x)          ((x) << 28)
-#define GSC_PRESC_V_RATIO(x)           ((x) << 16)
-#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_VALUE(x)      ((x) << 0)
-
-/* G-Scaler main scale vertical ratio */
-#define GSC_MAIN_V_RATIO               0x30
-#define GSC_MAIN_V_RATIO_VALUE(x)      ((x) << 0)
-
-/* G-Scaler destination image size */
-#define GSC_DSTIMG_SIZE                        0x40
-#define GSC_DSTIMG_HEIGHT(x)           ((x) << 16)
-#define GSC_DSTIMG_WIDTH(x)            ((x) << 0)
-
-/* G-Scaler destination image offset */
-#define GSC_DSTIMG_OFFSET              0x44
-#define GSC_DSTIMG_OFFSET_Y(x)         ((x) << 16)
-#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 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)
-
-#endif /* REGS_GSC_H_ */
diff --git a/drivers/media/platform/samsung/exynos-gsc/Kconfig b/drivers/media/platform/samsung/exynos-gsc/Kconfig
new file mode 100644 (file)
index 0000000..f9bdffe
--- /dev/null
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config VIDEO_SAMSUNG_EXYNOS_GSC
+       tristate "Samsung Exynos G-Scaler driver"
+       depends on V4L_MEM2MEM_DRIVERS
+       depends on VIDEO_DEV && VIDEO_V4L2
+       depends on ARCH_EXYNOS || COMPILE_TEST
+       select VIDEOBUF2_DMA_CONTIG
+       select V4L2_MEM2MEM_DEV
+       help
+         This is a v4l2 driver for Samsung EXYNOS5 SoC G-Scaler.
diff --git a/drivers/media/platform/samsung/exynos-gsc/Makefile b/drivers/media/platform/samsung/exynos-gsc/Makefile
new file mode 100644 (file)
index 0000000..bcefbad
--- /dev/null
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+exynos-gsc-objs := gsc-core.o gsc-m2m.o gsc-regs.o
+
+obj-$(CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC) += exynos-gsc.o
diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-core.c b/drivers/media/platform/samsung/exynos-gsc/gsc-core.c
new file mode 100644 (file)
index 0000000..e3559b0
--- /dev/null
@@ -0,0 +1,1327 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Samsung EXYNOS5 SoC series G-Scaler driver
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.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 <linux/of.h>
+#include <linux/of_device.h>
+#include <media/v4l2-ioctl.h>
+
+#include "gsc-core.h"
+
+static const struct gsc_fmt gsc_formats[] = {
+       {
+               .pixelformat    = V4L2_PIX_FMT_RGB565X,
+               .depth          = { 16 },
+               .color          = GSC_RGB,
+               .num_planes     = 1,
+               .num_comp       = 1,
+       }, {
+               .pixelformat    = V4L2_PIX_FMT_BGR32,
+               .depth          = { 32 },
+               .color          = GSC_RGB,
+               .num_planes     = 1,
+               .num_comp       = 1,
+       }, {
+               .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      = MEDIA_BUS_FMT_YUYV8_2X8,
+       }, {
+               .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      = MEDIA_BUS_FMT_UYVY8_2X8,
+       }, {
+               .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      = MEDIA_BUS_FMT_VYUY8_2X8,
+       }, {
+               .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      = MEDIA_BUS_FMT_YVYU8_2X8,
+       }, {
+               .pixelformat    = V4L2_PIX_FMT_YUV32,
+               .depth          = { 32 },
+               .color          = GSC_YUV444,
+               .yorder         = GSC_LSB_Y,
+               .corder         = GSC_CBCR,
+               .num_planes     = 1,
+               .num_comp       = 1,
+       }, {
+               .pixelformat    = V4L2_PIX_FMT_YUV422P,
+               .depth          = { 16 },
+               .color          = GSC_YUV422,
+               .yorder         = GSC_LSB_Y,
+               .corder         = GSC_CBCR,
+               .num_planes     = 1,
+               .num_comp       = 3,
+       }, {
+               .pixelformat    = V4L2_PIX_FMT_NV16,
+               .depth          = { 16 },
+               .color          = GSC_YUV422,
+               .yorder         = GSC_LSB_Y,
+               .corder         = GSC_CBCR,
+               .num_planes     = 1,
+               .num_comp       = 2,
+       }, {
+               .pixelformat    = V4L2_PIX_FMT_NV16M,
+               .depth          = { 8, 8 },
+               .color          = GSC_YUV422,
+               .yorder         = GSC_LSB_Y,
+               .corder         = GSC_CBCR,
+               .num_planes     = 2,
+               .num_comp       = 2,
+       }, {
+               .pixelformat    = V4L2_PIX_FMT_NV61,
+               .depth          = { 16 },
+               .color          = GSC_YUV422,
+               .yorder         = GSC_LSB_Y,
+               .corder         = GSC_CRCB,
+               .num_planes     = 1,
+               .num_comp       = 2,
+       }, {
+               .pixelformat    = V4L2_PIX_FMT_NV61M,
+               .depth          = { 8, 8 },
+               .color          = GSC_YUV422,
+               .yorder         = GSC_LSB_Y,
+               .corder         = GSC_CRCB,
+               .num_planes     = 2,
+               .num_comp       = 2,
+       }, {
+               .pixelformat    = V4L2_PIX_FMT_YUV420,
+               .depth          = { 12 },
+               .color          = GSC_YUV420,
+               .yorder         = GSC_LSB_Y,
+               .corder         = GSC_CBCR,
+               .num_planes     = 1,
+               .num_comp       = 3,
+       }, {
+               .pixelformat    = V4L2_PIX_FMT_YVU420,
+               .depth          = { 12 },
+               .color          = GSC_YUV420,
+               .yorder         = GSC_LSB_Y,
+               .corder         = GSC_CRCB,
+               .num_planes     = 1,
+               .num_comp       = 3,
+
+       }, {
+               .pixelformat    = V4L2_PIX_FMT_NV12,
+               .depth          = { 12 },
+               .color          = GSC_YUV420,
+               .yorder         = GSC_LSB_Y,
+               .corder         = GSC_CBCR,
+               .num_planes     = 1,
+               .num_comp       = 2,
+       }, {
+               .pixelformat    = V4L2_PIX_FMT_NV21,
+               .depth          = { 12 },
+               .color          = GSC_YUV420,
+               .yorder         = GSC_LSB_Y,
+               .corder         = GSC_CRCB,
+               .num_planes     = 1,
+               .num_comp       = 2,
+       }, {
+               .pixelformat    = V4L2_PIX_FMT_NV21M,
+               .depth          = { 8, 4 },
+               .color          = GSC_YUV420,
+               .yorder         = GSC_LSB_Y,
+               .corder         = GSC_CRCB,
+               .num_planes     = 2,
+               .num_comp       = 2,
+       }, {
+               .pixelformat    = V4L2_PIX_FMT_NV12M,
+               .depth          = { 8, 4 },
+               .color          = GSC_YUV420,
+               .yorder         = GSC_LSB_Y,
+               .corder         = GSC_CBCR,
+               .num_planes     = 2,
+               .num_comp       = 2,
+       }, {
+               .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,
+       }, {
+               .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,
+       }, {
+               .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,
+       }
+};
+
+const struct gsc_fmt *get_format(int index)
+{
+       if (index >= ARRAY_SIZE(gsc_formats))
+               return NULL;
+
+       return (struct gsc_fmt *)&gsc_formats[index];
+}
+
+const struct gsc_fmt *find_fmt(u32 *pixelformat, u32 *mbus_code, u32 index)
+{
+       const 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) {
+               pr_err("Exceeded maximum downscaling 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);
+               pr_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);
+               pr_info("cropped src height size is recalculated from %d to %d",
+                       s_frame->crop.height + remainder, s_frame->crop.height);
+       }
+}
+
+int gsc_enum_fmt(struct v4l2_fmtdesc *f)
+{
+       const struct gsc_fmt *fmt;
+
+       fmt = find_fmt(NULL, NULL, f->index);
+       if (!fmt)
+               return -EINVAL;
+
+       f->pixelformat = fmt->pixelformat;
+
+       return 0;
+}
+
+static int get_plane_info(struct gsc_frame *frm, u32 addr, u32 *index, u32 *ret_addr)
+{
+       if (frm->addr.y == addr) {
+               *index = 0;
+               *ret_addr = frm->addr.y;
+       } else if (frm->addr.cb == addr) {
+               *index = 1;
+               *ret_addr = frm->addr.cb;
+       } else if (frm->addr.cr == addr) {
+               *index = 2;
+               *ret_addr = frm->addr.cr;
+       } else {
+               pr_err("Plane address is wrong");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+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);
+               if (get_plane_info(frm, t_min, &low_plane, &low_addr))
+                       return;
+               t_max = max3(frm->addr.y, frm->addr.cb, frm->addr.cr);
+               if (get_plane_info(frm, t_max, &high_plane, &high_addr))
+                       return;
+
+               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];
+               }
+       }
+       pr_debug("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;
+       const struct gsc_fmt *fmt;
+       u32 max_w, max_h, mod_x, mod_y;
+       u32 min_w, min_h, tmp_w, tmp_h;
+       int i;
+
+       pr_debug("user put w: %d, h: %d", pix_mp->width, pix_mp->height);
+
+       fmt = find_fmt(&pix_mp->pixelformat, NULL, 0);
+       if (!fmt) {
+               pr_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) {
+               pr_debug("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;
+
+       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;
+
+       if (V4L2_TYPE_IS_OUTPUT(f->type)) {
+               min_w = variant->pix_min->org_w;
+               min_h = variant->pix_min->org_h;
+       } else {
+               min_w = variant->pix_min->target_rot_dis_w;
+               min_h = variant->pix_min->target_rot_dis_h;
+               pix_mp->colorspace = ctx->out_colorspace;
+       }
+
+       pr_debug("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)
+               pr_debug("Image size has been modified from %dx%d to %dx%d\n",
+                        tmp_w, tmp_h, pix_mp->width, pix_mp->height);
+
+       pix_mp->num_planes = fmt->num_planes;
+
+       if (V4L2_TYPE_IS_OUTPUT(f->type))
+               ctx->out_colorspace = pix_mp->colorspace;
+
+       for (i = 0; i < pix_mp->num_planes; ++i) {
+               struct v4l2_plane_pix_format *plane_fmt = &pix_mp->plane_fmt[i];
+               u32 bpl = plane_fmt->bytesperline;
+
+               if (fmt->num_comp == 1 && /* Packed */
+                   (bpl == 0 || (bpl * 8 / fmt->depth[i]) < pix_mp->width))
+                       bpl = pix_mp->width * fmt->depth[i] / 8;
+
+               if (fmt->num_comp > 1 && /* Planar */
+                   (bpl == 0 || bpl < pix_mp->width))
+                       bpl = pix_mp->width;
+
+               if (i != 0 && fmt->num_comp == 3)
+                       bpl /= 2;
+
+               plane_fmt->bytesperline = bpl;
+               plane_fmt->sizeimage = max(pix_mp->width * pix_mp->height *
+                                          fmt->depth[i] / 8,
+                                          plane_fmt->sizeimage);
+               pr_debug("[%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->num_planes      = frame->fmt->num_planes;
+       pix_mp->colorspace = ctx->out_colorspace;
+
+       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) {
+               pr_info("Cropped size has been modified from %dx%d to %dx%d",
+                                                       *w, *h, tmp_w, tmp_h);
+               *w = tmp_w;
+               *h = tmp_h;
+       }
+}
+
+int gsc_try_selection(struct gsc_ctx *ctx, struct v4l2_selection *s)
+{
+       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 (s->r.top < 0 || s->r.left < 0) {
+               pr_err("doesn't support negative values for top & left\n");
+               return -EINVAL;
+       }
+       pr_debug("user put w: %d, h: %d", s->r.width, s->r.height);
+
+       if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               f = &ctx->d_frame;
+       else if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+               f = &ctx->s_frame;
+       else
+               return -EINVAL;
+
+       max_w = f->f_width;
+       max_h = f->f_height;
+       tmp_w = s->r.width;
+       tmp_h = s->r.height;
+
+       if (V4L2_TYPE_IS_OUTPUT(s->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 = s->r.height;
+                       tmp_h = s->r.width;
+               } else {
+                       min_w = variant->pix_min->target_rot_dis_w;
+                       min_h = variant->pix_min->target_rot_dis_h;
+               }
+       }
+       pr_debug("mod_x: %d, mod_y: %d, min_w: %d, min_h = %d",
+                                       mod_x, mod_y, min_w, min_h);
+       pr_debug("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_CAPTURE(s->type) &&
+           (ctx->gsc_ctrls.rotate->val == 90 ||
+            ctx->gsc_ctrls.rotate->val == 270))
+               gsc_check_crop_change(tmp_h, tmp_w,
+                                       &s->r.width, &s->r.height);
+       else
+               gsc_check_crop_change(tmp_w, tmp_h,
+                                       &s->r.width, &s->r.height);
+
+
+       /* adjust left/top if cropping rectangle is out of bounds */
+       /* Need to add code to algin left value with 2's multiple */
+       if (s->r.left + tmp_w > max_w)
+               s->r.left = max_w - tmp_w;
+       if (s->r.top + tmp_h > max_h)
+               s->r.top = max_h - tmp_h;
+
+       if ((is_yuv420(f->fmt->color) || is_yuv422(f->fmt->color)) &&
+           s->r.left & 1)
+               s->r.left -= 1;
+
+       pr_debug("Aligned l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
+                s->r.left, s->r.top, s->r.width, s->r.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;
+
+       if (out_path == GSC_DMA)
+               sc_down_max = var->sc_down_max;
+       else
+               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;
+       struct device *dev = &ctx->gsc_dev->pdev->dev;
+       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) {
+               pr_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;
+       }
+
+       if (tx <= 0 || ty <= 0) {
+               dev_err(dev, "Invalid target size: %dx%d", tx, ty);
+               return -EINVAL;
+       }
+
+       ret = gsc_cal_prescaler_ratio(variant, s_frame->crop.width,
+                                     tx, &sc->pre_hratio);
+       if (ret) {
+               pr_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) {
+               pr_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;
+
+       pr_debug("scaler input/output size : sx = %d, sy = %d, tx = %d, ty = %d",
+                       s_frame->crop.width, s_frame->crop.height, tx, ty);
+       pr_debug("scaler ratio info : pre_shfactor : %d, pre_h : %d",
+                       sc->pre_shfactor, sc->pre_hratio);
+       pr_debug("pre_v :%d, main_h : %d, main_v : %d",
+                       sc->pre_vratio, sc->main_hratio, sc->main_vratio);
+
+       return 0;
+}
+
+static int __gsc_s_ctrl(struct gsc_ctx *ctx, struct v4l2_ctrl *ctrl)
+{
+       struct gsc_dev *gsc = ctx->gsc_dev;
+       struct gsc_variant *variant = gsc->variant;
+       unsigned int flags = GSC_DST_FMT | GSC_SRC_FMT;
+       int ret = 0;
+
+       if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
+               return 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_HFLIP:
+               ctx->hflip = ctrl->val;
+               break;
+
+       case V4L2_CID_VFLIP:
+               ctx->vflip = ctrl->val;
+               break;
+
+       case V4L2_CID_ROTATE:
+               if ((ctx->state & flags) == flags) {
+                       ret = gsc_check_scaler_ratio(variant,
+                                       ctx->s_frame.crop.width,
+                                       ctx->s_frame.crop.height,
+                                       ctx->d_frame.crop.width,
+                                       ctx->d_frame.crop.height,
+                                       ctx->gsc_ctrls.rotate->val,
+                                       ctx->out_path);
+
+                       if (ret)
+                               return -EINVAL;
+               }
+
+               ctx->rotation = ctrl->val;
+               break;
+
+       case V4L2_CID_ALPHA_COMPONENT:
+               ctx->d_frame.alpha = ctrl->val;
+               break;
+       }
+
+       ctx->state |= GSC_PARAMS;
+       return 0;
+}
+
+static int gsc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct gsc_ctx *ctx = ctrl_to_ctx(ctrl);
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&ctx->gsc_dev->slock, flags);
+       ret = __gsc_s_ctrl(ctx, ctrl);
+       spin_unlock_irqrestore(&ctx->gsc_dev->slock, flags);
+
+       return ret;
+}
+
+static const struct v4l2_ctrl_ops gsc_ctrl_ops = {
+       .s_ctrl = gsc_s_ctrl,
+};
+
+int gsc_ctrls_create(struct gsc_ctx *ctx)
+{
+       if (ctx->ctrls_rdy) {
+               pr_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_std(&ctx->ctrl_handler,
+                       &gsc_ctrl_ops, V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 0);
+
+       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);
+               pr_err("Failed to create G-Scaler control handlers");
+               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 ((vb == NULL) || (frame == NULL))
+               return -EINVAL;
+
+       pix_size = frame->f_width * frame->f_height;
+
+       pr_debug("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:
+                       /* decompose Y into Y/Cb/Cr */
+                       addr->cb = (dma_addr_t)(addr->y + pix_size);
+                       if (GSC_YUV420 == frame->fmt->color)
+                               addr->cr = (dma_addr_t)(addr->cb
+                                               + (pix_size >> 2));
+                       else /* 422 */
+                               addr->cr = (dma_addr_t)(addr->cb
+                                               + (pix_size >> 1));
+                       break;
+               default:
+                       pr_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_VYUY) ||
+               (frame->fmt->pixelformat == V4L2_PIX_FMT_YVYU) ||
+               (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420) ||
+               (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420M))
+               swap(addr->cb, addr->cr);
+
+       pr_debug("ADDR: y= %pad  cb= %pad cr= %pad 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;
+       struct gsc_ctx *ctx;
+       int gsc_irq;
+
+       gsc_irq = gsc_hw_get_irq_status(gsc);
+       gsc_hw_clear_irq(gsc, gsc_irq);
+
+       if (gsc_irq == GSC_IRQ_OVERRUN) {
+               pr_err("Local path input over-run interrupt has occurred!\n");
+               return IRQ_HANDLED;
+       }
+
+       spin_lock(&gsc->slock);
+
+       if (test_and_clear_bit(ST_M2M_PEND, &gsc->state)) {
+
+               gsc_hw_enable_control(gsc, false);
+
+               if (test_and_clear_bit(ST_M2M_SUSPENDING, &gsc->state)) {
+                       set_bit(ST_M2M_SUSPENDED, &gsc->state);
+                       wake_up(&gsc->irq_queue);
+                       goto isr_unlock;
+               }
+               ctx = v4l2_m2m_get_curr_priv(gsc->m2m.m2m_dev);
+
+               if (!ctx || !ctx->m2m_ctx)
+                       goto isr_unlock;
+
+               spin_unlock(&gsc->slock);
+               gsc_m2m_job_finish(ctx, VB2_BUF_STATE_DONE);
+
+               /* wake_up job_abort, stop_streaming */
+               if (ctx->state & GSC_CTX_STOP_REQ) {
+                       ctx->state &= ~GSC_CTX_STOP_REQ;
+                       wake_up(&gsc->irq_queue);
+               }
+               return IRQ_HANDLED;
+       }
+
+isr_unlock:
+       spin_unlock(&gsc->slock);
+       return IRQ_HANDLED;
+}
+
+static 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,
+};
+
+static struct gsc_pix_max gsc_v_5250_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          = 2016,
+       .real_rot_en_h          = 2016,
+       .target_rot_dis_w       = 4800,
+       .target_rot_dis_h       = 3344,
+       .target_rot_en_w        = 2016,
+       .target_rot_en_h        = 2016,
+};
+
+static struct gsc_pix_max gsc_v_5420_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          = 2048,
+       .real_rot_en_h          = 2048,
+       .target_rot_dis_w       = 4800,
+       .target_rot_dis_h       = 3344,
+       .target_rot_en_w        = 2016,
+       .target_rot_en_h        = 2016,
+};
+
+static struct gsc_pix_max gsc_v_5433_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,
+};
+
+static 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,
+};
+
+static 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 */
+};
+
+static 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             = 32,
+       .out_buf_cnt            = 32,
+       .sc_up_max              = 8,
+       .sc_down_max            = 16,
+       .poly_sc_down_max       = 4,
+       .pre_sc_down_max        = 4,
+       .local_sc_down          = 2,
+};
+
+static struct gsc_variant gsc_v_5250_variant = {
+       .pix_max                = &gsc_v_5250_max,
+       .pix_min                = &gsc_v_100_min,
+       .pix_align              = &gsc_v_100_align,
+       .in_buf_cnt             = 32,
+       .out_buf_cnt            = 32,
+       .sc_up_max              = 8,
+       .sc_down_max            = 16,
+       .poly_sc_down_max       = 4,
+       .pre_sc_down_max        = 4,
+       .local_sc_down          = 2,
+};
+
+static struct gsc_variant gsc_v_5420_variant = {
+       .pix_max                = &gsc_v_5420_max,
+       .pix_min                = &gsc_v_100_min,
+       .pix_align              = &gsc_v_100_align,
+       .in_buf_cnt             = 32,
+       .out_buf_cnt            = 32,
+       .sc_up_max              = 8,
+       .sc_down_max            = 16,
+       .poly_sc_down_max       = 4,
+       .pre_sc_down_max        = 4,
+       .local_sc_down          = 2,
+};
+
+static struct gsc_variant gsc_v_5433_variant = {
+       .pix_max                = &gsc_v_5433_max,
+       .pix_min                = &gsc_v_100_min,
+       .pix_align              = &gsc_v_100_align,
+       .in_buf_cnt             = 32,
+       .out_buf_cnt            = 32,
+       .sc_up_max              = 8,
+       .sc_down_max            = 16,
+       .poly_sc_down_max       = 4,
+       .pre_sc_down_max        = 4,
+       .local_sc_down          = 2,
+};
+
+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,
+       .clk_names = { "gscl" },
+       .num_clocks = 1,
+};
+
+static struct gsc_driverdata gsc_v_5250_drvdata = {
+       .variant = {
+               [0] = &gsc_v_5250_variant,
+               [1] = &gsc_v_5250_variant,
+               [2] = &gsc_v_5250_variant,
+               [3] = &gsc_v_5250_variant,
+       },
+       .num_entities = 4,
+       .clk_names = { "gscl" },
+       .num_clocks = 1,
+};
+
+static struct gsc_driverdata gsc_v_5420_drvdata = {
+       .variant = {
+               [0] = &gsc_v_5420_variant,
+               [1] = &gsc_v_5420_variant,
+       },
+       .num_entities = 2,
+       .clk_names = { "gscl" },
+       .num_clocks = 1,
+};
+
+static struct gsc_driverdata gsc_5433_drvdata = {
+       .variant = {
+               [0] = &gsc_v_5433_variant,
+               [1] = &gsc_v_5433_variant,
+               [2] = &gsc_v_5433_variant,
+       },
+       .num_entities = 3,
+       .clk_names = { "pclk", "aclk", "aclk_xiu", "aclk_gsclbend" },
+       .num_clocks = 4,
+};
+
+static const struct of_device_id exynos_gsc_match[] = {
+       {
+               .compatible = "samsung,exynos5250-gsc",
+               .data = &gsc_v_5250_drvdata,
+       },
+       {
+               .compatible = "samsung,exynos5420-gsc",
+               .data = &gsc_v_5420_drvdata,
+       },
+       {
+               .compatible = "samsung,exynos5433-gsc",
+               .data = &gsc_5433_drvdata,
+       },
+       {
+               .compatible = "samsung,exynos5-gsc",
+               .data = &gsc_v_100_drvdata,
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, exynos_gsc_match);
+
+static int gsc_probe(struct platform_device *pdev)
+{
+       struct gsc_dev *gsc;
+       struct device *dev = &pdev->dev;
+       const struct gsc_driverdata *drv_data = of_device_get_match_data(dev);
+       int irq;
+       int ret;
+       int i;
+
+       gsc = devm_kzalloc(dev, sizeof(struct gsc_dev), GFP_KERNEL);
+       if (!gsc)
+               return -ENOMEM;
+
+       ret = of_alias_get_id(pdev->dev.of_node, "gsc");
+       if (ret < 0)
+               return ret;
+
+       if (drv_data == &gsc_v_100_drvdata)
+               dev_info(dev, "compatible 'exynos5-gsc' is deprecated\n");
+
+       gsc->id = ret;
+       if (gsc->id >= drv_data->num_entities) {
+               dev_err(dev, "Invalid platform device id: %d\n", gsc->id);
+               return -EINVAL;
+       }
+
+       gsc->num_clocks = drv_data->num_clocks;
+       gsc->variant = drv_data->variant[gsc->id];
+       gsc->pdev = pdev;
+
+       init_waitqueue_head(&gsc->irq_queue);
+       spin_lock_init(&gsc->slock);
+       mutex_init(&gsc->lock);
+
+       gsc->regs = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(gsc->regs))
+               return PTR_ERR(gsc->regs);
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
+
+       for (i = 0; i < gsc->num_clocks; i++) {
+               gsc->clock[i] = devm_clk_get(dev, drv_data->clk_names[i]);
+               if (IS_ERR(gsc->clock[i])) {
+                       dev_err(dev, "failed to get clock: %s\n",
+                               drv_data->clk_names[i]);
+                       return PTR_ERR(gsc->clock[i]);
+               }
+       }
+
+       for (i = 0; i < gsc->num_clocks; i++) {
+               ret = clk_prepare_enable(gsc->clock[i]);
+               if (ret) {
+                       dev_err(dev, "clock prepare failed for clock: %s\n",
+                               drv_data->clk_names[i]);
+                       while (--i >= 0)
+                               clk_disable_unprepare(gsc->clock[i]);
+                       return ret;
+               }
+       }
+
+       ret = devm_request_irq(dev, irq, gsc_irq_handler,
+                              0, pdev->name, gsc);
+       if (ret) {
+               dev_err(dev, "failed to install irq (%d)\n", ret);
+               goto err_clk;
+       }
+
+       ret = v4l2_device_register(dev, &gsc->v4l2_dev);
+       if (ret)
+               goto err_clk;
+
+       ret = gsc_register_m2m_device(gsc);
+       if (ret)
+               goto err_v4l2;
+
+       platform_set_drvdata(pdev, gsc);
+
+       gsc_hw_set_sw_reset(gsc);
+       gsc_wait_reset(gsc);
+
+       vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32));
+
+       dev_dbg(dev, "gsc-%d registered successfully\n", gsc->id);
+
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+
+       return 0;
+
+err_v4l2:
+       v4l2_device_unregister(&gsc->v4l2_dev);
+err_clk:
+       for (i = gsc->num_clocks - 1; i >= 0; i--)
+               clk_disable_unprepare(gsc->clock[i]);
+       return ret;
+}
+
+static int gsc_remove(struct platform_device *pdev)
+{
+       struct gsc_dev *gsc = platform_get_drvdata(pdev);
+       int i;
+
+       gsc_unregister_m2m_device(gsc);
+       v4l2_device_unregister(&gsc->v4l2_dev);
+
+       vb2_dma_contig_clear_max_seg_size(&pdev->dev);
+
+       pm_runtime_disable(&pdev->dev);
+
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               for (i = 0; i < gsc->num_clocks; i++)
+                       clk_disable_unprepare(gsc->clock[i]);
+
+       pm_runtime_set_suspended(&pdev->dev);
+
+       dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int gsc_m2m_suspend(struct gsc_dev *gsc)
+{
+       unsigned long flags;
+       int timeout;
+
+       spin_lock_irqsave(&gsc->slock, flags);
+       if (!gsc_m2m_pending(gsc)) {
+               spin_unlock_irqrestore(&gsc->slock, flags);
+               return 0;
+       }
+       clear_bit(ST_M2M_SUSPENDED, &gsc->state);
+       set_bit(ST_M2M_SUSPENDING, &gsc->state);
+       spin_unlock_irqrestore(&gsc->slock, flags);
+
+       timeout = wait_event_timeout(gsc->irq_queue,
+                            test_bit(ST_M2M_SUSPENDED, &gsc->state),
+                            GSC_SHUTDOWN_TIMEOUT);
+
+       clear_bit(ST_M2M_SUSPENDING, &gsc->state);
+       return timeout == 0 ? -EAGAIN : 0;
+}
+
+static void gsc_m2m_resume(struct gsc_dev *gsc)
+{
+       struct gsc_ctx *ctx;
+       unsigned long flags;
+
+       spin_lock_irqsave(&gsc->slock, flags);
+       /* Clear for full H/W setup in first run after resume */
+       ctx = gsc->m2m.ctx;
+       gsc->m2m.ctx = NULL;
+       spin_unlock_irqrestore(&gsc->slock, flags);
+
+       if (test_and_clear_bit(ST_M2M_SUSPENDED, &gsc->state))
+               gsc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
+}
+
+static int gsc_runtime_resume(struct device *dev)
+{
+       struct gsc_dev *gsc = dev_get_drvdata(dev);
+       int ret = 0;
+       int i;
+
+       pr_debug("gsc%d: state: 0x%lx\n", gsc->id, gsc->state);
+
+       for (i = 0; i < gsc->num_clocks; i++) {
+               ret = clk_prepare_enable(gsc->clock[i]);
+               if (ret) {
+                       while (--i >= 0)
+                               clk_disable_unprepare(gsc->clock[i]);
+                       return ret;
+               }
+       }
+
+       gsc_hw_set_sw_reset(gsc);
+       gsc_wait_reset(gsc);
+       gsc_m2m_resume(gsc);
+
+       return 0;
+}
+
+static int gsc_runtime_suspend(struct device *dev)
+{
+       struct gsc_dev *gsc = dev_get_drvdata(dev);
+       int ret = 0;
+       int i;
+
+       ret = gsc_m2m_suspend(gsc);
+       if (ret)
+               return ret;
+
+       for (i = gsc->num_clocks - 1; i >= 0; i--)
+               clk_disable_unprepare(gsc->clock[i]);
+
+       pr_debug("gsc%d: state: 0x%lx\n", gsc->id, gsc->state);
+       return ret;
+}
+#endif
+
+static const struct dev_pm_ops gsc_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
+       SET_RUNTIME_PM_OPS(gsc_runtime_suspend, gsc_runtime_resume, NULL)
+};
+
+static struct platform_driver gsc_driver = {
+       .probe          = gsc_probe,
+       .remove         = gsc_remove,
+       .driver = {
+               .name   = GSC_MODULE_NAME,
+               .pm     = &gsc_pm_ops,
+               .of_match_table = exynos_gsc_match,
+       }
+};
+
+module_platform_driver(gsc_driver);
+
+MODULE_AUTHOR("Hyunwong Kim <khw0178.kim@samsung.com>");
+MODULE_DESCRIPTION("Samsung EXYNOS5 Soc series G-Scaler driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-core.h b/drivers/media/platform/samsung/exynos-gsc/gsc-core.h
new file mode 100644 (file)
index 0000000..e894e85
--- /dev/null
@@ -0,0 +1,521 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * header file for Samsung EXYNOS5 SoC series G-Scaler driver
+
+ */
+
+#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-v4l2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-mediabus.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "gsc-regs.h"
+
+#define CONFIG_VB2_GSC_DMA_CONTIG      1
+#define GSC_MODULE_NAME                        "exynos-gsc"
+
+#define GSC_SHUTDOWN_TIMEOUT           ((100*HZ)/1000)
+#define GSC_MAX_DEVS                   4
+#define GSC_MAX_CLOCKS                 4
+#define GSC_M2M_BUF_NUM                        0
+#define GSC_MAX_CTRL_NUM               10
+#define GSC_SC_ALIGN_4                 4
+#define GSC_SC_ALIGN_2                 2
+#define DEFAULT_CSC_EQ                 1
+#define DEFAULT_CSC_RANGE              1
+
+#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_STOP_REQ               (1 << 6)
+#define        GSC_CTX_ABORT                   (1 << 7)
+
+enum gsc_dev_flags {
+       /* for m2m node */
+       ST_M2M_OPEN,
+       ST_M2M_RUN,
+       ST_M2M_PEND,
+       ST_M2M_SUSPENDED,
+       ST_M2M_SUSPENDING,
+};
+
+enum gsc_irq {
+       GSC_IRQ_DONE,
+       GSC_IRQ_OVERRUN
+};
+
+/**
+ * enum gsc_datapath - the path of data used for G-Scaler
+ * @GSC_CAMERA: from camera
+ * @GSC_DMA: from/to DMA
+ * @GSC_WRITEBACK: from FIMD
+ */
+enum gsc_datapath {
+       GSC_CAMERA = 0x1,
+       GSC_DMA,
+       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_active(dev)    test_bit(ST_M2M_RUN, &(dev)->state)
+#define gsc_m2m_pending(dev)   test_bit(ST_M2M_PEND, &(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
+ * @pixelformat: the fourcc code for this format, 0 if not applicable
+ * @color: color encoding
+ * @yorder: Y/C order
+ * @corder: Chrominance order control
+ * @num_planes: number of physically non-contiguous data planes
+ * @num_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 {
+       u32 mbus_code;
+       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_v4l2_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
+ */
+struct gsc_ctrls {
+       struct v4l2_ctrl *rotate;
+       struct v4l2_ctrl *hflip;
+       struct v4l2_ctrl *vflip;
+       struct v4l2_ctrl *global_alpha;
+};
+
+/**
+ * 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;
+       u32 main_hratio;
+       u32 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
+ * @colorspace: value indicating v4l2_colorspace
+ * @alpha:     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;
+       const struct gsc_fmt *fmt;
+       u32 colorspace;
+       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.
+ * @num_entities: the number of g-scalers
+ * @clk_names: clock names
+ * @num_clocks: the number of clocks in @clk_names
+ * @num_entities: the number of g-scalers
+ */
+struct gsc_driverdata {
+       struct gsc_variant *variant[GSC_MAX_DEVS];
+       const char      *clk_names[GSC_MAX_CLOCKS];
+       int             num_clocks;
+       int             num_entities;
+};
+
+/**
+ * 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)
+ * @num_clocks:        number of clocks required for G-Scaler operation
+ * @clock:     clocks required for G-Scaler operation
+ * @regs:      the mapped hardware registers
+ * @irq_queue: interrupt handler waitqueue
+ * @m2m:       memory-to-memory V4L2 device information
+ * @state:     flags used to synchronize m2m and capture mode operation
+ * @vdev:      video device for G-Scaler instance
+ * @v4l2_dev:  v4l2_device for G-Scaler instance
+ */
+struct gsc_dev {
+       spinlock_t                      slock;
+       struct mutex                    lock;
+       struct platform_device          *pdev;
+       struct gsc_variant              *variant;
+       u16                             id;
+       int                             num_clocks;
+       struct clk                      *clock[GSC_MAX_CLOCKS];
+       void __iomem                    *regs;
+       wait_queue_head_t               irq_queue;
+       struct gsc_m2m_device           m2m;
+       unsigned long                   state;
+       struct video_device             vdev;
+       struct v4l2_device              v4l2_dev;
+};
+
+/**
+ * struct gsc_ctx - the device context data
+ * @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
+ * @rotation:          rotation
+ * @hflip:             horizontal flip
+ * @vflip:             vertical flip
+ * @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
+ * @gsc_ctrls:         G-Scaler control set
+ * @ctrls_rdy:          true if the control handler is initialized
+ * @out_colorspace:     the colorspace of the OUTPUT queue
+ */
+struct gsc_ctx {
+       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;
+       int                     rotation;
+       unsigned int            hflip:1;
+       unsigned int            vflip:1;
+       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;
+       enum v4l2_colorspace out_colorspace;
+};
+
+void gsc_set_prefbuf(struct gsc_dev *gsc, struct gsc_frame *frm);
+int gsc_register_m2m_device(struct gsc_dev *gsc);
+void gsc_unregister_m2m_device(struct gsc_dev *gsc);
+void gsc_m2m_job_finish(struct gsc_ctx *ctx, int vb_state);
+
+u32 get_plane_size(struct gsc_frame *fr, unsigned int plane);
+const struct gsc_fmt *get_format(int index);
+const struct gsc_fmt *find_fmt(u32 *pixelformat, u32 *mbus_code, u32 index);
+int gsc_enum_fmt(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_try_selection(struct gsc_ctx *ctx, struct v4l2_selection *s);
+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_prepare_addr(struct gsc_ctx *ctx, struct vb2_buffer *vb,
+                    struct gsc_frame *frame, struct gsc_addr *addr);
+
+static inline void gsc_ctx_state_lock_set(u32 state, struct gsc_ctx *ctx)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ctx->gsc_dev->slock, flags);
+       ctx->state |= state;
+       spin_unlock_irqrestore(&ctx->gsc_dev->slock, flags);
+}
+
+static inline void gsc_ctx_state_lock_clear(u32 state, struct gsc_ctx *ctx)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ctx->gsc_dev->slock, flags);
+       ctx->state &= ~state;
+       spin_unlock_irqrestore(&ctx->gsc_dev->slock, flags);
+}
+
+static inline int is_tiled(const struct gsc_fmt *fmt)
+{
+       return fmt->pixelformat == V4L2_PIX_FMT_NV12MT_16X16;
+}
+
+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 & GSC_IRQ_STATUS_OR_IRQ)
+               return GSC_IRQ_OVERRUN;
+       else
+               return GSC_IRQ_DONE;
+
+}
+
+static inline void gsc_hw_clear_irq(struct gsc_dev *dev, int irq)
+{
+       u32 cfg = readl(dev->regs + GSC_IRQ);
+       if (irq == GSC_IRQ_OVERRUN)
+               cfg |= GSC_IRQ_STATUS_OR_IRQ;
+       else if (irq == GSC_IRQ_DONE)
+               cfg |= GSC_IRQ_STATUS_FRM_DONE_IRQ;
+       writel(cfg, dev->regs + GSC_IRQ);
+}
+
+static inline bool gsc_ctx_state_is_set(u32 mask, struct gsc_ctx *ctx)
+{
+       unsigned long flags;
+       bool ret;
+
+       spin_lock_irqsave(&ctx->gsc_dev->slock, flags);
+       ret = (ctx->state & mask) == mask;
+       spin_unlock_irqrestore(&ctx->gsc_dev->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 {
+               pr_err("Wrong buffer/video queue type (%d)", type);
+               return ERR_PTR(-EINVAL);
+       }
+
+       return frame;
+}
+
+void gsc_hw_set_sw_reset(struct gsc_dev *dev);
+int gsc_wait_reset(struct gsc_dev *dev);
+
+void gsc_hw_set_frm_done_irq_mask(struct gsc_dev *dev, bool mask);
+void gsc_hw_set_gsc_irq_enable(struct gsc_dev *dev, bool mask);
+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);
+
+#endif /* GSC_CORE_H_ */
diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c b/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c
new file mode 100644 (file)
index 0000000..f1cf847
--- /dev/null
@@ -0,0 +1,794 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Samsung EXYNOS5 SoC series G-Scaler driver
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.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_m2m_ctx_stop_req(struct gsc_ctx *ctx)
+{
+       struct gsc_ctx *curr_ctx;
+       struct gsc_dev *gsc = ctx->gsc_dev;
+       int ret;
+
+       curr_ctx = v4l2_m2m_get_curr_priv(gsc->m2m.m2m_dev);
+       if (!gsc_m2m_pending(gsc) || (curr_ctx != ctx))
+               return 0;
+
+       gsc_ctx_state_lock_set(GSC_CTX_STOP_REQ, ctx);
+       ret = wait_event_timeout(gsc->irq_queue,
+                       !gsc_ctx_state_is_set(GSC_CTX_STOP_REQ, ctx),
+                       GSC_SHUTDOWN_TIMEOUT);
+
+       return ret == 0 ? -ETIMEDOUT : ret;
+}
+
+static void __gsc_m2m_job_abort(struct gsc_ctx *ctx)
+{
+       int ret;
+
+       ret = gsc_m2m_ctx_stop_req(ctx);
+       if ((ret == -ETIMEDOUT) || (ctx->state & GSC_CTX_ABORT)) {
+               gsc_ctx_state_lock_clear(GSC_CTX_STOP_REQ | GSC_CTX_ABORT, ctx);
+               gsc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
+       }
+}
+
+static int gsc_m2m_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+       struct gsc_ctx *ctx = q->drv_priv;
+
+       return pm_runtime_resume_and_get(&ctx->gsc_dev->pdev->dev);
+}
+
+static void __gsc_m2m_cleanup_queue(struct gsc_ctx *ctx)
+{
+       struct vb2_v4l2_buffer *src_vb, *dst_vb;
+
+       while (v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) > 0) {
+               src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+               v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR);
+       }
+
+       while (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) > 0) {
+               dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+               v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR);
+       }
+}
+
+static void gsc_m2m_stop_streaming(struct vb2_queue *q)
+{
+       struct gsc_ctx *ctx = q->drv_priv;
+
+       __gsc_m2m_job_abort(ctx);
+
+       __gsc_m2m_cleanup_queue(ctx);
+
+       pm_runtime_put(&ctx->gsc_dev->pdev->dev);
+}
+
+void gsc_m2m_job_finish(struct gsc_ctx *ctx, int vb_state)
+{
+       struct vb2_v4l2_buffer *src_vb, *dst_vb;
+
+       if (!ctx || !ctx->m2m_ctx)
+               return;
+
+       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) {
+               dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp;
+               dst_vb->timecode = src_vb->timecode;
+               dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+               dst_vb->flags |=
+                       src_vb->flags
+                       & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+
+               v4l2_m2m_buf_done(src_vb, vb_state);
+               v4l2_m2m_buf_done(dst_vb, vb_state);
+
+               v4l2_m2m_job_finish(ctx->gsc_dev->m2m.m2m_dev,
+                                   ctx->m2m_ctx);
+       }
+}
+
+static void gsc_m2m_job_abort(void *priv)
+{
+       __gsc_m2m_job_abort((struct gsc_ctx *)priv);
+}
+
+static int gsc_get_bufs(struct gsc_ctx *ctx)
+{
+       struct gsc_frame *s_frame, *d_frame;
+       struct vb2_v4l2_buffer *src_vb, *dst_vb;
+       int ret;
+
+       s_frame = &ctx->s_frame;
+       d_frame = &ctx->d_frame;
+
+       src_vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+       ret = gsc_prepare_addr(ctx, &src_vb->vb2_buf, s_frame, &s_frame->addr);
+       if (ret)
+               return ret;
+
+       dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+       ret = gsc_prepare_addr(ctx, &dst_vb->vb2_buf, d_frame, &d_frame->addr);
+       if (ret)
+               return ret;
+
+       dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp;
+
+       return 0;
+}
+
+static void gsc_m2m_device_run(void *priv)
+{
+       struct gsc_ctx *ctx = priv;
+       struct gsc_dev *gsc;
+       unsigned long flags;
+       int ret;
+       bool is_set = false;
+
+       if (WARN(!ctx, "null hardware context\n"))
+               return;
+
+       gsc = ctx->gsc_dev;
+       spin_lock_irqsave(&gsc->slock, flags);
+
+       set_bit(ST_M2M_PEND, &gsc->state);
+
+       /* Reconfigure hardware if the context has changed. */
+       if (gsc->m2m.ctx != ctx) {
+               pr_debug("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;
+       if (is_set) {
+               ctx->state &= ~GSC_CTX_STOP_REQ;
+               ctx->state |= GSC_CTX_ABORT;
+               wake_up(&gsc->irq_queue);
+               goto put_device;
+       }
+
+       ret = gsc_get_bufs(ctx);
+       if (ret) {
+               pr_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)) {
+                       pr_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);
+       }
+
+       /* update shadow registers */
+       gsc_hw_set_sfr_update(ctx);
+
+       ctx->state &= ~GSC_PARAMS;
+       gsc_hw_enable_control(gsc, true);
+
+       spin_unlock_irqrestore(&gsc->slock, flags);
+       return;
+
+put_device:
+       ctx->state &= ~GSC_PARAMS;
+       spin_unlock_irqrestore(&gsc->slock, flags);
+}
+
+static int gsc_m2m_queue_setup(struct vb2_queue *vq,
+                       unsigned int *num_buffers, unsigned int *num_planes,
+                       unsigned int sizes[], struct device *alloc_devs[])
+{
+       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] = frame->payload[i];
+       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_CAPTURE(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 vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+       struct gsc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+       pr_debug("ctx: %p, ctx->state: 0x%x", ctx, ctx->state);
+
+       if (ctx->m2m_ctx)
+               v4l2_m2m_buf_queue(ctx->m2m_ctx, vbuf);
+}
+
+static const 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    = vb2_ops_wait_prepare,
+       .wait_finish     = vb2_ops_wait_finish,
+       .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;
+
+       strscpy(cap->driver, GSC_MODULE_NAME, sizeof(cap->driver));
+       strscpy(cap->card, GSC_MODULE_NAME " gscaler", sizeof(cap->card));
+       snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+                dev_name(&gsc->pdev->dev));
+       return 0;
+}
+
+static int gsc_m2m_enum_fmt(struct file *file, void *priv,
+                           struct v4l2_fmtdesc *f)
+{
+       return gsc_enum_fmt(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)) {
+               pr_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);
+       frame->colorspace = pix->colorspace;
+       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);
+
+       pr_debug("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;
+       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;
+
+       return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int gsc_m2m_expbuf(struct file *file, void *fh,
+                               struct v4l2_exportbuffer *eb)
+{
+       struct gsc_ctx *ctx = fh_to_ctx(fh);
+       return v4l2_m2m_expbuf(file, ctx->m2m_ctx, eb);
+}
+
+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) &&
+           (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
+               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:
+       case V4L2_SEL_TGT_CROP:
+               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 gsc_variant *variant = ctx->gsc_dev->variant;
+       struct v4l2_selection sel = *s;
+       int ret;
+
+       if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+           (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
+               return -EINVAL;
+
+       ret = gsc_try_selection(ctx, &sel);
+       if (ret)
+               return ret;
+
+       if (s->flags & V4L2_SEL_FLAG_LE &&
+           !is_rectangle_enclosed(&sel.r, &s->r))
+               return -ERANGE;
+
+       if (s->flags & V4L2_SEL_FLAG_GE &&
+           !is_rectangle_enclosed(&s->r, &sel.r))
+               return -ERANGE;
+
+       s->r = sel.r;
+
+       switch (s->target) {
+       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+       case V4L2_SEL_TGT_COMPOSE:
+               frame = &ctx->s_frame;
+               break;
+
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+       case V4L2_SEL_TGT_CROP:
+       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, sel.r.width,
+                               sel.r.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, sel.r.width,
+                               sel.r.height, ctx->gsc_ctrls.rotate->val,
+                               ctx->out_path);
+               }
+
+               if (ret) {
+                       pr_err("Out of scaler range");
+                       return -EINVAL;
+               }
+       }
+
+       frame->crop = sel.r;
+
+       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        = gsc_m2m_enum_fmt,
+       .vidioc_enum_fmt_vid_out        = gsc_m2m_enum_fmt,
+       .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_expbuf                  = gsc_m2m_expbuf,
+       .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 | VB2_DMABUF;
+       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);
+       src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+       src_vq->lock = &ctx->gsc_dev->lock;
+       src_vq->dev = &ctx->gsc_dev->pdev->dev;
+
+       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 | VB2_DMABUF;
+       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);
+       dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+       dst_vq->lock = &ctx->gsc_dev->lock;
+       dst_vq->dev = &ctx->gsc_dev->pdev->dev;
+
+       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;
+
+       pr_debug("pid: %d, state: 0x%lx", task_pid_nr(current), gsc->state);
+
+       if (mutex_lock_interruptible(&gsc->lock))
+               return -ERESTARTSYS;
+
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       if (!ctx) {
+               ret = -ENOMEM;
+               goto unlock;
+       }
+
+       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;
+
+       ctx->m2m_ctx = v4l2_m2m_ctx_init(gsc->m2m.m2m_dev, ctx, queue_init);
+       if (IS_ERR(ctx->m2m_ctx)) {
+               pr_err("Failed to initialize m2m context");
+               ret = PTR_ERR(ctx->m2m_ctx);
+               goto error_ctrls;
+       }
+
+       if (gsc->m2m.refcnt++ == 0)
+               set_bit(ST_M2M_OPEN, &gsc->state);
+
+       pr_debug("gsc m2m driver is opened, ctx(0x%p)", ctx);
+
+       mutex_unlock(&gsc->lock);
+       return 0;
+
+error_ctrls:
+       gsc_ctrls_delete(ctx);
+       v4l2_fh_del(&ctx->fh);
+error_fh:
+       v4l2_fh_exit(&ctx->fh);
+       kfree(ctx);
+unlock:
+       mutex_unlock(&gsc->lock);
+       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;
+
+       pr_debug("pid: %d, state: 0x%lx, refcnt= %d",
+               task_pid_nr(current), gsc->state, gsc->m2m.refcnt);
+
+       mutex_lock(&gsc->lock);
+
+       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);
+
+       mutex_unlock(&gsc->lock);
+       return 0;
+}
+
+static __poll_t gsc_m2m_poll(struct file *file,
+                                       struct poll_table_struct *wait)
+{
+       struct gsc_ctx *ctx = fh_to_ctx(file->private_data);
+       struct gsc_dev *gsc = ctx->gsc_dev;
+       __poll_t ret;
+
+       if (mutex_lock_interruptible(&gsc->lock))
+               return EPOLLERR;
+
+       ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+       mutex_unlock(&gsc->lock);
+
+       return ret;
+}
+
+static int gsc_m2m_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct gsc_ctx *ctx = fh_to_ctx(file->private_data);
+       struct gsc_dev *gsc = ctx->gsc_dev;
+       int ret;
+
+       if (mutex_lock_interruptible(&gsc->lock))
+               return -ERESTARTSYS;
+
+       ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+       mutex_unlock(&gsc->lock);
+
+       return ret;
+}
+
+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 const 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 platform_device *pdev;
+       int ret;
+
+       if (!gsc)
+               return -ENODEV;
+
+       pdev = gsc->pdev;
+
+       gsc->vdev.fops          = &gsc_m2m_fops;
+       gsc->vdev.ioctl_ops     = &gsc_m2m_ioctl_ops;
+       gsc->vdev.release       = video_device_release_empty;
+       gsc->vdev.lock          = &gsc->lock;
+       gsc->vdev.vfl_dir       = VFL_DIR_M2M;
+       gsc->vdev.v4l2_dev      = &gsc->v4l2_dev;
+       gsc->vdev.device_caps   = V4L2_CAP_STREAMING |
+                                 V4L2_CAP_VIDEO_M2M_MPLANE;
+       snprintf(gsc->vdev.name, sizeof(gsc->vdev.name), "%s.%d:m2m",
+                                       GSC_MODULE_NAME, gsc->id);
+
+       video_set_drvdata(&gsc->vdev, gsc);
+
+       gsc->m2m.vfd = &gsc->vdev;
+       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");
+               return PTR_ERR(gsc->m2m.m2m_dev);
+       }
+
+       ret = video_register_device(&gsc->vdev, VFL_TYPE_VIDEO, -1);
+       if (ret) {
+               dev_err(&pdev->dev,
+                        "%s(): failed to register video device\n", __func__);
+               goto err_m2m_release;
+       }
+
+       pr_debug("gsc m2m driver registered as /dev/video%d", gsc->vdev.num);
+       return 0;
+
+err_m2m_release:
+       v4l2_m2m_release(gsc->m2m.m2m_dev);
+
+       return ret;
+}
+
+void gsc_unregister_m2m_device(struct gsc_dev *gsc)
+{
+       if (gsc) {
+               v4l2_m2m_release(gsc->m2m.m2m_dev);
+               video_unregister_device(&gsc->vdev);
+       }
+}
diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-regs.c b/drivers/media/platform/samsung/exynos-gsc/gsc-regs.c
new file mode 100644 (file)
index 0000000..995a1f0
--- /dev/null
@@ -0,0 +1,426 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Samsung EXYNOS5 SoC series G-Scaler driver
+ */
+
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#include "gsc-core.h"
+
+void gsc_hw_set_sw_reset(struct gsc_dev *dev)
+{
+       writel(GSC_SW_RESET_SRESET, dev->regs + GSC_SW_RESET);
+}
+
+int gsc_wait_reset(struct gsc_dev *dev)
+{
+       unsigned long end = jiffies + msecs_to_jiffies(50);
+       u32 cfg;
+
+       while (time_before(jiffies, end)) {
+               cfg = readl(dev->regs + GSC_SW_RESET);
+               if (!cfg)
+                       return 0;
+               usleep_range(10, 20);
+       }
+
+       return -EBUSY;
+}
+
+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_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_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);
+}
+
+void gsc_hw_set_input_addr(struct gsc_dev *dev, struct gsc_addr *addr,
+                               int index)
+{
+       pr_debug("src_buf[%d]: %pad, cb: %pad, cr: %pad", 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)
+{
+       pr_debug("dst_buf[%d]: %pad, cb: %pad, cr: %pad",
+                       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 (frame->colorspace == V4L2_COLORSPACE_REC709)
+               cfg |= GSC_IN_RGB_HD_WIDE;
+       else
+               cfg |= GSC_IN_RGB_SD_WIDE;
+
+       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 (frame->colorspace == V4L2_COLORSPACE_REC709)
+               cfg |= GSC_OUT_RGB_HD_WIDE;
+       else
+               cfg |= GSC_OUT_RGB_SD_WIDE;
+
+       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)) {
+               pr_debug("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/platform/samsung/exynos-gsc/gsc-regs.h b/drivers/media/platform/samsung/exynos-gsc/gsc-regs.h
new file mode 100644 (file)
index 0000000..d4f7ead
--- /dev/null
@@ -0,0 +1,169 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Register definition file for Samsung G-Scaler driver
+ */
+
+#ifndef REGS_GSC_H_
+#define REGS_GSC_H_
+
+/* G-Scaler enable */
+#define GSC_ENABLE                     0x00
+#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_FRM_DONE_IRQ    (1 << 16)
+#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_NARROW           (3 << 14)
+#define GSC_IN_RGB_HD_WIDE             (2 << 14)
+#define GSC_IN_RGB_SD_NARROW           (1 << 14)
+#define GSC_IN_RGB_SD_WIDE             (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_MODE               (1 << 3)
+#define GSC_IN_LOCAL_SEL_MASK          (3 << 1)
+#define GSC_IN_PATH_MASK               (1 << 0)
+#define GSC_IN_PATH_MEMORY             (0 << 0)
+
+/* G-Scaler source image size */
+#define GSC_SRCIMG_SIZE                        0x14
+#define GSC_SRCIMG_HEIGHT(x)           ((x) << 16)
+#define GSC_SRCIMG_WIDTH(x)            ((x) << 0)
+
+/* G-Scaler source image offset */
+#define GSC_SRCIMG_OFFSET              0x18
+#define GSC_SRCIMG_OFFSET_Y(x)         ((x) << 16)
+#define GSC_SRCIMG_OFFSET_X(x)         ((x) << 0)
+
+/* G-Scaler cropped source image size */
+#define GSC_CROPPED_SIZE               0x1c
+#define GSC_CROPPED_HEIGHT(x)          ((x) << 16)
+#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_WIDE            (3 << 10)
+#define GSC_OUT_RGB_HD_NARROW          (2 << 10)
+#define GSC_OUT_RGB_SD_WIDE            (1 << 10)
+#define GSC_OUT_RGB_SD_NARROW          (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_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(x)           ((x) << 16)
+#define GSC_SCALED_WIDTH(x)            ((x) << 0)
+
+/* G-Scaler pre scale ratio */
+#define GSC_PRE_SCALE_RATIO            0x28
+#define GSC_PRESC_SHFACTOR(x)          ((x) << 28)
+#define GSC_PRESC_V_RATIO(x)           ((x) << 16)
+#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_VALUE(x)      ((x) << 0)
+
+/* G-Scaler main scale vertical ratio */
+#define GSC_MAIN_V_RATIO               0x30
+#define GSC_MAIN_V_RATIO_VALUE(x)      ((x) << 0)
+
+/* G-Scaler destination image size */
+#define GSC_DSTIMG_SIZE                        0x40
+#define GSC_DSTIMG_HEIGHT(x)           ((x) << 16)
+#define GSC_DSTIMG_WIDTH(x)            ((x) << 0)
+
+/* G-Scaler destination image offset */
+#define GSC_DSTIMG_OFFSET              0x44
+#define GSC_DSTIMG_OFFSET_Y(x)         ((x) << 16)
+#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 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)
+
+#endif /* REGS_GSC_H_ */