linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/3] Initial driver support for Xilinx M2M Video Scaler
@ 2018-02-21 22:43 Rohit Athavale
  2018-02-21 22:43 ` [PATCH v2 1/3] staging: xm2mvscale: Driver " Rohit Athavale
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Rohit Athavale @ 2018-02-21 22:43 UTC (permalink / raw)
  To: devel; +Cc: gregkh, linux-media, rohit.athavale

This patch series has three commits :
 - Driver support for the Xilinx M2M Video Scaler IP
 - TODO document
 - DT binding doc

Changes in HW register map is expected as the IP undergoes changes.
This is a first attempt at the driver as an early prototype.

This is a M2M Video Scaler IP that uses polyphases filters to perform
video scaling. The driver will be used by an application like a
gstreamer plugin.

Change Log:

v2 
 - Cc'ing linux-media mailing list as suggested by Dan Carpenter.
   Dan wanted to see if someone from linux-media can review the 
   driver interface in xm2m_vscale.c to see if it makes sense.
 - Another question would be the right place to keep the driver,
   in drivers/staging/media or drivers/staging/ 
 - Dropped empty mmap_open, mmap_close ops.
 - Removed incorrect DMA_SHARED_BUFFER select from Kconfig
v1 - Initial version


Rohit Athavale (3):
  staging: xm2mvscale: Driver support for Xilinx M2M Video Scaler
  staging: xm2mvscale: Add TODO for the driver
  Documentation: devicetree: bindings: Add DT binding doc for xm2mvsc
    driver

 drivers/staging/Kconfig                            |   2 +
 drivers/staging/Makefile                           |   1 +
 .../devicetree/bindings/xm2mvscaler.txt            |  25 +
 drivers/staging/xm2mvscale/Kconfig                 |  11 +
 drivers/staging/xm2mvscale/Makefile                |   3 +
 drivers/staging/xm2mvscale/TODO                    |  18 +
 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 +++++
 11 files changed, 2263 insertions(+)
 create mode 100644 drivers/staging/xm2mvscale/Documentation/devicetree/bindings/xm2mvscaler.txt
 create mode 100644 drivers/staging/xm2mvscale/Kconfig
 create mode 100644 drivers/staging/xm2mvscale/Makefile
 create mode 100644 drivers/staging/xm2mvscale/TODO
 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

-- 
1.9.1

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2 1/3] staging: xm2mvscale: Driver support for Xilinx M2M Video Scaler
  2018-02-21 22:43 [PATCH v2 0/3] Initial driver support for Xilinx M2M Video Scaler Rohit Athavale
@ 2018-02-21 22:43 ` Rohit Athavale
  2018-02-22 13:46   ` Greg KH
  2018-02-21 22:43 ` [PATCH v2 2/3] staging: xm2mvscale: Add TODO for the driver Rohit Athavale
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 10+ messages in thread
From: Rohit Athavale @ 2018-02-21 22:43 UTC (permalink / raw)
  To: devel; +Cc: gregkh, linux-media, rohit.athavale

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@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

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 2/3] staging: xm2mvscale: Add TODO for the driver
  2018-02-21 22:43 [PATCH v2 0/3] Initial driver support for Xilinx M2M Video Scaler Rohit Athavale
  2018-02-21 22:43 ` [PATCH v2 1/3] staging: xm2mvscale: Driver " Rohit Athavale
@ 2018-02-21 22:43 ` Rohit Athavale
  2018-02-21 22:43 ` [PATCH v2 3/3] Documentation: devicetree: bindings: Add DT binding doc for xm2mvsc driver Rohit Athavale
  2018-02-23  0:42 ` [PATCH v2 0/3] Initial driver support for Xilinx M2M Video Scaler Nicolas Dufresne
  3 siblings, 0 replies; 10+ messages in thread
From: Rohit Athavale @ 2018-02-21 22:43 UTC (permalink / raw)
  To: devel; +Cc: gregkh, linux-media, rohit.athavale

This commit highlights the key functionalities that will be
improved upon in a future patch set.

Signed-off-by: Rohit Athavale <rohit.athavale@xilinx.com>
---
 drivers/staging/xm2mvscale/TODO | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
 create mode 100644 drivers/staging/xm2mvscale/TODO

