[PATCH v2 1/3] staging: xm2mvscale: Driver support for Xilinx M2M Video Scaler

Rohit Athavale rohit.athavale at xilinx.com
Wed Feb 21 22:43:14 UTC 2018


This commit adds driver support for the pre-release Xilinx M2M Video
Scaler IP. There are three parts to this driver :

 - The Hardware/IP layer that reads and writes register of the IP
   contained in the scaler_hw_xm2m.c
 - The set of ioctls that applications would need to know contained
   in ioctl_xm2mvsc.h
 - The char driver that consumes the IP layer in xm2m_vscale.c

Signed-off-by: Rohit Athavale <rohit.athavale at xilinx.com>
---
 drivers/staging/Kconfig                       |   2 +
 drivers/staging/Makefile                      |   1 +
 drivers/staging/xm2mvscale/Kconfig            |  11 +
 drivers/staging/xm2mvscale/Makefile           |   3 +
 drivers/staging/xm2mvscale/ioctl_xm2mvsc.h    | 134 ++++
 drivers/staging/xm2mvscale/scaler_hw_xm2m.c   | 945 ++++++++++++++++++++++++++
 drivers/staging/xm2mvscale/scaler_hw_xm2m.h   | 152 +++++
 drivers/staging/xm2mvscale/xm2m_vscale.c      | 768 +++++++++++++++++++++
 drivers/staging/xm2mvscale/xvm2mvsc_hw_regs.h | 204 ++++++
 9 files changed, 2220 insertions(+)
 create mode 100644 drivers/staging/xm2mvscale/Kconfig
 create mode 100644 drivers/staging/xm2mvscale/Makefile
 create mode 100644 drivers/staging/xm2mvscale/ioctl_xm2mvsc.h
 create mode 100644 drivers/staging/xm2mvscale/scaler_hw_xm2m.c
 create mode 100644 drivers/staging/xm2mvscale/scaler_hw_xm2m.h
 create mode 100644 drivers/staging/xm2mvscale/xm2m_vscale.c
 create mode 100644 drivers/staging/xm2mvscale/xvm2mvsc_hw_regs.h

diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index e95ab68..3ee3a3e 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -122,4 +122,6 @@ source "drivers/staging/vboxvideo/Kconfig"
 
 source "drivers/staging/pi433/Kconfig"
 
+source "drivers/staging/xm2mvscale/Kconfig"
+
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index af8cd6a..29ce417 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -52,3 +52,4 @@ obj-$(CONFIG_BCM2835_VCHIQ)	+= vc04_services/
 obj-$(CONFIG_CRYPTO_DEV_CCREE)	+= ccree/
 obj-$(CONFIG_DRM_VBOXVIDEO)	+= vboxvideo/
 obj-$(CONFIG_PI433)		+= pi433/
