[PATCH] [media]: exynos-mscl: Add new driver for M2M scaler

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

 



This patch adds support for M-Scaler (M2M Scaler) device which is a
new device for scaling, blending, color fill  and color space
conversion on EXYNOS5 SoCs.

This device supports the followings as key feature.
    input image format
        - YCbCr420 2P(UV/VU), 3P
        - YCbCr422 1P(YUYV/UYVY/YVYU), 2P(UV,VU), 3P
        - YCbCr444 2P(UV,VU), 3P
        - RGB565, ARGB1555, ARGB4444, ARGB8888, RGBA8888
        - Pre-multiplexed ARGB8888, L8A8 and L8
    output image format
        - YCbCr420 2P(UV/VU), 3P
        - YCbCr422 1P(YUYV/UYVY/YVYU), 2P(UV,VU), 3P
        - YCbCr444 2P(UV,VU), 3P
        - RGB565, ARGB1555, ARGB4444, ARGB8888, RGBA8888
        - Pre-multiplexed ARGB8888
    input rotation
        - 0/90/180/270 degree, X/Y/XY Flip
    scale ratio
        - 1/4 scale down to 16 scale up
    color space conversion
        - RGB to YUV / YUV to RGB
    Size
        - Input : 16x16 to 8192x8192
        - Output:   4x4 to 8192x8192
    alpha blending, color fill

Signed-off-by: Shaik Ameer Basha <shaik.ameer@xxxxxxxxxxx>
---
 drivers/media/platform/Kconfig                 |    8 +
 drivers/media/platform/Makefile                |    1 +
 drivers/media/platform/exynos-mscl/Makefile    |    3 +
 drivers/media/platform/exynos-mscl/mscl-core.c | 1326 ++++++++++++++++++++++++
 drivers/media/platform/exynos-mscl/mscl-core.h |  554 ++++++++++
 drivers/media/platform/exynos-mscl/mscl-m2m.c  |  773 ++++++++++++++
 drivers/media/platform/exynos-mscl/mscl-regs.c |  386 +++++++
 drivers/media/platform/exynos-mscl/mscl-regs.h |  282 +++++
 8 files changed, 3333 insertions(+)
 create mode 100644 drivers/media/platform/exynos-mscl/Makefile
 create mode 100644 drivers/media/platform/exynos-mscl/mscl-core.c
 create mode 100644 drivers/media/platform/exynos-mscl/mscl-core.h
 create mode 100644 drivers/media/platform/exynos-mscl/mscl-m2m.c
 create mode 100644 drivers/media/platform/exynos-mscl/mscl-regs.c
 create mode 100644 drivers/media/platform/exynos-mscl/mscl-regs.h

diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 08de865..f6e5510 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -201,6 +201,14 @@ config VIDEO_SAMSUNG_EXYNOS_GSC
 	help
 	  This is a v4l2 driver for Samsung EXYNOS5 SoC G-Scaler.
 
+config VIDEO_SAMSUNG_EXYNOS_MSCL
+	tristate "Samsung Exynos M2M-Scaler driver"
+	depends on VIDEO_DEV && VIDEO_V4L2 && ARCH_EXYNOS5
+	select VIDEOBUF2_DMA_CONTIG
+	select V4L2_MEM2MEM_DEV
+	help
+	  This is a v4l2 driver for Samsung EXYNOS5 SoC M2M-Scaler.
+
 config VIDEO_SH_VEU
 	tristate "SuperH VEU mem2mem video processing driver"
 	depends on VIDEO_DEV && VIDEO_V4L2 && GENERIC_HARDIRQS
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index eee28dd..2452b09 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_TV)	+= s5p-tv/
 
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D)	+= s5p-g2d/
 obj-$(CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC)	+= exynos-gsc/
+obj-$(CONFIG_VIDEO_SAMSUNG_EXYNOS_MSCL)	+= exynos-mscl/
 
 obj-$(CONFIG_BLACKFIN)                  += blackfin/
 