diff --git a/drivers/staging/xm2mvscale/TODO b/drivers/staging/xm2mvscale/TODO
new file mode 100644
index 0000000..f0a0733
--- /dev/null
+++ b/drivers/staging/xm2mvscale/TODO
@@ -0,0 +1,18 @@
+* Fix checkpatch.pl complaints
+* Investigate if V4L2/Media framework can be used on top of HW Layer instead
+  of exisiting char driver.
+* Possible remaining coding style fix.
+* Add support for DMABUF.
+* This is an early prototype, hardware register map changes are expected.
+* Update driver for 64-bit DMA address once the new Xilinx M2M Scaler IP
+  has support for 64-bit DMA Addresses. Current IP supports 32-bit DMA addresses.
+* Remove deadcode.
+* Add documents in Documentation beyond the DT binding doc.
+* This needs a home  in the proper drivers area (example : drivers/misc/),
+  once the quality of the driver is improved. Suggestions about where
+  it should be placed are welcome.
+* The IOCTL header could be moved to an uapi/* area once this is out of staging.
+
+Please send any patches to:
+Greg Kroah-Hartman <greg@kroah.com> and Rohit Athavale <rathaval@xilinx.com>
+
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 3/3] Documentation: devicetree: bindings: Add DT binding doc for xm2mvsc driver
  2018-02-21 22:43 [PATCH v2 0/3] Initial driver support for Xilinx M2M Video Scaler Rohit Athavale
  2018-02-21 22:43 ` [PATCH v2 1/3] staging: xm2mvscale: Driver " Rohit Athavale
  2018-02-21 22:43 ` [PATCH v2 2/3] staging: xm2mvscale: Add TODO for the driver Rohit Athavale
@ 2018-02-21 22:43 ` Rohit Athavale
  2018-02-23  0:42 ` [PATCH v2 0/3] Initial driver support for Xilinx M2M Video Scaler Nicolas Dufresne
  3 siblings, 0 replies; 10+ messages in thread
From: Rohit Athavale @ 2018-02-21 22:43 UTC (permalink / raw)
  To: devel; +Cc: gregkh, linux-media, rohit.athavale

This commit adds the binding doc for the DT that the driver expects.
Driver has been tested against Zynq US+ board.

Signed-off-by: Rohit Athavale <rohit.athavale@xilinx.com>
---
 .../devicetree/bindings/xm2mvscaler.txt            | 25 ++++++++++++++++++++++
 1 file changed, 25 insertions(+)
 create mode 100644 drivers/staging/xm2mvscale/Documentation/devicetree/bindings/xm2mvscaler.txt

diff --git a/drivers/staging/xm2mvscale/Documentation/devicetree/bindings/xm2mvscaler.txt b/drivers/staging/xm2mvscale/Documentation/devicetree/bindings/xm2mvscaler.txt
new file mode 100644
index 0000000..1f3d805
--- /dev/null
+++ b/drivers/staging/xm2mvscale/Documentation/devicetree/bindings/xm2mvscaler.txt
@@ -0,0 +1,25 @@
+Xilinx M2M Video Scaler
+-----------------------
+This document describes the DT bindings required by the
+Xilinx M2M Video Scaler driver.
+
+Required Properties:
+- compatible		: Must be "xlnx,v-m2m-scaler"
+- reg			: Memory map for module access
+- reset-gpios		: Should contain GPIO reset phandle
+- interrupt-parent	: Interrupt controller the interrupt is routed through
+- interrupts		: Should contain DMA channel interrupt
+- xlnx,scaler-num-taps	: The number of filter taps for scaling filter
+- xlnx,scaler-max-chan	: The maximum number of supported scaling channels
+
+Examples
+---------
+	v_multi_scaler: v_multi_scaler@a0000000 {
+		compatible = "xlnx,v-m2m-scaler";
+		reg = <0x0 0xa0000000 0x0 0x10000>;
+		reset-gpios = <&gpio 78 1>;
+		interrupt-parent = <&gic>;
+		interrupts = <0 89 4>;
+		xlnx,scaler-num-taps = <6>;
+		xlnx,scaler-max-chan = <4>;
+	};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 1/3] staging: xm2mvscale: Driver support for Xilinx M2M Video Scaler
  2018-02-21 22:43 ` [PATCH v2 1/3] staging: xm2mvscale: Driver " Rohit Athavale
@ 2018-02-22 13:46   ` Greg KH
  2018-03-09 11:57     ` Hans Verkuil
  0 siblings, 1 reply; 10+ messages in thread
From: Greg KH @ 2018-02-22 13:46 UTC (permalink / raw)
  To: Rohit Athavale; +Cc: devel, linux-media

On Wed, Feb 21, 2018 at 02:43:14PM -0800, Rohit Athavale wrote:
> 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@xilinx.com>
> ---

I need an ack from the linux-media maintainers before I can consider
this for staging, as this really looks like an "odd" video driver...

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 0/3] Initial driver support for Xilinx M2M Video Scaler
  2018-02-21 22:43 [PATCH v2 0/3] Initial driver support for Xilinx M2M Video Scaler Rohit Athavale
                   ` (2 preceding siblings ...)
  2018-02-21 22:43 ` [PATCH v2 3/3] Documentation: devicetree: bindings: Add DT binding doc for xm2mvsc driver Rohit Athavale
@ 2018-02-23  0:42 ` Nicolas Dufresne
  3 siblings, 0 replies; 10+ messages in thread
From: Nicolas Dufresne @ 2018-02-23  0:42 UTC (permalink / raw)
  To: Rohit Athavale, devel; +Cc: gregkh, linux-media

Le mercredi 21 février 2018 à 14:43 -0800, Rohit Athavale a écrit :
> This patch series has three commits :
>  - Driver support for the Xilinx M2M Video Scaler IP
>  - TODO document
>  - DT binding doc
> 
> Changes in HW register map is expected as the IP undergoes changes.
> This is a first attempt at the driver as an early prototype.
> 
> This is a M2M Video Scaler IP that uses polyphases filters to perform
> video scaling. The driver will be used by an application like a
> gstreamer plugin.

I'm hoping you know all this already, but just in case, rebasing your
driver on videobuf2-v4l2.h interface would be automatically supported
by GStreamer, and likely a better proposal for upstreaming.

There few drivers already that could be use as an inspiration.

./drivers/media/platform/vim2m.c: Which demonstrate the API
./drivers/media/platform/exynos4-is/: Exynos4 imaging functions
./drivers/media/platform/exynos-gsc/: Exynos4 scaler (and more)
./drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c: MediaTek CSC/Scale
./drivers/media/platform/s5p-g2d/g2d.c: A 2D blitter iirc ?
. . .

I don't know them all, I have developped the GStreamer code with the
Exynos4/5 platform, but also had success report on IMX6 (not upstream
yet apparently). With the framework, you'll gain DMABuf with very
little code.

> 
> Change Log:
> 
> v2 
>  - Cc'ing linux-media mailing list as suggested by Dan Carpenter.
>    Dan wanted to see if someone from linux-media can review the 
>    driver interface in xm2m_vscale.c to see if it makes sense.
>  - Another question would be the right place to keep the driver,
>    in drivers/staging/media or drivers/staging/ 
>  - Dropped empty mmap_open, mmap_close ops.
>  - Removed incorrect DMA_SHARED_BUFFER select from Kconfig
> v1 - Initial version
> 
> 
> Rohit Athavale (3):
>   staging: xm2mvscale: Driver support for Xilinx M2M Video Scaler
>   staging: xm2mvscale: Add TODO for the driver
>   Documentation: devicetree: bindings: Add DT binding doc for xm2mvsc
>     driver
> 
>  drivers/staging/Kconfig                            |   2 +
>  drivers/staging/Makefile                           |   1 +
>  .../devicetree/bindings/xm2mvscaler.txt            |  25 +
>  drivers/staging/xm2mvscale/Kconfig                 |  11 +
>  drivers/staging/xm2mvscale/Makefile                |   3 +
>  drivers/staging/xm2mvscale/TODO                    |  18 +
>  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 +++++
>  11 files changed, 2263 insertions(+)
>  create mode 100644
> drivers/staging/xm2mvscale/Documentation/devicetree/bindings/xm2mvsca
> ler.txt
>  create mode 100644 drivers/staging/xm2mvscale/Kconfig
>  create mode 100644 drivers/staging/xm2mvscale/Makefile
>  create mode 100644 drivers/staging/xm2mvscale/TODO
>  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
> 

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 1/3] staging: xm2mvscale: Driver support for Xilinx M2M Video Scaler
  2018-02-22 13:46   ` Greg KH
@ 2018-03-09 11:57     ` Hans Verkuil
  2018-03-20  0:46       ` Rohit Athavale
  0 siblings, 1 reply; 10+ messages in thread
From: Hans Verkuil @ 2018-03-09 11:57 UTC (permalink / raw)
  To: Greg KH, Rohit Athavale; +Cc: devel, linux-media

On 22/02/18 14:46, Greg KH wrote:
> On Wed, Feb 21, 2018 at 02:43:14PM -0800, Rohit Athavale wrote:
>> 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@xilinx.com>
>> ---
> 
> I need an ack from the linux-media maintainers before I can consider
> this for staging, as this really looks like an "odd" video driver...

This should definitely use the V4L2 API. I guess it could be added
to staging/media with a big fat TODO that this should be converted to
the V4L2 mem2mem framework.

But it makes no sense to re-invent the V4L2 streaming API :-)

drivers/media/platform/mx2_emmaprp.c does something similar to this.
It's a little bit outdated (not using the latest m2m helper functions)
but it is a good starting point.

So for this series:

Nacked-by: Hans Verkuil <hans.verkuil@cisco.com>

If this was added to drivers/staging/media instead and with an updated
TODO, then we can accept it, but we need to see some real effort afterwards
to switch this to the right API. Otherwise it will be removed again
after a few kernel cycles.

Regards,

	Hans

^ permalink raw reply	[flat|nested] 10+ messages in thread

* RE: [PATCH v2 1/3] staging: xm2mvscale: Driver support for Xilinx M2M Video Scaler
  2018-03-09 11:57     ` Hans Verkuil
@ 2018-03-20  0:46       ` Rohit Athavale
  2018-03-20  1:41         ` Nicolas Dufresne
  0 siblings, 1 reply; 10+ messages in thread
From: Rohit Athavale @ 2018-03-20  0:46 UTC (permalink / raw)
  To: Hans Verkuil, Greg KH; +Cc: devel, linux-media, Rohit Athavale

Hi Hans,

Thanks for taking the time to take a look at this.

> This should definitely use the V4L2 API. I guess it could be added
> to staging/media with a big fat TODO that this should be converted to
> the V4L2 mem2mem framework.
> 
> But it makes no sense to re-invent the V4L2 streaming API :-)
> 
> drivers/media/platform/mx2_emmaprp.c does something similar to this.
> It's a little bit outdated (not using the latest m2m helper functions)
> but it is a good starting point.

I looked at the mx2_emmaprp.c and the Samsung G-Scaler M2M driver. IMHO, the main difference between
the Hardware registers/capabilities is that mx2_emmaprp driver or the gsc driver, have one scaling "channel"
if we might call it. Whereas the HW/IP I have in mind has 4-8 scaling channels.

By a scaling channel, I mean an entity of the HW or IP, that can take the following parameters :
 - Input height, stride , width, color format, input Y and Cb/Cr physically contiguous memory pointers 
 - Output height, stride, width, color format, output Y and Cb/Cr physically contiguous  memory pointers

Based on the above parameters, when the above are provided and the IP is started, we get an interrupt on completion.
I'm sure you are familiar with this model. However, in the case of this IP, there could be 4-8 such channels and a single interrupt
on the completion of the all 4-8 scaling operations.

In this IP, we are trying to have 4-8 input sources being scaled by this single piece of hardware, by time multiplexing.

An example use case is :

Four applications (sources) will feed (enqueue) 4 input buffers to the scaler, the scaler driver will synchronize the programming of these buffers, when the number of buffers received  by the driver meets our batch size (say a batch size of 4), it will kick start the IP. The four applications  will poll on the fd, upon receiving an interrupt from the hardware the poll will unblock. And all four applications can dequeue their respective buffers and display them on a sink.

But each "channel" can be set to do accept its own individual input and output formats. When I went through :
https://www.kernel.org/doc/html/v4.14/media/uapi/v4l/open.html#multiple-opens

It appears, once an application has invoked VIDIOC_REQBUFS or VIDIOC_CREATE_BUFS, other applications cannot VIDIOC_S_FMT on them. However to maximize the available number of channels, it would be necessary to allow several applications to be able to 
perform VIDIOC_S_FMT on the device node in the case of this hardware as different channels can be expected to deal with different scaling operations.

One option is to create a logical /dev/videoX node for each such channel, and have a parent driver perform the interrupt handling, batch size setting and other such common functionalities. Is there a way to allow multiple applications talk to the same video device node/file handle without creating logical video nodes for each channel ?

Please let me know if the description of HW is not clear. I will look forward to hear comments from you.

> 
> So for this series:
> 
> Nacked-by: Hans Verkuil <hans.verkuil@cisco.com>
> 
> If this was added to drivers/staging/media instead and with an updated
> TODO, then we can accept it, but we need to see some real effort afterwards
> to switch this to the right API. Otherwise it will be removed again
> after a few kernel cycles.
> 

Many thanks for providing a pathway to get this into drivers/staging/media

I will drop this series, and re-send with the driver being placed in drivers/staging/media.
I'll add some references to this conversation, so a new reviewer gets some context of what
was discussed. In the meanwhile I will look into re-writing this to utilize the M2M V4L2 API.

> Regards,
> 
> 	Hans


Best Regards,
Rohit


> -----Original Message-----
> From: Hans Verkuil [mailto:hverkuil@xs4all.nl]
> Sent: Friday, March 09, 2018 3:58 AM
> To: Greg KH <gregkh@linuxfoundation.org>; Rohit Athavale
> <RATHAVAL@xilinx.com>
> Cc: devel@driverdev.osuosl.org; linux-media@vger.kernel.org
> Subject: Re: [PATCH v2 1/3] staging: xm2mvscale: Driver support for Xilinx M2M
> Video Scaler
> 
> On 22/02/18 14:46, Greg KH wrote:
> > On Wed, Feb 21, 2018 at 02:43:14PM -0800, Rohit Athavale wrote:
> >> 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@xilinx.com>
> >> ---
> >
> > I need an ack from the linux-media maintainers before I can consider
> > this for staging, as this really looks like an "odd" video driver...
> 
> This should definitely use the V4L2 API. I guess it could be added
> to staging/media with a big fat TODO that this should be converted to
> the V4L2 mem2mem framework.
> 
> But it makes no sense to re-invent the V4L2 streaming API :-)
> 
> drivers/media/platform/mx2_emmaprp.c does something similar to this.
> It's a little bit outdated (not using the latest m2m helper functions)
> but it is a good starting point.
> 
> So for this series:
> 
> Nacked-by: Hans Verkuil <hans.verkuil@cisco.com>
> 
> If this was added to drivers/staging/media instead and with an updated
> TODO, then we can accept it, but we need to see some real effort afterwards
> to switch this to the right API. Otherwise it will be removed again
> after a few kernel cycles.
> 
> Regards,
> 
> 	Hans

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 1/3] staging: xm2mvscale: Driver support for Xilinx M2M Video Scaler
  2018-03-20  0:46       ` Rohit Athavale
@ 2018-03-20  1:41         ` Nicolas Dufresne
  2018-03-20  7:27           ` Hans Verkuil
  0 siblings, 1 reply; 10+ messages in thread
From: Nicolas Dufresne @ 2018-03-20  1:41 UTC (permalink / raw)
  To: Rohit Athavale, Hans Verkuil, Greg KH; +Cc: devel, linux-media

Le mardi 20 mars 2018 à 00:46 +0000, Rohit Athavale a écrit :
> Hi Hans,
> 
> Thanks for taking the time to take a look at this.
> 
> > This should definitely use the V4L2 API. I guess it could be added
> > to staging/media with a big fat TODO that this should be converted
> > to
> > the V4L2 mem2mem framework.
> > 
> > But it makes no sense to re-invent the V4L2 streaming API :-)
> > 
> > drivers/media/platform/mx2_emmaprp.c does something similar to
> > this.
> > It's a little bit outdated (not using the latest m2m helper
> > functions)
> > but it is a good starting point.
> 
> I looked at the mx2_emmaprp.c and the Samsung G-Scaler M2M driver.
> IMHO, the main difference between
> the Hardware registers/capabilities is that mx2_emmaprp driver or the
> gsc driver, have one scaling "channel"
> if we might call it. Whereas the HW/IP I have in mind has 4-8 scaling
> channels.
> 
> By a scaling channel, I mean an entity of the HW or IP, that can take
> the following parameters :
>  - Input height, stride , width, color format, input Y and Cb/Cr
> physically contiguous memory pointers 
>  - Output height, stride, width, color format, output Y and Cb/Cr
> physically contiguous  memory pointers
> 
> Based on the above parameters, when the above are provided and the IP
> is started, we get an interrupt on completion.
> I'm sure you are familiar with this model. However, in the case of
> this IP, there could be 4-8 such channels and a single interrupt
> on the completion of the all 4-8 scaling operations.
> 
> In this IP, we are trying to have 4-8 input sources being scaled by
> this single piece of hardware, by time multiplexing.
> 
> An example use case is :
> 
> Four applications (sources) will feed (enqueue) 4 input buffers to
> the scaler, the scaler driver will synchronize the programming of
> these buffers, when the number of buffers received  by the driver
> meets our batch size (say a batch size of 4), it will kick start the
> IP. The four applications  will poll on the fd, upon receiving an
> interrupt from the hardware the poll will unblock. And all four
> applications can dequeue their respective buffers and display them on
> a sink.

You should think of a better scheduling model, it will be really hard
to design userspace that collaborate in order to optimize the IP usage.
I think a better approach would be to queue while the IP is busy. These
queues can then be sorted and prioritized.

> 
> But each "channel" can be set to do accept its own individual input
> and output formats. When I went through :
> https://www.kernel.org/doc/html/v4.14/media/uapi/v4l/open.html#multip
> le-opens
> 
> It appears, once an application has invoked VIDIOC_REQBUFS or
> VIDIOC_CREATE_BUFS, other applications cannot VIDIOC_S_FMT on them.
> However to maximize the available number of channels, it would be
> necessary to allow several applications to be able to 
> perform VIDIOC_S_FMT on the device node in the case of this hardware
> as different channels can be expected to deal with different scaling
> operations.

This does not apply to M2M devices. Each time userspace open an M2M
device, it will get a different instance (unless there is no more
resource available). What drivers like Samsung FIMC, GSCALER, MFC. etc.
do, is that they limit the number of instances (open calls) to the
number of streams they can handle in parallel. They don't seem to share
an IRQ when doing batch though.

> 
> One option is to create a logical /dev/videoX node for each such
> channel, and have a parent driver perform the interrupt handling,
> batch size setting and other such common functionalities. Is there a
> way to allow multiple applications talk to the same video device
> node/file handle without creating logical video nodes for each
> channel ?

FIMC used to expose a node per instance and it was terribly hard to
use. I don't think this is a good idea.

> 
> Please let me know if the description of HW is not clear. I will look
> forward to hear comments from you.
> 
> > 
> > So for this series:
> > 
> > Nacked-by: Hans Verkuil <hans.verkuil@cisco.com>
> > 
> > If this was added to drivers/staging/media instead and with an
> > updated
> > TODO, then we can accept it, but we need to see some real effort
> > afterwards
> > to switch this to the right API. Otherwise it will be removed again
> > after a few kernel cycles.
> > 
> 
> Many thanks for providing a pathway to get this into
> drivers/staging/media
> 
> I will drop this series, and re-send with the driver being placed in
> drivers/staging/media.
> I'll add some references to this conversation, so a new reviewer gets
> some context of what
> was discussed. In the meanwhile I will look into re-writing this to
> utilize the M2M V4L2 API.
> 
> > Regards,
> > 
> > 	Hans
> 
> 
> Best Regards,
> Rohit
> 
> 
> > -----Original Message-----
> > From: Hans Verkuil [mailto:hverkuil@xs4all.nl]
> > Sent: Friday, March 09, 2018 3:58 AM
> > To: Greg KH <gregkh@linuxfoundation.org>; Rohit Athavale
> > <RATHAVAL@xilinx.com>
> > Cc: devel@driverdev.osuosl.org; linux-media@vger.kernel.org
> > Subject: Re: [PATCH v2 1/3] staging: xm2mvscale: Driver support for
> > Xilinx M2M
> > Video Scaler
> > 
> > On 22/02/18 14:46, Greg KH wrote:
> > > On Wed, Feb 21, 2018 at 02:43:14PM -0800, Rohit Athavale wrote:
> > > > 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@xilinx.com>
> > > > ---
> > > 
> > > I need an ack from the linux-media maintainers before I can
> > > consider
> > > this for staging, as this really looks like an "odd" video
> > > driver...
> > 
> > This should definitely use the V4L2 API. I guess it could be added
> > to staging/media with a big fat TODO that this should be converted
> > to
> > the V4L2 mem2mem framework.
> > 
> > But it makes no sense to re-invent the V4L2 streaming API :-)
> > 
> > drivers/media/platform/mx2_emmaprp.c does something similar to
> > this.
> > It's a little bit outdated (not using the latest m2m helper
> > functions)
> > but it is a good starting point.
> > 
> > So for this series:
> > 
> > Nacked-by: Hans Verkuil <hans.verkuil@cisco.com>
> > 
> > If this was added to drivers/staging/media instead and with an
> > updated
> > TODO, then we can accept it, but we need to see some real effort
> > afterwards
> > to switch this to the right API. Otherwise it will be removed again
> > after a few kernel cycles.
> > 
> > Regards,
> > 
> > 	Hans

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 1/3] staging: xm2mvscale: Driver support for Xilinx M2M Video Scaler
  2018-03-20  1:41         ` Nicolas Dufresne
@ 2018-03-20  7:27           ` Hans Verkuil
  0 siblings, 0 replies; 10+ messages in thread
From: Hans Verkuil @ 2018-03-20  7:27 UTC (permalink / raw)
  To: Nicolas Dufresne, Rohit Athavale, Greg KH; +Cc: devel, linux-media

On 03/20/2018 02:41 AM, Nicolas Dufresne wrote:
> Le mardi 20 mars 2018 à 00:46 +0000, Rohit Athavale a écrit :
>> Hi Hans,
>>
>> Thanks for taking the time to take a look at this.
>>
>>> This should definitely use the V4L2 API. I guess it could be added
>>> to staging/media with a big fat TODO that this should be converted
>>> to
>>> the V4L2 mem2mem framework.
>>>
>>> But it makes no sense to re-invent the V4L2 streaming API :-)
>>>
>>> drivers/media/platform/mx2_emmaprp.c does something similar to
>>> this.
>>> It's a little bit outdated (not using the latest m2m helper
>>> functions)
>>> but it is a good starting point.
>>
>> I looked at the mx2_emmaprp.c and the Samsung G-Scaler M2M driver.
>> IMHO, the main difference between
>> the Hardware registers/capabilities is that mx2_emmaprp driver or the
>> gsc driver, have one scaling "channel"
>> if we might call it. Whereas the HW/IP I have in mind has 4-8 scaling
>> channels.
>>
>> By a scaling channel, I mean an entity of the HW or IP, that can take
>> the following parameters :
>>  - Input height, stride , width, color format, input Y and Cb/Cr
>> physically contiguous memory pointers 
>>  - Output height, stride, width, color format, output Y and Cb/Cr
>> physically contiguous  memory pointers
>>
>> Based on the above parameters, when the above are provided and the IP
>> is started, we get an interrupt on completion.
>> I'm sure you are familiar with this model. However, in the case of
>> this IP, there could be 4-8 such channels and a single interrupt
>> on the completion of the all 4-8 scaling operations.
>>
>> In this IP, we are trying to have 4-8 input sources being scaled by
>> this single piece of hardware, by time multiplexing.
>>
>> An example use case is :
>>
>> Four applications (sources) will feed (enqueue) 4 input buffers to
>> the scaler, the scaler driver will synchronize the programming of
>> these buffers, when the number of buffers received  by the driver
>> meets our batch size (say a batch size of 4), it will kick start the
>> IP. The four applications  will poll on the fd, upon receiving an
>> interrupt from the hardware the poll will unblock. And all four
>> applications can dequeue their respective buffers and display them on
>> a sink.
> 
> You should think of a better scheduling model, it will be really hard
> to design userspace that collaborate in order to optimize the IP usage.
> I think a better approach would be to queue while the IP is busy. These
> queues can then be sorted and prioritized.
> 
>>
>> But each "channel" can be set to do accept its own individual input
>> and output formats. When I went through :
>> https://www.kernel.org/doc/html/v4.14/media/uapi/v4l/open.html#multip
>> le-opens
>>
>> It appears, once an application has invoked VIDIOC_REQBUFS or
>> VIDIOC_CREATE_BUFS, other applications cannot VIDIOC_S_FMT on them.
>> However to maximize the available number of channels, it would be
>> necessary to allow several applications to be able to 
>> perform VIDIOC_S_FMT on the device node in the case of this hardware
>> as different channels can be expected to deal with different scaling
>> operations.
> 
> This does not apply to M2M devices. Each time userspace open an M2M
> device, it will get a different instance (unless there is no more
> resource available). What drivers like Samsung FIMC, GSCALER, MFC. etc.
> do, is that they limit the number of instances (open calls) to the
> number of streams they can handle in parallel. They don't seem to share
> an IRQ when doing batch though.
> 
>>
>> One option is to create a logical /dev/videoX node for each such
>> channel, and have a parent driver perform the interrupt handling,
>> batch size setting and other such common functionalities. Is there a
>> way to allow multiple applications talk to the same video device
>> node/file handle without creating logical video nodes for each
>> channel ?
> 
> FIMC used to expose a node per instance and it was terribly hard to
> use. I don't think this is a good idea.

See Nicolas' answers. The mem2mem framework should work well for you,
I think. The job_ready callback can be used to signal when enough
buffers are queued to satisfy your IP requirements.

BTW, those requirements sound really weird. Is this really how Xilinx
wants to implement this? It's not how scalers are used 'in the real world'.
This whole 'batching' thing is strange.

Regards,

	Hans

> 
>>
>> Please let me know if the description of HW is not clear. I will look
>> forward to hear comments from you.
>>
>>>
>>> So for this series:
>>>
>>> Nacked-by: Hans Verkuil <hans.verkuil@cisco.com>
>>>
>>> If this was added to drivers/staging/media instead and with an
>>> updated
>>> TODO, then we can accept it, but we need to see some real effort
>>> afterwards
>>> to switch this to the right API. Otherwise it will be removed again
>>> after a few kernel cycles.
>>>
>>
>> Many thanks for providing a pathway to get this into
>> drivers/staging/media
>>
>> I will drop this series, and re-send with the driver being placed in
>> drivers/staging/media.
>> I'll add some references to this conversation, so a new reviewer gets
>> some context of what
>> was discussed. In the meanwhile I will look into re-writing this to
>> utilize the M2M V4L2 API.
>>
>>> Regards,
>>>
>>> 	Hans
>>
>>
>> Best Regards,
>> Rohit
>>
>>
>>> -----Original Message-----
>>> From: Hans Verkuil [mailto:hverkuil@xs4all.nl]
>>> Sent: Friday, March 09, 2018 3:58 AM
>>> To: Greg KH <gregkh@linuxfoundation.org>; Rohit Athavale
>>> <RATHAVAL@xilinx.com>
>>> Cc: devel@driverdev.osuosl.org; linux-media@vger.kernel.org
>>> Subject: Re: [PATCH v2 1/3] staging: xm2mvscale: Driver support for
>>> Xilinx M2M
>>> Video Scaler
>>>
>>> On 22/02/18 14:46, Greg KH wrote:
>>>> On Wed, Feb 21, 2018 at 02:43:14PM -0800, Rohit Athavale wrote:
>>>>> 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@xilinx.com>
>>>>> ---
>>>>
>>>> I need an ack from the linux-media maintainers before I can
>>>> consider
>>>> this for staging, as this really looks like an "odd" video
>>>> driver...
>>>
>>> This should definitely use the V4L2 API. I guess it could be added
>>> to staging/media with a big fat TODO that this should be converted
>>> to
>>> the V4L2 mem2mem framework.
>>>
>>> But it makes no sense to re-invent the V4L2 streaming API :-)
>>>
>>> drivers/media/platform/mx2_emmaprp.c does something similar to
>>> this.
>>> It's a little bit outdated (not using the latest m2m helper
>>> functions)
>>> but it is a good starting point.
>>>
>>> So for this series:
>>>
>>> Nacked-by: Hans Verkuil <hans.verkuil@cisco.com>
>>>
>>> If this was added to drivers/staging/media instead and with an
>>> updated
>>> TODO, then we can accept it, but we need to see some real effort
>>> afterwards
>>> to switch this to the right API. Otherwise it will be removed again
>>> after a few kernel cycles.
>>>
>>> Regards,
>>>
>>> 	Hans

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2018-03-20  7:27 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-02-21 22:43 [PATCH v2 0/3] Initial driver support for Xilinx M2M Video Scaler Rohit Athavale
2018-02-21 22:43 ` [PATCH v2 1/3] staging: xm2mvscale: Driver " Rohit Athavale
2018-02-22 13:46   ` Greg KH
2018-03-09 11:57     ` Hans Verkuil
2018-03-20  0:46       ` Rohit Athavale
2018-03-20  1:41         ` Nicolas Dufresne
2018-03-20  7:27           ` Hans Verkuil
2018-02-21 22:43 ` [PATCH v2 2/3] staging: xm2mvscale: Add TODO for the driver Rohit Athavale
2018-02-21 22:43 ` [PATCH v2 3/3] Documentation: devicetree: bindings: Add DT binding doc for xm2mvsc driver Rohit Athavale
2018-02-23  0:42 ` [PATCH v2 0/3] Initial driver support for Xilinx M2M Video Scaler Nicolas Dufresne

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).