This patch adds the core functionality for the M-Scaler driver.

Signed-off-by: Shaik Ameer Basha <shaik.am...@samsung.com>
---
 drivers/media/platform/exynos-mscl/mscl-core.c | 1312 ++++++++++++++++++++++++
 drivers/media/platform/exynos-mscl/mscl-core.h |  549 ++++++++++
 2 files changed, 1861 insertions(+)
 create mode 100644 drivers/media/platform/exynos-mscl/mscl-core.c
 create mode 100644 drivers/media/platform/exynos-mscl/mscl-core.h

diff --git a/drivers/media/platform/exynos-mscl/mscl-core.c 
b/drivers/media/platform/exynos-mscl/mscl-core.c
new file mode 100644
index 0000000..4a3a851
--- /dev/null
+++ b/drivers/media/platform/exynos-mscl/mscl-core.c
@@ -0,0 +1,1312 @@
+/*
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Samsung EXYNOS5 SoC series M-Scaler driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 2 of the License,
+ * or (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
+
+#ifdef CONFIG_EXYNOS_IOMMU
+#include <asm/dma-iommu.h>
+#endif
+
+#include "mscl-core.h"
+
+#define MSCL_CLOCK_GATE_NAME   "mscl"
+
+static const struct mscl_fmt mscl_formats[] = {
+       {
+               .name           = "YUV 4:2:0 non-contig. 2p, Y/CbCr",
+               .pixelformat    = V4L2_PIX_FMT_NV12M,
+               .depth          = { 8, 4 },
+               .color          = MSCL_YUV420,
+               .corder         = MSCL_CBCR,
+               .num_planes     = 2,
+               .num_comp       = 2,
+               .mscl_color     = MSCL_YUV420_2P_Y_UV,
+               .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
+
+       }, {
+               .name           = "YUV 4:2:0 contig. 2p, Y/CbCr",
+               .pixelformat    = V4L2_PIX_FMT_NV12,
+               .depth          = { 12 },
+               .color          = MSCL_YUV420,
+               .corder         = MSCL_CBCR,
+               .num_planes     = 1,
+               .num_comp       = 2,
+               .mscl_color     = MSCL_YUV420_2P_Y_UV,
+               .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
+       }, {
+               .name           = "YUV 4:2:0 n.c. 2p, Y/CbCr tiled",
+               .pixelformat    = V4L2_PIX_FMT_NV12MT_16X16,
+               .depth          = { 8, 4 },
+               .color          = MSCL_YUV420,
+               .corder         = MSCL_CBCR,
+               .num_planes     = 2,
+               .num_comp       = 2,
+               .mscl_color     = MSCL_YUV420_2P_Y_UV,
+               .mscl_color_fmt_type = (MSCL_FMT_SRC),
+               .is_tiled       = true,
+       }, {
+               .name           = "YUV 4:2:2 contig. 2p, Y/CbCr",
+               .pixelformat    = V4L2_PIX_FMT_NV16,
+               .depth          = { 16 },
+               .color          = MSCL_YUV422,
+               .corder         = MSCL_CBCR,
+               .num_planes     = 1,
+               .num_comp       = 2,
+               .mscl_color     = MSCL_YUV422_2P_Y_UV,
+               .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
+       }, {
+               .name           = "YUV 4:4:4 contig. 2p, Y/CbCr",
+               .pixelformat    = V4L2_PIX_FMT_NV24,
+               .depth          = { 24 },
+               .color          = MSCL_YUV444,
+               .corder         = MSCL_CBCR,
+               .num_planes     = 1,
+               .num_comp       = 2,
+               .mscl_color     = MSCL_YUV444_2P_Y_UV,
+               .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
+       }, {
+               .name           = "RGB565",
+               .pixelformat    = V4L2_PIX_FMT_RGB565X,
+               .depth          = { 16 },
+               .color          = MSCL_RGB,
+               .num_planes     = 1,
+               .num_comp       = 1,
+               .mscl_color     = MSCL_RGB565,
+               .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
+       }, {
+               .name           = "XRGB-1555, 16 bpp",
+               .pixelformat    = V4L2_PIX_FMT_RGB555,
+               .depth          = { 16 },
+               .color          = MSCL_RGB,
+               .num_planes     = 1,
+               .num_comp       = 1,
+               .mscl_color     = MSCL_ARGB1555,
+               .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
+       }, {
+               .name           = "XRGB-8888, 32 bpp",
+               .pixelformat    = V4L2_PIX_FMT_RGB32,
+               .depth          = { 32 },
+               .color          = MSCL_RGB,
+               .num_planes     = 1,
+               .num_comp       = 1,
+               .mscl_color     = MSCL_ARGB8888,
+               .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
+       }, {
+               .name           = "YUV 4:2:2 packed, YCrYCb",
+               .pixelformat    = V4L2_PIX_FMT_YVYU,
+               .depth          = { 16 },
+               .color          = MSCL_YUV422,
+               .corder         = MSCL_CRCB,
+               .num_planes     = 1,
+               .num_comp       = 1,
+               .mbus_code      = V4L2_MBUS_FMT_YVYU8_2X8,
+               .mscl_color     = MSCL_YUV422_1P_YVYU,
+               .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
+       }, {
+               .name           = "YUV 4:2:2 packed, YCbYCr",
+               .pixelformat    = V4L2_PIX_FMT_YUYV,
+               .depth          = { 16 },
+               .color          = MSCL_YUV422,
+               .corder         = MSCL_CBCR,
+               .num_planes     = 1,
+               .num_comp       = 1,
+               .mbus_code      = V4L2_MBUS_FMT_YUYV8_2X8,
+               .mscl_color     = MSCL_YUV422_1P_YUYV,
+               .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
+       }, {
+               .name           = "YUV 4:2:2 packed, CbYCrY",
+               .pixelformat    = V4L2_PIX_FMT_UYVY,
+               .depth          = { 16 },
+               .color          = MSCL_YUV422,
+               .corder         = MSCL_CBCR,
+               .num_planes     = 1,
+               .num_comp       = 1,
+               .mbus_code      = V4L2_MBUS_FMT_UYVY8_2X8,
+               .mscl_color     = MSCL_YUV422_1P_UYVY,
+               .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
+       }, {
+               .name           = "XRGB-4444, 16 bpp",
+               .pixelformat    = V4L2_PIX_FMT_RGB444,
+               .depth          = { 16 },
+               .color          = MSCL_RGB,
+               .num_planes     = 1,
+               .num_comp       = 1,
+               .mscl_color     = MSCL_ARGB4444,
+               .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
+       }, {
+               .name           = "YUV 4:2:0 non-contig. 2p, Y/CrCb",
+               .pixelformat    = V4L2_PIX_FMT_NV21M,
+               .depth          = { 8, 4 },
+               .color          = MSCL_YUV420,
+               .corder         = MSCL_CRCB,
+               .num_planes     = 2,
+               .num_comp       = 2,
+               .mscl_color     = MSCL_YUV420_2P_Y_VU,
+               .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
+       }, {
+               .name           = "YUV 4:2:0 contig. 2p, Y/CrCb",
+               .pixelformat    = V4L2_PIX_FMT_NV21,
+               .depth          = { 12 },
+               .color          = MSCL_YUV420,
+               .corder         = MSCL_CRCB,
+               .num_planes     = 1,
+               .num_comp       = 2,
+               .mscl_color     = MSCL_YUV420_2P_Y_VU,
+               .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
+       }, {
+               .name           = "YUV 4:2:2 contig. 2p, Y/CrCb",
+               .pixelformat    = V4L2_PIX_FMT_NV61,
+               .depth          = { 16 },
+               .color          = MSCL_YUV422,
+               .corder         = MSCL_CRCB,
+               .num_planes     = 1,
+               .num_comp       = 2,
+               .mscl_color     = MSCL_YUV422_2P_Y_VU,
+               .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
+       }, {
+               .name           = "YUV 4:4:4 contig. 2p, Y/CrCb",
+               .pixelformat    = V4L2_PIX_FMT_NV42,
+               .depth          = { 24 },
+               .color          = MSCL_YUV444,
+               .corder         = MSCL_CRCB,
+               .num_planes     = 1,
+               .num_comp       = 2,
+               .mscl_color     = MSCL_YUV444_2P_Y_VU,
+               .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
+       }, {
+               .name           = "YUV 4:2:0 contig. 3p, YCbCr",
+               .pixelformat    = V4L2_PIX_FMT_YUV420,
+               .depth          = { 12 },
+               .color          = MSCL_YUV420,
+               .corder         = MSCL_CBCR,
+               .num_planes     = 1,
+               .num_comp       = 3,
+               .mscl_color     = MSCL_YUV420_3P_Y_U_V,
+               .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
+       }, {
+               .name           = "YUV 4:2:0 contig. 3p, YCrCb",
+               .pixelformat    = V4L2_PIX_FMT_YVU420,
+               .depth          = { 12 },
+               .color          = MSCL_YUV420,
+               .corder         = MSCL_CRCB,
+               .num_planes     = 1,
+               .num_comp       = 3,
+               .mscl_color     = MSCL_YUV420_3P_Y_U_V,
+               .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
+       }, {
+               .name           = "YUV 4:2:0 non-contig. 3p, Y/Cb/Cr",
+               .pixelformat    = V4L2_PIX_FMT_YUV420M,
+               .depth          = { 8, 2, 2 },
+               .color          = MSCL_YUV420,
+               .corder         = MSCL_CBCR,
+               .num_planes     = 3,
+               .num_comp       = 3,
+               .mscl_color     = MSCL_YUV420_3P_Y_U_V,
+               .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
+       }, {
+               .name           = "YUV 4:2:0 non-contig. 3p, Y/Cr/Cb",
+               .pixelformat    = V4L2_PIX_FMT_YVU420M,
+               .depth          = { 8, 2, 2 },
+               .color          = MSCL_YUV420,
+               .corder         = MSCL_CRCB,
+               .num_planes     = 3,
+               .num_comp       = 3,
+               .mscl_color     = MSCL_YUV420_3P_Y_U_V,
+               .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
+       }, {
+               .name           = "YUV 4:2:2 contig. 3p, Y/Cb/Cr",
+               .pixelformat    = V4L2_PIX_FMT_YUV422P,
+               .depth          = { 16 },
+               .color          = MSCL_YUV422,
+               .corder         = MSCL_CBCR,
+               .num_planes     = 1,
+               .num_comp       = 3,
+               .mscl_color     = MSCL_YUV422_3P_Y_U_V,
+               .mscl_color_fmt_type = (MSCL_FMT_SRC | MSCL_FMT_DST),
+       },
+
+       /* [TBD] support pixel formats, corresponds to these mscl_color formats
+        * MSCL_L8A8, MSCL_RGBA8888, MSCL_L8 etc
+        */
+};
+
+const struct mscl_fmt *mscl_get_format(int index)
+{
+       if (index >= ARRAY_SIZE(mscl_formats))
+               return NULL;
+
+       return (struct mscl_fmt *)&mscl_formats[index];
+}
+
+const struct mscl_fmt *mscl_find_fmt(u32 *pixelformat,
+                               u32 *mbus_code, u32 index)
+{
+       const struct mscl_fmt *fmt, *def_fmt = NULL;
+       unsigned int i;
+
+       if (index >= ARRAY_SIZE(mscl_formats))
+               return NULL;
+
+       for (i = 0; i < ARRAY_SIZE(mscl_formats); ++i) {
+               fmt = mscl_get_format(i);
+               if (pixelformat && fmt->pixelformat == *pixelformat)
+                       return fmt;
+               if (mbus_code && fmt->mbus_code == *mbus_code)
+                       return fmt;
+               if (index == i)
+                       def_fmt = fmt;
+       }
+
+       return def_fmt;
+}
+
+void mscl_set_frame_size(struct mscl_frame *frame, int width, int height)
+{
+       frame->f_width  = width;
+       frame->f_height = height;
+       frame->crop.width = width;
+       frame->crop.height = height;
+       frame->crop.left = 0;
+       frame->crop.top = 0;
+}
+
+int mscl_enum_fmt_mplane(struct v4l2_fmtdesc *f)
+{
+       const struct mscl_fmt *fmt;
+
+       fmt = mscl_find_fmt(NULL, NULL, f->index);
+       if (!fmt)
+               return -EINVAL;
+
+       /* input supports all mscl_formats but all mscl_formats are not
+        * supported for output. don't return the unsupported formats for output
+        */
+       if (!(V4L2_TYPE_IS_OUTPUT(f->type) &&
+               (fmt->mscl_color_fmt_type & MSCL_FMT_SRC)))
+               return -EINVAL;
+
+       strlcpy(f->description, fmt->name, sizeof(f->description));
+       f->pixelformat = fmt->pixelformat;
+
+       return 0;
+}
+
+static u32 get_plane_info(struct mscl_frame *frm, u32 addr, u32 *index)
+{
+       if (frm->addr.y == addr) {
+               *index = 0;
+               return frm->addr.y;
+       } else if (frm->addr.cb == addr) {
+               *index = 1;
+               return frm->addr.cb;
+       } else if (frm->addr.cr == addr) {
+               *index = 2;
+               return frm->addr.cr;
+       } else {
+               pr_debug("Plane address is wrong");
+               return -EINVAL;
+       }
+}
+
+void mscl_set_prefbuf(struct mscl_dev *mscl, struct mscl_frame *frm)
+{
+       u32 f_chk_addr, f_chk_len, s_chk_addr, s_chk_len;
+       f_chk_addr = f_chk_len = s_chk_addr = s_chk_len = 0;
+
+       f_chk_addr = frm->addr.y;
+       f_chk_len = frm->payload[0];
+       if (frm->fmt->num_planes == 2) {
+               s_chk_addr = frm->addr.cb;
+               s_chk_len = frm->payload[1];
+       } else if (frm->fmt->num_planes == 3) {
+               u32 low_addr, low_plane, mid_addr, mid_plane;
+               u32 high_addr, high_plane;
+               u32 t_min, t_max;
+
+               t_min = min3(frm->addr.y, frm->addr.cb, frm->addr.cr);
+               low_addr = get_plane_info(frm, t_min, &low_plane);
+               t_max = max3(frm->addr.y, frm->addr.cb, frm->addr.cr);
+               high_addr = get_plane_info(frm, t_max, &high_plane);
+
+               mid_plane = 3 - (low_plane + high_plane);
+               if (mid_plane == 0)
+                       mid_addr = frm->addr.y;
+               else if (mid_plane == 1)
+                       mid_addr = frm->addr.cb;
+               else if (mid_plane == 2)
+                       mid_addr = frm->addr.cr;
+               else
+                       return;
+
+               f_chk_addr = low_addr;
+               if (mid_addr + frm->payload[mid_plane] - low_addr >
+                   high_addr + frm->payload[high_plane] - mid_addr) {
+                       f_chk_len = frm->payload[low_plane];
+                       s_chk_addr = mid_addr;
+                       s_chk_len = high_addr +
+                                       frm->payload[high_plane] - mid_addr;
+               } else {
+                       f_chk_len = mid_addr +
+                                       frm->payload[mid_plane] - low_addr;
+                       s_chk_addr = high_addr;
+                       s_chk_len = frm->payload[high_plane];
+               }
+       }
+       dev_dbg(&mscl->pdev->dev,
+               "f_addr = 0x%08x, f_len = %d, s_addr = 0x%08x, s_len = %d\n",
+               f_chk_addr, f_chk_len, s_chk_addr, s_chk_len);
+}
+
+int mscl_try_fmt_mplane(struct mscl_ctx *ctx, struct v4l2_format *f)
+{
+       struct mscl_dev *mscl = ctx->mscl_dev;
+       struct device *dev = &mscl->pdev->dev;
+       struct mscl_variant *variant = mscl->variant;
+       struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+       const struct mscl_fmt *fmt;
+       u32 max_w, max_h, mod_w = 0, mod_h = 0;
+       u32 min_w, min_h, tmp_w, tmp_h;
+       int i;
+       struct mscl_frm_limit *frm_limit;
+
+       dev_dbg(dev, "user put w: %d, h: %d",
+                       pix_mp->width, pix_mp->height);
+
+       fmt = mscl_find_fmt(&pix_mp->pixelformat, NULL, 0);
+       if (!fmt) {
+               dev_dbg(dev, "pixelformat format (0x%X) invalid\n",
+                                               pix_mp->pixelformat);
+               return -EINVAL;
+       }
+
+       if (pix_mp->field == V4L2_FIELD_ANY)
+               pix_mp->field = V4L2_FIELD_NONE;
+       else if (pix_mp->field != V4L2_FIELD_NONE) {
+               dev_dbg(dev, "Not supported field order(%d)\n", pix_mp->field);
+               return -EINVAL;
+       }
+
+       if (V4L2_TYPE_IS_OUTPUT(f->type))
+               frm_limit = variant->pix_out;
+       else
+               frm_limit = variant->pix_in;
+
+       max_w = frm_limit->max_w;
+       max_h = frm_limit->max_h;
+       min_w = frm_limit->min_w;
+       min_h = frm_limit->min_h;
+
+       /* Span has to be even number for YCbCr422-2p or YCbCr420 format */
+       if (is_yuv422_2p(fmt) || is_yuv420(fmt))
+               mod_w = 1;
+
+       dev_dbg(dev, "mod_w: %d, mod_h: %d, max_w: %d, max_h = %d",
+                       mod_w, mod_h, max_w, max_h);
+
+       /* To check if image size is modified to adjust parameter against
+          hardware abilities */
+       tmp_w = pix_mp->width;
+       tmp_h = pix_mp->height;
+
+       v4l_bound_align_image(&pix_mp->width, min_w, max_w, mod_w,
+               &pix_mp->height, min_h, max_h, mod_h, 0);
+       if (tmp_w != pix_mp->width || tmp_h != pix_mp->height)
+               dev_info(dev,
+                        "Image size has been modified from %dx%d to %dx%d",
+                        tmp_w, tmp_h, pix_mp->width, pix_mp->height);
+
+       pix_mp->num_planes = fmt->num_planes;
+
+       /* nothing mentioned about the colorspace in m2m-scaler
+        * default value is set to V4L2_COLORSPACE_REC709
+        */
+       pix_mp->colorspace = V4L2_COLORSPACE_REC709;
+
+       for (i = 0; i < pix_mp->num_planes; ++i) {
+               int bpl = (pix_mp->width * fmt->depth[i]) >> 3;
+               pix_mp->plane_fmt[i].bytesperline = bpl;
+               pix_mp->plane_fmt[i].sizeimage = bpl * pix_mp->height;
+
+               dev_dbg(dev, "[%d]: bpl: %d, sizeimage: %d",
+                               i, bpl, pix_mp->plane_fmt[i].sizeimage);
+       }
+
+       return 0;
+}
+
+int mscl_g_fmt_mplane(struct mscl_ctx *ctx, struct v4l2_format *f)
+{
+       struct mscl_frame *frame;
+       struct v4l2_pix_format_mplane *pix_mp;
+       int i;
+
+       frame = ctx_get_frame(ctx, f->type);
+       if (IS_ERR(frame))
+               return PTR_ERR(frame);
+
+       pix_mp = &f->fmt.pix_mp;
+
+       pix_mp->width           = frame->f_width;
+       pix_mp->height          = frame->f_height;
+       pix_mp->field           = V4L2_FIELD_NONE;
+       pix_mp->pixelformat     = frame->fmt->pixelformat;
+       pix_mp->colorspace      = V4L2_COLORSPACE_REC709;
+       pix_mp->num_planes      = frame->fmt->num_planes;
+
+       for (i = 0; i < pix_mp->num_planes; ++i) {
+               pix_mp->plane_fmt[i].bytesperline = (frame->f_width *
+                       frame->fmt->depth[i]) / 8;
+               pix_mp->plane_fmt[i].sizeimage =
+                        pix_mp->plane_fmt[i].bytesperline * frame->f_height;
+       }
+
+       return 0;
+}
+
+void mscl_check_crop_change(u32 tmp_w, u32 tmp_h, u32 *w, u32 *h)
+{
+       if (tmp_w != *w || tmp_h != *h) {
+               pr_info("Cropped size has been modified from %dx%d to %dx%d",
+                                                       *w, *h, tmp_w, tmp_h);
+               *w = tmp_w;
+               *h = tmp_h;
+       }
+}
+
+int mscl_g_crop(struct mscl_ctx *ctx, struct v4l2_crop *cr)
+{
+       struct mscl_frame *frame;
+
+       frame = ctx_get_frame(ctx, cr->type);
+       if (IS_ERR(frame))
+               return PTR_ERR(frame);
+
+       cr->c = frame->crop;
+
+       return 0;
+}
+
+int mscl_try_crop(struct mscl_ctx *ctx, struct v4l2_crop *cr)
+{
+       struct mscl_frame *f;
+       const struct mscl_fmt *fmt;
+       struct mscl_dev *mscl = ctx->mscl_dev;
+       struct device *dev = &mscl->pdev->dev;
+       struct mscl_variant *variant = mscl->variant;
+       u32 mod_w = 0, mod_h = 0, tmp_w, tmp_h;
+       u32 min_w, min_h, max_w, max_h;
+       struct mscl_frm_limit *frm_limit;
+
+       if (cr->c.top < 0 || cr->c.left < 0) {
+               dev_dbg(dev, "doesn't support negative values\n");
+               return -EINVAL;
+       }
+       dev_dbg(dev, "user requested width: %d, height: %d",
+                                       cr->c.width, cr->c.height);
+
+       f = ctx_get_frame(ctx, cr->type);
+       if (IS_ERR(f))
+               return PTR_ERR(f);
+
+       fmt = f->fmt;
+       tmp_w = cr->c.width;
+       tmp_h = cr->c.height;
+
+       if (V4L2_TYPE_IS_OUTPUT(cr->type))
+               frm_limit = variant->pix_out;
+       else
+               frm_limit = variant->pix_in;
+
+       max_w = f->f_width;
+       max_h = f->f_height;
+       min_w = frm_limit->min_w;
+       min_h = frm_limit->min_h;
+
+       if (V4L2_TYPE_IS_OUTPUT(cr->type)) {
+               if (is_yuv420(fmt)) {
+                       mod_w = ffs(variant->pix_align->dst_w_420) - 1;
+                       mod_h = ffs(variant->pix_align->dst_h_420) - 1;
+               } else if (is_yuv422(fmt)) {
+                       mod_w = ffs(variant->pix_align->dst_w_422) - 1;
+               }
+       } else {
+               if (is_yuv420(fmt)) {
+                       mod_w = ffs(variant->pix_align->src_w_420) - 1;
+                       mod_h = ffs(variant->pix_align->src_h_420) - 1;
+               } else if (is_yuv422(fmt)) {
+                       mod_w = ffs(variant->pix_align->src_w_422) - 1;
+               }
+
+               if (ctx->ctrls_mscl.rotate->val == 90 ||
+                   ctx->ctrls_mscl.rotate->val == 270) {
+                       max_w = f->f_height;
+                       max_h = f->f_width;
+                       tmp_w = cr->c.height;
+                       tmp_h = cr->c.width;
+               }
+       }
+
+       dev_dbg(dev, "mod_x: %d, mod_y: %d, min_w: %d, min_h = %d",
+                                       mod_w, mod_h, min_w, min_h);
+       dev_dbg(dev, "tmp_w : %d, tmp_h : %d", tmp_w, tmp_h);
+
+       v4l_bound_align_image(&tmp_w, min_w, max_w, mod_w,
+                             &tmp_h, min_h, max_h, mod_h, 0);
+
+       if (!V4L2_TYPE_IS_OUTPUT(cr->type) &&
+               (ctx->ctrls_mscl.rotate->val == 90 ||
+                ctx->ctrls_mscl.rotate->val == 270))
+               mscl_check_crop_change(tmp_h, tmp_w,
+                                       &cr->c.width, &cr->c.height);
+       else
+               mscl_check_crop_change(tmp_w, tmp_h,
+                                       &cr->c.width, &cr->c.height);
+
+       /* adjust left/top if cropping rectangle is out of bounds */
+       /* Need to add code to algin left value with 2's multiple */
+       if (cr->c.left + tmp_w > max_w)
+               cr->c.left = max_w - tmp_w;
+       if (cr->c.top + tmp_h > max_h)
+               cr->c.top = max_h - tmp_h;
+
+       if (is_yuv422_1p(fmt) && (cr->c.left & 1))
+               cr->c.left -= 1;
+
+       dev_dbg(dev, "Aligned l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
+           cr->c.left, cr->c.top, cr->c.width, cr->c.height, max_w, max_h);
+
+       return 0;
+}
+
+int mscl_check_scaler_ratio(struct mscl_variant *var, int sw, int sh, int dw,
+                          int dh, int rot)
+{
+       if ((dw == 0) || (dh == 0))
+               return -EINVAL;
+
+       if (rot == 90 || rot == 270)
+               swap(dh, dw);
+
+       pr_debug("sw: %d, sh: %d, dw: %d, dh: %d\n", sw, sh, dw, dh);
+
+       if ((sw/dw) > var->scl_down_max || (sh/dh) > var->scl_down_max ||
+           (dw/sw) > var->scl_up_max   || (dh/sh) > var->scl_up_max)
+               return -EINVAL;
+
+       return 0;
+}
+
+int mscl_set_scaler_info(struct mscl_ctx *ctx)
+{
+       struct mscl_scaler *sc = &ctx->scaler;
+       struct mscl_frame *s_frame = &ctx->s_frame;
+       struct mscl_frame *d_frame = &ctx->d_frame;
+       struct mscl_variant *variant = ctx->mscl_dev->variant;
+       struct device *dev = &ctx->mscl_dev->pdev->dev;
+       int src_w, src_h, ret;
+
+       ret = mscl_check_scaler_ratio(variant,
+                               s_frame->crop.width, s_frame->crop.height,
+                               d_frame->crop.width, d_frame->crop.height,
+                               ctx->ctrls_mscl.rotate->val);
+       if (ret) {
+               dev_dbg(dev, "out of scaler range\n");
+               return ret;
+       }
+
+       if (ctx->ctrls_mscl.rotate->val == 90 ||
+               ctx->ctrls_mscl.rotate->val == 270) {
+               src_w = s_frame->crop.height;
+               src_h = s_frame->crop.width;
+       } else {
+               src_w = s_frame->crop.width;
+               src_h = s_frame->crop.height;
+       }
+
+       sc->hratio = (src_w << 16) / d_frame->crop.width;
+       sc->vratio = (src_h << 16) / d_frame->crop.height;
+
+       dev_dbg(dev, "scaler settings::\n"
+                "sx = %d, sy = %d, sw = %d, sh = %d\n"
+                "dx = %d, dy = %d, dw = %d, dh = %d\n"
+                "h-ratio : %d, v-ratio: %d\n",
+                s_frame->crop.left, s_frame->crop.top,
+                s_frame->crop.width, s_frame->crop.height,
+                d_frame->crop.left, d_frame->crop.top,
+                d_frame->crop.width, s_frame->crop.height,
+                sc->hratio, sc->vratio);
+
+       return 0;
+}
+
+static int __mscl_s_ctrl(struct mscl_ctx *ctx, struct v4l2_ctrl *ctrl)
+{
+       struct mscl_dev *mscl = ctx->mscl_dev;
+       struct mscl_variant *variant = mscl->variant;
+       unsigned int flags = MSCL_DST_FMT | MSCL_SRC_FMT;
+       int ret = 0;
+
+       if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
+               return 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_HFLIP:
+               ctx->hflip = ctrl->val;
+               break;
+
+       case V4L2_CID_VFLIP:
+               ctx->vflip = ctrl->val;
+               break;
+
+       case V4L2_CID_ROTATE:
+               if ((ctx->state & flags) == flags) {
+                       ret = mscl_check_scaler_ratio(variant,
+                                       ctx->s_frame.crop.width,
+                                       ctx->s_frame.crop.height,
+                                       ctx->d_frame.crop.width,
+                                       ctx->d_frame.crop.height,
+                                       ctx->ctrls_mscl.rotate->val);
+
+                       if (ret)
+                               return -EINVAL;
+               }
+
+               ctx->rotation = ctrl->val;
+               break;
+
+       case V4L2_CID_ALPHA_COMPONENT:
+               ctx->d_frame.alpha = ctrl->val;
+               break;
+       }
+
+       ctx->state |= MSCL_PARAMS;
+       return 0;
+}
+
+static int mscl_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct mscl_ctx *ctx = ctrl_to_ctx(ctrl);
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&ctx->mscl_dev->slock, flags);
+       ret = __mscl_s_ctrl(ctx, ctrl);
+       spin_unlock_irqrestore(&ctx->mscl_dev->slock, flags);
+
+       return ret;
+}
+
+static const struct v4l2_ctrl_ops mscl_ctrl_ops = {
+       .s_ctrl = mscl_s_ctrl,
+};
+
+int mscl_ctrls_create(struct mscl_ctx *ctx)
+{
+       struct device *dev = &ctx->mscl_dev->pdev->dev;
+
+       if (ctx->ctrls_rdy) {
+               dev_dbg(dev, "Control handler of this ctx was created already");
+               return 0;
+       }
+
+       v4l2_ctrl_handler_init(&ctx->ctrl_handler, MSCL_MAX_CTRL_NUM);
+
+       ctx->ctrls_mscl.rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+                       &mscl_ctrl_ops, V4L2_CID_ROTATE, 0, 270, 90, 0);
+       ctx->ctrls_mscl.hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+                       &mscl_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
+       ctx->ctrls_mscl.vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+                       &mscl_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
+       ctx->ctrls_mscl.global_alpha = v4l2_ctrl_new_std(&ctx->ctrl_handler,
+                       &mscl_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);
+               dev_dbg(dev, "Failed to create M-Scaler control handlers");
+               return err;
+       }
+
+       return 0;
+}
+
+void mscl_ctrls_delete(struct mscl_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 mscl_prepare_addr(struct mscl_ctx *ctx, struct vb2_buffer *vb,
+                       struct mscl_frame *frame, struct mscl_addr *addr)
+{
+       struct device *dev = &ctx->mscl_dev->pdev->dev;
+       int ret = 0;
+       u32 pix_size;
+
+       if ((vb == NULL) || (frame == NULL))
+               return -EINVAL;
+
+       pix_size = frame->f_width * frame->f_height;
+
+       dev_dbg(dev, "planes= %d, comp= %d, pix_size= %d, fmt = %d\n",
+                    frame->fmt->num_planes, frame->fmt->num_comp,
+                    pix_size, frame->fmt->mscl_color);
+
+       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 (MSCL_YUV420 == frame->fmt->color)
+                               addr->cr = (dma_addr_t)(addr->cb
+                                               + (pix_size >> 2));
+                       else if (MSCL_YUV422 == frame->fmt->color)
+                               addr->cr = (dma_addr_t)(addr->cb
+                                               + (pix_size >> 1));
+                       else /* 444 */
+                               addr->cr = (dma_addr_t)(addr->cb + pix_size);
+                       break;
+               default:
+                       dev_dbg(dev, "Invalid number of color planes\n");
+                       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->corder == MSCL_CRCB) && (frame->fmt->num_planes == 3))
+               swap(addr->cb, addr->cr);
+
+       if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type))
+               dev_dbg(dev, "\nIN:ADDR: y= 0x%X  cb= 0x%X cr= 0x%X ret= %d\n",
+                                       addr->y, addr->cb, addr->cr, ret);
+       else
+               dev_dbg(dev, "\nOUT:ADDR: y= 0x%X  cb= 0x%X cr= 0x%X ret= %d\n",
+                                       addr->y, addr->cb, addr->cr, ret);
+
+       return ret;
+}
+
+static void mscl_sw_reset(struct mscl_dev *mscl)
+{
+       mscl_hw_set_sw_reset(mscl);
+       mscl_wait_reset(mscl);
+
+       mscl->coeff_type = MSCL_CSC_COEFF_NONE;
+}
+
+static void mscl_check_for_illegal_status(struct device *dev,
+                                         unsigned int irq_status)
+{
+       if (irq_status & MSCL_INT_STATUS_TIMEOUT)
+               dev_err(dev, "ERROR:: MSCL_INT_STATUS_TIMEOUT\n");
+       if (irq_status & MSCL_INT_STATUS_ILLEGAL_BLEND)
+               dev_err(dev, "ERROR:: MSCL_INT_STATUS_ILLEGAL_BLEND\n");
+       if (irq_status & MSCL_INT_STATUS_ILLEGAL_RATIO)
+               dev_err(dev, "ERROR:: MSCL_INT_STATUS_ILLEGAL_RATIO\n");
+       if (irq_status & MSCL_INT_STATUS_ILLEGAL_DST_HEIGHT)
+               dev_err(dev, "ERROR:: MSCL_INT_STATUS_ILLEGAL_DST_HEIGHT\n");
+       if (irq_status & MSCL_INT_STATUS_ILLEGAL_DST_WIDTH)
+               dev_err(dev, "ERROR:: MSCL_INT_STATUS_ILLEGAL_DST_WIDTH\n");
+       if (irq_status & MSCL_INT_STATUS_ILLEGAL_DST_V_POS)
+               dev_err(dev, "ERROR:: MSCL_INT_STATUS_ILLEGAL_DST_V_POS\n");
+       if (irq_status & MSCL_INT_STATUS_ILLEGAL_DST_H_POS)
+               dev_err(dev, "ERROR:: MSCL_INT_STATUS_ILLEGAL_DST_H_POS\n");
+       if (irq_status & MSCL_INT_STATUS_ILLEGAL_DST_C_SPAN)
+               dev_err(dev, "ERROR:: MSCL_INT_STATUS_ILLEGAL_DST_C_SPAN\n");
+       if (irq_status & MSCL_INT_STATUS_ILLEGAL_DST_Y_SPAN)
+               dev_err(dev, "ERROR:: MSCL_INT_STATUS_ILLEGAL_DST_Y_SPAN\n");
+       if (irq_status & MSCL_INT_STATUS_ILLEGAL_DST_CR_BASE)
+               dev_err(dev, "ERROR:: MSCL_INT_STATUS_ILLEGAL_DST_CR_BASE\n");
+       if (irq_status & MSCL_INT_STATUS_ILLEGAL_DST_CB_BASE)
+               dev_err(dev, "ERROR:: MSCL_INT_STATUS_ILLEGAL_DST_CB_BASE\n");
+       if (irq_status & MSCL_INT_STATUS_ILLEGAL_DST_Y_BASE)
+               dev_err(dev, "ERROR:: MSCL_INT_STATUS_ILLEGAL_DST_Y_BASE\n");
+       if (irq_status & MSCL_INT_STATUS_ILLEGAL_DST_COLOR)
+               dev_err(dev, "ERROR:: MSCL_INT_STATUS_ILLEGAL_DST_COLOR\n");
+       if (irq_status & MSCL_INT_STATUS_ILLEGAL_SRC_HEIGHT)
+               dev_err(dev, "ERROR:: MSCL_INT_STATUS_ILLEGAL_SRC_HEIGHT\n");
+       if (irq_status & MSCL_INT_STATUS_ILLEGAL_SRC_WIDTH)
+               dev_err(dev, "ERROR:: MSCL_INT_STATUS_ILLEGAL_SRC_WIDTH\n");
+       if (irq_status & MSCL_INT_STATUS_ILLEGAL_SRC_CV_POS)
+               dev_err(dev, "ERROR:: MSCL_INT_STATUS_ILLEGAL_SRC_CV_POS\n");
+       if (irq_status & MSCL_INT_STATUS_ILLEGAL_SRC_CH_POS)
+               dev_err(dev, "ERROR:: MSCL_INT_STATUS_ILLEGAL_SRC_CH_POS\n");
+       if (irq_status & MSCL_INT_STATUS_ILLEGAL_SRC_YV_POS)
+               dev_err(dev, "ERROR:: MSCL_INT_STATUS_ILLEGAL_SRC_YV_POS\n");
+       if (irq_status & MSCL_INT_STATUS_ILLEGAL_SRC_YH_POS)
+               dev_err(dev, "ERROR:: MSCL_INT_STATUS_ILLEGAL_SRC_YH_POS\n");
+       if (irq_status & MSCL_INT_STATUS_ILLEGAL_SRC_C_SPAN)
+               dev_err(dev, "ERROR:: MSCL_INT_STATUS_ILLEGAL_SRC_C_SPAN\n");
+       if (irq_status & MSCL_INT_STATUS_ILLEGAL_SRC_Y_SPAN)
+               dev_err(dev, "ERROR:: MSCL_INT_STATUS_ILLEGAL_SRC_Y_SPAN\n");
+       if (irq_status & MSCL_INT_STATUS_ILLEGAL_SRC_CR_BASE)
+               dev_err(dev, "ERROR:: MSCL_INT_STATUS_ILLEGAL_SRC_CR_BASE\n");
+       if (irq_status & MSCL_INT_STATUS_ILLEGAL_SRC_CB_BASE)
+               dev_err(dev, "ERROR:: MSCL_INT_STATUS_ILLEGAL_SRC_CB_BASE\n");
+       if (irq_status & MSCL_INT_STATUS_ILLEGAL_SRC_Y_BASE)
+               dev_err(dev, "ERROR:: MSCL_INT_STATUS_ILLEGAL_SRC_Y_BASE\n");
+       if (irq_status & MSCL_INT_STATUS_ILLEGAL_SRC_COLOR)
+               dev_err(dev, "ERROR:: MSCL_INT_STATUS_ILLEGAL_SRC_COLOR\n");
+}
+
+static irqreturn_t mscl_irq_handler(int irq, void *priv)
+{
+       struct mscl_dev *mscl = priv;
+       struct mscl_ctx *ctx;
+       unsigned int mscl_irq;
+       struct device *dev = &mscl->pdev->dev;
+
+       mscl_irq = mscl_hw_get_irq_status(mscl);
+       dev_dbg(dev, "irq_status: 0x%x\n", mscl_irq);
+       mscl_hw_clear_irq(mscl, mscl_irq);
+
+       if (mscl_irq & MSCL_INT_STATUS_ERROR)
+               mscl_check_for_illegal_status(dev, mscl_irq);
+
+       if (!(mscl_irq & MSCL_INT_EN_FRAME_END))
+               return IRQ_HANDLED;
+
+       spin_lock(&mscl->slock);
+
+       if (test_and_clear_bit(ST_M2M_PEND, &mscl->state)) {
+
+               mscl_hw_enable_control(mscl, false);
+
+               if (test_and_clear_bit(ST_M2M_SUSPENDING, &mscl->state)) {
+                       set_bit(ST_M2M_SUSPENDED, &mscl->state);
+                       wake_up(&mscl->irq_queue);
+                       goto isr_unlock;
+               }
+               ctx = v4l2_m2m_get_curr_priv(mscl->m2m.m2m_dev);
+
+               if (!ctx || !ctx->m2m_ctx)
+                       goto isr_unlock;
+
+               spin_unlock(&mscl->slock);
+               mscl_m2m_job_finish(ctx, VB2_BUF_STATE_DONE);
+
+               /* wake_up job_abort, stop_streaming */
+               if (ctx->state & MSCL_CTX_STOP_REQ) {
+                       ctx->state &= ~MSCL_CTX_STOP_REQ;
+                       wake_up(&mscl->irq_queue);
+               }
+               return IRQ_HANDLED;
+       }
+
+isr_unlock:
+       spin_unlock(&mscl->slock);
+       return IRQ_HANDLED;
+}
+
+static struct mscl_frm_limit mscl_inp_frm_limit = {
+       .min_w  = 16,
+       .min_h  = 16,
+       .max_w  = 8192,
+       .max_h  = 8192,
+};
+
+static struct mscl_frm_limit mscl_out_frm_limit = {
+       .min_w  = 4,
+       .min_h  = 4,
+       .max_w  = 8192,
+       .max_h  = 8192,
+};
+
+static struct mscl_pix_align mscl_align_v0 = {
+       .src_w_420 = 2,
+       .src_w_422 = 2,
+       .src_h_420 = 2,
+       .dst_w_420 = 2,
+       .dst_w_422 = 2,
+       .dst_h_420 = 2,
+};
+
+
+static struct mscl_variant mscl_variant0 = {
+       .pix_in = &mscl_inp_frm_limit,
+       .pix_out = &mscl_out_frm_limit,
+       .pix_align = &mscl_align_v0,
+       .scl_up_max = 16,
+       .scl_down_max = 4,
+       .in_buf_cnt = 32,
+       .out_buf_cnt = 32,
+};
+
+static struct mscl_driverdata mscl_drvdata = {
+       .variant = {
+               [0] = &mscl_variant0,
+               [1] = &mscl_variant0,
+               [2] = &mscl_variant0,
+       },
+       .num_entities = 3,
+       .lclk_frequency = 266000000UL,
+};
+
+static struct platform_device_id mscl_driver_ids[] = {
+       {
+               .name           = "exynos-mscl",
+               .driver_data    = (unsigned long)&mscl_drvdata,
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(platform, mscl_driver_ids);
+
+static const struct of_device_id exynos_mscl_match[] = {
+       {
+               .compatible = "samsung,exynos5-mscl",
+               .data = &mscl_drvdata,
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, exynos_mscl_match);
+
+static void *mscl_get_drv_data(struct platform_device *pdev)
+{
+       struct mscl_driverdata *driver_data = NULL;
+
+       if (pdev->dev.of_node) {
+               const struct of_device_id *match;
+               match = of_match_node(of_match_ptr(exynos_mscl_match),
+                                       pdev->dev.of_node);
+               if (match)
+                       driver_data = (struct mscl_driverdata *)match->data;
+       }
+
+       return driver_data;
+}
+
+static void mscl_clk_put(struct mscl_dev *mscl)
+{
+       if (!IS_ERR(mscl->clock))
+               clk_unprepare(mscl->clock);
+}
+
+static int mscl_clk_get(struct mscl_dev *mscl)
+{
+       int ret;
+
+       dev_dbg(&mscl->pdev->dev, "mscl_clk_get Called\n");
+
+       mscl->clock = devm_clk_get(&mscl->pdev->dev, MSCL_CLOCK_GATE_NAME);
+       if (IS_ERR(mscl->clock)) {
+               dev_err(&mscl->pdev->dev, "failed to get clock~~~: %s\n",
+                       MSCL_CLOCK_GATE_NAME);
+               return PTR_ERR(mscl->clock);
+       }
+
+       ret = clk_prepare(mscl->clock);
+       if (ret < 0) {
+               dev_err(&mscl->pdev->dev, "clock prepare fail for clock: %s\n",
+                       MSCL_CLOCK_GATE_NAME);
+               mscl->clock = ERR_PTR(-EINVAL);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int mscl_m2m_suspend(struct mscl_dev *mscl)
+{
+       unsigned long flags;
+       int timeout;
+
+       spin_lock_irqsave(&mscl->slock, flags);
+       if (!mscl_m2m_pending(mscl)) {
+               spin_unlock_irqrestore(&mscl->slock, flags);
+               return 0;
+       }
+       clear_bit(ST_M2M_SUSPENDED, &mscl->state);
+       set_bit(ST_M2M_SUSPENDING, &mscl->state);
+       spin_unlock_irqrestore(&mscl->slock, flags);
+
+       timeout = wait_event_timeout(mscl->irq_queue,
+                            test_bit(ST_M2M_SUSPENDED, &mscl->state),
+                            MSCL_SHUTDOWN_TIMEOUT);
+
+       clear_bit(ST_M2M_SUSPENDING, &mscl->state);
+       return timeout == 0 ? -EAGAIN : 0;
+}
+
+static int mscl_m2m_resume(struct mscl_dev *mscl)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mscl->slock, flags);
+       /* Clear for full H/W setup in first run after resume */
+       mscl->m2m.ctx = NULL;
+       spin_unlock_irqrestore(&mscl->slock, flags);
+
+       if (test_and_clear_bit(ST_M2M_SUSPENDED, &mscl->state))
+               mscl_m2m_job_finish(mscl->m2m.ctx,
+                                   VB2_BUF_STATE_ERROR);
+       return 0;
+}
+
+#ifdef CONFIG_EXYNOS_IOMMU
+static int mscl_iommu_init(struct mscl_dev *mscl)
+{
+       struct dma_iommu_mapping *mapping;
+       struct device *dev = &mscl->pdev->dev;
+
+       mapping = arm_iommu_create_mapping(&platform_bus_type, 0x20000000,
+                                               SZ_256M, 4);
+       if (mapping == NULL) {
+               dev_err(dev, "IOMMU mapping failed for MSCL\n");
+               return -EFAULT;
+       }
+
+       dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms),
+                                               GFP_KERNEL);
+       dma_set_max_seg_size(dev, 0xffffffffu);
+       arm_iommu_attach_device(dev, mapping);
+
+       mscl->mapping = mapping;
+
+       return 0;
+}
+
+static void mscl_iommu_deinit(struct mscl_dev *mscl)
+{
+       if (mscl->mapping)
+               arm_iommu_release_mapping(mscl->mapping);
+
+       mscl->mapping = NULL;
+}
+
+#else
+static int mscl_iommu_init(struct mscl_dev *mscl)
+{
+       return 0;
+}
+
+static void mscl_iommu_deinit(struct mscl_dev *mscl)
+{
+       return;
+}
+#endif
+
+static int mscl_probe(struct platform_device *pdev)
+{
+       struct mscl_dev *mscl;
+       struct resource *res;
+       struct mscl_driverdata *drv_data = mscl_get_drv_data(pdev);
+       struct device *dev = &pdev->dev;
+       int ret = 0;
+
+       if (!dev->of_node) {
+               dev_err(dev, "Invalid device node\n");
+               return -EINVAL;
+       }
+
+       mscl = devm_kzalloc(dev, sizeof(struct mscl_dev), GFP_KERNEL);
+       if (!mscl)
+               return -ENOMEM;
+
+       mscl->id = of_alias_get_id(pdev->dev.of_node, "mscl");
+       if (mscl->id < 0 || mscl->id >= drv_data->num_entities) {
+               dev_err(dev, "Invalid platform device id: %d\n", mscl->id);
+               return -EINVAL;
+       }
+
+       mscl->variant = drv_data->variant[mscl->id];
+       mscl->pdev = pdev;
+       mscl->pdata = dev->platform_data;
+
+       init_waitqueue_head(&mscl->irq_queue);
+       spin_lock_init(&mscl->slock);
+       mutex_init(&mscl->lock);
+       mscl->clock = ERR_PTR(-EINVAL);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       mscl->regs = devm_request_and_ioremap(dev, res);
+       if (!mscl->regs)
+               return -ENODEV;
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!res) {
+               dev_err(dev, "failed to get IRQ resource\n");
+               return -ENXIO;
+       }
+
+       ret = mscl_clk_get(mscl);
+       if (ret)
+               return ret;
+
+       if (mscl_iommu_init(mscl)) {
+               dev_err(&pdev->dev, "IOMMU Initialization failed\n");
+               return -EINVAL;
+       }
+
+       ret = devm_request_irq(dev, res->start, mscl_irq_handler,
+                               0, pdev->name, mscl);
+       if (ret) {
+               dev_err(dev, "failed to install irq (%d)\n", ret);
+               goto err_clk;
+       }
+
+       ret = mscl_register_m2m_device(mscl);
+       if (ret)
+               goto err_clk;
+
+       platform_set_drvdata(pdev, mscl);
+       pm_runtime_enable(dev);
+       ret = pm_runtime_get_sync(&pdev->dev);
+       if (ret < 0)
+               goto err_m2m;
+
+       /* Initialize continious memory allocator */
+       mscl->alloc_ctx = vb2_dma_contig_init_ctx(dev);
+       if (IS_ERR(mscl->alloc_ctx)) {
+               ret = PTR_ERR(mscl->alloc_ctx);
+               goto err_pm;
+       }
+
+       dev_err(dev, "mscl-%d registered successfully\n", mscl->id);
+
+       pm_runtime_put(dev);
+       return 0;
+err_pm:
+       pm_runtime_put(dev);
+err_m2m:
+       mscl_unregister_m2m_device(mscl);
+err_clk:
+       mscl_iommu_deinit(mscl);
+       mscl_clk_put(mscl);
+       return ret;
+}
+
+static int mscl_remove(struct platform_device *pdev)
+{
+       struct mscl_dev *mscl = platform_get_drvdata(pdev);
+
+       mscl_unregister_m2m_device(mscl);
+
+       vb2_dma_contig_cleanup_ctx(mscl->alloc_ctx);
+       pm_runtime_disable(&pdev->dev);
+       mscl_iommu_deinit(mscl);
+       mscl_clk_put(mscl);
+
+       dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);
+       return 0;
+}
+
+static int mscl_runtime_resume(struct device *dev)
+{
+       struct mscl_dev *mscl = dev_get_drvdata(dev);
+       int ret = 0;
+
+       dev_dbg(dev, "mscl%d: state: 0x%lx", mscl->id, mscl->state);
+
+       ret = clk_enable(mscl->clock);
+       if (ret)
+               return ret;
+
+       mscl_sw_reset(mscl);
+
+       return mscl_m2m_resume(mscl);
+}
+
+static int mscl_runtime_suspend(struct device *dev)
+{
+       struct mscl_dev *mscl = dev_get_drvdata(dev);
+       int ret = 0;
+
+       ret = mscl_m2m_suspend(mscl);
+       if (!ret)
+               clk_disable(mscl->clock);
+
+       dev_dbg(dev, "mscl%d: state: 0x%lx", mscl->id, mscl->state);
+       return ret;
+}
+
+static int mscl_resume(struct device *dev)
+{
+       struct mscl_dev *mscl = dev_get_drvdata(dev);
+       unsigned long flags;
+
+       dev_dbg(dev, "mscl%d: state: 0x%lx", mscl->id, mscl->state);
+
+       /* Do not resume if the device was idle before system suspend */
+       spin_lock_irqsave(&mscl->slock, flags);
+       if (!test_and_clear_bit(ST_SUSPEND, &mscl->state) ||
+           !mscl_m2m_active(mscl)) {
+               spin_unlock_irqrestore(&mscl->slock, flags);
+               return 0;
+       }
+
+       mscl_sw_reset(mscl);
+       spin_unlock_irqrestore(&mscl->slock, flags);
+
+       return mscl_m2m_resume(mscl);
+}
+
+static int mscl_suspend(struct device *dev)
+{
+       struct mscl_dev *mscl = dev_get_drvdata(dev);
+
+       dev_dbg(dev, "mscl%d: state: 0x%lx", mscl->id, mscl->state);
+
+       if (test_and_set_bit(ST_SUSPEND, &mscl->state))
+               return 0;
+
+       return mscl_m2m_suspend(mscl);
+}
+
+static const struct dev_pm_ops mscl_pm_ops = {
+       .suspend                = mscl_suspend,
+       .resume                 = mscl_resume,
+       .runtime_suspend        = mscl_runtime_suspend,
+       .runtime_resume         = mscl_runtime_resume,
+};
+
+static struct platform_driver mscl_driver = {
+       .probe          = mscl_probe,
+       .remove         = mscl_remove,
+       .id_table       = mscl_driver_ids,
+       .driver = {
+               .name   = MSCL_MODULE_NAME,
+               .owner  = THIS_MODULE,
+               .pm     = &mscl_pm_ops,
+               .of_match_table = exynos_mscl_match,
+       }
+};
+
+module_platform_driver(mscl_driver);
+
+MODULE_AUTHOR("Shaik Ameer Basha <shaik.am...@samsung.com>");
+MODULE_DESCRIPTION("Samsung EXYNOS5 Soc series M-Scaler driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/exynos-mscl/mscl-core.h 
b/drivers/media/platform/exynos-mscl/mscl-core.h
new file mode 100644
index 0000000..09149a2
--- /dev/null
+++ b/drivers/media/platform/exynos-mscl/mscl-core.h
@@ -0,0 +1,549 @@
+/*
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * header file for Samsung EXYNOS5 SoC series M-Scaler driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef MSCL_CORE_H_
+#define MSCL_CORE_H_
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "mscl-regs.h"
+
+#define CONFIG_VB2_MSCL_DMA_CONTIG     1
+#define MSCL_MODULE_NAME               "exynos-mscl"
+
+#define MSCL_SHUTDOWN_TIMEOUT          ((100*HZ)/1000)
+#define MSCL_MAX_DEVS                  4
+#define MSCL_MAX_CTRL_NUM              10
+#define MSCL_SC_ALIGN_4                        4
+#define MSCL_SC_ALIGN_2                        2
+#define DEFAULT_CSC_EQ                 1
+#define DEFAULT_CSC_RANGE              1
+
+#define MSCL_PARAMS                    (1 << 0)
+#define MSCL_SRC_FMT                   (1 << 1)
+#define MSCL_DST_FMT                   (1 << 2)
+#define MSCL_CTX_M2M                   (1 << 3)
+#define MSCL_CTX_STOP_REQ              (1 << 4)
+
+enum mscl_dev_flags {
+       /* for global */
+       ST_SUSPEND,
+
+       /* for m2m node */
+       ST_M2M_OPEN,
+       ST_M2M_RUN,
+       ST_M2M_PEND,
+       ST_M2M_SUSPENDED,
+       ST_M2M_SUSPENDING,
+};
+
+enum mscl_irq {
+       MSCL_INT_FRAME_END = 0,
+       MSCL_INT_ILLEGAL_SRC_COLOR,
+       MSCL_INT_ILLEGAL_SRC_Y_BASE,
+       MSCL_INT_ILLEGAL_SRC_CB_BASE,
+       MSCL_INT_ILLEGAL_SRC_CR_BASE,
+       MSCL_INT_ILLEGAL_SRC_Y_SPAN,
+       MSCL_INT_ILLEGAL_SRC_C_SPAN,
+       MSCL_INT_ILLEGAL_SRC_YH_POS,
+       MSCL_INT_ILLEGAL_SRC_YV_POS,
+       MSCL_INT_ILLEGAL_SRC_CH_POS,
+       MSCL_INT_ILLEGAL_SRC_CV_POS,
+       MSCL_INT_ILLEGAL_SRC_WIDTH,
+       MSCL_INT_ILLEGAL_SRC_HEIGHT,
+       MSCL_INT_ILLEGAL_DST_COLOR,
+       MSCL_INT_ILLEGAL_DST_Y_BASE,
+       MSCL_INT_ILLEGAL_DST_CB_BASE,
+       MSCL_INT_ILLEGAL_DST_CR_BASE,
+       MSCL_INT_ILLEGAL_DST_Y_SPAN,
+       MSCL_INT_ILLEGAL_DST_C_SPAN,
+       MSCL_INT_ILLEGAL_DST_H_POS,
+       MSCL_INT_ILLEGAL_DST_V_POS,
+       MSCL_INT_ILLEGAL_DST_WIDTH,
+       MSCL_INT_ILLEGAL_DST_HEIGHT,
+       MSCL_INT_ILLEGAL_RATIO,
+       MSCL_INT_ILLEGAL_BLEND,
+       MSCL_INT_TIMEOUT,
+};
+
+enum mscl_color_fmt {
+       MSCL_RGB = (0x1 << 0),
+       MSCL_YUV420 = (0x1 << 1),
+       MSCL_YUV422 = (0x1 << 2),
+       MSCL_YUV444 = (0x1 << 3),
+};
+
+enum mscl_yuv_fmt {
+       MSCL_CBCR = 0x10,
+       MSCL_CRCB,
+};
+
+enum mscl_clr_fmt_type {
+       MSCL_FMT_SRC = (0x1 << 0),
+       MSCL_FMT_DST = (0x1 << 1),
+};
+
+enum mscl_clr_fmt {
+       MSCL_YUV420_2P_Y_UV = 0,
+       MSCL_YUV422_2P_Y_UV = 2,
+       MSCL_YUV444_2P_Y_UV,
+       MSCL_RGB565,
+       MSCL_ARGB1555,
+       MSCL_ARGB8888,
+       MSCL_PREMULTIPLIED_ARGB8888,
+       MSCL_YUV422_1P_YVYU = 9,
+       MSCL_YUV422_1P_YUYV,
+       MSCL_YUV422_1P_UYVY,
+       MSCL_ARGB4444,
+       MSCL_L8A8,
+       MSCL_RGBA8888,
+       MSCL_L8,
+       MSCL_YUV420_2P_Y_VU,
+       MSCL_YUV422_2P_Y_VU = 18,
+       MSCL_YUV444_2P_Y_VU,
+       MSCL_YUV420_3P_Y_U_V,
+       MSCL_YUV422_3P_Y_U_V = 22,
+       MSCL_YUV444_3P_Y_U_V,
+};
+
+#define fh_to_ctx(__fh) container_of(__fh, struct mscl_ctx, fh)
+#define is_rgb(fmt) (!!(((fmt)->color) & MSCL_RGB))
+#define is_yuv(fmt) ((fmt->color >= MSCL_YUV420) && (fmt->color <= 
MSCL_YUV444))
+#define is_yuv420(fmt) (!!((fmt->color) & MSCL_YUV420))
+#define is_yuv422(fmt) (!!((fmt->color) & MSCL_YUV422))
+#define is_yuv422_1p(fmt) (is_yuv422(fmt) && (fmt->num_planes == 1))
+#define is_yuv420_2p(fmt) (is_yuv420(fmt) && (fmt->num_planes == 2))
+#define is_yuv422_2p(fmt) (is_yuv422(fmt) && (fmt->num_planes == 2))
+#define is_yuv42x_2p(fmt) (is_yuv420_2p(fmt) || is_yuv422_2p(fmt))
+#define is_src_fmt(fmt)        ((fmt->mscl_color_fmt_type) & MSCL_FMT_SRC)
+#define is_dst_fmt(fmt)        ((fmt->mscl_color_fmt_type) & MSCL_FMT_DST)
+
+#define mscl_m2m_active(dev)   test_bit(ST_M2M_RUN, &(dev)->state)
+#define mscl_m2m_pending(dev)  test_bit(ST_M2M_PEND, &(dev)->state)
+#define mscl_m2m_opened(dev)   test_bit(ST_M2M_OPEN, &(dev)->state)
+
+#define ctrl_to_ctx(__ctrl) \
+       container_of((__ctrl)->handler, struct mscl_ctx, ctrl_handler)
+/**
+ * struct mscl_fmt - the driver's internal color format data
+ * @mbus_code: Media Bus pixel code, -1 if not applicable
+ * @mscl_color: M-Scaler color format
+ * @mscl_color_fmt_type: specifies whether src/dst format
+ * @is_tiled: tiled format or not
+ * @name: format description
+ * @pixelformat: the fourcc code for this format, 0 if not applicable
+ * @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 mscl_fmt {
+       enum v4l2_mbus_pixelcode mbus_code;
+       enum mscl_clr_fmt mscl_color;
+       enum mscl_clr_fmt_type mscl_color_fmt_type;
+       u32     is_tiled;
+       char    *name;
+       u32     pixelformat;
+       u32     color;
+       u32     corder;
+       u16     num_planes;
+       u16     num_comp;
+       u8      depth[VIDEO_MAX_PLANES];
+       u32     flags;
+};
+
+/**
+ * struct mscl_input_buf - the driver's video buffer
+ * @vb:        videobuf2 buffer
+ * @list : linked list structure for buffer queue
+ * @idx : index of M-Scaler input buffer
+ */
+struct mscl_input_buf {
+       struct vb2_buffer       vb;
+       struct list_head        list;
+       int                     idx;
+};
+
+/**
+ * struct mscl_addr - the M-Scaler physical address set
+ * @y:  luminance plane address
+ * @cb:         Cb plane address
+ * @cr:         Cr plane address
+ */
+struct mscl_addr {
+       dma_addr_t y;
+       dma_addr_t cb;
+       dma_addr_t cr;
+};
+
+/* struct mscl_ctrls - the M-Scaler control set
+ * @rotate: rotation degree
+ * @hflip: horizontal flip
+ * @vflip: vertical flip
+ * @global_alpha: the alpha value of current frame
+ */
+struct mscl_ctrls {
+       struct v4l2_ctrl *rotate;
+       struct v4l2_ctrl *hflip;
+       struct v4l2_ctrl *vflip;
+       struct v4l2_ctrl *global_alpha;
+};
+
+/* struct mscl_csc_info - color space conversion information
+ *
+ */
+enum mscl_csc_coeff {
+       MSCL_CSC_COEFF_YCBCR_TO_RGB,
+       MSCL_CSC_COEFF_YCBCR_TO_RGB_OFF16,
+       MSCL_CSC_COEFF_RGB_TO_YCBCR,
+       MSCL_CSC_COEFF_RGB_TO_YCBCR_OFF16,
+       MSCL_CSC_COEFF_MAX,
+       MSCL_CSC_COEFF_NONE,
+};
+
+struct mscl_csc_info {
+       enum mscl_csc_coeff coeff_type;
+};
+
+/**
+ * struct mscl_scaler - the configuration data for M-Scaler inetrnal scaler
+ * @hratio:    the main scaler's horizontal ratio
+ * @vratio:    the main scaler's vertical ratio
+ */
+struct mscl_scaler {
+       u32 hratio;
+       u32 vratio;
+};
+
+struct mscl_dev;
+
+struct mscl_ctx;
+
+/**
+ * struct mscl_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:       M-Scaler color format pointer
+ * @colorspace: value indicating v4l2_colorspace
+ * @alpha:     frame's alpha value
+ */
+struct mscl_frame {
+       u32 f_width;
+       u32 f_height;
+       struct v4l2_rect crop;
+       unsigned long payload[VIDEO_MAX_PLANES];
+       struct mscl_addr        addr;
+       const struct mscl_fmt *fmt;
+       u32 colorspace;
+       u8 alpha;
+};
+
+/**
+ * struct mscl_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 mscl_m2m_device {
+       struct video_device     *vfd;
+       struct v4l2_m2m_dev     *m2m_dev;
+       struct mscl_ctx         *ctx;
+       int                     refcnt;
+};
+
+/**
+ *  struct mscl_pix_input - image pixel size limits for input frame
+ *
+ */
+struct mscl_frm_limit {
+       u16     min_w;
+       u16     min_h;
+       u16     max_w;
+       u16     max_h;
+
+};
+
+struct mscl_pix_align {
+       u16 src_w_420;
+       u16 src_w_422;
+       u16 src_h_420;
+       u16 dst_w_420;
+       u16 dst_w_422;
+       u16 dst_h_420;
+};
+
+/**
+ * struct mscl_variant - M-Scaler variant information
+ */
+struct mscl_variant {
+       struct mscl_frm_limit   *pix_in;
+       struct mscl_frm_limit   *pix_out;
+       struct mscl_pix_align   *pix_align;
+       u16     scl_up_max;
+       u16     scl_down_max;
+       u16     in_buf_cnt;
+       u16     out_buf_cnt;
+};
+
+/**
+ * struct mscl_driverdata - per device type driver data for init time.
+ *
+ * @variant: the variant information for this driver.
+ * @lclk_frequency: M-Scaler clock frequency
+ * @num_entities: the number of g-scalers
+ */
+struct mscl_driverdata {
+       struct mscl_variant *variant[MSCL_MAX_DEVS];
+       unsigned long   lclk_frequency;
+       int             num_entities;
+};
+
+/**
+ * struct mscl_dev - abstraction for M-Scaler entity
+ * @slock: the spinlock protecting this data structure
+ * @lock: the mutex protecting this data structure
+ * @pdev: pointer to the M-Scaler platform device
+ * @variant: the IP variant information
+ * @id: M-Scaler device index (0..MSCL_MAX_DEVS)
+ * @clock: clocks required for M-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
+ * @alloc_ctx: videobuf2 memory allocator context
+ * @vdev: video device for M-Scaler instance
+ */
+struct mscl_dev {
+       spinlock_t                      slock;
+       struct mutex                    lock;
+       struct platform_device          *pdev;
+       struct mscl_variant             *variant;
+       u16                             id;
+       struct clk                      *clock;
+       void __iomem                    *regs;
+       wait_queue_head_t               irq_queue;
+       struct mscl_m2m_device          m2m;
+       struct exynos_platform_msclaler *pdata;
+       unsigned long                   state;
+       struct vb2_alloc_ctx            *alloc_ctx;
+       struct video_device             vdev;
+       enum mscl_csc_coeff             coeff_type;
+#ifdef CONFIG_EXYNOS_IOMMU
+       struct dma_iommu_mapping        *mapping;
+#endif
+};
+
+/**
+ * mscl_ctx - the device context data
+ * @s_frame: source frame properties
+ * @d_frame: destination frame properties
+ * @scaler: image scaler properties
+ * @flags: additional flags for image conversion
+ * @state: flags to keep track of user configuration
+ * @mscl_dev: the M-Scaler device this context applies to
+ * @m2m_ctx: memory-to-memory device context
+ * @fh: v4l2 file handle
+ * @ctrl_handler: v4l2 controls handler
+ * @ctrls_mscl: M-Scaler control set
+ * @ctrls_rdy: true if the control handler is initialized
+ */
+struct mscl_ctx {
+       struct mscl_frame       s_frame;
+       struct mscl_frame       d_frame;
+       struct mscl_scaler      scaler;
+       u32                     flags;
+       u32                     state;
+       int                     rotation;
+       unsigned int            hflip:1;
+       unsigned int            vflip:1;
+       struct mscl_dev         *mscl_dev;
+       struct v4l2_m2m_ctx     *m2m_ctx;
+       struct v4l2_fh          fh;
+       struct v4l2_ctrl_handler ctrl_handler;
+       struct mscl_ctrls       ctrls_mscl;
+       bool                    ctrls_rdy;
+};
+
+void mscl_set_prefbuf(struct mscl_dev *mscl, struct mscl_frame *frm);
+int mscl_register_m2m_device(struct mscl_dev *mscl);
+void mscl_unregister_m2m_device(struct mscl_dev *mscl);
+void mscl_m2m_job_finish(struct mscl_ctx *ctx, int vb_state);
+
+u32 get_plane_size(struct mscl_frame *fr, unsigned int plane);
+const struct mscl_fmt *mscl_get_format(int index);
+const struct mscl_fmt *mscl_find_fmt(u32 *pixelformat,
+                               u32 *mbus_code, u32 index);
+int mscl_enum_fmt_mplane(struct v4l2_fmtdesc *f);
+int mscl_try_fmt_mplane(struct mscl_ctx *ctx, struct v4l2_format *f);
+void mscl_set_frame_size(struct mscl_frame *frame, int width, int height);
+int mscl_g_fmt_mplane(struct mscl_ctx *ctx, struct v4l2_format *f);
+void mscl_check_crop_change(u32 tmp_w, u32 tmp_h, u32 *w, u32 *h);
+int mscl_g_crop(struct mscl_ctx *ctx, struct v4l2_crop *cr);
+int mscl_try_crop(struct mscl_ctx *ctx, struct v4l2_crop *cr);
+int mscl_cal_prescaler_ratio(struct mscl_variant *var, u32 src, u32 dst,
+                                                       u32 *ratio);
+void mscl_get_prescaler_shfactor(u32 hratio, u32 vratio, u32 *sh);
+void mscl_check_src_scale_info(struct mscl_variant *var,
+                               struct mscl_frame *s_frame,
+                               u32 *wratio, u32 tx, u32 ty, u32 *hratio);
+int mscl_check_scaler_ratio(struct mscl_variant *var, int sw, int sh, int dw,
+                          int dh, int rot);
+int mscl_set_scaler_info(struct mscl_ctx *ctx);
+int mscl_ctrls_create(struct mscl_ctx *ctx);
+void mscl_ctrls_delete(struct mscl_ctx *ctx);
+int mscl_prepare_addr(struct mscl_ctx *ctx, struct vb2_buffer *vb,
+                    struct mscl_frame *frame, struct mscl_addr *addr);
+
+static inline void mscl_ctx_state_lock_set(u32 state, struct mscl_ctx *ctx)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ctx->mscl_dev->slock, flags);
+       ctx->state |= state;
+       spin_unlock_irqrestore(&ctx->mscl_dev->slock, flags);
+}
+
+static inline void mscl_ctx_state_lock_clear(u32 state, struct mscl_ctx *ctx)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ctx->mscl_dev->slock, flags);
+       ctx->state &= ~state;
+       spin_unlock_irqrestore(&ctx->mscl_dev->slock, flags);
+}
+
+static inline int is_tiled(const struct mscl_fmt *fmt)
+{
+       return fmt->pixelformat == V4L2_PIX_FMT_NV12MT_16X16;
+}
+
+static inline void mscl_hw_src_y_offset_en(struct mscl_dev *dev, bool on)
+{
+       u32 cfg;
+
+       cfg = readl(dev->regs + MSCL_CFG);
+       if (on)
+               cfg |= MSCL_CFG_CSC_Y_OFFSET_SRC_EN;
+       else
+               cfg &= ~MSCL_CFG_CSC_Y_OFFSET_SRC_EN;
+
+       writel(cfg, dev->regs + MSCL_CFG);
+}
+
+static inline void mscl_hw_dst_y_offset_en(struct mscl_dev *dev, bool on)
+{
+       u32 cfg;
+
+       cfg = readl(dev->regs + MSCL_CFG);
+       if (on)
+               cfg |= MSCL_CFG_CSC_Y_OFFSET_DST_EN;
+       else
+               cfg &= ~MSCL_CFG_CSC_Y_OFFSET_DST_EN;
+
+       writel(cfg, dev->regs + MSCL_CFG);
+}
+
+static inline void mscl_hw_enable_control(struct mscl_dev *dev, bool on)
+{
+       u32 cfg;
+
+       if (on)
+               writel(0xFFFFFFFF, dev->regs + MSCL_INT_EN);
+
+       cfg = readl(dev->regs + MSCL_CFG);
+       cfg |= MSCL_CFG_16_BURST_MODE;
+       if (on)
+               cfg |= MSCL_CFG_START_CMD;
+       else
+               cfg &= ~MSCL_CFG_START_CMD;
+
+       dev_dbg(&dev->pdev->dev,
+               "mscl_hw_enable_control: MSCL_CFG:0x%x\n", cfg);
+
+       writel(cfg, dev->regs + MSCL_CFG);
+}
+
+static inline unsigned int mscl_hw_get_irq_status(struct mscl_dev *dev)
+{
+       return readl(dev->regs + MSCL_INT_STATUS);
+}
+
+static inline void mscl_hw_clear_irq(struct mscl_dev *dev, unsigned int irq)
+{
+       writel(irq, dev->regs + MSCL_INT_STATUS);
+}
+
+static inline void mscl_lock(struct vb2_queue *vq)
+{
+       struct mscl_ctx *ctx = vb2_get_drv_priv(vq);
+       mutex_lock(&ctx->mscl_dev->lock);
+}
+
+static inline void mscl_unlock(struct vb2_queue *vq)
+{
+       struct mscl_ctx *ctx = vb2_get_drv_priv(vq);
+       mutex_unlock(&ctx->mscl_dev->lock);
+}
+
+static inline bool mscl_ctx_state_is_set(u32 mask, struct mscl_ctx *ctx)
+{
+       unsigned long flags;
+       bool ret;
+
+       spin_lock_irqsave(&ctx->mscl_dev->slock, flags);
+       ret = (ctx->state & mask) == mask;
+       spin_unlock_irqrestore(&ctx->mscl_dev->slock, flags);
+       return ret;
+}
+
+static inline struct mscl_frame *ctx_get_frame(struct mscl_ctx *ctx,
+                                             enum v4l2_buf_type type)
+{
+       struct mscl_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 {
+               dev_dbg(&ctx->mscl_dev->pdev->dev,
+                       "Wrong buffer/video queue type (%d)", type);
+               return ERR_PTR(-EINVAL);
+       }
+
+       return frame;
+}
+
+void mscl_hw_set_sw_reset(struct mscl_dev *dev);
+int mscl_wait_reset(struct mscl_dev *dev);
+void mscl_hw_set_irq_mask(struct mscl_dev *dev, int interrupt, bool mask);
+void mscl_hw_set_input_addr(struct mscl_dev *dev, struct mscl_addr *addr);
+void mscl_hw_set_output_addr(struct mscl_dev *dev, struct mscl_addr *addr);
+void mscl_hw_set_in_size(struct mscl_ctx *ctx);
+void mscl_hw_set_in_image_format(struct mscl_ctx *ctx);
+void mscl_hw_set_out_size(struct mscl_ctx *ctx);
+void mscl_hw_set_out_image_format(struct mscl_ctx *ctx);
+void mscl_hw_set_scaler_ratio(struct mscl_ctx *ctx);
+void mscl_hw_set_rotation(struct mscl_ctx *ctx);
+void mscl_hw_address_queue_reset(struct mscl_ctx *ctx);
+void mscl_hw_set_csc_coeff(struct mscl_ctx *ctx);
+
+#endif /* MSCL_CORE_H_ */
-- 
1.7.9.5

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

Reply via email to