+obj-$(CONFIG_XILINX_M2M_VSC)	+= xm2mvscale/
diff --git a/drivers/staging/xm2mvscale/Kconfig b/drivers/staging/xm2mvscale/Kconfig
new file mode 100644
index 0000000..949a8e4
--- /dev/null
+++ b/drivers/staging/xm2mvscale/Kconfig
@@ -0,0 +1,11 @@
+config XILINX_M2M_VSC
+	tristate "Xilinx M2M Video Scaler"
+	depends on ARCH_ZYNQMP && OF
+	---help---
+	  This driver is developed for Xilinx M2M Video Scaler IP,
+	  designed to allow passage of frame buffers from the source
+	  kernel sub-system, apply video scaling and forward to the
+	  sink kernel sub-system.
+
+	  To compile this driver as a module, choose M here.
+	  If unsure, choose N.
diff --git a/drivers/staging/xm2mvscale/Makefile b/drivers/staging/xm2mvscale/Makefile
new file mode 100644
index 0000000..ec777e1
--- /dev/null
+++ b/drivers/staging/xm2mvscale/Makefile
@@ -0,0 +1,3 @@
+xm2m_vscale_drv-y := scaler_hw_xm2m.o
+xm2m_vscale_drv-y += xm2m_vscale.o
+obj-$(CONFIG_XILINX_M2M_VSC) += xm2m_vscale_drv.o
diff --git a/drivers/staging/xm2mvscale/ioctl_xm2mvsc.h b/drivers/staging/xm2mvscale/ioctl_xm2mvsc.h
new file mode 100644
index 0000000..03bd7ab
--- /dev/null
+++ b/drivers/staging/xm2mvscale/ioctl_xm2mvsc.h
@@ -0,0 +1,134 @@
+/*
+ * Xilinx Memory-to-Memory Video Scaler IP
+ *
+ * Copyright (C) 2018 Xilinx, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+ */
+#ifndef __IOCTL_XM2MVSC_H__
+#define __IOCTL_XM2MVSC_H__
+
+/* Xilinx Video Specific Color/Pixel Formats */
+enum xm2mvsc_pix_fmt {
+	XILINX_FRMBUF_FMT_RGBX8 = 10,
+	XILINX_FRMBUF_FMT_YUVX8,
+	XILINX_FRMBUF_FMT_YUYV8,
+	XILINX_FRMBUF_FMT_RGBA8,
+	XILINX_FRMBUF_FMT_YUVA8,
+	XILINX_FRMBUF_FMT_RGBX10,
+	XILINX_FRMBUF_FMT_YUVX10,
+	/* RGB565 takes the value of 17 */
+	XILINX_FRMBUF_FMT_Y_UV8 = 18,
+	XILINX_FRMBUF_FMT_Y_UV8_420,
+	XILINX_FRMBUF_FMT_RGB8,
+	XILINX_FRMBUF_FMT_YUV8,
+	XILINX_FRMBUF_FMT_Y_UV10,
+	XILINX_FRMBUF_FMT_Y_UV10_420,
+	XILINX_FRMBUF_FMT_Y8,
+	XILINX_FRMBUF_FMT_Y10,
+	XILINX_FRMBUF_FMT_BGRA8,
+	XILINX_FRMBUF_FMT_BGRX8,
+	XILINX_FRMBUF_FMT_UYVY8,
+	XILINX_FRMBUF_FMT_BGR8,
+};
+
+/* struct xm2mvsc_qdata - Struct to enqueue a descriptor
+ * @srcbuf_ht: Height of source buffer
+ * @srcbuf_wt: Width of source buffer
+ * @srcbuf_bpp: Bytes per pixel of source buffer
+ * @srcbuf_cft: Color/Pixel format of source buffer
+ * @srcbuf_size: Size of the source buffer requested
+ * @srcbuf_mmap: Identify if srcbuf is mmap'ed
+ * @srcbuf_stride: Stride of the source buffer
+ * @dstbuf_ht: Height of destination buffer
+ * @dstbuf_wt: Width of destination buffer
+ * @dstbuf_bpp: Bytes per pixel of destination buffer
+ * @dstbuf_cft: Color/Pixel format of source buffer
+ * @dstbuf_size: Size of the source buffer requested
+ * @dstbuf_mmap: Identify if srcbuf is mmap'ed
+ * @dstbuf_stride: Stride of the source buffer
+ * @dstbuf_cft: Color Format of destination buffer
+ * @desc_id: Keep a track of the descriptors
+ */
+struct xm2mvsc_qdata {
+	/* Source information */
+	u32 srcbuf_ht;
+	u32 srcbuf_wt;
+	u32 srcbuf_bpp;
+	enum xm2mvsc_pix_fmt srcbuf_cft;
+	size_t srcbuf_size;
+	/* srcbuf_mmap : For use by the library, do not touch */
+	bool srcbuf_mmap;
+	u16 srcbuf_stride;
+	/* Destination information */
+	u32 dstbuf_ht;
+	u32 dstbuf_wt;
+	u32 dstbuf_bpp;
+	enum xm2mvsc_pix_fmt dstbuf_cft;
+	size_t dstbuf_size;
+	/* dstbuf_mmap : For use by the library, do not touch */
+	bool dstbuf_mmap;
+	u16 dstbuf_stride;
+	u32 desc_id;
+};
+
+/**
+ * struct xm2mvsc_dqdata - Struct to dequeue a completed descriptor
+ * @desc_id: Descriptor ID that needs to be dequeued
+ */
+struct xm2mvsc_dqdata {
+	u32 desc_id;
+};
+
+/**
+ * struct xm2mvsc_batch - Struct to specify the batch size
+ * @batch_size: Number of channels the scaler should operate per scaling op
+ */
+struct xm2mvsc_batch {
+	u16 batch_size;
+};
+
+/* XM2MVSCALE IOCTL LIST */
+#define XM2MVSC_MAGIC		'X'
+
+/*
+ * DOC: XM2MVSC_ENQUEUE
+ * Enqueue  a descriptor that describes the scaling operation for a channel.
+ * Returns the descriptor ID
+ */
+#define XM2MVSC_ENQUEUE		_IOWR(XM2MVSC_MAGIC, 1, struct xm2mvsc_qdata *)
+
+/*
+ * DOC: XM2MVSC_START
+ * Start the M2M Scaler IP. Driver will operate on descriptors in the
+ * pending list.
+ */
+#define XM2MVSC_START		_IO(XM2MVSC_MAGIC, 2)
+
+/*
+ * DOC: XM2MVSC_DEQUEUE
+ * Dequeue a descriptor by providing the driver with information about the
+ * descriptor that needs to be dequeued.
+ */
+#define XM2MVSC_DEQUEUE		_IOW(XM2MVSC_MAGIC, 3, struct xm2mvsc_dqdata *)
+
+/*
+ * DOC: XM2MVSC_STOP
+ * Stop the M2M Scaler IP. Clear driver state and reset the IP.
+ */
+#define XM2MVSC_STOP		_IO(XM2MVSC_MAGIC, 4)
+
+/*
+ * DOC: XM2MVSC_FREE
+ * Free a descriptor after being dequeued via XM2MVSC_DEQUEUE ioctl.
+ */
+#define XM2MVSC_FREE		_IOW(XM2MVSC_MAGIC, 5, struct xm2mvsc_dqdata *)
+
+/*
+ * DOC: XM2MVSC_BATCH_SIZE
+ * Set the batch size that the M2M Scaler IP should use when programming the
+ * scaler. Driver may reject the incoming batch size.
+ */
+#define XM2MVSC_BATCH_SIZE	_IOW(XM2MVSC_MAGIC, 6, struct xm2mvsc_batch *)
+
+#endif /* __IOCTL_XM2MVSC_H__ */
diff --git a/drivers/staging/xm2mvscale/scaler_hw_xm2m.c b/drivers/staging/xm2mvscale/scaler_hw_xm2m.c
new file mode 100644
index 0000000..a6e35ae
--- /dev/null
+++ b/drivers/staging/xm2mvscale/scaler_hw_xm2m.c
@@ -0,0 +1,945 @@
+/*
+ * Xilinx Memory-to-Memory Video Scaler IP
+ *
+ * Copyright (C) 2018 Xilinx, Inc. All rights reserved.
+ *
+ * Description:
+ * This driver is developed for the Xilinx M2M Video Scaler IP. It allows
+ * userspace to access the IP registers and takes care of interrupt handling
+ * and framebuffer programming within the driver.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <linux/bitops.h>
+
+#include "xvm2mvsc_hw_regs.h"
+#include "scaler_hw_xm2m.h"
+
+/* H-scaler coefficients for 6, 8, 10 and 12 tap filters */
+static const u16
+xhsc_coeff_taps6[XSCALER_MAX_PHASES][XV_SCALER_TAPS_6] = {
+	{  -132,   236,  3824,   236,  -132,    64, },
+	{  -116,   184,  3816,   292,  -144,    64, },
+	{  -100,   132,  3812,   348,  -160,    64, },
+	{   -88,    84,  3808,   404,  -176,    64, },
+	{   -72,    36,  3796,   464,  -192,    64, },
+	{   -60,    -8,  3780,   524,  -208,    68, },
+	{   -48,   -52,  3768,   588,  -228,    68, },
+	{   -32,   -96,  3748,   652,  -244,    68, },
+	{   -20,  -136,  3724,   716,  -260,    72, },
+	{    -8,  -172,  3696,   784,  -276,    72, },
+	{     0,  -208,  3676,   848,  -292,    72, },
+	{    12,  -244,  3640,   920,  -308,    76, },
+	{    20,  -276,  3612,   988,  -324,    76, },
+	{    32,  -304,  3568,  1060,  -340,    80, },
+	{    40,  -332,  3532,  1132,  -356,    80, },
+	{    48,  -360,  3492,  1204,  -372,    84, },
+	{    56,  -384,  3448,  1276,  -388,    88, },
+	{    64,  -408,  3404,  1352,  -404,    88, },
+	{    72,  -428,  3348,  1428,  -416,    92, },
+	{    76,  -448,  3308,  1500,  -432,    92, },
+	{    84,  -464,  3248,  1576,  -444,    96, },
+	{    88,  -480,  3200,  1652,  -460,    96, },
+	{    92,  -492,  3140,  1728,  -472,   100, },
+	{    96,  -504,  3080,  1804,  -484,   104, },
+	{   100,  -516,  3020,  1880,  -492,   104, },
+	{   104,  -524,  2956,  1960,  -504,   104, },
+	{   104,  -532,  2892,  2036,  -512,   108, },
+	{   108,  -540,  2832,  2108,  -520,   108, },
+	{   108,  -544,  2764,  2184,  -528,   112, },
+	{   112,  -544,  2688,  2260,  -532,   112, },
+	{   112,  -548,  2624,  2336,  -540,   112, },
+	{   112,  -548,  2556,  2408,  -544,   112, },
+	{   112,  -544,  2480,  2480,  -544,   112, },
+	{   112,  -544,  2408,  2556,  -548,   112, },
+	{   112,  -540,  2336,  2624,  -548,   112, },
+	{   112,  -532,  2260,  2688,  -544,   112, },
+	{   112,  -528,  2184,  2764,  -544,   108, },
+	{   108,  -520,  2108,  2832,  -540,   108, },
+	{   108,  -512,  2036,  2892,  -532,   104, },
+	{   104,  -504,  1960,  2956,  -524,   104, },
+	{   104,  -492,  1880,  3020,  -516,   100, },
+	{   104,  -484,  1804,  3080,  -504,    96, },
+	{   100,  -472,  1728,  3140,  -492,    92, },
+	{    96,  -460,  1652,  3200,  -480,    88, },
+	{    96,  -444,  1576,  3248,  -464,    84, },
+	{    92,  -432,  1500,  3308,  -448,    76, },
+	{    92,  -416,  1428,  3348,  -428,    72, },
+	{    88,  -404,  1352,  3404,  -408,    64, },
+	{    88,  -388,  1276,  3448,  -384,    56, },
+	{    84,  -372,  1204,  3492,  -360,    48, },
+	{    80,  -356,  1132,  3532,  -332,    40, },
+	{    80,  -340,  1060,  3568,  -304,    32, },
+	{    76,  -324,   988,  3612,  -276,    20, },
+	{    76,  -308,   920,  3640,  -244,    12, },
+	{    72,  -292,   848,  3676,  -208,     0, },
+	{    72,  -276,   784,  3696,  -172,    -8, },
+	{    72,  -260,   716,  3724,  -136,   -20, },
+	{    68,  -244,   652,  3748,   -96,   -32, },
+	{    68,  -228,   588,  3768,   -52,   -48, },
+	{    68,  -208,   524,  3780,    -8,   -60, },
+	{    64,  -192,   464,  3796,    36,   -72, },
+	{    64,  -176,   404,  3808,    84,   -88, },
+	{    64,  -160,   348,  3812,   132,  -100, },
+	{    64,  -144,   292,  3816,   184,  -116, }
+};
+
+static const u16
+xhsc_coeff_taps8[XSCALER_MAX_PHASES][XV_SCALER_TAPS_8] = {
+	{-5, 309, 1023, 1445, 1034, 317, -3, -24, },
+	{-6, 300, 1011, 1445, 1045, 326, -1, -24, },
+	{-7, 291, 1000, 1444, 1056, 336, 0, -24, },
+	{-9, 282, 988, 1444, 1067, 345, 2, -24, },
+	{-10, 274, 977, 1443, 1078, 354, 4, -24, },
+	{-11, 266, 965, 1441, 1089, 364, 6, -24, },
+	{-12, 258, 953, 1440, 1100, 373, 8, -24, },
+	{-13, 250, 942, 1438, 1110, 383, 10, -24, },
+	{-14, 242, 930, 1437, 1121, 393, 12, -24, },
+	{-15, 234, 918, 1434, 1131, 403, 14, -24, },
+	{-16, 226, 906, 1432, 1142, 413, 17, -24, },
+	{-17, 219, 894, 1430, 1152, 423, 19, -24, },
+	{-17, 211, 882, 1427, 1162, 433, 22, -24, },
+	{-18, 204, 870, 1424, 1172, 443, 24, -24, },
+	{-19, 197, 858, 1420, 1182, 454, 27, -24, },
+	{-19, 190, 846, 1417, 1191, 464, 30, -24, },
+	{-20, 183, 834, 1413, 1201, 475, 33, -24, },
+	{-20, 176, 822, 1409, 1210, 486, 36, -24, },
+	{-21, 170, 810, 1405, 1220, 497, 39, -24, },
+	{-21, 163, 798, 1401, 1229, 507, 42, -24, },
+	{-22, 157, 786, 1396, 1238, 518, 46, -24, },
+	{-22, 151, 774, 1392, 1247, 529, 49, -24, },
+	{-22, 144, 762, 1387, 1255, 540, 53, -24, },
+	{-23, 139, 750, 1382, 1264, 552, 57, -24, },
+	{-23, 133, 738, 1376, 1272, 563, 60, -24, },
+	{-23, 127, 726, 1371, 1280, 574, 64, -24, },
+	{-23, 121, 714, 1365, 1288, 586, 69, -24, },
+	{-23, 116, 703, 1359, 1296, 597, 73, -24, },
+	{-24, 111, 691, 1353, 1304, 609, 77, -24, },
+	{-24, 105, 679, 1346, 1312, 620, 81, -24, },
+	{-24, 100, 667, 1340, 1319, 632, 86, -24, },
+	{-24, 96, 655, 1333, 1326, 644, 91, -24, },
+	{-24, 91, 644, 1326, 1333, 655, 96, -24, },
+	{-24, 86, 632, 1319, 1340, 667, 100, -24, },
+	{-24, 81, 620, 1312, 1346, 679, 105, -24, },
+	{-24, 77, 609, 1304, 1353, 691, 111, -24, },
+	{-24, 73, 597, 1296, 1359, 703, 116, -23, },
+	{-24, 69, 586, 1288, 1365, 714, 121, -23, },
+	{-24, 64, 574, 1280, 1371, 726, 127, -23, },
+	{-24, 60, 563, 1272, 1376, 738, 133, -23, },
+	{-24, 57, 552, 1264, 1382, 750, 139, -23, },
+	{-24, 53, 540, 1255, 1387, 762, 144, -22, },
+	{-24, 49, 529, 1247, 1392, 774, 151, -22, },
+	{-24, 46, 518, 1238, 1396, 786, 157, -22, },
+	{-24, 42, 507, 1229, 1401, 798, 163, -21, },
+	{-24, 39, 497, 1220, 1405, 810, 170, -21, },
+	{-24, 36, 486, 1210, 1409, 822, 176, -20, },
+	{-24, 33, 475, 1201, 1413, 834, 183, -20, },
+	{-24, 30, 464, 1191, 1417, 846, 190, -19, },
+	{-24, 27, 454, 1182, 1420, 858, 197, -19, },
+	{-24, 24, 443, 1172, 1424, 870, 204, -18, },
+	{-24, 22, 433, 1162, 1427, 882, 211, -17, },
+	{-24, 19, 423, 1152, 1430, 894, 219, -17, },
+	{-24, 17, 413, 1142, 1432, 906, 226, -16, },
+	{-24, 14, 403, 1131, 1434, 918, 234, -15, },
+	{-24, 12, 393, 1121, 1437, 930, 242, -14, },
+	{-24, 10, 383, 1110, 1438, 942, 250, -13, },
+	{-24, 8, 373, 1100, 1440, 953, 258, -12, },
+	{-24, 6, 364, 1089, 1441, 965, 266, -11, },
+	{-24, 4, 354, 1078, 1443, 977, 274, -10, },
+	{-24, 2, 345, 1067, 1444, 988, 282, -9, },
+	{-24, 0, 336, 1056, 1444, 1000, 291, -7, },
+	{-24, -1, 326, 1045, 1445, 1011, 300, -6, },
+	{-24, -3, 317, 1034, 1445, 1023, 309, -5, },
+};
+
+static const u16
+xhsc_coeff_taps10[XSCALER_MAX_PHASES][XV_SCALER_TAPS_10] = {
+	{59, 224, 507, 790, 911, 793, 512, 227, 61, 13, },
+	{58, 220, 502, 786, 911, 797, 516, 231, 62, 13, },
+	{56, 216, 497, 783, 911, 800, 521, 235, 64, 13, },
+	{55, 213, 492, 779, 910, 804, 526, 238, 65, 13, },
+	{54, 209, 487, 775, 910, 807, 531, 242, 67, 14, },
+	{52, 206, 482, 772, 910, 810, 536, 246, 69, 14, },
+	{51, 202, 477, 768, 909, 813, 541, 250, 70, 14, },
+	{50, 199, 473, 764, 909, 817, 545, 254, 72, 14, },
+	{48, 195, 468, 760, 908, 820, 550, 258, 74, 15, },
+	{47, 192, 463, 756, 908, 823, 555, 262, 76, 15, },
+	{46, 188, 458, 752, 907, 826, 560, 266, 78, 15, },
+	{45, 185, 453, 748, 906, 829, 565, 270, 79, 16, },
+	{44, 182, 448, 744, 906, 832, 569, 274, 81, 16, },
+	{42, 179, 444, 740, 905, 835, 574, 278, 83, 16, },
+	{41, 175, 439, 736, 904, 837, 579, 282, 85, 17, },
+	{40, 172, 434, 732, 903, 840, 584, 286, 87, 17, },
+	{39, 169, 429, 728, 902, 843, 589, 290, 89, 18, },
+	{38, 166, 425, 724, 901, 846, 593, 294, 91, 18, },
+	{37, 163, 420, 720, 900, 848, 598, 298, 93, 18, },
+	{36, 160, 415, 716, 899, 851, 603, 302, 95, 19, },
+	{35, 157, 410, 711, 897, 854, 608, 307, 98, 19, },
+	{34, 154, 406, 707, 896, 856, 612, 311, 100, 20, },
+	{33, 151, 401, 703, 895, 859, 617, 315, 102, 20, },
+	{33, 148, 396, 698, 893, 861, 622, 320, 104, 21, },
+	{32, 145, 392, 694, 892, 863, 626, 324, 107, 21, },
+	{31, 142, 387, 690, 890, 866, 631, 328, 109, 22, },
+	{30, 140, 382, 685, 889, 868, 636, 333, 111, 23, },
+	{29, 137, 378, 681, 887, 870, 640, 337, 114, 23, },
+	{28, 134, 373, 677, 886, 872, 645, 342, 116, 24, },
+	{28, 131, 369, 672, 884, 874, 649, 346, 119, 24, },
+	{27, 129, 364, 668, 882, 876, 654, 350, 121, 25, },
+	{26, 126, 359, 663, 880, 878, 659, 355, 124, 26, },
+	{26, 124, 355, 659, 878, 880, 663, 359, 126, 26, },
+	{25, 121, 350, 654, 876, 882, 668, 364, 129, 27, },
+	{24, 119, 346, 649, 874, 884, 672, 369, 131, 28, },
+	{24, 116, 342, 645, 872, 886, 677, 373, 134, 28, },
+	{23, 114, 337, 640, 870, 887, 681, 378, 137, 29, },
+	{23, 111, 333, 636, 868, 889, 685, 382, 140, 30, },
+	{22, 109, 328, 631, 866, 890, 690, 387, 142, 31, },
+	{21, 107, 324, 626, 863, 892, 694, 392, 145, 32, },
+	{21, 104, 320, 622, 861, 893, 698, 396, 148, 33, },
+	{20, 102, 315, 617, 859, 895, 703, 401, 151, 33, },
+	{20, 100, 311, 612, 856, 896, 707, 406, 154, 34, },
+	{19, 98, 307, 608, 854, 897, 711, 410, 157, 35, },
+	{19, 95, 302, 603, 851, 899, 716, 415, 160, 36, },
+	{18, 93, 298, 598, 848, 900, 720, 420, 163, 37, },
+	{18, 91, 294, 593, 846, 901, 724, 425, 166, 38, },
+	{18, 89, 290, 589, 843, 902, 728, 429, 169, 39, },
+	{17, 87, 286, 584, 840, 903, 732, 434, 172, 40, },
+	{17, 85, 282, 579, 837, 904, 736, 439, 175, 41, },
+	{16, 83, 278, 574, 835, 905, 740, 444, 179, 42, },
+	{16, 81, 274, 569, 832, 906, 744, 448, 182, 44, },
+	{16, 79, 270, 565, 829, 906, 748, 453, 185, 45, },
+	{15, 78, 266, 560, 826, 907, 752, 458, 188, 46, },
+	{15, 76, 262, 555, 823, 908, 756, 463, 192, 47, },
+	{15, 74, 258, 550, 820, 908, 760, 468, 195, 48, },
+	{14, 72, 254, 545, 817, 909, 764, 473, 199, 50, },
+	{14, 70, 250, 541, 813, 909, 768, 477, 202, 51, },
+	{14, 69, 246, 536, 810, 910, 772, 482, 206, 52, },
+	{14, 67, 242, 531, 807, 910, 775, 487, 209, 54, },
+	{13, 65, 238, 526, 804, 910, 779, 492, 213, 55, },
+	{13, 64, 235, 521, 800, 911, 783, 497, 216, 56, },
+	{13, 62, 231, 516, 797, 911, 786, 502, 220, 58, },
+	{13, 61, 227, 512, 793, 911, 790, 507, 224, 59, },
+};
+
+static const u16
+xhsc_coeff_taps12[XSCALER_MAX_PHASES][XV_SCALER_TAPS_12] = {
+	{48, 143, 307, 504, 667, 730, 669, 507, 310, 145, 49, 18, },
+	{47, 141, 304, 501, 665, 730, 670, 510, 313, 147, 50, 18, },
+	{46, 138, 301, 498, 663, 730, 672, 513, 316, 149, 51, 18, },
+	{45, 136, 298, 495, 661, 730, 674, 516, 319, 151, 52, 18, },
+	{44, 134, 295, 492, 659, 730, 676, 519, 322, 153, 53, 18, },
+	{44, 132, 292, 489, 657, 730, 677, 522, 325, 155, 54, 18, },
+	{43, 130, 289, 486, 655, 729, 679, 525, 328, 157, 55, 19, },
+	{42, 129, 287, 483, 653, 729, 681, 528, 331, 160, 56, 19, },
+	{41, 127, 284, 480, 651, 729, 683, 531, 334, 162, 57, 19, },
+	{40, 125, 281, 477, 648, 729, 684, 534, 337, 164, 58, 19, },
+	{40, 123, 278, 474, 646, 728, 686, 537, 340, 166, 59, 20, },
+	{39, 121, 275, 471, 644, 728, 687, 539, 343, 169, 60, 20, },
+	{38, 119, 272, 468, 642, 727, 689, 542, 346, 171, 61, 20, },
+	{37, 117, 269, 465, 640, 727, 690, 545, 349, 173, 62, 20, },
+	{37, 115, 266, 461, 638, 727, 692, 548, 353, 175, 63, 21, },
+	{36, 114, 264, 458, 635, 726, 693, 551, 356, 178, 65, 21, },
+	{35, 112, 261, 455, 633, 726, 695, 554, 359, 180, 66, 21, },
+	{35, 110, 258, 452, 631, 725, 696, 556, 362, 183, 67, 21, },
+	{34, 108, 255, 449, 628, 724, 698, 559, 365, 185, 68, 22, },
+	{33, 107, 252, 446, 626, 724, 699, 562, 368, 187, 69, 22, },
+	{33, 105, 250, 443, 624, 723, 700, 565, 371, 190, 71, 22, },
+	{32, 103, 247, 440, 621, 723, 702, 567, 374, 192, 72, 23, },
+	{32, 101, 244, 437, 619, 722, 703, 570, 377, 195, 73, 23, },
+	{31, 100, 241, 433, 617, 721, 704, 573, 380, 197, 75, 23, },
+	{31, 98, 239, 430, 614, 720, 705, 576, 383, 200, 76, 24, },
+	{30, 97, 236, 427, 612, 720, 707, 578, 387, 202, 77, 24, },
+	{29, 95, 233, 424, 609, 719, 708, 581, 390, 205, 79, 24, },
+	{29, 93, 231, 421, 607, 718, 709, 584, 393, 207, 80, 25, },
+	{28, 92, 228, 418, 604, 717, 710, 586, 396, 210, 81, 25, },
+	{28, 90, 225, 415, 602, 716, 711, 589, 399, 212, 83, 26, },
+	{27, 89, 223, 412, 599, 715, 712, 591, 402, 215, 84, 26, },
+	{27, 87, 220, 408, 597, 714, 713, 594, 405, 217, 86, 27, },
+	{27, 86, 217, 405, 594, 713, 714, 597, 408, 220, 87, 27, },
+	{26, 84, 215, 402, 591, 712, 715, 599, 412, 223, 89, 27, },
+	{26, 83, 212, 399, 589, 711, 716, 602, 415, 225, 90, 28, },
+	{25, 81, 210, 396, 586, 710, 717, 604, 418, 228, 92, 28, },
+	{25, 80, 207, 393, 584, 709, 718, 607, 421, 231, 93, 29, },
+	{24, 79, 205, 390, 581, 708, 719, 609, 424, 233, 95, 29, },
+	{24, 77, 202, 387, 578, 707, 720, 612, 427, 236, 97, 30, },
+	{24, 76, 200, 383, 576, 705, 720, 614, 430, 239, 98, 31, },
+	{23, 75, 197, 380, 573, 704, 721, 617, 433, 241, 100, 31, },
+	{23, 73, 195, 377, 570, 703, 722, 619, 437, 244, 101, 32, },
+	{23, 72, 192, 374, 567, 702, 723, 621, 440, 247, 103, 32, },
+	{22, 71, 190, 371, 565, 700, 723, 624, 443, 250, 105, 33, },
+	{22, 69, 187, 368, 562, 699, 724, 626, 446, 252, 107, 33, },
+	{22, 68, 185, 365, 559, 698, 724, 628, 449, 255, 108, 34, },
+	{21, 67, 183, 362, 556, 696, 725, 631, 452, 258, 110, 35, },
+	{21, 66, 180, 359, 554, 695, 726, 633, 455, 261, 112, 35, },
+	{21, 65, 178, 356, 551, 693, 726, 635, 458, 264, 114, 36, },
+	{21, 63, 175, 353, 548, 692, 727, 638, 461, 266, 115, 37, },
+	{20, 62, 173, 349, 545, 690, 727, 640, 465, 269, 117, 37, },
+	{20, 61, 171, 346, 542, 689, 727, 642, 468, 272, 119, 38, },
+	{20, 60, 169, 343, 539, 687, 728, 644, 471, 275, 121, 39, },
+	{20, 59, 166, 340, 537, 686, 728, 646, 474, 278, 123, 40, },
+	{19, 58, 164, 337, 534, 684, 729, 648, 477, 281, 125, 40, },
+	{19, 57, 162, 334, 531, 683, 729, 651, 480, 284, 127, 41, },
+	{19, 56, 160, 331, 528, 681, 729, 653, 483, 287, 129, 42, },
+	{19, 55, 157, 328, 525, 679, 729, 655, 486, 289, 130, 43, },
+	{18, 54, 155, 325, 522, 677, 730, 657, 489, 292, 132, 44, },
+	{18, 53, 153, 322, 519, 676, 730, 659, 492, 295, 134, 44, },
+	{18, 52, 151, 319, 516, 674, 730, 661, 495, 298, 136, 45, },
+	{18, 51, 149, 316, 513, 672, 730, 663, 498, 301, 138, 46, },
+	{18, 50, 147, 313, 510, 670, 730, 665, 501, 304, 141, 47, },
+	{18, 49, 145, 310, 507, 669, 730, 667, 504, 307, 143, 48, },
+};
+
+/* V-scaler coefficients for 6, 8, 10 and 12 tap filters */
+static const u16
+xvsc_coeff_taps6[XSCALER_MAX_PHASES][XV_SCALER_TAPS_6] = {
+	{-132, 236, 3824, 236, -132, 64, },
+	{-116, 184, 3816, 292, -144, 64, },
+	{-100, 132, 3812, 348, -160, 64, },
+	{-88, 84, 3808, 404, -176, 64, },
+	{-72, 36, 3796, 464, -192, 64, },
+	{-60, -8, 3780, 524, -208, 68, },
+	{-48, -52, 3768, 588, -228, 68, },
+	{-32, -96, 3748, 652, -244, 68, },
+	{-20, -136, 3724, 716, -260, 72, },
+	{-8,  -172, 3696, 784, -276, 72, },
+	{0, -208, 3676,  848, -292, 72, },
+	{12, -244, 3640, 920, -308, 76, },
+	{20, -276, 3612, 988, -324, 76, },
+	{32, -304, 3568, 1060, -340, 80, },
+	{40, -332, 3532, 1132, -356, 80, },
+	{48, -360, 3492, 1204, -372, 84, },
+	{56, -384, 3448, 1276, -388, 88, },
+	{64, -408, 3404, 1352, -404, 88, },
+	{72, -428, 3348, 1428, -416, 92, },
+	{76, -448, 3308, 1500, -432, 92, },
+	{84, -464, 3248, 1576, -444, 96, },
+	{88, -480, 3200, 1652, -460, 96, },
+	{92, -492, 3140, 1728, -472, 100, },
+	{96, -504, 3080, 1804, -484, 104, },
+	{100, -516, 3020, 1880, -492, 104, },
+	{104, -524, 2956, 1960, -504, 104, },
+	{104, -532, 2892, 2036, -512, 108, },
+	{108, -540, 2832, 2108, -520, 108, },
+	{108, -544, 2764, 2184, -528, 112, },
+	{112, -544, 2688, 2260, -532, 112, },
+	{112, -548, 2624, 2336, -540, 112, },
+	{112, -548, 2556, 2408, -544, 112, },
+	{112, -544, 2480, 2480, -544, 112, },
+	{112, -544, 2408, 2556, -548, 112, },
+	{112, -540, 2336, 2624, -548, 112, },
+	{112, -532, 2260, 2688, -544, 112, },
+	{112, -528, 2184, 2764, -544, 108, },
+	{108, -520, 2108, 2832, -540, 108, },
+	{108, -512, 2036, 2892, -532, 104, },
+	{104, -504, 1960, 2956, -524, 104, },
+	{104, -492, 1880, 3020, -516, 100, },
+	{104, -484, 1804, 3080, -504, 96, },
+	{100, -472, 1728, 3140, -492, 92, },
+	{ 96, -460, 1652, 3200, -480, 88, },
+	{ 96, -444, 1576, 3248, -464, 84, },
+	{ 92, -432, 1500, 3308, -448, 76, },
+	{ 92, -416, 1428, 3348, -428, 72, },
+	{ 88, -404, 1352, 3404, -408, 64, },
+	{ 88, -388, 1276, 3448, -384, 56, },
+	{ 84, -372, 1204, 3492, -360, 48, },
+	{ 80, -356, 1132, 3532, -332, 40, },
+	{ 80, -340, 1060, 3568, -304, 32, },
+	{ 76, -324, 988, 3612, -276, 20, },
+	{ 76, -308, 920, 3640, -244, 12, },
+	{ 72, -292, 848, 3676, -208, 0, },
+	{ 72, -276, 784, 3696, -172, -8, },
+	{ 72, -260, 716, 3724, -136, -20, },
+	{ 68, -244, 652, 3748, -96, -32, },
+	{ 68, -228, 588, 3768, -52, -48, },
+	{ 68, -208, 524, 3780, -8, -60, },
+	{ 64, -192, 464, 3796, 36, -72, },
+	{ 64, -176, 404, 3808, 84, -88, },
+	{ 64, -160, 348, 3812,  132, -100, },
+	{ 64, -144, 292, 3816,  184, -116, }
+};
+
+static const u16
+xvsc_coeff_taps8[XSCALER_MAX_PHASES][XV_SCALER_TAPS_8] = {
+	{-5, 309, 1023, 1445, 1034, 317, -3, -24, },
+	{-6, 300, 1011, 1445, 1045, 326, -1, -24, },
+	{-7, 291, 1000, 1444, 1056, 336, 0, -24, },
+	{-9, 282, 988, 1444, 1067, 345, 2, -24, },
+	{-10, 274, 977, 1443, 1078, 354, 4, -24, },
+	{-11, 266, 965, 1441, 1089, 364, 6, -24, },
+	{-12, 258, 953, 1440, 1100, 373, 8, -24, },
+	{-13, 250, 942, 1438, 1110, 383, 10, -24, },
+	{-14, 242, 930, 1437, 1121, 393, 12, -24, },
+	{-15, 234, 918, 1434, 1131, 403, 14, -24, },
+	{-16, 226, 906, 1432, 1142, 413, 17, -24, },
+	{-17, 219, 894, 1430, 1152, 423, 19, -24, },
+	{-17, 211, 882, 1427, 1162, 433, 22, -24, },
+	{-18, 204, 870, 1424, 1172, 443, 24, -24, },
+	{-19, 197, 858, 1420, 1182, 454, 27, -24, },
+	{-19, 190, 846, 1417, 1191, 464, 30, -24, },
+	{-20, 183, 834, 1413, 1201, 475, 33, -24, },
+	{-20, 176, 822, 1409, 1210, 486, 36, -24, },
+	{-21, 170, 810, 1405, 1220, 497, 39, -24, },
+	{-21, 163, 798, 1401, 1229, 507, 42, -24, },
+	{-22, 157, 786, 1396, 1238, 518, 46, -24, },
+	{-22, 151, 774, 1392, 1247, 529, 49, -24, },
+	{-22, 144, 762, 1387, 1255, 540, 53, -24, },
+	{-23, 139, 750, 1382, 1264, 552, 57, -24, },
+	{-23, 133, 738, 1376, 1272, 563, 60, -24, },
+	{-23, 127, 726, 1371, 1280, 574, 64, -24, },
+	{-23, 121, 714, 1365, 1288, 586, 69, -24, },
+	{-23, 116, 703, 1359, 1296, 597, 73, -24, },
+	{-24, 111, 691, 1353, 1304, 609, 77, -24, },
+	{-24, 105, 679, 1346, 1312, 620, 81, -24, },
+	{-24, 100, 667, 1340, 1319, 632, 86, -24, },
+	{-24, 96, 655, 1333, 1326, 644, 91, -24, },
+	{-24, 91, 644, 1326, 1333, 655, 96, -24, },
+	{-24, 86, 632, 1319, 1340, 667, 100, -24, },
+	{-24, 81, 620, 1312, 1346, 679, 105, -24, },
+	{-24, 77, 609, 1304, 1353, 691, 111, -24, },
+	{-24, 73, 597, 1296, 1359, 703, 116, -23, },
+	{-24, 69, 586, 1288, 1365, 714, 121, -23, },
+	{-24, 64, 574, 1280, 1371, 726, 127, -23, },
+	{-24, 60, 563, 1272, 1376, 738, 133, -23, },
+	{-24, 57, 552, 1264, 1382, 750, 139, -23, },
+	{-24, 53, 540, 1255, 1387, 762, 144, -22, },
+	{-24, 49, 529, 1247, 1392, 774, 151, -22, },
+	{-24, 46, 518, 1238, 1396, 786, 157, -22, },
+	{-24, 42, 507, 1229, 1401, 798, 163, -21, },
+	{-24, 39, 497, 1220, 1405, 810, 170, -21, },
+	{-24, 36, 486, 1210, 1409, 822, 176, -20, },
+	{-24, 33, 475, 1201, 1413, 834, 183, -20, },
+	{-24, 30, 464, 1191, 1417, 846, 190, -19, },
+	{-24, 27, 454, 1182, 1420, 858, 197, -19, },
+	{-24, 24, 443, 1172, 1424, 870, 204, -18, },
+	{-24, 22, 433, 1162, 1427, 882, 211, -17, },
+	{-24, 19, 423, 1152, 1430, 894, 219, -17, },
+	{-24, 17, 413, 1142, 1432, 906, 226, -16, },
+	{-24, 14, 403, 1131, 1434, 918, 234, -15, },
+	{-24, 12, 393, 1121, 1437, 930, 242, -14, },
+	{-24, 10, 383, 1110, 1438, 942, 250, -13, },
+	{-24, 8, 373, 1100, 1440, 953, 258, -12, },
+	{-24, 6, 364, 1089, 1441, 965, 266, -11, },
+	{-24, 4, 354, 1078, 1443, 977, 274, -10, },
+	{-24, 2, 345, 1067, 1444, 988, 282, -9, },
+	{-24, 0, 336, 1056, 1444, 1000, 291, -7, },
+	{-24, -1, 326, 1045, 1445, 1011, 300, -6, },
+	{-24, -3, 317, 1034, 1445, 1023, 309, -5, },
+};
+
+static const u16
+xvsc_coeff_taps10[XSCALER_MAX_PHASES][XV_SCALER_TAPS_10] = {
+	{59, 224, 507, 790, 911, 793, 512, 227, 61, 13, },
+	{58, 220, 502, 786, 911, 797, 516, 231, 62, 13, },
+	{56, 216, 497, 783, 911, 800, 521, 235, 64, 13, },
+	{55, 213, 492, 779, 910, 804, 526, 238, 65, 13, },
+	{54, 209, 487, 775, 910, 807, 531, 242, 67, 14, },
+	{52, 206, 482, 772, 910, 810, 536, 246, 69, 14, },
+	{51, 202, 477, 768, 909, 813, 541, 250, 70, 14, },
+	{50, 199, 473, 764, 909, 817, 545, 254, 72, 14, },
+	{48, 195, 468, 760, 908, 820, 550, 258, 74, 15, },
+	{47, 192, 463, 756, 908, 823, 555, 262, 76, 15, },
+	{46, 188, 458, 752, 907, 826, 560, 266, 78, 15, },
+	{45, 185, 453, 748, 906, 829, 565, 270, 79, 16, },
+	{44, 182, 448, 744, 906, 832, 569, 274, 81, 16, },
+	{42, 179, 444, 740, 905, 835, 574, 278, 83, 16, },
+	{41, 175, 439, 736, 904, 837, 579, 282, 85, 17, },
+	{40, 172, 434, 732, 903, 840, 584, 286, 87, 17, },
+	{39, 169, 429, 728, 902, 843, 589, 290, 89, 18, },
+	{38, 166, 425, 724, 901, 846, 593, 294, 91, 18, },
+	{37, 163, 420, 720, 900, 848, 598, 298, 93, 18, },
+	{36, 160, 415, 716, 899, 851, 603, 302, 95, 19, },
+	{35, 157, 410, 711, 897, 854, 608, 307, 98, 19, },
+	{34, 154, 406, 707, 896, 856, 612, 311, 100, 20, },
+	{33, 151, 401, 703, 895, 859, 617, 315, 102, 20, },
+	{33, 148, 396, 698, 893, 861, 622, 320, 104, 21, },
+	{32, 145, 392, 694, 892, 863, 626, 324, 107, 21, },
+	{31, 142, 387, 690, 890, 866, 631, 328, 109, 22, },
+	{30, 140, 382, 685, 889, 868, 636, 333, 111, 23, },
+	{29, 137, 378, 681, 887, 870, 640, 337, 114, 23, },
+	{28, 134, 373, 677, 886, 872, 645, 342, 116, 24, },
+	{28, 131, 369, 672, 884, 874, 649, 346, 119, 24, },
+	{27, 129, 364, 668, 882, 876, 654, 350, 121, 25, },
+	{26, 126, 359, 663, 880, 878, 659, 355, 124, 26, },
+	{26, 124, 355, 659, 878, 880, 663, 359, 126, 26, },
+	{25, 121, 350, 654, 876, 882, 668, 364, 129, 27, },
+	{24, 119, 346, 649, 874, 884, 672, 369, 131, 28, },
+	{24, 116, 342, 645, 872, 886, 677, 373, 134, 28, },
+	{23, 114, 337, 640, 870, 887, 681, 378, 137, 29, },
+	{23, 111, 333, 636, 868, 889, 685, 382, 140, 30, },
+	{22, 109, 328, 631, 866, 890, 690, 387, 142, 31, },
+	{21, 107, 324, 626, 863, 892, 694, 392, 145, 32, },
+	{21, 104, 320, 622, 861, 893, 698, 396, 148, 33, },
+	{20, 102, 315, 617, 859, 895, 703, 401, 151, 33, },
+	{20, 100, 311, 612, 856, 896, 707, 406, 154, 34, },
+	{19, 98, 307, 608, 854, 897, 711, 410, 157, 35, },
+	{19, 95, 302, 603, 851, 899, 716, 415, 160, 36, },
+	{18, 93, 298, 598, 848, 900, 720, 420, 163, 37, },
+	{18, 91, 294, 593, 846, 901, 724, 425, 166, 38, },
+	{18, 89, 290, 589, 843, 902, 728, 429, 169, 39, },
+	{17, 87, 286, 584, 840, 903, 732, 434, 172, 40, },
+	{17, 85, 282, 579, 837, 904, 736, 439, 175, 41, },
+	{16, 83, 278, 574, 835, 905, 740, 444, 179, 42, },
+	{16, 81, 274, 569, 832, 906, 744, 448, 182, 44, },
+	{16, 79, 270, 565, 829, 906, 748, 453, 185, 45, },
+	{15, 78, 266, 560, 826, 907, 752, 458, 188, 46, },
+	{15, 76, 262, 555, 823, 908, 756, 463, 192, 47, },
+	{15, 74, 258, 550, 820, 908, 760, 468, 195, 48, },
+	{14, 72, 254, 545, 817, 909, 764, 473, 199, 50, },
+	{14, 70, 250, 541, 813, 909, 768, 477, 202, 51, },
+	{14, 69, 246, 536, 810, 910, 772, 482, 206, 52, },
+	{14, 67, 242, 531, 807, 910, 775, 487, 209, 54, },
+	{13, 65, 238, 526, 804, 910, 779, 492, 213, 55, },
+	{13, 64, 235, 521, 800, 911, 783, 497, 216, 56, },
+	{13, 62, 231, 516, 797, 911, 786, 502, 220, 58, },
+	{13, 61, 227, 512, 793, 911, 790, 507, 224, 59, },
+};
+
+static const u16
+xvsc_coeff_taps12[XSCALER_MAX_PHASES][XV_SCALER_TAPS_12] = {
+	{48, 143, 307, 504, 667, 730, 669, 507, 310, 145, 49, 18, },
+	{47, 141, 304, 501, 665, 730, 670, 510, 313, 147, 50, 18, },
+	{46, 138, 301, 498, 663, 730, 672, 513, 316, 149, 51, 18, },
+	{45, 136, 298, 495, 661, 730, 674, 516, 319, 151, 52, 18, },
+	{44, 134, 295, 492, 659, 730, 676, 519, 322, 153, 53, 18, },
+	{44, 132, 292, 489, 657, 730, 677, 522, 325, 155, 54, 18, },
+	{43, 130, 289, 486, 655, 729, 679, 525, 328, 157, 55, 19, },
+	{42, 129, 287, 483, 653, 729, 681, 528, 331, 160, 56, 19, },
+	{41, 127, 284, 480, 651, 729, 683, 531, 334, 162, 57, 19, },
+	{40, 125, 281, 477, 648, 729, 684, 534, 337, 164, 58, 19, },
+	{40, 123, 278, 474, 646, 728, 686, 537, 340, 166, 59, 20, },
+	{39, 121, 275, 471, 644, 728, 687, 539, 343, 169, 60, 20, },
+	{38, 119, 272, 468, 642, 727, 689, 542, 346, 171, 61, 20, },
+	{37, 117, 269, 465, 640, 727, 690, 545, 349, 173, 62, 20, },
+	{37, 115, 266, 461, 638, 727, 692, 548, 353, 175, 63, 21, },
+	{36, 114, 264, 458, 635, 726, 693, 551, 356, 178, 65, 21, },
+	{35, 112, 261, 455, 633, 726, 695, 554, 359, 180, 66, 21, },
+	{35, 110, 258, 452, 631, 725, 696, 556, 362, 183, 67, 21, },
+	{34, 108, 255, 449, 628, 724, 698, 559, 365, 185, 68, 22, },
+	{33, 107, 252, 446, 626, 724, 699, 562, 368, 187, 69, 22, },
+	{33, 105, 250, 443, 624, 723, 700, 565, 371, 190, 71, 22, },
+	{32, 103, 247, 440, 621, 723, 702, 567, 374, 192, 72, 23, },
+	{32, 101, 244, 437, 619, 722, 703, 570, 377, 195, 73, 23, },
+	{31, 100, 241, 433, 617, 721, 704, 573, 380, 197, 75, 23, },
+	{31, 98, 239, 430, 614, 720, 705, 576, 383, 200, 76, 24, },
+	{30, 97, 236, 427, 612, 720, 707, 578, 387, 202, 77, 24, },
+	{29, 95, 233, 424, 609, 719, 708, 581, 390, 205, 79, 24, },
+	{29, 93, 231, 421, 607, 718, 709, 584, 393, 207, 80, 25, },
+	{28, 92, 228, 418, 604, 717, 710, 586, 396, 210, 81, 25, },
+	{28, 90, 225, 415, 602, 716, 711, 589, 399, 212, 83, 26, },
+	{27, 89, 223, 412, 599, 715, 712, 591, 402, 215, 84, 26, },
+	{27, 87, 220, 408, 597, 714, 713, 594, 405, 217, 86, 27, },
+	{27, 86, 217, 405, 594, 713, 714, 597, 408, 220, 87, 27, },
+	{26, 84, 215, 402, 591, 712, 715, 599, 412, 223, 89, 27, },
+	{26, 83, 212, 399, 589, 711, 716, 602, 415, 225, 90, 28, },
+	{25, 81, 210, 396, 586, 710, 717, 604, 418, 228, 92, 28, },
+	{25, 80, 207, 393, 584, 709, 718, 607, 421, 231, 93, 29, },
+	{24, 79, 205, 390, 581, 708, 719, 609, 424, 233, 95, 29, },
+	{24, 77, 202, 387, 578, 707, 720, 612, 427, 236, 97, 30, },
+	{24, 76, 200, 383, 576, 705, 720, 614, 430, 239, 98, 31, },
+	{23, 75, 197, 380, 573, 704, 721, 617, 433, 241, 100, 31, },
+	{23, 73, 195, 377, 570, 703, 722, 619, 437, 244, 101, 32, },
+	{23, 72, 192, 374, 567, 702, 723, 621, 440, 247, 103, 32, },
+	{22, 71, 190, 371, 565, 700, 723, 624, 443, 250, 105, 33, },
+	{22, 69, 187, 368, 562, 699, 724, 626, 446, 252, 107, 33, },
+	{22, 68, 185, 365, 559, 698, 724, 628, 449, 255, 108, 34, },
+	{21, 67, 183, 362, 556, 696, 725, 631, 452, 258, 110, 35, },
+	{21, 66, 180, 359, 554, 695, 726, 633, 455, 261, 112, 35, },
+	{21, 65, 178, 356, 551, 693, 726, 635, 458, 264, 114, 36, },
+	{21, 63, 175, 353, 548, 692, 727, 638, 461, 266, 115, 37, },
+	{20, 62, 173, 349, 545, 690, 727, 640, 465, 269, 117, 37, },
+	{20, 61, 171, 346, 542, 689, 727, 642, 468, 272, 119, 38, },
+	{20, 60, 169, 343, 539, 687, 728, 644, 471, 275, 121, 39, },
+	{20, 59, 166, 340, 537, 686, 728, 646, 474, 278, 123, 40, },
+	{19, 58, 164, 337, 534, 684, 729, 648, 477, 281, 125, 40, },
+	{19, 57, 162, 334, 531, 683, 729, 651, 480, 284, 127, 41, },
+	{19, 56, 160, 331, 528, 681, 729, 653, 483, 287, 129, 42, },
+	{19, 55, 157, 328, 525, 679, 729, 655, 486, 289, 130, 43, },
+	{18, 54, 155, 325, 522, 677, 730, 657, 489, 292, 132, 44, },
+	{18, 53, 153, 322, 519, 676, 730, 659, 492, 295, 134, 44, },
+	{18, 52, 151, 319, 516, 674, 730, 661, 495, 298, 136, 45, },
+	{18, 51, 149, 316, 513, 672, 730, 663, 498, 301, 138, 46, },
+	{18, 50, 147, 313, 510, 670, 730, 665, 501, 304, 141, 47, },
+	{18, 49, 145, 310, 507, 669, 730, 667, 504, 307, 143, 48, },
+};
+
+/* Mask definitions for Low and high 16 bits in a 32 bit number */
+#define XHSC_MASK_LOW_16BITS		GENMASK(15, 0)
+#define XHSC_MASK_HIGH_16BITS		GENMASK(31, 16)
+#define XHSC_MASK_LOW_32BITS		GENMASK(31, 0)
+
+static void
+xv_hscaler_load_ext_coeff(struct xm2m_scaler_hw *xscaler,
+			  const short *coeff, u32 ntaps)
+{
+	unsigned int i, j, pad, offset;
+	const u32 nphases = XSCALER_MAX_PHASES;
+
+	/* Determine if coefficient needs padding (effective vs. max taps) */
+	pad = XV_SCALER_MAX_TAPS - ntaps;
+	offset = pad >> 1;
+
+	memset(xscaler->hscaler_coeff, 0, sizeof(xscaler->hscaler_coeff));
+
+	/* Load coefficients into scaler coefficient table */
+	for (i = 0; i < nphases; i++) {
+		for (j = 0; j < ntaps; ++j)
+			xscaler->hscaler_coeff[i][j + offset] =
+						coeff[i * ntaps + j];
+	}
+}
+
+#define XSCALER_BITSHIFT_16		(16)
+static void xv_hscaler_set_coeff(struct xm2m_scaler_hw *xscaler,
+				 const u32 base_addr)
+{
+	int val, i, j, offset, rd_indx;
+	u32 ntaps = xscaler->num_taps;
+	const u32 nphases = XSCALER_MAX_PHASES;
+
+	offset = (XV_SCALER_MAX_TAPS - ntaps) / 2;
+	for (i = 0; i < nphases; i++) {
+		for (j = 0; j < ntaps / 2; j++) {
+			rd_indx = j * 2 + offset;
+			val = (xscaler->hscaler_coeff[i][rd_indx + 1] <<
+			       XSCALER_BITSHIFT_16) |
+			       (xscaler->hscaler_coeff[i][rd_indx] &
+			       XHSC_MASK_LOW_16BITS);
+			 xvip_write(xscaler, base_addr +
+				    ((i * ntaps / 2 + j) * 4), val);
+		}
+	}
+}
+
+static void
+xv_vscaler_load_ext_coeff(struct xm2m_scaler_hw *xscaler,
+			  const short *coeff, const u32 ntaps)
+{
+	int i, j, pad, offset;
+	const u32 nphases = XSCALER_MAX_PHASES;
+
+	/* Determine if coefficient needs padding (effective vs. max taps) */
+	pad = XV_SCALER_MAX_TAPS - ntaps;
+	offset = pad ? (pad >> 1) : 0;
+
+	/* Zero Entire Array */
+	memset(xscaler->vscaler_coeff, 0, sizeof(xscaler->vscaler_coeff));
+
+	/* Load User defined coefficients into scaler coefficient table */
+	for (i = 0; i < nphases; i++) {
+		for (j = 0; j < ntaps; ++j)
+			xscaler->vscaler_coeff[i][j + offset] =
+						coeff[i * ntaps + j];
+	}
+}
+
+#define XVSC_MASK_LOW_16BITS            GENMASK(15, 0)
+static void xv_vscaler_set_coeff(struct xm2m_scaler_hw *xscaler,
+				 const u32 base_addr)
+{
+	int val, i, j, offset, rd_indx;
+	u32 ntaps   = xscaler->num_taps;
+	const u32 nphases = XSCALER_MAX_PHASES;
+
+	offset = (XV_SCALER_MAX_TAPS - ntaps) / 2;
+
+	for (i = 0; i < nphases; i++) {
+		for (j = 0; j < ntaps / 2; j++) {
+			rd_indx = j * 2 + offset;
+			val = (xscaler->vscaler_coeff[i][rd_indx + 1] <<
+			       XSCALER_BITSHIFT_16) |
+			       (xscaler->vscaler_coeff[i][rd_indx] &
+			       XVSC_MASK_LOW_16BITS);
+			xvip_write(xscaler,
+				   base_addr + ((i * ntaps / 2 + j) * 4), val);
+		}
+	}
+}
+
+void xm2mvsc_initialize_coeff_banks(struct xm2m_scaler_hw *hw)
+{
+	/* Bank 0 is init as 6 tap filter for 6, 8, 10 & 12 tap filters */
+	 xv_hscaler_load_ext_coeff(hw, &xhsc_coeff_taps6[0][0],
+				   XV_SCALER_TAPS_6);
+	 xv_hscaler_set_coeff(hw, XM2MVSC_HFLTCOEFF(0));
+	 xv_vscaler_load_ext_coeff(hw, &xvsc_coeff_taps6[0][0],
+				   XV_SCALER_TAPS_6);
+	 xv_vscaler_set_coeff(hw, XM2MVSC_VFLTCOEFF(0));
+	 dev_dbg(hw->dev, "%s: Init Bank 0", __func__);
+	/* Bank 1 is init as 8 tap filter for 8, 10 & 12 tap filters */
+	if (hw->num_taps == XV_SCALER_TAPS_8 ||
+	    hw->num_taps == XV_SCALER_TAPS_10 ||
+	    hw->num_taps == XV_SCALER_TAPS_12) {
+		xv_hscaler_load_ext_coeff(hw, &xhsc_coeff_taps8[0][0],
+					  XV_SCALER_TAPS_8);
+		xv_hscaler_set_coeff(hw, XM2MVSC_HFLTCOEFF(1));
+		xv_vscaler_load_ext_coeff(hw, &xvsc_coeff_taps8[0][0],
+					  XV_SCALER_TAPS_8);
+		xv_vscaler_set_coeff(hw, XM2MVSC_VFLTCOEFF(1));
+		dev_dbg(hw->dev, "%s: Init Bank 1", __func__);
+	}
+	/* Bank 2 is init as 8 tap filter for 10 & 12 tap filters */
+	if (hw->num_taps == XV_SCALER_TAPS_10 ||
+	    hw->num_taps == XV_SCALER_TAPS_12) {
+		xv_hscaler_load_ext_coeff(hw, &xhsc_coeff_taps10[0][0],
+					  XV_SCALER_TAPS_10);
+		xv_hscaler_set_coeff(hw, XM2MVSC_HFLTCOEFF(2));
+		xv_vscaler_load_ext_coeff(hw, &xvsc_coeff_taps10[0][0],
+					  XV_SCALER_TAPS_10);
+		xv_vscaler_set_coeff(hw, XM2MVSC_VFLTCOEFF(2));
+		dev_dbg(hw->dev, "%s: Init Bank 2", __func__);
+	}
+	/* Bank 3 is init as 8 tap filter for 12 tap filters */
+	if (hw->num_taps == XV_SCALER_TAPS_12) {
+		xv_hscaler_load_ext_coeff(hw, &xhsc_coeff_taps12[0][0],
+					  XV_SCALER_TAPS_12);
+		xv_hscaler_set_coeff(hw, XM2MVSC_HFLTCOEFF(3));
+		xv_vscaler_load_ext_coeff(hw, &xvsc_coeff_taps12[0][0],
+					  XV_SCALER_TAPS_12);
+		xv_vscaler_set_coeff(hw, XM2MVSC_VFLTCOEFF(3));
+		dev_dbg(hw->dev, "%s: Init Bank 2", __func__);
+	}
+}
+
+/**
+ * xm2mvsc_select_coeff_bank - Selection of Scaler coefficients of operation
+ * @xscaler: Scaler device information
+ * @width_in: Width of input video
+ * @width_out: Width of desired output video
+ * @height_in : Height of the input video
+ * @height_out : Height of the output video
+ * @filter_bank : Filter bank to be set by the function
+ *
+ * There are instances when a N-tap filter might operate in an M-tap
+ * configuration where N > M.
+ *
+ * For example :
+ * Depending on the ratio of scaling (while downscaling), a 12-tap
+ * filter may operate with 10 tap coefficients and zero-pads the remaining
+ * coefficients.
+ *
+ * While upscaling the driver will program 6-tap filter coefficients
+ * in any N-tap configurations (for N >= 6).
+ *
+ * This selection is adopted by the as it gives optimal
+ * video output determined by repeated testing of the IP
+ *
+ * Return: Will return 0 if successful. Returns -EINVAL on an unsupported
+ * H-scaler number of taps.
+ */
+static void xm2mvsc_select_coeff_bank(struct xm2m_scaler_hw *xscaler,
+				      const u32 width_in,
+				      const u32 width_out,
+				      const u32 height_in,
+				      const u32 height_out,
+				      u8 *filter_bank)
+{
+	u16 hscale_ratio;
+	u16 vscale_ratio;
+	u16 selection_ratio;
+
+	hscale_ratio = (width_in * 10) / width_out;
+	vscale_ratio = (height_in * 10) / height_out;
+	selection_ratio = (hscale_ratio > vscale_ratio ?
+			   hscale_ratio : vscale_ratio);
+	/*
+	 * Scale Down Mode will use dynamic filter selection logic
+	 * Scale Up Mode (including 1:1) will always use 6 tap filter
+	 */
+	if (selection_ratio > 10) {
+		switch (xscaler->num_taps) {
+		case XV_SCALER_TAPS_6:
+			*filter_bank = FILTER_BANK_TAPS_6;
+			break;
+		case XV_SCALER_TAPS_8:
+			if (selection_ratio > 15)
+				*filter_bank = FILTER_BANK_TAPS_8;
+			else
+				*filter_bank = FILTER_BANK_TAPS_6;
+			break;
+		case XV_SCALER_TAPS_10:
+			if (selection_ratio > 25)
+				*filter_bank = FILTER_BANK_TAPS_10;
+			else if (selection_ratio > 15)
+				*filter_bank = FILTER_BANK_TAPS_8;
+			else
+				*filter_bank = FILTER_BANK_TAPS_6;
+			break;
+		case XV_SCALER_TAPS_12:
+			if (selection_ratio > 35)
+				*filter_bank = FILTER_BANK_TAPS_12;
+			else if (selection_ratio > 25)
+				*filter_bank = FILTER_BANK_TAPS_10;
+			else if (selection_ratio > 15)
+				*filter_bank = FILTER_BANK_TAPS_8;
+			else
+				*filter_bank = FILTER_BANK_TAPS_6;
+			break;
+		default:
+			/* Should never get here */
+			WARN(1, "Impossible scaler tap selection");
+			return;
+		}
+	} else {
+		*filter_bank = FILTER_BANK_TAPS_6;
+	}
+}
+
+static void xm2mvsc_set_color_format(struct xm2m_vscale_desc *desc)
+{
+	xvip_write(&desc->xm2mvsc_dev->hw,
+		   XM2MVSC_PIXELFMT_IN(desc->channel_offset),
+		   desc->data.srcbuf_cft);
+	xvip_write(&desc->xm2mvsc_dev->hw,
+		   XM2MVSC_PIXELFMT_OUT(desc->channel_offset),
+		   desc->data.dstbuf_cft);
+}
+
+#define STEP_PRECISION	(65536)
+static void xm2mvsc_program_scaler(struct xm2m_vscale_desc *desc)
+{
+	desc->line_rate =
+	    (desc->data.srcbuf_ht * STEP_PRECISION) / desc->data.dstbuf_ht;
+	xvip_write(&desc->xm2mvsc_dev->hw,
+		   XM2MVSC_LINERATE(desc->channel_offset),
+		   desc->line_rate);
+	desc->pixel_rate =
+	    (desc->data.srcbuf_wt * STEP_PRECISION) / desc->data.dstbuf_wt;
+	xvip_write(&desc->xm2mvsc_dev->hw,
+		   XM2MVSC_PIXELRATE(desc->channel_offset),
+		   desc->pixel_rate);
+	xm2mvsc_select_coeff_bank(&desc->xm2mvsc_dev->hw,
+				  desc->data.srcbuf_wt, desc->data.dstbuf_wt,
+				  desc->data.srcbuf_ht, desc->data.dstbuf_ht,
+				  &desc->filter_bank);
+	xvip_write(&desc->xm2mvsc_dev->hw,
+		   XM2MVSC_FILTER_BANK(desc->channel_offset),
+		   desc->filter_bank);
+	xm2mvsc_set_color_format(desc);
+}
+
+void xm2mvsc_write_desc(struct xm2m_vscale_desc *desc)
+{
+	WARN(!desc, "%s : desc is NULL", __func__);
+	if (!desc)
+		return;
+	WARN(!desc->xm2mvsc_dev,
+	     "%s: desc->xm2mvsc_dev is NULL for desc_id = %d",
+	     __func__, desc->data.desc_id);
+	if (!desc->xm2mvsc_dev)
+		return;
+	dev_dbg(desc->xm2mvsc_dev->dev,
+		"%s: Writing desc %d with chan offset = %d",
+		__func__, desc->data.desc_id, desc->channel_offset);
+	xm2mvsc_program_scaler(desc);
+	xvip_write(&desc->xm2mvsc_dev->hw,
+		   XM2MVSC_HEIGHT_IN(desc->channel_offset),
+		   desc->data.srcbuf_ht);
+	xvip_write(&desc->xm2mvsc_dev->hw,
+		   XM2MVSC_WIDTH_IN(desc->channel_offset),
+		   desc->data.srcbuf_wt);
+	xvip_write(&desc->xm2mvsc_dev->hw,
+		   XM2MVSC_HEIGHT_OUT(desc->channel_offset),
+		   desc->data.dstbuf_ht);
+	xvip_write(&desc->xm2mvsc_dev->hw,
+		   XM2MVSC_WIDTH_OUT(desc->channel_offset),
+		   desc->data.dstbuf_wt);
+	xvip_write(&desc->xm2mvsc_dev->hw,
+		   XM2MVSC_SRC_BUF1(desc->channel_offset),
+		   desc->srcbuf_addr);
+	xvip_write(&desc->xm2mvsc_dev->hw,
+		   XM2MVSC_DST_BUF1(desc->channel_offset),
+		   desc->dstbuf_addr);
+	xvip_write(&desc->xm2mvsc_dev->hw,
+		   XM2MVSC_STRIDE_IN(desc->channel_offset),
+		   desc->data.srcbuf_stride);
+	xvip_write(&desc->xm2mvsc_dev->hw,
+		   XM2MVSC_STRIDE_OUT(desc->channel_offset),
+		   desc->data.dstbuf_stride);
+}
+
+#define XM2MVSC_GLOBAL_ENABLE_IRQ	BIT(0)
+#define XM2MVSC_IRQ_AP_DONE		BIT(0)
+#define XM2MVSC_IRQ_AP_READY		BIT(1)
+#define XM2MVSC_START_SCALING		BIT(0)
+void xm2mvsc_start_scaling(const struct xm2m_scaler_hw *hw, const u8 batch_size)
+{
+	WARN(!hw, "%s: hw is NULL", __func__);
+	if (!hw)
+		return;
+	/* Enable Interrupt on IER register */
+	xvip_write(hw, XM2MVSC_IER, XM2MVSC_IRQ_AP_DONE);
+	/* Enable Global IER */
+	xvip_write(hw, XM2MVSC_GIE, XM2MVSC_GLOBAL_ENABLE_IRQ);
+	/* Write Number of Outputs */
+	xvip_write(hw, XM2MVSC_NUM_OUTS, batch_size);
+	/* Start IP with Auto-Restart Disabled */
+	xvip_write(hw, XM2MVSC_AP_CTRL, XM2MVSC_START_SCALING);
+}
+
+void xm2mvsc_log_register(const struct xm2m_scaler_hw *hw, const u8 chan_off)
+{
+	dev_dbg(hw->dev, "-------- %s : XM2MVSC HW REG Channel %d --------",
+		__func__, chan_off);
+	dev_dbg(hw->dev, "CTRL = 0x%x", xvip_read(hw, XM2MVSC_AP_CTRL));
+	dev_dbg(hw->dev, "GIE  = 0x%x", xvip_read(hw, XM2MVSC_GIE));
+	dev_dbg(hw->dev, "IER  = 0x%x", xvip_read(hw, XM2MVSC_IER));
+	dev_dbg(hw->dev, "ISR  = 0x%x", xvip_read(hw, XM2MVSC_ISR));
+	dev_dbg(hw->dev, "Num Outs = %d", xvip_read(hw, XM2MVSC_NUM_OUTS));
+	dev_dbg(hw->dev, "SRC1 = 0x%x",
+		xvip_read(hw, XM2MVSC_SRC_BUF1(chan_off)));
+	dev_dbg(hw->dev, "SRC2 = 0x%x",
+		xvip_read(hw, XM2MVSC_SRC_BUF2(chan_off)));
+	dev_dbg(hw->dev, "HT_IN  = %d",
+		xvip_read(hw, XM2MVSC_HEIGHT_IN(chan_off)));
+	dev_dbg(hw->dev, "WT_IN  = %d",
+		xvip_read(hw, XM2MVSC_WIDTH_IN(chan_off)));
+	dev_dbg(hw->dev, "HT_OUT = %d",
+		xvip_read(hw, XM2MVSC_HEIGHT_OUT(chan_off)));
+	dev_dbg(hw->dev, "WT_OUT = %d",
+		xvip_read(hw, XM2MVSC_WIDTH_OUT(chan_off)));
+	dev_dbg(hw->dev, "Stride In = %d",
+		xvip_read(hw, XM2MVSC_STRIDE_IN(chan_off)));
+	dev_dbg(hw->dev, "Stride Out = %d",
+		xvip_read(hw, XM2MVSC_STRIDE_OUT(chan_off)));
+	dev_dbg(hw->dev, "Pixel Fmt In = %d",
+		xvip_read(hw, XM2MVSC_PIXELFMT_IN(chan_off)));
+	dev_dbg(hw->dev, "Pixel Fmt Out = %d",
+		xvip_read(hw, XM2MVSC_PIXELFMT_OUT(chan_off)));
+	dev_dbg(hw->dev, "PixRate  = 0x%x",
+		xvip_read(hw, XM2MVSC_PIXELRATE(chan_off)));
+	dev_dbg(hw->dev, "LineRate = 0x%x",
+		xvip_read(hw, XM2MVSC_LINERATE(chan_off)));
+	dev_dbg(hw->dev, "DST1 = 0x%x",
+		xvip_read(hw, XM2MVSC_DST_BUF1(chan_off)));
+	dev_dbg(hw->dev, "DST2 = 0x%x",
+		xvip_read(hw, XM2MVSC_DST_BUF2(chan_off)));
+	dev_dbg(hw->dev, "Filter Bank = %d",
+		xvip_read(hw, XM2MVSC_FILTER_BANK(chan_off)));
+}
+
+void xm2mvsc_stop_scaling(const struct xm2m_scaler_hw *hw)
+{
+	WARN(!hw, "%s: hw is NULL", __func__);
+	if (!hw)
+		return;
+	/* Disable Interrupt on IER Register */
+	xvip_write(hw, XM2MVSC_IER, 0);
+	/* Disable Global IER */
+	xvip_write(hw, XM2MVSC_GIE, 0);
+	/* Stop IP */
+	xvip_write(hw, XM2MVSC_AP_CTRL, 0);
+}
+
+u32 xm2mvsc_get_irq_status(const struct xm2m_scaler_hw *hw)
+{
+	u32 status;
+
+	WARN_ON(!hw || IS_ERR(hw));
+	status = xvip_read(hw, XM2MVSC_ISR);
+	status &=  (XM2MVSC_IRQ_AP_DONE);
+	if (status) {
+		xvip_write(hw, XM2MVSC_ISR, status);
+		return status;
+	}
+	return 0;
+}
diff --git a/drivers/staging/xm2mvscale/scaler_hw_xm2m.h b/drivers/staging/xm2mvscale/scaler_hw_xm2m.h
new file mode 100644
index 0000000..1429791
--- /dev/null
+++ b/drivers/staging/xm2mvscale/scaler_hw_xm2m.h
@@ -0,0 +1,152 @@
+/*
+ * Xilinx Memory-to-Memory Video Scaler IP
+ *
+ * Copyright (C) 2018 Xilinx, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef __SCALER_HW_XM2M_H__
+#define __SCALER_HW_XM2M_H__
+
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/types.h>
+
+#include "ioctl_xm2mvsc.h"
+
+#define XSCALER_MAX_WIDTH               (3840)
+#define XSCALER_MAX_HEIGHT              (2160)
+#define XSCALER_MAX_PHASES              (64)
+
+#define XV_SCALER_MAX_TAPS		(12)
+
+#define XV_SCALER_TAPS_6		(6)
+#define XV_SCALER_TAPS_8		(8)
+#define XV_SCALER_TAPS_10		(10)
+#define XV_SCALER_TAPS_12		(12)
+
+/* Filter bank ID  for various filter tap configurations */
+enum xm2mvsc_filter_bank_id {
+	FILTER_BANK_TAPS_6 = 0,
+	FILTER_BANK_TAPS_8,
+	FILTER_BANK_TAPS_10,
+	FILTER_BANK_TAPS_12,
+};
+
+#define XSCALER_BATCH_SIZE_MAX		(8)
+#define XSCALER_BATCH_SIZE_MIN		(1)
+
+struct xm2m_vscale_dev;
+
+/**
+ * struct xm2m_scaler_hw - Scaler Hardware Info
+ * @regs: IO mapped base address of the HW/IP
+ * @dev: Pointer to struct device instance
+ * @num_taps: Polyhphase filter taps Scaler IP
+ * @max_chan: Maximum number of Scaling Channels
+ * @max_pixels: Maximum number of pixel supported in a line
+ * @max_lines: Maximum number of lines supported in a frame
+ * @hscaler_coeff: Array of filter coefficients for the Horizontal Scaler
+ * @vscaler_coeff: Array of filter coefficients for the Vertical Scaler
+ */
+struct xm2m_scaler_hw {
+	void __iomem *regs;
+	struct device *dev;
+	u32 num_taps;
+	u32 max_chan;
+	u32 max_pixels;
+	u32 max_lines;
+	short hscaler_coeff[XSCALER_MAX_PHASES][XV_SCALER_MAX_TAPS];
+	short vscaler_coeff[XSCALER_MAX_PHASES][XV_SCALER_MAX_TAPS];
+};
+
+/**
+ * struct xm2m_vscale_desc - Video Scale Frame Descriptor
+ * @data: Data enqueued by the application
+ * @line_rate: Line rate needed by a scaling channel
+ * @pixel_rate: Pixel rate needed by a scaling channel
+ * @filter_bank: Filter Bank ID needed to source filter coefficients
+ * @channel_offset: Channel offset of the descriptor mapping to HW register
+ * @srcbuf_addr: physical address of source buffer
+ * @dstbuf_addr: physical address of destination buffer
+ * @xm2mvsc_dev: Pointer to parent xm2mvsc driver structure
+ * @node: List node to control descriptors in lists
+ * @src_kaddr: Kernel VA for source buffer allocated by the driver
+ * @dst_kaddr: Kernel VA for destination buffer allocated by the driver
+ */
+struct xm2m_vscale_desc {
+	struct xm2mvsc_qdata data;
+	u32 line_rate;
+	u32 pixel_rate;
+	u8 filter_bank;
+	u8 channel_offset;
+	dma_addr_t srcbuf_addr;
+	dma_addr_t dstbuf_addr;
+	struct xm2m_vscale_dev *xm2mvsc_dev;
+	struct list_head node;
+	void *src_kaddr;
+	void *dst_kaddr;
+};
+
+/**
+ * struct xm2m_vscale_dev - Xilinx M2M Scaler Device
+ * @dev: Pointer to struct device instance used by the driver
+ * @hw: HW/IP specific structure describing the capabilities
+ * @lock: Spinlock to protect driver data structures
+ * @pending_list: List containing descriptors not yet processed
+ * @ongoing_list: List containing descriptors that are in-flight
+ * @done_list: List containing descriptors that are done processing
+ * @free_list: List containing descriptors that need to be freed
+ * @waitq: Wait queue used by the driver
+ * @irq: IRQ number
+ * @chdev: Char device handle
+ * @id: Device instance ID
+ * @rst_gpio: GPIO reset line to bring VPSS Scaler out of reset
+ * @desc_count: Desc Count issued by the driver
+ * @user_count: Count of users who have opened the device
+ * @batch_size: Number of channel actively used in a scaling operation
+ * @ongoing_count: Number of channels already used in the ongoing operation
+ */
+struct xm2m_vscale_dev {
+	struct device *dev;
+	struct xm2m_scaler_hw hw;
+	/* Synchronize access to lists */
+	spinlock_t lock;
+	struct list_head pending_list;
+	struct list_head ongoing_list;
+	struct list_head done_list;
+	struct list_head free_list;
+	wait_queue_head_t waitq;
+	int irq;
+	struct cdev chdev;
+	u32 id;
+	struct gpio_desc *rst_gpio;
+	atomic_t desc_count;
+	atomic_t user_count;
+	u16 batch_size;
+	atomic_t ongoing_count;
+};
+
+static inline u32 xvip_read(const struct xm2m_scaler_hw *hw, const u32 addr)
+{
+	return ioread32(hw->regs + addr);
+}
+
+static inline void xvip_write(const struct xm2m_scaler_hw *hw,
+			      const u32 addr, const u32 value)
+{
+	iowrite32(value, hw->regs + addr);
+}
+
+void xm2mvsc_write_desc(struct xm2m_vscale_desc *desc);
+void xm2mvsc_start_scaling(const struct xm2m_scaler_hw *hw,
+			   const u8 batch_size);
+void xm2mvsc_stop_scaling(const struct xm2m_scaler_hw *hw);
+u32 xm2mvsc_get_irq_status(const struct xm2m_scaler_hw *hw);
+void xm2mvsc_log_register(const struct xm2m_scaler_hw *hw, const u8 chan_off);
+void xm2mvsc_initialize_coeff_banks(struct xm2m_scaler_hw *hw);
+
+#endif /* __XM2M_SCALER_SETUP_H__ */
diff --git a/drivers/staging/xm2mvscale/xm2m_vscale.c b/drivers/staging/xm2mvscale/xm2m_vscale.c
new file mode 100644
index 0000000..b294d31
--- /dev/null
+++ b/drivers/staging/xm2mvscale/xm2m_vscale.c
@@ -0,0 +1,768 @@
+/*
+ * Xilinx Memory-to-Memory Video Scaler IP
+ *
+ * Copyright (C) 2018 Xilinx, Inc. All rights reserved.
+ *
+ * Description:
+ * This driver is developed for the Xilinx M2M Video Scaler IP. It allows
+ * userspace to operate upon the IP and takes care of interrupt handling
+ * and framebuffer programming within the driver.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <linux/cdev.h>
+#include <linux/dma-buf.h>
+#include <linux/fs.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+
+#include "scaler_hw_xm2m.h"
+#include "ioctl_xm2mvsc.h"
+
+/* Forward Declaration */
+static int xm2mvsc_ioctl_stop(struct xm2m_vscale_dev *xm2mvsc);
+
+/* Module Parameters */
+static struct class *xm2mvsc_class;
+static dev_t xm2mvsc_devt;
+static atomic_t xm2mvsc_ndevs = ATOMIC_INIT(0);
+
+#define DRIVER_NAME	"xilinx-m2m-scaler"
+#define DRIVER_VERSION	"0.4"
+#define DRIVER_MAX_DEV	(10)
+
+static int xm2mvsc_open(struct inode *iptr, struct file *fptr)
+{
+	struct xm2m_vscale_dev *xm2mvsc;
+
+	xm2mvsc = container_of(iptr->i_cdev, struct xm2m_vscale_dev, chdev);
+	if (!xm2mvsc) {
+		pr_err("%s: failed to get xm2mvsc driver handle", __func__);
+		return -EAGAIN;
+	}
+	fptr->private_data = xm2mvsc;
+	xm2mvsc->batch_size = XSCALER_BATCH_SIZE_MIN;
+	atomic_inc(&xm2mvsc->user_count);
+	return 0;
+}
+
+static int xm2mvsc_release(struct inode *iptr, struct file *fptr)
+{
+	struct xm2m_vscale_dev *xm2mvsc;
+
+	xm2mvsc = container_of(iptr->i_cdev, struct xm2m_vscale_dev, chdev);
+	if (!xm2mvsc) {
+		pr_err("%s: failed to get xm2mvsc driver handle", __func__);
+		return -EAGAIN;
+	}
+	if (atomic_dec_and_test(&xm2mvsc->user_count)) {
+		/* Reset IP and clear driver state */
+		dev_dbg(xm2mvsc->dev,
+			"%s: Stopping and clearing device", __func__);
+		(void)xm2mvsc_ioctl_stop(xm2mvsc);
+		atomic_set(&xm2mvsc->desc_count, 0);
+		atomic_set(&xm2mvsc->ongoing_count, 0);
+	}
+	dev_dbg(xm2mvsc->dev, "%s: user count = %d",
+		__func__, atomic_read(&xm2mvsc->user_count));
+	return 0;
+}
+
+#define XM2MVSC_MAX_WIDTH	(3840)
+#define XM2MVSC_MAX_HEIGHT	(2160)
+#define XM2MVSC_MIN_WIDTH	(32)
+#define XM2MVSC_MIN_HEIGHT	(32)
+static int xm2mvsc_verify_desc(struct xm2m_vscale_desc *desc)
+{
+	if (!desc)
+		return -EIO;
+	if (desc->data.srcbuf_ht > XM2MVSC_MAX_HEIGHT ||
+	    desc->data.srcbuf_ht < XM2MVSC_MIN_HEIGHT ||
+	    desc->data.dstbuf_ht > XM2MVSC_MAX_HEIGHT ||
+	    desc->data.dstbuf_ht < XM2MVSC_MIN_HEIGHT)
+		return -EINVAL;
+	if (desc->data.srcbuf_wt > XM2MVSC_MAX_WIDTH ||
+	    desc->data.srcbuf_wt < XM2MVSC_MIN_WIDTH ||
+	    desc->data.dstbuf_wt > XM2MVSC_MAX_WIDTH ||
+	    desc->data.dstbuf_wt < XM2MVSC_MIN_WIDTH)
+		return -EINVAL;
+	return 0;
+}
+
+static int xm2mvsc_ioctl_batch_size(struct xm2m_vscale_dev *xm2mvsc,
+				    void __user *arg)
+{
+	int ret;
+	struct xm2mvsc_batch *batch;
+
+	batch = kzalloc(sizeof(*batch), GFP_KERNEL);
+	if (!batch)
+		return -ENOMEM;
+	ret = copy_from_user(batch, arg, sizeof(*batch));
+	if (ret) {
+		dev_err(xm2mvsc->dev,
+			"%s: Failed to copy from user", __func__);
+		kfree(batch);
+		return -EFAULT;
+	}
+
+	if (!batch->batch_size || batch->batch_size > xm2mvsc->hw.max_chan) {
+		dev_err(xm2mvsc->dev,
+			"Invalid batch size passed %d", batch->batch_size);
+		kfree(batch);
+		return -EINVAL;
+	}
+	xm2mvsc->batch_size = batch->batch_size;
+	kfree(batch);
+	return 0;
+}
+
+static int xm2mvsc_ioctl_enqueue(struct xm2m_vscale_dev *xm2mvsc,
+				 void __user *arg)
+{
+	struct xm2m_vscale_desc *desc;
+	int ret;
+	unsigned long flags;
+
+	desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+	ret = copy_from_user(&desc->data, arg, sizeof(desc->data));
+	if (ret)  {
+		dev_err(xm2mvsc->dev, "%s: Failed to copy from user", __func__);
+		return -EFAULT;
+	}
+	ret = xm2mvsc_verify_desc(desc);
+	if (ret < 0)
+		return ret;
+	/* Assign xm2m_vscale_dev handle */
+	desc->xm2mvsc_dev = xm2mvsc;
+	desc->data.desc_id = atomic_add_return(1, &xm2mvsc->desc_count);
+	desc->src_kaddr = dma_alloc_coherent(xm2mvsc->dev,
+					     desc->data.srcbuf_size,
+					     &desc->srcbuf_addr,
+					     GFP_KERNEL | GFP_DMA32);
+	if (!desc->src_kaddr)
+		return -ENOMEM;
+	desc->dst_kaddr = dma_alloc_coherent(xm2mvsc->dev,
+					     desc->data.dstbuf_size,
+					     &desc->dstbuf_addr,
+					     GFP_KERNEL | GFP_DMA32);
+	if (!desc->dst_kaddr)
+		return -ENOMEM;
+	spin_lock_irqsave(&xm2mvsc->lock, flags);
+	list_add_tail(&desc->node, &xm2mvsc->pending_list);
+	spin_unlock_irqrestore(&xm2mvsc->lock, flags);
+	if (copy_to_user(arg, &desc->data, sizeof(desc->data))) {
+		dev_err(xm2mvsc->dev,
+			"%s : Failed to copy to user for desc_id = %d",
+			__func__, desc->data.desc_id);
+		return -EFAULT;
+	}
+	dev_dbg(xm2mvsc->dev, "%s: Desc_id = %d", __func__, desc->data.desc_id);
+	return 0;
+}
+
+static int xm2mvsc_complete(struct xm2m_vscale_dev *xm2mvsc)
+{
+	struct xm2m_vscale_desc *desc, *next;
+	unsigned long flags;
+
+	spin_lock_irqsave(&xm2mvsc->lock, flags);
+	list_for_each_entry_safe(desc, next, &xm2mvsc->ongoing_list, node) {
+		list_del(&desc->node);
+		list_add_tail(&desc->node, &xm2mvsc->done_list);
+		atomic_dec(&xm2mvsc->ongoing_count);
+	}
+	spin_unlock_irqrestore(&xm2mvsc->lock, flags);
+	dev_dbg(xm2mvsc->dev, "%s: ongoing_count = %d",
+		__func__, atomic_read(&xm2mvsc->ongoing_count));
+	return 0;
+}
+
+static int xm2mvsc_ready(struct xm2m_vscale_dev *xm2mvsc)
+{
+	unsigned long flags;
+	struct xm2m_vscale_desc *desc, *next;
+
+	spin_lock_irqsave(&xm2mvsc->lock, flags);
+	if (list_empty_careful(&xm2mvsc->pending_list)) {
+		spin_unlock_irqrestore(&xm2mvsc->lock, flags);
+		return -EAGAIN;
+	}
+	if (atomic_read(&xm2mvsc->ongoing_count) < xm2mvsc->batch_size) {
+		list_for_each_entry_safe(desc, next,
+					 &xm2mvsc->pending_list, node) {
+			list_del(&desc->node);
+			desc->channel_offset =
+				atomic_read(&xm2mvsc->ongoing_count);
+			WARN(desc->channel_offset > xm2mvsc->hw.max_chan,
+			     "%s: Channel offset is beyond supported max",
+			     __func__);
+			list_add_tail(&desc->node, &xm2mvsc->ongoing_list);
+			atomic_inc(&xm2mvsc->ongoing_count);
+			dev_dbg(xm2mvsc->dev,
+				"%s: Desc_id=%d offset=%d ongoing count=%d",
+				__func__, desc->data.desc_id,
+				desc->channel_offset,
+				atomic_read(&xm2mvsc->ongoing_count));
+		}
+	}
+	spin_unlock_irqrestore(&xm2mvsc->lock, flags);
+
+	if (atomic_read(&xm2mvsc->ongoing_count) == xm2mvsc->batch_size) {
+		list_for_each_entry_safe(desc, next,
+					 &xm2mvsc->ongoing_list, node) {
+			xm2mvsc_write_desc(desc);
+		}
+		dev_dbg(xm2mvsc->dev, "%s: xm2mvsc_start_scaling", __func__);
+		/* Start the IP */
+		xm2mvsc_start_scaling(&xm2mvsc->hw, xm2mvsc->batch_size);
+	}
+	return 0;
+}
+
+/* Can be called from IRQ Handler, not allowed to sleep */
+static int xm2mvsc_start_running(struct xm2m_vscale_dev *xm2mvsc)
+{
+	/* Process and make ready */
+	return xm2mvsc_ready(xm2mvsc);
+}
+
+/*
+ * Implementation may need to change to coalesce
+ * completion of multiple buffers
+ */
+static int xm2mvsc_ioctl_dequeue(struct xm2m_vscale_dev *xm2mvsc,
+				 void __user *arg)
+{
+	struct xm2mvsc_dqdata *dqdata;
+	struct xm2m_vscale_desc *desc, *next;
+	unsigned long flags;
+
+	dqdata = kzalloc(sizeof(*dqdata), GFP_KERNEL);
+	if (!dqdata)
+		return -ENOMEM;
+
+	if (copy_from_user(dqdata, arg, sizeof(*dqdata))) {
+		dev_err(xm2mvsc->dev, "%s: Failed to copy from user", __func__);
+		return -EFAULT;
+	}
+
+	/* Underflow or ioctl called too early, try later */
+	spin_lock_irqsave(&xm2mvsc->lock, flags);
+	if (list_empty_careful(&xm2mvsc->done_list)) {
+		spin_unlock_irqrestore(&xm2mvsc->lock, flags);
+		dev_err(xm2mvsc->dev,
+			"%s: failed as done list empty", __func__);
+		return -EAGAIN;
+	}
+	/* Search through the done list, move to free list if found */
+	list_for_each_entry_safe(desc, next, &xm2mvsc->done_list, node) {
+		if (desc->data.desc_id == dqdata->desc_id) {
+			list_del(&desc->node);
+			list_add_tail(&desc->node, &xm2mvsc->free_list);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&xm2mvsc->lock, flags);
+
+	/* Reached end of the list */
+	if (!desc || desc->data.desc_id != dqdata->desc_id) {
+		dev_err(xm2mvsc->dev,
+			"%s: Unable to find desc_id = %d in done list",
+			__func__, dqdata->desc_id);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int xm2mvsc_ioctl_start(struct xm2m_vscale_dev *xm2mvsc)
+{
+	return xm2mvsc_start_running(xm2mvsc);
+}
+
+static void xm2mvsc_free_desc_list(struct list_head *list)
+{
+	struct xm2m_vscale_desc *desc, *next;
+
+	list_for_each_entry_safe(desc, next, list, node) {
+		list_del(&desc->node);
+		kfree(desc);
+	}
+}
+
+/*  PS GPIO RESET MACROS */
+#define XM2MVSC_RESET_ASSERT	(0x1)
+#define XM2MVSC_RESET_DEASSERT	(0x0)
+
+static void xm2mvsc_reset(struct xm2m_vscale_dev *xm2mvsc)
+{
+	gpiod_set_value_cansleep(xm2mvsc->rst_gpio, XM2MVSC_RESET_ASSERT);
+	gpiod_set_value_cansleep(xm2mvsc->rst_gpio, XM2MVSC_RESET_DEASSERT);
+}
+
+static void xm2mvsc_clear_state(struct xm2m_vscale_dev *xm2mvsc)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&xm2mvsc->lock, flags);
+	xm2mvsc_free_desc_list(&xm2mvsc->pending_list);
+	xm2mvsc_free_desc_list(&xm2mvsc->ongoing_list);
+	xm2mvsc_free_desc_list(&xm2mvsc->done_list);
+	xm2mvsc_free_desc_list(&xm2mvsc->free_list);
+	spin_unlock_irqrestore(&xm2mvsc->lock, flags);
+
+	spin_lock_irqsave(&xm2mvsc->lock, flags);
+	INIT_LIST_HEAD(&xm2mvsc->pending_list);
+	INIT_LIST_HEAD(&xm2mvsc->ongoing_list);
+	INIT_LIST_HEAD(&xm2mvsc->done_list);
+	INIT_LIST_HEAD(&xm2mvsc->free_list);
+	spin_unlock_irqrestore(&xm2mvsc->lock, flags);
+}
+
+static int xm2mvsc_ioctl_stop(struct xm2m_vscale_dev *xm2mvsc)
+{
+	xm2mvsc_clear_state(xm2mvsc);
+	/* Reset IP */
+	xm2mvsc_stop_scaling(&xm2mvsc->hw);
+	xm2mvsc_reset(xm2mvsc);
+	return 0;
+}
+
+static int xm2mvsc_ioctl_free(struct xm2m_vscale_dev *xm2mvsc,
+			      void __user *arg)
+{
+	struct xm2mvsc_dqdata *dqdata;
+	struct xm2m_vscale_desc *desc, *next;
+	int ret;
+
+	dqdata = kzalloc(sizeof(*desc), GFP_KERNEL);
+	if (!dqdata)
+		return -ENOMEM;
+
+	ret = copy_from_user(dqdata, arg, sizeof(*dqdata));
+	if (ret < 0) {
+		dev_err(xm2mvsc->dev,
+			"%s: Failed to copy from user", __func__);
+		return -EFAULT;
+	}
+
+	list_for_each_entry_safe(desc, next, &xm2mvsc->free_list, node) {
+		if (desc->data.desc_id == dqdata->desc_id) {
+			list_del(&desc->node);
+			break;
+		}
+	}
+
+	if (!desc || desc->data.desc_id != dqdata->desc_id) {
+		dev_err(xm2mvsc->dev,
+			"%s: Desc_id = %d not found in free list",
+			__func__, dqdata->desc_id);
+		kfree(dqdata);
+		return -EBADF;
+	}
+
+	dma_free_coherent(xm2mvsc->dev, desc->data.srcbuf_size,
+			  desc->src_kaddr, desc->srcbuf_addr);
+	dma_free_coherent(xm2mvsc->dev, desc->data.dstbuf_size,
+			  desc->dst_kaddr, desc->dstbuf_addr);
+	kfree(dqdata);
+	kfree(desc);
+	return 0;
+}
+
+static long xm2mvsc_ioctl(struct file *fptr,
+			  unsigned int cmd, unsigned long data)
+{
+	struct xm2m_vscale_dev *xm2mvsc;
+	void __user *arg;
+	int ret;
+
+	xm2mvsc = fptr->private_data;
+	arg = (void __user *)data;
+
+	if (!xm2mvsc || !arg) {
+		pr_err("%s: file op error", __func__);
+		return -EIO;
+	}
+
+	switch (cmd) {
+	case XM2MVSC_ENQUEUE:
+		ret = xm2mvsc_ioctl_enqueue(xm2mvsc, arg);
+		if (ret < 0)
+			return ret;
+		return 0;
+	case XM2MVSC_DEQUEUE:
+		ret = xm2mvsc_ioctl_dequeue(xm2mvsc, arg);
+		if (ret < 0)
+			return ret;
+		return 0;
+	case XM2MVSC_START:
+		ret = xm2mvsc_ioctl_start(xm2mvsc);
+		if (ret < 0)
+			return ret;
+		return 0;
+	case XM2MVSC_STOP:
+		ret = xm2mvsc_ioctl_stop(xm2mvsc);
+		if (ret < 0)
+			return ret;
+		return 0;
+	case XM2MVSC_FREE:
+		ret = xm2mvsc_ioctl_free(xm2mvsc, arg);
+		if (ret < 0)
+			return ret;
+		return 0;
+	case XM2MVSC_BATCH_SIZE:
+		ret = xm2mvsc_ioctl_batch_size(xm2mvsc, arg);
+		if (ret < 0)
+			return ret;
+		return 0;
+	default:
+		dev_err(xm2mvsc->dev, "Unsupported ioctl cmd");
+		return -EINVAL;
+	}
+}
+
+/*
+ * First call  maps the source buffer,
+ * second call maps the destination buffer
+ */
+static int xm2mvsc_mmap(struct file *fptr, struct vm_area_struct *vma)
+{
+	struct xm2m_vscale_dev *xm2mvsc = fptr->private_data;
+	struct xm2m_vscale_desc *desc, *next;
+	int ret, desc_id;
+	unsigned long flags;
+
+	if (!xm2mvsc) {
+		pr_err("xm2mvsc file private data is NULL");
+		return -EIO;
+	}
+
+	desc_id = vma->vm_pgoff;
+
+	spin_lock_irqsave(&xm2mvsc->lock, flags);
+	list_for_each_entry_safe(desc, next, &xm2mvsc->pending_list, node) {
+		if (desc->data.desc_id == desc_id)
+			break;
+	}
+	spin_unlock_irqrestore(&xm2mvsc->lock, flags);
+	if (!desc || desc->data.desc_id != desc_id) {
+		dev_err(xm2mvsc->dev,
+			"Unable to find desc_id = %d in pending list",
+			desc_id);
+		return -EIO;
+	}
+	if (!desc->src_kaddr && !desc->dst_kaddr) {
+		dev_err(xm2mvsc->dev, "Enqueue before mmap for desc_id = %d",
+			desc->data.desc_id);
+	}
+	if (desc->data.srcbuf_mmap && desc->data.dstbuf_mmap) {
+		dev_err(xm2mvsc->dev,
+			"Src and Dest buffs already mmap'ed for desc_id = %d",
+			desc->data.desc_id);
+		return -EIO;
+	}
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	if (!desc->data.srcbuf_mmap) {
+		ret = remap_pfn_range(vma, vma->vm_start,
+				      desc->srcbuf_addr >> PAGE_SHIFT,
+				      vma->vm_end - vma->vm_start,
+				      vma->vm_page_prot);
+		if (ret) {
+			dev_err(xm2mvsc->dev,
+				"mmap op failed for srcbuf of desc_id = %d",
+				desc->data.desc_id);
+			ret = -EAGAIN;
+			goto error_mmap;
+		}
+		desc->data.srcbuf_mmap = true;
+		goto success_mmap;
+	}
+	if (!desc->data.dstbuf_mmap) {
+		ret = remap_pfn_range(vma, vma->vm_start,
+				      desc->dstbuf_addr >> PAGE_SHIFT,
+				      vma->vm_end - vma->vm_start,
+				      vma->vm_page_prot);
+		if (ret) {
+			dev_err(xm2mvsc->dev,
+				"mmap op failed for dstbuf of desc_id = %d",
+				desc->data.desc_id);
+			ret = -EAGAIN;
+			goto error_mmap;
+		}
+		desc->data.dstbuf_mmap = true;
+		goto success_mmap;
+	}
+success_mmap:
+	vma->vm_private_data = xm2mvsc;
+	return 0;
+error_mmap:
+	dev_err(xm2mvsc->dev, "%s: failed %d", __func__, ret);
+	return ret;
+}
+
+static unsigned int xm2mvsc_poll(struct file *fptr, poll_table *wait)
+{
+	struct xm2m_vscale_dev *xm2mvsc = fptr->private_data;
+
+	if (!xm2mvsc)
+		return 0;
+
+	poll_wait(fptr, &xm2mvsc->waitq, wait);
+	if (!list_empty_careful(&xm2mvsc->done_list))
+		return POLLIN | POLLPRI;
+	return 0;
+}
+
+static const struct file_operations xm2mvsc_fops = {
+	.open = xm2mvsc_open,
+	.release = xm2mvsc_release,
+	.unlocked_ioctl = xm2mvsc_ioctl,
+	.poll = xm2mvsc_poll,
+	.mmap = xm2mvsc_mmap,
+};
+
+static irqreturn_t xm2mvsc_intr_handler(int irq, void *ctx)
+{
+	u32 status;
+	struct xm2m_vscale_dev *xm2mvsc = (struct xm2m_vscale_dev *)ctx;
+
+	WARN(!xm2mvsc, "%s: xm2mvsc is NULL", __func__);
+	WARN(xm2mvsc->irq != irq,
+	     "IRQ registered %d does not match IRQ received %d",
+	     xm2mvsc->irq, irq);
+
+	status = xm2mvsc_get_irq_status(&xm2mvsc->hw);
+	if (status) {
+		/* The ongoing descriptors list should be cleared */
+		(void)xm2mvsc_complete(xm2mvsc);
+		wake_up_interruptible(&xm2mvsc->waitq);
+		/* Program next operation if any*/
+		(void)xm2mvsc_start_running(xm2mvsc);
+		return IRQ_HANDLED;
+	}
+	return IRQ_NONE;
+}
+
+#define XM2MVSC_OF_TAPS		"xlnx,scaler-num-taps"
+#define XM2MVSC_OF_MAX_CHAN	"xlnx,scaler-max-chan"
+static int xm2m_vscale_parse_dt_prop(struct xm2m_vscale_dev *xm2mvsc)
+{
+	struct device_node *node;
+	int ret;
+
+	if (!xm2mvsc)
+		return -EIO;
+	node = xm2mvsc->dev->of_node;
+
+	ret = of_property_read_u32(node, XM2MVSC_OF_TAPS,
+				   &xm2mvsc->hw.num_taps);
+	if (ret < 0)
+		return ret;
+	switch (xm2mvsc->hw.num_taps) {
+	case XV_SCALER_TAPS_6:
+	case XV_SCALER_TAPS_8:
+	case XV_SCALER_TAPS_10:
+	case XV_SCALER_TAPS_12:
+		break;
+	default:
+		dev_err(xm2mvsc->dev,
+			"Unsupported M2M Scaler taps : %d",
+			xm2mvsc->hw.num_taps);
+		return -EINVAL;
+	}
+
+	ret = of_property_read_u32(node, XM2MVSC_OF_MAX_CHAN,
+				   &xm2mvsc->hw.max_chan);
+	if (ret < 0)
+		return ret;
+	if (xm2mvsc->hw.max_chan < XSCALER_BATCH_SIZE_MIN ||
+	    xm2mvsc->hw.max_chan > XSCALER_BATCH_SIZE_MAX) {
+		dev_err(xm2mvsc->dev,
+			"Invalid maximum scaler channels : %d",
+			xm2mvsc->hw.max_chan);
+		return -EINVAL;
+	}
+	/* Reset PS GPIO specifier is optional for now */
+	xm2mvsc->rst_gpio = devm_gpiod_get(xm2mvsc->dev,
+					   "reset", GPIOD_OUT_HIGH);
+	if (IS_ERR(xm2mvsc->rst_gpio)) {
+		if (PTR_ERR(xm2mvsc->rst_gpio) != -EPROBE_DEFER) {
+			dev_err(xm2mvsc->dev,
+				"Reset GPIO specifier not setup in DT");
+		}
+		return PTR_ERR(xm2mvsc->rst_gpio);
+	}
+
+	xm2mvsc->irq = irq_of_parse_and_map(node, 0);
+	if (xm2mvsc->irq < 0) {
+		dev_err(xm2mvsc->dev, "Unable to get IRQ");
+		return xm2mvsc->irq;
+	}
+
+	return 0;
+}
+
+static int xm2m_vscale_probe(struct platform_device *pdev)
+{
+	struct xm2m_vscale_dev *xm2mvsc;
+	struct device *dc;
+	struct resource *res;
+	int ret;
+
+	if (atomic_read(&xm2mvsc_ndevs) >= DRIVER_MAX_DEV) {
+		dev_err(&pdev->dev,
+			"Unable to create xm2mvsc devices beyond max %d",
+			DRIVER_MAX_DEV);
+		return -EIO;
+	}
+
+	xm2mvsc = devm_kzalloc(&pdev->dev, sizeof(*xm2mvsc), GFP_KERNEL);
+	if (!xm2mvsc)
+		return -ENOMEM;
+	xm2mvsc->dev = &pdev->dev;
+	xm2mvsc->hw.dev = &pdev->dev;
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	xm2mvsc->hw.regs = devm_ioremap_resource(xm2mvsc->dev, res);
+	if (IS_ERR(xm2mvsc->hw.regs))
+		return PTR_ERR(xm2mvsc->hw.regs);
+	ret = xm2m_vscale_parse_dt_prop(xm2mvsc);
+	if (ret < 0)
+		return ret;
+	xm2mvsc_reset(xm2mvsc);
+
+	/* Initialize Scaler Properties */
+	xm2mvsc->hw.max_lines = XM2MVSC_MAX_HEIGHT;
+	xm2mvsc->hw.max_pixels = XM2MVSC_MAX_WIDTH;
+	xm2mvsc_initialize_coeff_banks(&xm2mvsc->hw);
+
+	init_waitqueue_head(&xm2mvsc->waitq);
+	spin_lock_init(&xm2mvsc->lock);
+	INIT_LIST_HEAD(&xm2mvsc->pending_list);
+	INIT_LIST_HEAD(&xm2mvsc->ongoing_list);
+	INIT_LIST_HEAD(&xm2mvsc->done_list);
+	INIT_LIST_HEAD(&xm2mvsc->free_list);
+	ret = devm_request_irq(xm2mvsc->dev, xm2mvsc->irq,
+			       xm2mvsc_intr_handler, IRQF_SHARED,
+			       DRIVER_NAME, xm2mvsc);
+	if (ret < 0) {
+		dev_err(xm2mvsc->dev, "Unable to register IRQ");
+		return ret;
+	}
+
+	cdev_init(&xm2mvsc->chdev, &xm2mvsc_fops);
+	xm2mvsc->chdev.owner = THIS_MODULE;
+	xm2mvsc->id = atomic_read(&xm2mvsc_ndevs);
+	ret = cdev_add(&xm2mvsc->chdev,
+		       MKDEV(MAJOR(xm2mvsc_devt), xm2mvsc->id), 1);
+	if (ret < 0) {
+		dev_err(xm2mvsc->dev, "cdev_add failed");
+		return ret;
+	}
+
+	if (!xm2mvsc_class) {
+		dev_err(xm2mvsc->dev, "xm2mvsc device class not created");
+		goto err_cdev;
+	}
+	dc = device_create(xm2mvsc_class, xm2mvsc->dev,
+			   MKDEV(MAJOR(xm2mvsc_devt), xm2mvsc->id),
+			   xm2mvsc, "xm2mvsc%d", xm2mvsc->id);
+	if (IS_ERR(dc)) {
+		ret = PTR_ERR(dc);
+		dev_err(xm2mvsc->dev, "Unable to create device");
+		goto err_cdev;
+	}
+	platform_set_drvdata(pdev, xm2mvsc);
+	dev_info(xm2mvsc->dev,
+		 "Xilinx M2M Video Scaler %d tap %d channel device probe complete",
+		 xm2mvsc->hw.num_taps, xm2mvsc->hw.max_chan);
+	atomic_inc(&xm2mvsc_ndevs);
+	return 0;
+err_cdev:
+	cdev_del(&xm2mvsc->chdev);
+	return ret;
+}
+
+static int xm2m_vscale_remove(struct platform_device *pdev)
+{
+	struct xm2m_vscale_dev *xm2mvsc;
+
+	xm2mvsc = platform_get_drvdata(pdev);
+	if (!xm2mvsc || !xm2mvsc_class)
+		return -EIO;
+	device_destroy(xm2mvsc_class,
+		       MKDEV(MAJOR(xm2mvsc_devt), xm2mvsc->id));
+	cdev_del(&xm2mvsc->chdev);
+	atomic_dec(&xm2mvsc_ndevs);
+	return 0;
+}
+
+static const struct of_device_id xm2mvsc_of_match[] = {
+	{ .compatible = "xlnx,v-m2m-scaler", },
+	{ /* end of table*/ }
+};
+MODULE_DEVICE_TABLE(of, xm2mvsc_of_match);
+
+static struct platform_driver xm2mvsc_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+		.of_match_table = xm2mvsc_of_match,
+	},
+	.probe = xm2m_vscale_probe,
+	.remove = xm2m_vscale_remove,
+};
+
+static int __init xm2mvsc_init_mod(void)
+{
+	int err;
+
+	xm2mvsc_class = class_create(THIS_MODULE, DRIVER_NAME);
+	if (IS_ERR(xm2mvsc_class)) {
+		pr_err("%s : Unable to create xm2mvsc class", __func__);
+		return PTR_ERR(xm2mvsc_class);
+	}
+	err = alloc_chrdev_region(&xm2mvsc_devt, 0,
+				  DRIVER_MAX_DEV, DRIVER_NAME);
+	if (err < 0) {
+		pr_err("%s: Unable to get major number for xm2mvsc", __func__);
+		goto err_class;
+	}
+	err = platform_driver_register(&xm2mvsc_driver);
+	if (err < 0) {
+		pr_err("%s: Unable to register %s driver",
+		       __func__, DRIVER_NAME);
+		goto err_pdrv;
+	}
+	return 0;
+err_pdrv:
+	unregister_chrdev_region(xm2mvsc_devt, DRIVER_MAX_DEV);
+err_class:
+	class_destroy(xm2mvsc_class);
+	return err;
+}
+
+static void __exit xm2mvsc_cleanup_mod(void)
+{
+	platform_driver_unregister(&xm2mvsc_driver);
+	unregister_chrdev_region(xm2mvsc_devt, DRIVER_MAX_DEV);
+	class_destroy(xm2mvsc_class);
+	xm2mvsc_class = NULL;
+}
+module_init(xm2mvsc_init_mod);
+module_exit(xm2mvsc_cleanup_mod);
+
+MODULE_AUTHOR("Xilinx Inc.");
+MODULE_DESCRIPTION("Xilinx M2M Video Scaler IP Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/staging/xm2mvscale/xvm2mvsc_hw_regs.h b/drivers/staging/xm2mvscale/xvm2mvsc_hw_regs.h
new file mode 100644
index 0000000..966d3c8
--- /dev/null
+++ b/drivers/staging/xm2mvscale/xvm2mvsc_hw_regs.h
@@ -0,0 +1,204 @@
+// ==============================================================
+// File generated by Vivado(TM) HLS - High-Level Synthesis from
+// C, C++ and SystemC
+// Version: 2018.1.0
+// Copyright (C) 1986-2018 Xilinx, Inc. All Rights Reserved.
+// SPDX-License-Identifier: GPL-2.0
+// ==============================================================
+
+// CTRL
+// 0x0000 : Control signals
+//          bit 0  - ap_start (Read/Write/COH)
+//          bit 1  - ap_done (Read/COR)
+//          bit 2  - ap_idle (Read)
+//          bit 3  - ap_ready (Read)
+//          bit 7  - auto_restart (Read/Write)
+//          others - reserved
+// 0x0004 : Global Interrupt Enable Register
+//          bit 0  - Global Interrupt Enable (Read/Write)
+//          others - reserved
+// 0x0008 : IP Interrupt Enable Register (Read/Write)
+//          bit 0  - Channel 0 (ap_done)
+//          bit 1  - Channel 1 (ap_ready)
+//          others - reserved
+// 0x000c : IP Interrupt Status Register (Read/TOW)
+//          bit 0  - Channel 0 (ap_done)
+//          bit 1  - Channel 1 (ap_ready)
+//          others - reserved
+// 0x0010 : Data signal of HwReg_num_outs
+//          bit 7~0 - HwReg_num_outs[7:0] (Read/Write)
+//          others  - reserved
+// 0x0014 : reserved
+// 0x0100 : Data signal of HwReg_WidthIn_0
+//          bit 15~0 - HwReg_WidthIn_0[15:0] (Read/Write)
+//          others   - reserved
+// 0x0104 : reserved
+// 0x0108 : Data signal of HwReg_WidthOut_0
+//          bit 15~0 - HwReg_WidthOut_0[15:0] (Read/Write)
+//          others   - reserved
+// 0x010c : reserved
+// 0x0110 : Data signal of HwReg_HeightIn_0
+//          bit 15~0 - HwReg_HeightIn_0[15:0] (Read/Write)
+//          others   - reserved
+// 0x0114 : reserved
+// 0x0118 : Data signal of HwReg_HeightOut_0
+//          bit 15~0 - HwReg_HeightOut_0[15:0] (Read/Write)
+//          others   - reserved
+// 0x011c : reserved
+// 0x0120 : Data signal of HwReg_LineRate_0
+//          bit 31~0 - HwReg_LineRate_0[31:0] (Read/Write)
+// 0x0124 : reserved
+// 0x0128 : Data signal of HwReg_PixelRate_0
+//          bit 31~0 - HwReg_PixelRate_0[31:0] (Read/Write)
+// 0x012c : reserved
+// 0x0130 : Data signal of HwReg_InPixelFmt_0
+//          bit 7~0 - HwReg_InPixelFmt_0[7:0] (Read/Write)
+//          others  - reserved
+// 0x0134 : reserved
+// 0x0138 : Data signal of HwReg_OutPixelFmt_0
+//          bit 7~0 - HwReg_OutPixelFmt_0[7:0] (Read/Write)
+//          others  - reserved
+// 0x013c : reserved
+// 0x0140 : Data signal of HwReg_FiltIdx_0
+//          bit 7~0 - HwReg_FiltIdx_0[7:0] (Read/Write)
+//          others  - reserved
+// 0x0144 : reserved
+// 0x0150 : Data signal of HwReg_InStride_0
+//          bit 15~0 - HwReg_InStride_0[15:0] (Read/Write)
+//          others   - reserved
+// 0x0154 : reserved
+// 0x0158 : Data signal of HwReg_OutStride_0
+//          bit 15~0 - HwReg_OutStride_0[15:0] (Read/Write)
+//          others   - reserved
+// 0x015c : reserved
+// 0x0160 : Data signal of HwReg_srcImgBuf0_0
+//          bit 31~0 - HwReg_srcImgBuf0_0[31:0] (Read/Write)
+// 0x0164 : reserved
+// 0x0170 : Data signal of HwReg_srcImgBuf1_0
+//          bit 31~0 - HwReg_srcImgBuf1_0[31:0] (Read/Write)
+// 0x0174 : reserved
+// 0x0190 : Data signal of HwReg_dstImgBuf0_0
+//          bit 31~0 - HwReg_dstImgBuf0_0[31:0] (Read/Write)
+// 0x0194 : reserved
+// 0x0200 : Data signal of HwReg_dstImgBuf1_0
+//          bit 31~0 - HwReg_dstImgBuf1_0[31:0] (Read/Write)
+// 0x0204 : reserved
+// 0x1500 : Data signal of HwReg_WidthIn_7
+//          bit 15~0 - HwReg_WidthIn_7[15:0] (Read/Write)
+//          others   - reserved
+// 0x1504 : reserved
+// 0x1508 : Data signal of HwReg_WidthOut_7
+//          bit 15~0 - HwReg_WidthOut_7[15:0] (Read/Write)
+//          others   - reserved
+// 0x150c : reserved
+// 0x1510 : Data signal of HwReg_HeightIn_7
+//          bit 15~0 - HwReg_HeightIn_7[15:0] (Read/Write)
+//          others   - reserved
+// 0x1514 : reserved
+// 0x1518 : Data signal of HwReg_HeightOut_7
+//          bit 15~0 - HwReg_HeightOut_7[15:0] (Read/Write)
+//          others   - reserved
+// 0x151c : reserved
+// 0x1520 : Data signal of HwReg_LineRate_7
+//          bit 31~0 - HwReg_LineRate_7[31:0] (Read/Write)
+// 0x1524 : reserved
+// 0x1528 : Data signal of HwReg_PixelRate_7
+//          bit 31~0 - HwReg_PixelRate_7[31:0] (Read/Write)
+// 0x152c : reserved
+// 0x1530 : Data signal of HwReg_InPixelFmt_7
+//          bit 7~0 - HwReg_InPixelFmt_7[7:0] (Read/Write)
+//          others  - reserved
+// 0x1534 : reserved
+// 0x1538 : Data signal of HwReg_OutPixelFmt_7
+//          bit 7~0 - HwReg_OutPixelFmt_7[7:0] (Read/Write)
+//          others  - reserved
+// 0x153c : reserved
+// 0x1540 : Data signal of HwReg_FiltIdx_7
+//          bit 7~0 - HwReg_FiltIdx_7[7:0] (Read/Write)
+//          others  - reserved
+// 0x1544 : reserved
+// 0x1550 : Data signal of HwReg_InStride_7
+//          bit 15~0 - HwReg_InStride_7[15:0] (Read/Write)
+//          others   - reserved
+// 0x1554 : reserved
+// 0x1558 : Data signal of HwReg_OutStride_7
+//          bit 15~0 - HwReg_OutStride_7[15:0] (Read/Write)
+//          others   - reserved
+// 0x155c : reserved
+// 0x1560 : Data signal of HwReg_srcImgBuf0_7
+//          bit 31~0 - HwReg_srcImgBuf0_7[31:0] (Read/Write)
+// 0x1564 : reserved
+// 0x1570 : Data signal of HwReg_srcImgBuf1_7
+//          bit 31~0 - HwReg_srcImgBuf1_7[31:0] (Read/Write)
+// 0x1574 : reserved
+// 0x1590 : Data signal of HwReg_dstImgBuf0_7
+//          bit 31~0 - HwReg_dstImgBuf0_7[31:0] (Read/Write)
+// 0x1594 : reserved
+// 0x1600 : Data signal of HwReg_dstImgBuf1_7
+//          bit 31~0 - HwReg_dstImgBuf1_7[31:0] (Read/Write)
+// 0x1604 : reserved
+// 0x2000 ~
+// 0x23ff : Memory 'HwReg_mm_vfltCoeff_L' (384 * 16b)
+//          Word n : bit [15: 0] - HwReg_mm_vfltCoeff_L[2n]
+//                   bit [31:16] - HwReg_mm_vfltCoeff_L[2n+1]
+// 0x2800 ~
+// 0x2bff : Memory 'HwReg_mm_vfltCoeff_H' (384 * 16b)
+//          Word n : bit [15: 0] - HwReg_mm_vfltCoeff_H[2n]
+//                   bit [31:16] - HwReg_mm_vfltCoeff_H[2n+1]
+// 0x4000 ~
+// 0x43ff : Memory 'HwReg_mm_hfltCoeff_L' (384 * 16b)
+//          Word n : bit [15: 0] - HwReg_mm_hfltCoeff_L[2n]
+//                   bit [31:16] - HwReg_mm_hfltCoeff_L[2n+1]
+// 0x4800 ~
+// 0x4bff : Memory 'HwReg_mm_hfltCoeff_H' (384 * 16b)
+//          Word n : bit [15: 0] - HwReg_mm_hfltCoeff_H[2n]
+//                   bit [31:16] - HwReg_mm_hfltCoeff_H[2n+1]
+// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write,
+//  COH = Clear on Handshake)
+#ifndef __HW_REGS_XM2MVSC_H__
+#define __HW_REGS_XM2MVSC_H__
+
+#define XM2MVSC_AP_CTRL			0x0000
+#define XM2MVSC_GIE			0x0004
+#define XM2MVSC_IER			0x0008
+#define XM2MVSC_ISR			0x000c
+#define XM2MVSC_NUM_OUTS		0x0010
+
+#define XM2MVSC_WIDTHIN_0		0x0100
+#define XM2MVSC_WIDTHOUT_0		0x0108
+#define XM2MVSC_HEIGHTIN_0		0x0110
+#define XM2MVSC_HEIGHTOUT_0		0x0118
+#define XM2MVSC_LINERATE_0		0x0120
+#define XM2MVSC_PIXELRATE_0		0x0128
+#define XM2MVSC_INPIXELFMT_0		0x0130
+#define XM2MVSC_OUTPIXELFMT_0		0x0138
+#define XM2MVSC_FILTIDX_0		0x0140
+#define XM2MVSC_INSTRIDE_0		0x0150
+#define XM2MVSC_OUTSTRIDE_0		0x0158
+#define XM2MVSC_SRCIMGBUF0_0		0x0160
+#define XM2MVSC_SRCIMGBUF1_0		0x0170
+#define XM2MVSC_DSTIMGBUF0_0		0x0190
+#define XM2MVSC_DSTIMGBUF1_0		0x0200
+
+#define XM2MVSC_WIDTH_IN(x)	(XM2MVSC_WIDTHIN_0     + 0x200 * (x))
+#define XM2MVSC_WIDTH_OUT(x)	(XM2MVSC_WIDTHOUT_0    + 0x200 * (x))
+#define XM2MVSC_HEIGHT_IN(x)	(XM2MVSC_HEIGHTIN_0    + 0x200 * (x))
+#define XM2MVSC_HEIGHT_OUT(x)	(XM2MVSC_HEIGHTOUT_0   + 0x200 * (x))
+#define XM2MVSC_LINERATE(x)	(XM2MVSC_LINERATE_0    + 0x200 * (x))
+#define XM2MVSC_PIXELRATE(x)	(XM2MVSC_PIXELRATE_0   + 0x200 * (x))
+#define XM2MVSC_PIXELFMT_IN(x)	(XM2MVSC_INPIXELFMT_0  + 0x200 * (x))
+#define XM2MVSC_PIXELFMT_OUT(x)	(XM2MVSC_OUTPIXELFMT_0 + 0x200 * (x))
+#define XM2MVSC_FILTER_BANK(x)	(XM2MVSC_FILTIDX_0     + 0x200 * (x))
+#define XM2MVSC_STRIDE_IN(x)	(XM2MVSC_INSTRIDE_0    + 0x200 * (x))
+#define XM2MVSC_STRIDE_OUT(x)	(XM2MVSC_OUTSTRIDE_0   + 0x200 * (x))
+#define XM2MVSC_SRC_BUF1(x)	(XM2MVSC_SRCIMGBUF0_0  + 0x200 * (x))
+#define XM2MVSC_SRC_BUF2(x)	(XM2MVSC_SRCIMGBUF1_0  + 0x200 * (x))
+#define XM2MVSC_DST_BUF1(x)	(XM2MVSC_DSTIMGBUF0_0  + 0x200 * (x))
+#define XM2MVSC_DST_BUF2(x)	(XM2MVSC_DSTIMGBUF1_0  + 0x200 * (x))
+
+#define XM2MVSC_VFLTCOEFF_L		0x2000
+#define XM2MVSC_VFLTCOEFF(x)	(XM2MVSC_VFLTCOEFF_L + 0x800 * (x))
+#define XM2MVSC_HFLTCOEFF_L		0x4000
+#define XM2MVSC_HFLTCOEFF(x)	(XM2MVSC_HFLTCOEFF_L + 0x800 * (x))
+
+#endif /* __HW_REGS_XM2MVSC_H__ */
-- 
1.9.1



More information about the devel mailing list