diff --git a/drivers/media/platform/exynos-mscl/Makefile b/drivers/media/platform/exynos-mscl/Makefile
new file mode 100644
index 0000000..c9ffcd8
--- /dev/null
+++ b/drivers/media/platform/exynos-mscl/Makefile
@@ -0,0 +1,3 @@
+exynos-mscl-objs := mscl-core.o mscl-m2m.o mscl-regs.o
+
+obj-$(CONFIG_VIDEO_SAMSUNG_EXYNOS_MSCL)	+= exynos-mscl.o
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..81ce122
--- /dev/null
+++ b/drivers/media/platform/exynos-mscl/mscl-core.c
@@ -0,0 +1,1326 @@
+/*
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Samsung EXYNOS5 SoC series M2M SCALER driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 2 of the License,
+ * or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/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 <media/v4l2-ioctl.h>
+#ifdef CONFIG_EXYNOS_IOMMU
+#include <linux/dma-mapping.h>
+#include <linux/iommu.h>
+#include <linux/kref.h>
+#include <linux/of_platform.h>
+
+#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 G-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_CBCR) && (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.ameer@xxxxxxxxxxx>");
+MODULE_DESCRIPTION("Samsung EXYNOS5 Soc series M2M 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..32e94b7
--- /dev/null
+++ b/drivers/media/platform/exynos-mscl/mscl-core.h
@@ -0,0 +1,554 @@
+/*
+ * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * header file for Samsung EXYNOS5 SoC series G-Scaler driver
+
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef MSCL_CORE_H_
+#define MSCL_CORE_H_
+
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <media/videobuf2-core.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-mediabus.h>
+#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
+ * @name: format description
+ * @pixelformat: the fourcc code for this format, 0 if not applicable
+ * @yorder: Y/C order
+ * @corder: Chrominance order control
+ * @num_planes: number of physically non-contiguous data planes
+ * @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 G-Scaler input buffer
+ */
+struct mscl_input_buf {
+	struct vb2_buffer	vb;
+	struct list_head	list;
+	int			idx;
+};
+
+/**
+ * struct mscl_addr - the G-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 G-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 G-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:	G-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 - M2M-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: G-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 G-Scaler entity
+ * @slock: the spinlock protecting this data structure
+ * @lock: the mutex protecting this data structure
+ * @pdev: pointer to the M2M-Scaler platform device
+ * @variant: the IP variant information
+ * @id: M2M-Scaler device index (0..MSCL_MAX_DEVS)
+ * @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
+ * @alloc_ctx: videobuf2 memory allocator context
+ * @vdev: video device for G-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 G-Scaler device this context applies to
+ * @m2m_ctx: memory-to-memory device context
+ * @fh: v4l2 file handle
+ * @ctrl_handler: v4l2 controls handler
+ * @ctrls_mscl: M2M-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_ */
diff --git a/drivers/media/platform/exynos-mscl/mscl-m2m.c b/drivers/media/platform/exynos-mscl/mscl-m2m.c
new file mode 100644
index 0000000..3ac6999
--- /dev/null
+++ b/drivers/media/platform/exynos-mscl/mscl-m2m.c
@@ -0,0 +1,773 @@
+/*
+ * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Samsung EXYNOS5 SoC series G-Scaler driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 2 of the License,
+ * or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/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 "mscl-core.h"
+
+static int mscl_m2m_ctx_stop_req(struct mscl_ctx *ctx)
+{
+	struct mscl_ctx *curr_ctx;
+	struct mscl_dev *mscl = ctx->mscl_dev;
+	int ret;
+
+	curr_ctx = v4l2_m2m_get_curr_priv(mscl->m2m.m2m_dev);
+	if (!mscl_m2m_pending(mscl) || (curr_ctx != ctx))
+		return 0;
+
+	mscl_ctx_state_lock_set(MSCL_CTX_STOP_REQ, ctx);
+	ret = wait_event_timeout(mscl->irq_queue,
+			!mscl_ctx_state_is_set(MSCL_CTX_STOP_REQ, ctx),
+			MSCL_SHUTDOWN_TIMEOUT);
+
+	return ret == 0 ? -ETIMEDOUT : ret;
+}
+
+static int mscl_m2m_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+	struct mscl_ctx *ctx = q->drv_priv;
+	int ret;
+
+	ret = pm_runtime_get_sync(&ctx->mscl_dev->pdev->dev);
+
+	return ret > 0 ? 0 : ret;
+}
+
+static int mscl_m2m_stop_streaming(struct vb2_queue *q)
+{
+	struct mscl_ctx *ctx = q->drv_priv;
+	int ret;
+
+	ret = mscl_m2m_ctx_stop_req(ctx);
+	if (ret == -ETIMEDOUT)
+		mscl_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
+
+	pm_runtime_put(&ctx->mscl_dev->pdev->dev);
+
+	return 0;
+}
+
+void mscl_m2m_job_finish(struct mscl_ctx *ctx, int vb_state)
+{
+	struct vb2_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) {
+		v4l2_m2m_buf_done(src_vb, vb_state);
+		v4l2_m2m_buf_done(dst_vb, vb_state);
+
+		v4l2_m2m_job_finish(ctx->mscl_dev->m2m.m2m_dev,
+							ctx->m2m_ctx);
+	}
+}
+
+
+static void mscl_m2m_job_abort(void *priv)
+{
+	struct mscl_ctx *ctx = priv;
+	int ret;
+
+	ret = mscl_m2m_ctx_stop_req(ctx);
+	if (ret == -ETIMEDOUT)
+		mscl_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
+}
+
+static int mscl_get_bufs(struct mscl_ctx *ctx)
+{
+	struct mscl_frame *s_frame, *d_frame;
+	struct vb2_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 = mscl_prepare_addr(ctx, src_vb, s_frame, &s_frame->addr);
+	if (ret)
+		return ret;
+
+	dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+	ret = mscl_prepare_addr(ctx, dst_vb, d_frame, &d_frame->addr);
+	if (ret)
+		return ret;
+
+	dst_vb->v4l2_buf.timestamp = src_vb->v4l2_buf.timestamp;
+
+	return 0;
+}
+
+static void mscl_m2m_device_run(void *priv)
+{
+	struct mscl_ctx *ctx = priv;
+	struct mscl_dev *mscl;
+	unsigned long flags;
+	int ret;
+	bool is_set = false;
+
+	if (WARN(!ctx, "null hardware context\n"))
+		return;
+
+	mscl = ctx->mscl_dev;
+	spin_lock_irqsave(&mscl->slock, flags);
+
+	set_bit(ST_M2M_PEND, &mscl->state);
+
+	/* Reconfigure hardware if the context has changed. */
+	if (mscl->m2m.ctx != ctx) {
+		dev_dbg(&mscl->pdev->dev,
+			"mscl->m2m.ctx = 0x%p, current_ctx = 0x%p",
+			mscl->m2m.ctx, ctx);
+		ctx->state |= MSCL_PARAMS;
+		mscl->m2m.ctx = ctx;
+	}
+
+	is_set = (ctx->state & MSCL_CTX_STOP_REQ) ? 1 : 0;
+	ctx->state &= ~MSCL_CTX_STOP_REQ;
+	if (is_set) {
+		wake_up(&mscl->irq_queue);
+		goto put_device;
+	}
+
+	ret = mscl_get_bufs(ctx);
+	if (ret) {
+		dev_dbg(&mscl->pdev->dev, "Wrong address");
+		goto put_device;
+	}
+
+	mscl_hw_address_queue_reset(ctx);
+	mscl_set_prefbuf(mscl, &ctx->s_frame);
+	mscl_hw_set_input_addr(mscl, &ctx->s_frame.addr);
+	mscl_hw_set_output_addr(mscl, &ctx->d_frame.addr);
+	mscl_hw_set_csc_coeff(ctx);
+
+	if (ctx->state & MSCL_PARAMS) {
+		mscl_hw_set_irq_mask(mscl, MSCL_INT_FRAME_END, false);
+		if (mscl_set_scaler_info(ctx)) {
+			dev_dbg(&mscl->pdev->dev, "Scaler setup error");
+			goto put_device;
+		}
+
+		mscl_hw_set_in_size(ctx);
+		mscl_hw_set_in_image_format(ctx);
+
+		mscl_hw_set_out_size(ctx);
+		mscl_hw_set_out_image_format(ctx);
+
+		mscl_hw_set_scaler_ratio(ctx);
+		mscl_hw_set_rotation(ctx);
+	}
+
+	ctx->state &= ~MSCL_PARAMS;
+	mscl_hw_enable_control(mscl, true);
+
+	spin_unlock_irqrestore(&mscl->slock, flags);
+	return;
+
+put_device:
+	ctx->state &= ~MSCL_PARAMS;
+	spin_unlock_irqrestore(&mscl->slock, flags);
+}
+
+static int mscl_m2m_queue_setup(struct vb2_queue *vq,
+			const struct v4l2_format *fmt,
+			unsigned int *num_buffers, unsigned int *num_planes,
+			unsigned int sizes[], void *allocators[])
+{
+	struct mscl_ctx *ctx = vb2_get_drv_priv(vq);
+	struct mscl_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];
+		allocators[i] = ctx->mscl_dev->alloc_ctx;
+	}
+	return 0;
+}
+
+static int mscl_m2m_buf_prepare(struct vb2_buffer *vb)
+{
+	struct mscl_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct mscl_frame *frame;
+	int i;
+
+	frame = ctx_get_frame(ctx, vb->vb2_queue->type);
+	if (IS_ERR(frame))
+		return PTR_ERR(frame);
+
+	if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
+		for (i = 0; i < frame->fmt->num_planes; i++)
+			vb2_set_plane_payload(vb, i, frame->payload[i]);
+	}
+
+	return 0;
+}
+
+static void mscl_m2m_buf_queue(struct vb2_buffer *vb)
+{
+	struct mscl_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+	dev_dbg(&ctx->mscl_dev->pdev->dev,
+		"ctx: %p, ctx->state: 0x%x", ctx, ctx->state);
+
+	if (ctx->m2m_ctx)
+		v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+}
+
+static struct vb2_ops mscl_m2m_qops = {
+	.queue_setup	 = mscl_m2m_queue_setup,
+	.buf_prepare	 = mscl_m2m_buf_prepare,
+	.buf_queue	 = mscl_m2m_buf_queue,
+	.wait_prepare	 = mscl_unlock,
+	.wait_finish	 = mscl_lock,
+	.stop_streaming	 = mscl_m2m_stop_streaming,
+	.start_streaming = mscl_m2m_start_streaming,
+};
+
+static int mscl_m2m_querycap(struct file *file, void *fh,
+			   struct v4l2_capability *cap)
+{
+	struct mscl_ctx *ctx = fh_to_ctx(fh);
+	struct mscl_dev *mscl = ctx->mscl_dev;
+
+	strlcpy(cap->driver, mscl->pdev->name, sizeof(cap->driver));
+	strlcpy(cap->card, mscl->pdev->name, sizeof(cap->card));
+	strlcpy(cap->bus_info, "platform", sizeof(cap->bus_info));
+	cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE |
+		V4L2_CAP_VIDEO_CAPTURE_MPLANE |	V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+
+	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+	return 0;
+}
+
+static int mscl_m2m_enum_fmt_mplane(struct file *file, void *priv,
+				struct v4l2_fmtdesc *f)
+{
+	return mscl_enum_fmt_mplane(f);
+}
+
+static int mscl_m2m_g_fmt_mplane(struct file *file, void *fh,
+			     struct v4l2_format *f)
+{
+	struct mscl_ctx *ctx = fh_to_ctx(fh);
+
+	return mscl_g_fmt_mplane(ctx, f);
+}
+
+static int mscl_m2m_try_fmt_mplane(struct file *file, void *fh,
+				  struct v4l2_format *f)
+{
+	struct mscl_ctx *ctx = fh_to_ctx(fh);
+
+	return mscl_try_fmt_mplane(ctx, f);
+}
+
+static int mscl_m2m_s_fmt_mplane(struct file *file, void *fh,
+				 struct v4l2_format *f)
+{
+	struct mscl_ctx *ctx = fh_to_ctx(fh);
+	struct vb2_queue *vq;
+	struct mscl_frame *frame;
+	struct v4l2_pix_format_mplane *pix;
+	int i, ret = 0;
+
+	ret = mscl_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)) {
+		dev_dbg(&ctx->mscl_dev->pdev->dev, "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 = mscl_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;
+
+	mscl_set_frame_size(frame, pix->width, pix->height);
+
+	if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		mscl_ctx_state_lock_set(MSCL_PARAMS | MSCL_DST_FMT, ctx);
+	else
+		mscl_ctx_state_lock_set(MSCL_PARAMS | MSCL_SRC_FMT, ctx);
+
+	dev_dbg(&ctx->mscl_dev->pdev->dev, "f_w: %d, f_h: %d",
+					   frame->f_width, frame->f_height);
+
+	return 0;
+}
+
+static int mscl_m2m_reqbufs(struct file *file, void *fh,
+			  struct v4l2_requestbuffers *reqbufs)
+{
+	struct mscl_ctx *ctx = fh_to_ctx(fh);
+	struct mscl_dev *mscl = ctx->mscl_dev;
+	struct mscl_frame *frame;
+	u32 max_cnt;
+
+	max_cnt = (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ?
+		mscl->variant->in_buf_cnt : mscl->variant->out_buf_cnt;
+	if (reqbufs->count > max_cnt) {
+		return -EINVAL;
+	} else if (reqbufs->count == 0) {
+		if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+			mscl_ctx_state_lock_clear(MSCL_SRC_FMT, ctx);
+		else
+			mscl_ctx_state_lock_clear(MSCL_DST_FMT, ctx);
+	}
+
+	frame = ctx_get_frame(ctx, reqbufs->type);
+
+	return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int mscl_m2m_expbuf(struct file *file, void *fh,
+				struct v4l2_exportbuffer *eb)
+{
+	struct mscl_ctx *ctx = fh_to_ctx(fh);
+	return v4l2_m2m_expbuf(file, ctx->m2m_ctx, eb);
+}
+
+static int mscl_m2m_querybuf(struct file *file, void *fh,
+					struct v4l2_buffer *buf)
+{
+	struct mscl_ctx *ctx = fh_to_ctx(fh);
+	return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int mscl_m2m_qbuf(struct file *file, void *fh,
+			  struct v4l2_buffer *buf)
+{
+	struct mscl_ctx *ctx = fh_to_ctx(fh);
+	return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int mscl_m2m_dqbuf(struct file *file, void *fh,
+			   struct v4l2_buffer *buf)
+{
+	struct mscl_ctx *ctx = fh_to_ctx(fh);
+	return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int mscl_m2m_streamon(struct file *file, void *fh,
+			   enum v4l2_buf_type type)
+{
+	struct mscl_ctx *ctx = fh_to_ctx(fh);
+
+	/* The source and target color format need to be set */
+	if (V4L2_TYPE_IS_OUTPUT(type)) {
+		if (!mscl_ctx_state_is_set(MSCL_SRC_FMT, ctx))
+			return -EINVAL;
+	} else if (!mscl_ctx_state_is_set(MSCL_DST_FMT, ctx)) {
+		return -EINVAL;
+	}
+
+	return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int mscl_m2m_streamoff(struct file *file, void *fh,
+			    enum v4l2_buf_type type)
+{
+	struct mscl_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 mscl_m2m_g_selection(struct file *file, void *fh,
+			struct v4l2_selection *s)
+{
+	struct mscl_frame *frame;
+	struct mscl_ctx *ctx = fh_to_ctx(fh);
+
+	if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
+	    (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE))
+		return -EINVAL;
+
+	frame = ctx_get_frame(ctx, s->type);
+	if (IS_ERR(frame))
+		return PTR_ERR(frame);
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+		s->r.left = 0;
+		s->r.top = 0;
+		s->r.width = frame->f_width;
+		s->r.height = frame->f_height;
+		return 0;
+
+	case V4L2_SEL_TGT_COMPOSE:
+	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 mscl_m2m_s_selection(struct file *file, void *fh,
+				struct v4l2_selection *s)
+{
+	struct mscl_frame *frame;
+	struct mscl_ctx *ctx = fh_to_ctx(fh);
+	struct v4l2_crop cr;
+	struct mscl_variant *variant = ctx->mscl_dev->variant;
+	int ret;
+
+	cr.type = s->type;
+	cr.c = s->r;
+
+	if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
+	    (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE))
+		return -EINVAL;
+
+	ret = mscl_try_crop(ctx, &cr);
+	if (ret)
+		return ret;
+
+	if (s->flags & V4L2_SEL_FLAG_LE &&
+	    !is_rectangle_enclosed(&cr.c, &s->r))
+		return -ERANGE;
+
+	if (s->flags & V4L2_SEL_FLAG_GE &&
+	    !is_rectangle_enclosed(&s->r, &cr.c))
+		return -ERANGE;
+
+	s->r = cr.c;
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+	case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+	case V4L2_SEL_TGT_COMPOSE:
+		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 (mscl_ctx_state_is_set(MSCL_DST_FMT | MSCL_SRC_FMT, ctx)) {
+		if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+			ret = mscl_check_scaler_ratio(variant, cr.c.width,
+				cr.c.height, ctx->d_frame.crop.width,
+				ctx->d_frame.crop.height,
+				ctx->ctrls_mscl.rotate->val);
+		} else {
+			ret = mscl_check_scaler_ratio(variant,
+				ctx->s_frame.crop.width,
+				ctx->s_frame.crop.height, cr.c.width,
+				cr.c.height, ctx->ctrls_mscl.rotate->val);
+		}
+
+		if (ret) {
+			dev_dbg(&ctx->mscl_dev->pdev->dev,
+				"Out of scaler range");
+			return -EINVAL;
+		}
+	}
+
+	frame->crop = cr.c;
+
+	mscl_ctx_state_lock_set(MSCL_PARAMS, ctx);
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops mscl_m2m_ioctl_ops = {
+	.vidioc_querycap		= mscl_m2m_querycap,
+	.vidioc_enum_fmt_vid_cap_mplane	= mscl_m2m_enum_fmt_mplane,
+	.vidioc_enum_fmt_vid_out_mplane	= mscl_m2m_enum_fmt_mplane,
+	.vidioc_g_fmt_vid_cap_mplane	= mscl_m2m_g_fmt_mplane,
+	.vidioc_g_fmt_vid_out_mplane	= mscl_m2m_g_fmt_mplane,
+	.vidioc_try_fmt_vid_cap_mplane	= mscl_m2m_try_fmt_mplane,
+	.vidioc_try_fmt_vid_out_mplane	= mscl_m2m_try_fmt_mplane,
+	.vidioc_s_fmt_vid_cap_mplane	= mscl_m2m_s_fmt_mplane,
+	.vidioc_s_fmt_vid_out_mplane	= mscl_m2m_s_fmt_mplane,
+	.vidioc_reqbufs			= mscl_m2m_reqbufs,
+	.vidioc_expbuf                  = mscl_m2m_expbuf,
+	.vidioc_querybuf		= mscl_m2m_querybuf,
+	.vidioc_qbuf			= mscl_m2m_qbuf,
+	.vidioc_dqbuf			= mscl_m2m_dqbuf,
+	.vidioc_streamon		= mscl_m2m_streamon,
+	.vidioc_streamoff		= mscl_m2m_streamoff,
+	.vidioc_g_selection		= mscl_m2m_g_selection,
+	.vidioc_s_selection		= mscl_m2m_s_selection
+};
+
+static int queue_init(void *priv, struct vb2_queue *src_vq,
+			struct vb2_queue *dst_vq)
+{
+	struct mscl_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 = &mscl_m2m_qops;
+	src_vq->mem_ops = &vb2_dma_contig_memops;
+	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+
+	ret = vb2_queue_init(src_vq);
+	if (ret)
+		return ret;
+
+	memset(dst_vq, 0, sizeof(*dst_vq));
+	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+	dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+	dst_vq->drv_priv = ctx;
+	dst_vq->ops = &mscl_m2m_qops;
+	dst_vq->mem_ops = &vb2_dma_contig_memops;
+	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+
+	return vb2_queue_init(dst_vq);
+}
+
+static int mscl_m2m_open(struct file *file)
+{
+	struct mscl_dev *mscl = video_drvdata(file);
+	struct mscl_ctx *ctx = NULL;
+	int ret;
+
+	dev_dbg(&mscl->pdev->dev,
+		"pid: %d, state: 0x%lx", task_pid_nr(current), mscl->state);
+
+	if (mutex_lock_interruptible(&mscl->lock))
+		return -ERESTARTSYS;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx) {
+		ret = -ENOMEM;
+		goto unlock;
+	}
+
+	v4l2_fh_init(&ctx->fh, mscl->m2m.vfd);
+	ret = mscl_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->mscl_dev = mscl;
+	/* Default color format */
+	ctx->s_frame.fmt = mscl_get_format(0);
+	ctx->d_frame.fmt = mscl_get_format(0);
+	/* Setup the device context for mem2mem mode. */
+	ctx->state = MSCL_CTX_M2M;
+	ctx->flags = 0;
+
+	ctx->m2m_ctx = v4l2_m2m_ctx_init(mscl->m2m.m2m_dev, ctx, queue_init);
+	if (IS_ERR(ctx->m2m_ctx)) {
+		dev_dbg(&mscl->pdev->dev, "Failed to initialize m2m context");
+		ret = PTR_ERR(ctx->m2m_ctx);
+		goto error_ctrls;
+	}
+
+	if (mscl->m2m.refcnt++ == 0)
+		set_bit(ST_M2M_OPEN, &mscl->state);
+
+	dev_dbg(&mscl->pdev->dev, "mscl m2m driver is opened, ctx(0x%p)", ctx);
+
+	mutex_unlock(&mscl->lock);
+	return 0;
+
+error_ctrls:
+	mscl_ctrls_delete(ctx);
+error_fh:
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	kfree(ctx);
+unlock:
+	mutex_unlock(&mscl->lock);
+	return ret;
+}
+
+static int mscl_m2m_release(struct file *file)
+{
+	struct mscl_ctx *ctx = fh_to_ctx(file->private_data);
+	struct mscl_dev *mscl = ctx->mscl_dev;
+
+	dev_dbg(&mscl->pdev->dev, "pid: %d, state: 0x%lx, refcnt= %d",
+		task_pid_nr(current), mscl->state, mscl->m2m.refcnt);
+
+	mutex_lock(&mscl->lock);
+
+	v4l2_m2m_ctx_release(ctx->m2m_ctx);
+	mscl_ctrls_delete(ctx);
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+
+	if (--mscl->m2m.refcnt <= 0)
+		clear_bit(ST_M2M_OPEN, &mscl->state);
+	kfree(ctx);
+
+	mutex_unlock(&mscl->lock);
+	return 0;
+}
+
+static unsigned int mscl_m2m_poll(struct file *file,
+					struct poll_table_struct *wait)
+{
+	struct mscl_ctx *ctx = fh_to_ctx(file->private_data);
+	struct mscl_dev *mscl = ctx->mscl_dev;
+	int ret;
+
+	if (mutex_lock_interruptible(&mscl->lock))
+		return -ERESTARTSYS;
+
+	ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+	mutex_unlock(&mscl->lock);
+
+	return ret;
+}
+
+static int mscl_m2m_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct mscl_ctx *ctx = fh_to_ctx(file->private_data);
+	struct mscl_dev *mscl = ctx->mscl_dev;
+	int ret;
+
+	if (mutex_lock_interruptible(&mscl->lock))
+		return -ERESTARTSYS;
+
+	ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+	mutex_unlock(&mscl->lock);
+
+	return ret;
+}
+
+static const struct v4l2_file_operations mscl_m2m_fops = {
+	.owner		= THIS_MODULE,
+	.open		= mscl_m2m_open,
+	.release	= mscl_m2m_release,
+	.poll		= mscl_m2m_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= mscl_m2m_mmap,
+};
+
+static struct v4l2_m2m_ops mscl_m2m_ops = {
+	.device_run	= mscl_m2m_device_run,
+	.job_abort	= mscl_m2m_job_abort,
+};
+
+int mscl_register_m2m_device(struct mscl_dev *mscl)
+{
+	struct platform_device *pdev;
+	int ret;
+
+	if (!mscl)
+		return -ENODEV;
+
+	pdev = mscl->pdev;
+
+	mscl->vdev.fops		= &mscl_m2m_fops;
+	mscl->vdev.ioctl_ops	= &mscl_m2m_ioctl_ops;
+	mscl->vdev.release	= video_device_release_empty;
+	mscl->vdev.lock		= &mscl->lock;
+	mscl->vdev.vfl_dir	= VFL_DIR_M2M;
+	snprintf(mscl->vdev.name, sizeof(mscl->vdev.name), "%s.%d:m2m",
+					MSCL_MODULE_NAME, mscl->id);
+
+	video_set_drvdata(&mscl->vdev, mscl);
+
+	mscl->m2m.vfd = &mscl->vdev;
+	mscl->m2m.m2m_dev = v4l2_m2m_init(&mscl_m2m_ops);
+	if (IS_ERR(mscl->m2m.m2m_dev)) {
+		dev_err(&pdev->dev, "failed to initialize v4l2-m2m device\n");
+		return PTR_ERR(mscl->m2m.m2m_dev);
+	}
+
+	ret = video_register_device(&mscl->vdev, VFL_TYPE_GRABBER, -1);
+	if (ret) {
+		dev_err(&pdev->dev,
+			 "%s(): failed to register video device\n", __func__);
+		v4l2_m2m_release(mscl->m2m.m2m_dev);
+		return ret;
+	}
+
+	dev_info(&pdev->dev,
+		 "mscl m2m driver registered as /dev/video%d", mscl->vdev.num);
+	return 0;
+}
+
+void mscl_unregister_m2m_device(struct mscl_dev *mscl)
+{
+	if (mscl)
+		v4l2_m2m_release(mscl->m2m.m2m_dev);
+}
diff --git a/drivers/media/platform/exynos-mscl/mscl-regs.c b/drivers/media/platform/exynos-mscl/mscl-regs.c
new file mode 100644
index 0000000..a0bd00f
--- /dev/null
+++ b/drivers/media/platform/exynos-mscl/mscl-regs.c
@@ -0,0 +1,386 @@
+/*
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Samsung EXYNOS5 SoC series M2M-Scaler driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 2 of the License,
+ * or (at your option) any later version.
+ */
+
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <mach/map.h>
+
+#include "mscl-core.h"
+
+void mscl_hw_set_sw_reset(struct mscl_dev *dev)
+{
+	u32 cfg;
+
+	cfg = readl(dev->regs + MSCL_CFG);
+	cfg |= MSCL_CFG_SOFT_RESET;
+
+	writel(cfg, dev->regs + MSCL_CFG);
+}
+
+int mscl_wait_reset(struct mscl_dev *dev)
+{
+	unsigned long end = jiffies + msecs_to_jiffies(50);
+	u32 cfg, reset_done = 0;
+
+	while (time_before(jiffies, end)) {
+		cfg = readl(dev->regs + MSCL_CFG);
+		if (!(cfg & MSCL_CFG_SOFT_RESET)) {
+			reset_done = 1;
+			break;
+		}
+		usleep_range(10, 20);
+	}
+
+	/* write any value to r/w reg and read it back */
+	while (reset_done) {
+
+		/* [TBD:SAB] need to define number to tries before returning
+		 * -EBUSY to the caller
+		 */
+
+		writel(MSCL_CFG_SOFT_RESET_CHECK_VAL,
+				dev->regs + MSCL_CFG_SOFT_RESET_CHECK_REG);
+		if (MSCL_CFG_SOFT_RESET_CHECK_VAL ==
+			readl(dev->regs + MSCL_CFG_SOFT_RESET_CHECK_REG))
+			return 0;
+	}
+
+	return -EBUSY;
+}
+
+void mscl_hw_set_irq_mask(struct mscl_dev *dev, int interrupt, bool mask)
+{
+	u32 cfg;
+
+	switch (interrupt) {
+	case MSCL_INT_TIMEOUT:
+	case MSCL_INT_ILLEGAL_BLEND:
+	case MSCL_INT_ILLEGAL_RATIO:
+	case MSCL_INT_ILLEGAL_DST_HEIGHT:
+	case MSCL_INT_ILLEGAL_DST_WIDTH:
+	case MSCL_INT_ILLEGAL_DST_V_POS:
+	case MSCL_INT_ILLEGAL_DST_H_POS:
+	case MSCL_INT_ILLEGAL_DST_C_SPAN:
+	case MSCL_INT_ILLEGAL_DST_Y_SPAN:
+	case MSCL_INT_ILLEGAL_DST_CR_BASE:
+	case MSCL_INT_ILLEGAL_DST_CB_BASE:
+	case MSCL_INT_ILLEGAL_DST_Y_BASE:
+	case MSCL_INT_ILLEGAL_DST_COLOR:
+	case MSCL_INT_ILLEGAL_SRC_HEIGHT:
+	case MSCL_INT_ILLEGAL_SRC_WIDTH:
+	case MSCL_INT_ILLEGAL_SRC_CV_POS:
+	case MSCL_INT_ILLEGAL_SRC_CH_POS:
+	case MSCL_INT_ILLEGAL_SRC_YV_POS:
+	case MSCL_INT_ILLEGAL_SRC_YH_POS:
+	case MSCL_INT_ILLEGAL_SRC_C_SPAN:
+	case MSCL_INT_ILLEGAL_SRC_Y_SPAN:
+	case MSCL_INT_ILLEGAL_SRC_CR_BASE:
+	case MSCL_INT_ILLEGAL_SRC_CB_BASE:
+	case MSCL_INT_ILLEGAL_SRC_Y_BASE:
+	case MSCL_INT_ILLEGAL_SRC_COLOR:
+	case MSCL_INT_FRAME_END:
+		break;
+	default:
+		return;
+	}
+	cfg = readl(dev->regs + MSCL_INT_EN);
+	if (mask)
+		cfg |= interrupt;
+	else
+		cfg &= ~interrupt;
+	writel(cfg, dev->regs + MSCL_INT_EN);
+}
+
+void mscl_hw_set_input_addr(struct mscl_dev *dev, struct mscl_addr *addr)
+{
+	dev_dbg(&dev->pdev->dev, "src_buf: 0x%X, cb: 0x%X, cr: 0x%X",
+				addr->y, addr->cb, addr->cr);
+	writel(addr->y, dev->regs + MSCL_SRC_Y_BASE);
+	writel(addr->cb, dev->regs + MSCL_SRC_CB_BASE);
+	writel(addr->cr, dev->regs + MSCL_SRC_CR_BASE);
+}
+
+void mscl_hw_set_output_addr(struct mscl_dev *dev,
+			     struct mscl_addr *addr)
+{
+	dev_dbg(&dev->pdev->dev, "dst_buf: 0x%X, cb: 0x%X, cr: 0x%X",
+				addr->y, addr->cb, addr->cr);
+	writel(addr->y, dev->regs + MSCL_DST_Y_BASE);
+	writel(addr->cb, dev->regs + MSCL_DST_CB_BASE);
+	writel(addr->cr, dev->regs + MSCL_DST_CR_BASE);
+}
+
+void mscl_hw_set_in_size(struct mscl_ctx *ctx)
+{
+	struct mscl_dev *dev = ctx->mscl_dev;
+	struct mscl_frame *frame = &ctx->s_frame;
+	u32 cfg;
+
+	/* set input pixel offset */
+	cfg = MSCL_SRC_YH_POS(frame->crop.left);
+	cfg |= MSCL_SRC_YV_POS(frame->crop.top);
+	writel(cfg, dev->regs + MSCL_SRC_Y_POS);
+
+	/* [TBD] calculate 'C' plane h/v offset using 'Y' plane h/v offset */
+
+	/* set input span */
+	cfg = MSCL_SRC_Y_SPAN(frame->f_width);
+	if (is_yuv420_2p(frame->fmt))
+		cfg |= MSCL_SRC_C_SPAN(frame->f_width);
+	else
+		cfg |= MSCL_SRC_C_SPAN(frame->f_width); /* [TBD] Verify */
+
+	writel(cfg, dev->regs + MSCL_SRC_SPAN);
+
+	/* Set input cropped size */
+	cfg = MSCL_SRC_WIDTH(frame->crop.width);
+	cfg |= MSCL_SRC_HEIGHT(frame->crop.height);
+	writel(cfg, dev->regs + MSCL_SRC_WH);
+
+	dev_dbg(&dev->pdev->dev,
+		"src: posx: %d, posY: %d, spanY: %d, spanC: %d, "
+		"cropX: %d, cropY: %d\n",
+		frame->crop.left, frame->crop.top, frame->f_width,
+		frame->f_width, frame->crop.width, frame->crop.height);
+}
+
+void mscl_hw_set_in_image_format(struct mscl_ctx *ctx)
+{
+	struct mscl_dev *dev = ctx->mscl_dev;
+	struct mscl_frame *frame = &ctx->s_frame;
+	u32 cfg;
+
+	cfg = readl(dev->regs + MSCL_SRC_CFG);
+	cfg &= ~MSCL_SRC_COLOR_FORMAT_MASK;
+	cfg |= MSCL_SRC_COLOR_FORMAT(frame->fmt->mscl_color);
+
+	/* setting tile/linear format */
+	if (frame->fmt->is_tiled)
+		cfg |= MSCL_SRC_TILE_EN;
+	else
+		cfg &= ~MSCL_SRC_TILE_EN;
+
+	writel(cfg, dev->regs + MSCL_SRC_CFG);
+}
+
+void mscl_hw_set_out_size(struct mscl_ctx *ctx)
+{
+	struct mscl_dev *dev = ctx->mscl_dev;
+	struct mscl_frame *frame = &ctx->d_frame;
+	u32 cfg;
+
+	/* set output pixel offset */
+	cfg = MSCL_DST_H_POS(frame->crop.left);
+	cfg |= MSCL_DST_V_POS(frame->crop.top);
+	writel(cfg, dev->regs + MSCL_DST_POS);
+
+	/* set output span */
+	cfg = MSCL_DST_Y_SPAN(frame->f_width);
+	if (is_yuv420_2p(frame->fmt))
+		cfg |= MSCL_DST_C_SPAN(frame->f_width/2);
+	else
+		cfg |= MSCL_DST_C_SPAN(frame->f_width);
+	writel(cfg, dev->regs + MSCL_DST_SPAN);
+
+	/* set output scaled size */
+	cfg = MSCL_DST_WIDTH(frame->crop.width);
+	cfg |= MSCL_DST_HEIGHT(frame->crop.height);
+	writel(cfg, dev->regs + MSCL_DST_WH);
+
+	dev_dbg(&dev->pdev->dev,
+		"dst: posx: %d, posY: %d, spanY: %d, spanC: %d, "
+		"cropX: %d, cropY: %d\n",
+		frame->crop.left, frame->crop.top, frame->f_width,
+		frame->f_width, frame->crop.width, frame->crop.height);
+}
+
+void mscl_hw_set_out_image_format(struct mscl_ctx *ctx)
+{
+	struct mscl_dev *dev = ctx->mscl_dev;
+	struct mscl_frame *frame = &ctx->d_frame;
+	u32 cfg;
+
+	cfg = readl(dev->regs + MSCL_DST_CFG);
+	cfg &= ~MSCL_DST_COLOR_FORMAT_MASK;
+	cfg |= MSCL_DST_COLOR_FORMAT(frame->fmt->mscl_color);
+
+	writel(cfg, dev->regs + MSCL_DST_CFG);
+}
+
+void mscl_hw_set_scaler_ratio(struct mscl_ctx *ctx)
+{
+	struct mscl_dev *dev = ctx->mscl_dev;
+	struct mscl_scaler *sc = &ctx->scaler;
+	u32 cfg;
+
+	cfg = MSCL_H_RATIO_VALUE(sc->hratio);
+	writel(cfg, dev->regs + MSCL_H_RATIO);
+
+	cfg = MSCL_V_RATIO_VALUE(sc->vratio);
+	writel(cfg, dev->regs + MSCL_V_RATIO);
+}
+
+void mscl_hw_set_rotation(struct mscl_ctx *ctx)
+{
+	struct mscl_dev *dev = ctx->mscl_dev;
+	u32 cfg = 0;
+
+	cfg = MSCL_ROTMODE(ctx->ctrls_mscl.rotate->val/90);
+
+	if (ctx->ctrls_mscl.hflip->val)
+		cfg |= MSCL_FLIP_X_EN;
+
+	if (ctx->ctrls_mscl.vflip->val)
+		cfg |= MSCL_FLIP_Y_EN;
+
+	writel(cfg, dev->regs + MSCL_ROT_CFG);
+}
+
+void mscl_hw_address_queue_reset(struct mscl_ctx *ctx)
+{
+	struct mscl_dev *dev = ctx->mscl_dev;
+
+	writel(MSCL_ADDR_QUEUE_RST, dev->regs + MSCL_ADDR_QUEUE_CONFIG);
+}
+
+void mscl_hw_set_csc_coeff(struct mscl_ctx *ctx)
+{
+	struct mscl_dev *dev = ctx->mscl_dev;
+	enum mscl_csc_coeff type;
+	u32 cfg = 0;
+	int i, j;
+	static const u32 csc_coeff[MSCL_CSC_COEFF_MAX][3][3] = {
+		{ /* YCbCr to RGB */
+			{0x200, 0x000, 0x2be},
+			{0x200, 0xeac, 0x165},
+			{0x200, 0x377, 0x000}
+		},
+		{ /* YCbCr to RGB with -16 offset */
+			{0x254, 0x000, 0x331},
+			{0x254, 0xec8, 0xFA0},
+			{0x254, 0x409, 0x000}
+		},
+		{ /* RGB to YCbCr */
+			{0x099, 0x12d, 0x03a},
+			{0xe58, 0xeae, 0x106},
+			{0x106, 0xedb, 0xe2a}
+		},
+		{ /* RGB to YCbCr with -16 offset */
+			{0x084, 0x102, 0x032},
+			{0xe4c, 0xe95, 0x0e1},
+			{0x0e1, 0xebc, 0xe24}
+		} };
+
+	if (is_rgb(ctx->s_frame.fmt) == is_rgb(ctx->d_frame.fmt))
+		type = MSCL_CSC_COEFF_NONE;
+	else if (is_rgb(ctx->d_frame.fmt))
+		type = MSCL_CSC_COEFF_YCBCR_TO_RGB_OFF16;
+	else
+		type = MSCL_CSC_COEFF_RGB_TO_YCBCR_OFF16;
+
+	if ((type == ctx->mscl_dev->coeff_type) || (type >= MSCL_CSC_COEFF_MAX))
+		return;
+
+	for (i = 0; i < 3; i++) {
+		for (j = 0; j < 3; j++) {
+			cfg = csc_coeff[type][i][j];
+			writel(cfg, dev->regs + MSCL_CSC_COEF(i, j));
+		}
+	}
+
+	switch (type) {
+	case MSCL_CSC_COEFF_YCBCR_TO_RGB:
+		mscl_hw_src_y_offset_en(ctx->mscl_dev, false);
+		break;
+	case MSCL_CSC_COEFF_YCBCR_TO_RGB_OFF16:
+		mscl_hw_src_y_offset_en(ctx->mscl_dev, true);
+		break;
+	case MSCL_CSC_COEFF_RGB_TO_YCBCR:
+		mscl_hw_src_y_offset_en(ctx->mscl_dev, false);
+		break;
+	case MSCL_CSC_COEFF_RGB_TO_YCBCR_OFF16:
+		mscl_hw_src_y_offset_en(ctx->mscl_dev, true);
+		break;
+	default:
+		return;
+	}
+
+	ctx->mscl_dev->coeff_type = type;
+	return;
+}
+
+void mscl_hw_set_blending(struct mscl_ctx *ctx)
+{
+#if 0 /* Blending */
+
+	/* CO		[7:0]	src_color_op�CS + dst_color_op�CD
+	 * AO		[7:0]	src_alpha_op�AS + dst_color_op�AD
+	 * where
+	 * CO		[7:0]	output color
+	 * AO		[7:0]	output alpha
+	 * CS		[7:0]	SRC color selected
+	 * AS		[7:0]	SRC alpha selected
+	 * CD		[7:0]	DST color selected
+	 * AD		[7:0]	DST alpha selected
+	 * src_color_op	[7:0]	SRC color operand selected
+	 * src_alpha_op	[7:0]	SRC alpha operand selected
+	 * dst_color_op	[7:0]	DST color operand selected
+	 * dst_alpha_op	[7:0]	DST alpha operand selected
+	 */
+
+	/* Set src alpha/color blending */
+	cfg  = MSCL_SRC_COLOR_SEL(0);
+	cfg |= MSCL_SRC_COLOR_OP_SEL(0);
+	cfg |= MSCL_SRC_GLOBAL_COLOR0(0xff);
+	cfg |= MSCL_SRC_GLOBAL_COLOR1(0xff);
+	cfg |= MSCL_SRC_GLOBAL_COLOR2(0xff);
+	writel(cfg, dev->regs + MSCL_SRC_BLEND_COLOR);
+
+	cfg  = MSCL_SRC_ALPHA_SEL(0);
+	cfg |= MSCL_SRC_ALPHA_OP_SEL(0);
+	cfg |= MSCL_SRC_GLOBAL_ALPHA(0xff);
+	writel(cfg, dev->regs + MSCL_SRC_BLEND_ALPHA);
+
+	/* set dst alpha/color blending */
+	cfg  = MSCL_DST_COLOR_SEL(0);
+	cfg |= MSCL_DST_COLOR_OP_SEL(0);
+	cfg |= MSCL_DST_GLOBAL_COLOR0(0xff);
+	cfg |= MSCL_DST_GLOBAL_COLOR1(0xff);
+	cfg |= MSCL_DST_GLOBAL_COLOR2(0xff);
+	writel(cfg, dev->regs + MSCL_DST_BLEND_COLOR);
+
+	cfg  = MSCL_DST_ALPHA_SEL(0);
+	cfg |= MSCL_DST_ALPHA_OP_SEL(0);
+	cfg |= MSCL_DST_GLOBAL_ALPHA(0xff);
+	writel(cfg, dev->regs + MSCL_DST_BLEND_ALPHA);
+
+#endif
+}
+
+void mscl_hw_set_fill_color(struct mscl_ctx *ctx)
+{
+#if 0 /* fill color */
+	/* fill color */
+	cfg  = MSCL_FILL_ALPHA(0xff);
+	cfg |= MSCL_FILL_COLOR0(0xff);
+	cfg |= MSCL_FILL_COLOR1(0xff);
+	cfg |= MSCL_FILL_COLOR2(0xff);
+	writel(cfg, dev->regs + MSCL_FILL_COLOR);
+
+	/* enable fill color */
+	cfg = readl(dev->regs + MSCL_CFG);
+	cfg |= MSCL_CFG_FILL_EN;
+	writel(cfg, dev->regs + MSCL_CFG);
+#endif
+}
diff --git a/drivers/media/platform/exynos-mscl/mscl-regs.h b/drivers/media/platform/exynos-mscl/mscl-regs.h
new file mode 100644
index 0000000..874b9ff
--- /dev/null
+++ b/drivers/media/platform/exynos-mscl/mscl-regs.h
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * Register definition file for Samsung M2M-Scaler driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef REGS_MSCL_H_
+#define REGS_MSCL_H_
+
+/* m2m-scaler status */
+#define MSCL_STATUS				0x00
+#define MSCL_STATUS_RUNNING			(1 << 1)
+#define MSCL_STATUS_READY_CLK_DOWN		(1 << 0)
+
+/* m2m-scaler config */
+#define MSCL_CFG				0x04
+#define MSCL_CFG_FILL_EN			(1 << 24)
+#define MSCL_CFG_BLEND_CLR_DIV_ALPHA_EN		(1 << 17)
+#define MSCL_CFG_BLEND_EN			(1 << 16)
+#define MSCL_CFG_CSC_Y_OFFSET_SRC_EN		(1 << 10)
+#define MSCL_CFG_CSC_Y_OFFSET_DST_EN		(1 << 9)
+#define MSCL_CFG_16_BURST_MODE			(1 << 8)
+#define MSCL_CFG_SOFT_RESET			(1 << 1)
+#define MSCL_CFG_START_CMD			(1 << 0)
+
+/* m2m-scaler interrupt enable */
+#define MSCL_INT_EN				0x08
+#define MSCL_INT_EN_DEFAULT			0x81ffffff
+#define MSCL_INT_EN_TIMEOUT			(1 << 31)
+#define MSCL_INT_EN_ILLEGAL_BLEND		(1 << 24)
+#define MSCL_INT_EN_ILLEGAL_RATIO		(1 << 23)
+#define MSCL_INT_EN_ILLEGAL_DST_HEIGHT		(1 << 22)
+#define MSCL_INT_EN_ILLEGAL_DST_WIDTH		(1 << 21)
+#define MSCL_INT_EN_ILLEGAL_DST_V_POS		(1 << 20)
+#define MSCL_INT_EN_ILLEGAL_DST_H_POS		(1 << 19)
+#define MSCL_INT_EN_ILLEGAL_DST_C_SPAN		(1 << 18)
+#define MSCL_INT_EN_ILLEGAL_DST_Y_SPAN		(1 << 17)
+#define MSCL_INT_EN_ILLEGAL_DST_CR_BASE		(1 << 16)
+#define MSCL_INT_EN_ILLEGAL_DST_CB_BASE		(1 << 15)
+#define MSCL_INT_EN_ILLEGAL_DST_Y_BASE		(1 << 14)
+#define MSCL_INT_EN_ILLEGAL_DST_COLOR		(1 << 13)
+#define MSCL_INT_EN_ILLEGAL_SRC_HEIGHT		(1 << 12)
+#define MSCL_INT_EN_ILLEGAL_SRC_WIDTH		(1 << 11)
+#define MSCL_INT_EN_ILLEGAL_SRC_CV_POS		(1 << 10)
+#define MSCL_INT_EN_ILLEGAL_SRC_CH_POS		(1 << 9)
+#define MSCL_INT_EN_ILLEGAL_SRC_YV_POS		(1 << 8)
+#define MSCL_INT_EN_ILLEGAL_SRC_YH_POS		(1 << 7)
+#define MSCL_INT_EN_ILLEGAL_SRC_C_SPAN		(1 << 6)
+#define MSCL_INT_EN_ILLEGAL_SRC_Y_SPAN		(1 << 5)
+#define MSCL_INT_EN_ILLEGAL_SRC_CR_BASE		(1 << 4)
+#define MSCL_INT_EN_ILLEGAL_SRC_CB_BASE		(1 << 3)
+#define MSCL_INT_EN_ILLEGAL_SRC_Y_BASE		(1 << 2)
+#define MSCL_INT_EN_ILLEGAL_SRC_COLOR		(1 << 1)
+#define MSCL_INT_EN_FRAME_END			(1 << 0)
+
+/* m2m-scaler interrupt status */
+#define MSCL_INT_STATUS				0x0c
+#define MSCL_INT_STATUS_CLEAR			(0xffffffff)
+#define MSCL_INT_STATUS_ERROR			(0x81fffffe)
+#define MSCL_INT_STATUS_TIMEOUT			(1 << 31)
+#define MSCL_INT_STATUS_ILLEGAL_BLEND		(1 << 24)
+#define MSCL_INT_STATUS_ILLEGAL_RATIO		(1 << 23)
+#define MSCL_INT_STATUS_ILLEGAL_DST_HEIGHT	(1 << 22)
+#define MSCL_INT_STATUS_ILLEGAL_DST_WIDTH	(1 << 21)
+#define MSCL_INT_STATUS_ILLEGAL_DST_V_POS	(1 << 20)
+#define MSCL_INT_STATUS_ILLEGAL_DST_H_POS	(1 << 19)
+#define MSCL_INT_STATUS_ILLEGAL_DST_C_SPAN	(1 << 18)
+#define MSCL_INT_STATUS_ILLEGAL_DST_Y_SPAN	(1 << 17)
+#define MSCL_INT_STATUS_ILLEGAL_DST_CR_BASE	(1 << 16)
+#define MSCL_INT_STATUS_ILLEGAL_DST_CB_BASE	(1 << 15)
+#define MSCL_INT_STATUS_ILLEGAL_DST_Y_BASE	(1 << 14)
+#define MSCL_INT_STATUS_ILLEGAL_DST_COLOR	(1 << 13)
+#define MSCL_INT_STATUS_ILLEGAL_SRC_HEIGHT	(1 << 12)
+#define MSCL_INT_STATUS_ILLEGAL_SRC_WIDTH	(1 << 11)
+#define MSCL_INT_STATUS_ILLEGAL_SRC_CV_POS	(1 << 10)
+#define MSCL_INT_STATUS_ILLEGAL_SRC_CH_POS	(1 << 9)
+#define MSCL_INT_STATUS_ILLEGAL_SRC_YV_POS	(1 << 8)
+#define MSCL_INT_STATUS_ILLEGAL_SRC_YH_POS	(1 << 7)
+#define MSCL_INT_STATUS_ILLEGAL_SRC_C_SPAN	(1 << 6)
+#define MSCL_INT_STATUS_ILLEGAL_SRC_Y_SPAN	(1 << 5)
+#define MSCL_INT_STATUS_ILLEGAL_SRC_CR_BASE	(1 << 4)
+#define MSCL_INT_STATUS_ILLEGAL_SRC_CB_BASE	(1 << 3)
+#define MSCL_INT_STATUS_ILLEGAL_SRC_Y_BASE	(1 << 2)
+#define MSCL_INT_STATUS_ILLEGAL_SRC_COLOR	(1 << 1)
+#define MSCL_INT_STATUS_FRAME_END		(1 << 0)
+
+/* m2m-scaler source format configuration */
+#define MSCL_SRC_CFG				0x10
+#define MSCL_SRC_TILE_EN			(0x1 << 10)
+#define MSCL_SRC_BYTE_SWAP_MASK			(0x3 << 5)
+#define MSCL_SRC_BYTE_SWAP(x)			(((x) & 0x3) << 5)
+#define MSCL_SRC_COLOR_FORMAT_MASK		(0xf << 0)
+#define MSCL_SRC_COLOR_FORMAT(x)		(((x) & 0xf) << 0)
+
+/* m2m-scaler source y-base */
+#define MSCL_SRC_Y_BASE				0x14
+
+/* m2m-scaler source cb-base */
+#define MSCL_SRC_CB_BASE			0x18
+
+/* m2m-scaler source cr-base */
+#define MSCL_SRC_CR_BASE			0x294
+
+/* m2m-scaler source span */
+#define MSCL_SRC_SPAN				0x1c
+#define MSCL_SRC_C_SPAN_MASK			(0x3fff << 16)
+#define MSCL_SRC_C_SPAN(x)			(((x) & 0x3fff) << 16)
+#define MSCL_SRC_Y_SPAN_MASK			(0x3fff << 0)
+#define MSCL_SRC_Y_SPAN(x)			(((x) & 0x3fff) << 0)
+
+/* m2m-scaler source y-position */
+#define MSCL_SRC_Y_POS				0x20
+#define MSCL_SRC_YH_POS_MASK			(0xffff << (16 + 2))
+#define MSCL_SRC_YH_POS(x)			(((x) & 0xffff) << (16 + 2))
+#define MSCL_SRC_YV_POS_MASK			(0xffff << (0 + 2))
+#define MSCL_SRC_YV_POS(x)			(((x) & 0xffff) << (0 + 2))
+
+/* m2m-scaler source width/height */
+#define MSCL_SRC_WH				0x24
+#define MSCL_SRC_WIDTH_MASK			(0x3fff << 16)
+#define MSCL_SRC_WIDTH(x)			(((x) & 0x3fff) << 16)
+#define MSCL_SRC_HEIGHT_MASK			(0x3fff << 0)
+#define MSCL_SRC_HEIGHT(x)			(((x) & 0x3fff) << 0)
+
+/* m2m-scaler source c-position */
+#define MSCL_SRC_C_POS				0x28
+#define MSCL_SRC_CH_POS_MASK			(0xffff << (16 + 2))
+#define MSCL_SRC_CH_POS(x)			(((x) & 0xffff) << (16 + 2))
+#define MSCL_SRC_CV_POS_MASK			(0xffff << (0 + 2))
+#define MSCL_SRC_CV_POS(x)			(((x) & 0xffff) << (0 + 2))
+
+/* m2m-scaler destination format configuration */
+#define MSCL_DST_CFG				0x30
+#define MSCL_DST_BYTE_SWAP_MASK			(0x3 << 5)
+#define MSCL_DST_BYTE_SWAP(x)			(((x) & 0x3) << 5)
+#define MSCL_DST_COLOR_FORMAT_MASK		(0xf << 0)
+#define MSCL_DST_COLOR_FORMAT(x)		(((x) & 0xf) << 0)
+
+/* m2m-scaler destination y-base */
+#define MSCL_DST_Y_BASE				0x34
+
+/* m2m-scaler destination cb-base */
+#define MSCL_DST_CB_BASE			0x38
+
+/* m2m-scaler destination cr-base */
+#define MSCL_DST_CR_BASE			0x298
+
+/* m2m-scaler destination span */
+#define MSCL_DST_SPAN				0x3c
+#define MSCL_DST_C_SPAN_MASK			(0x3fff << 16)
+#define MSCL_DST_C_SPAN(x)			(((x) & 0x3fff) << 16)
+#define MSCL_DST_Y_SPAN_MASK			(0x3fff << 0)
+#define MSCL_DST_Y_SPAN(x)			(((x) & 0x3fff) << 0)
+
+/* m2m-scaler destination width/height */
+#define MSCL_DST_WH				0x40
+#define MSCL_DST_WIDTH_MASK			(0x3fff << 16)
+#define MSCL_DST_WIDTH(x)			(((x) & 0x3fff) << 16)
+#define MSCL_DST_HEIGHT_MASK			(0x3fff << 0)
+#define MSCL_DST_HEIGHT(x)			(((x) & 0x3fff) << 0)
+
+/* m2m-scaler destination position */
+#define MSCL_DST_POS				0x44
+#define MSCL_DST_H_POS_MASK			(0x3fff << 16)
+#define MSCL_DST_H_POS(x)			(((x) & 0x3fff) << 16)
+#define MSCL_DST_V_POS_MASK			(0x3fff << 0)
+#define MSCL_DST_V_POS(x)			(((x) & 0x3fff) << 0)
+
+/* m2m-scaler horizontal scale ratio */
+#define MSCL_H_RATIO				0x50
+#define MSCL_H_RATIO_VALUE(x)			(((x) & 0x7ffff) << 0)
+
+/* m2m-scaler vertical scale ratio */
+#define MSCL_V_RATIO				0x54
+#define MSCL_V_RATIO_VALUE(x)			(((x) & 0x7ffff) << 0)
+
+/* m2m-scaler rotation config */
+#define MSCL_ROT_CFG				0x58
+#define MSCL_FLIP_X_EN				(1 << 3)
+#define MSCL_FLIP_Y_EN				(1 << 2)
+#define MSCL_ROTMODE_MASK			(0x3 << 0)
+#define MSCL_ROTMODE(x)				(((x) & 0x3) << 0)
+
+/* m2m-scaler csc coefficients */
+#define MSCL_CSC_COEF_00			0x220
+#define MSCL_CSC_COEF_10			0x224
+#define MSCL_CSC_COEF_20			0x228
+#define MSCL_CSC_COEF_01			0x22C
+#define MSCL_CSC_COEF_11			0x230
+#define MSCL_CSC_COEF_21			0x234
+#define MSCL_CSC_COEF_02			0x238
+#define MSCL_CSC_COEF_12			0x23C
+#define MSCL_CSC_COEF_22			0x240
+
+#define MSCL_CSC_COEF(x, y)			(0x220 + ((x * 12) + (y * 4)))
+
+/* m2m-scaler dither config */
+#define MSCL_DITH_CFG				0x250
+#define MSCL_DITHER_R_TYPE_MASK			(0x7 << 6)
+#define MSCL_DITHER_R_TYPE(x)			(((x) & 0x7) << 6)
+#define MSCL_DITHER_G_TYPE_MASK			(0x7 << 3)
+#define MSCL_DITHER_G_TYPE(x)			(((x) & 0x7) << 3)
+#define MSCL_DITHER_B_TYPE_MASK			(0x7 << 0)
+#define MSCL_DITHER_B_TYPE(x)			(((x) & 0x7) << 0)
+
+/* m2m-scaler src blend color */
+#define MSCL_SRC_BLEND_COLOR			0x280
+#define MSCL_SRC_COLOR_SEL_INV			(1 << 31)
+#define MSCL_SRC_COLOR_SEL_MASK			(0x3 << 29)
+#define MSCL_SRC_COLOR_SEL(x)			(((x) & 0x3) << 29)
+#define MSCL_SRC_COLOR_OP_SEL_INV		(1 << 28)
+#define MSCL_SRC_COLOR_OP_SEL_MASK		(0xf << 24)
+#define MSCL_SRC_COLOR_OP_SEL(x)		(((x) & 0xf) << 24)
+#define MSCL_SRC_GLOBAL_COLOR0_MASK		(0xff << 16)
+#define MSCL_SRC_GLOBAL_COLOR0(x)		(((x) & 0xff) << 16)
+#define MSCL_SRC_GLOBAL_COLOR1_MASK		(0xff << 8)
+#define MSCL_SRC_GLOBAL_COLOR1(x)		(((x) & 0xff) << 8)
+#define MSCL_SRC_GLOBAL_COLOR2_MASK		(0xff << 0)
+#define MSCL_SRC_GLOBAL_COLOR2(x)		(((x) & 0xff) << 0)
+
+/* m2m-scaler src blend alpha */
+#define MSCL_SRC_BLEND_ALPHA			0x284
+#define MSCL_SRC_ALPHA_SEL_INV			(1 << 31)
+#define MSCL_SRC_ALPHA_SEL_MASK			(0x3 << 29)
+#define MSCL_SRC_ALPHA_SEL(x)			(((x) & 0x3) << 29)
+#define MSCL_SRC_ALPHA_OP_SEL_INV		(1 << 28)
+#define MSCL_SRC_ALPHA_OP_SEL_MASK		(0xf << 24)
+#define MSCL_SRC_ALPHA_OP_SEL(x)		(((x) & 0xf) << 24)
+#define MSCL_SRC_GLOBAL_ALPHA_MASK		(0xff << 0)
+#define MSCL_SRC_GLOBAL_ALPHA(x)		(((x) & 0xff) << 0)
+
+/* m2m-scaler dst blend color */
+#define MSCL_DST_BLEND_COLOR			0x288
+#define MSCL_DST_COLOR_SEL_INV			(1 << 31)
+#define MSCL_DST_COLOR_SEL_MASK			(0x3 << 29)
+#define MSCL_DST_COLOR_SEL(x)			(((x) & 0x3) << 29)
+#define MSCL_DST_COLOR_OP_SEL_INV		(1 << 28)
+#define MSCL_DST_COLOR_OP_SEL_MASK		(0xf << 24)
+#define MSCL_DST_COLOR_OP_SEL(x)		(((x) & 0xf) << 24)
+#define MSCL_DST_GLOBAL_COLOR0_MASK		(0xff << 16)
+#define MSCL_DST_GLOBAL_COLOR0(x)		(((x) & 0xff) << 16)
+#define MSCL_DST_GLOBAL_COLOR1_MASK		(0xff << 8)
+#define MSCL_DST_GLOBAL_COLOR1(x)		(((x) & 0xff) << 8)
+#define MSCL_DST_GLOBAL_COLOR2_MASK		(0xff << 0)
+#define MSCL_DST_GLOBAL_COLOR2(x)		(((x) & 0xff) << 0)
+
+/* m2m-scaler dst blend alpha */
+#define MSCL_DST_BLEND_ALPHA			0x28C
+#define MSCL_DST_ALPHA_SEL_INV			(1 << 31)
+#define MSCL_DST_ALPHA_SEL_MASK			(0x3 << 29)
+#define MSCL_DST_ALPHA_SEL(x)			(((x) & 0x3) << 29)
+#define MSCL_DST_ALPHA_OP_SEL_INV		(1 << 28)
+#define MSCL_DST_ALPHA_OP_SEL_MASK		(0xf << 24)
+#define MSCL_DST_ALPHA_OP_SEL(x)		(((x) & 0xf) << 24)
+#define MSCL_DST_GLOBAL_ALPHA_MASK		(0xff << 0)
+#define MSCL_DST_GLOBAL_ALPHA(x)		(((x) & 0xff) << 0)
+
+/* m2m-scaler fill color */
+#define MSCL_FILL_COLOR				0x290
+#define MSCL_FILL_ALPHA_MASK			(0xff << 24)
+#define MSCL_FILL_ALPHA(x)			(((x) & 0xff) << 24)
+#define MSCL_FILL_COLOR0_MASK			(0xff << 16)
+#define MSCL_FILL_COLOR0(x)			(((x) & 0xff) << 16)
+#define MSCL_FILL_COLOR1_MASK			(0xff << 8)
+#define MSCL_FILL_COLOR1(x)			(((x) & 0xff) << 8)
+#define MSCL_FILL_COLOR2_MASK			(0xff << 0)
+#define MSCL_FILL_COLOR2(x)			(((x) & 0xff) << 0)
+
+/* m2m-scaler address queue config */
+#define MSCL_ADDR_QUEUE_CONFIG			0x2a0
+#define MSCL_ADDR_QUEUE_RST			(1 << 0)
+
+/* arbitrary r/w register and reg-value to check soft reset is success */
+#define MSCL_CFG_SOFT_RESET_CHECK_REG		MSCL_SRC_CFG
+#define MSCL_CFG_SOFT_RESET_CHECK_VAL		0x3
+
+#endif /* REGS_MSCL_H_ */
-- 
1.7.9.5

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




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