aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/platform/xilinx
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/xilinx')
-rw-r--r--drivers/media/platform/xilinx/Kconfig134
-rw-r--r--drivers/media/platform/xilinx/Makefile19
-rw-r--r--drivers/media/platform/xilinx/xilinx-axis-switch.c588
-rw-r--r--drivers/media/platform/xilinx/xilinx-cfa.c394
-rw-r--r--drivers/media/platform/xilinx/xilinx-cresample.c447
-rw-r--r--drivers/media/platform/xilinx/xilinx-csi2rxss.c2023
-rw-r--r--drivers/media/platform/xilinx/xilinx-demosaic.c418
-rw-r--r--drivers/media/platform/xilinx/xilinx-dma.c754
-rw-r--r--drivers/media/platform/xilinx/xilinx-dma.h16
-rw-r--r--drivers/media/platform/xilinx/xilinx-gamma-coeff.h5385
-rw-r--r--drivers/media/platform/xilinx/xilinx-gamma.c543
-rw-r--r--drivers/media/platform/xilinx/xilinx-hls-common.h36
-rw-r--r--drivers/media/platform/xilinx/xilinx-hls.c481
-rw-r--r--drivers/media/platform/xilinx/xilinx-m2m.c2106
-rw-r--r--drivers/media/platform/xilinx/xilinx-multi-scaler-coeff.h574
-rw-r--r--drivers/media/platform/xilinx/xilinx-multi-scaler.c2449
-rw-r--r--drivers/media/platform/xilinx/xilinx-remapper.c546
-rw-r--r--drivers/media/platform/xilinx/xilinx-rgb2yuv.c566
-rw-r--r--drivers/media/platform/xilinx/xilinx-scaler.c708
-rw-r--r--drivers/media/platform/xilinx/xilinx-scenechange-channel.c352
-rw-r--r--drivers/media/platform/xilinx/xilinx-scenechange-dma.c554
-rw-r--r--drivers/media/platform/xilinx/xilinx-scenechange.c191
-rw-r--r--drivers/media/platform/xilinx/xilinx-scenechange.h234
-rw-r--r--drivers/media/platform/xilinx/xilinx-sdirxss.c1855
-rw-r--r--drivers/media/platform/xilinx/xilinx-switch.c460
-rw-r--r--drivers/media/platform/xilinx/xilinx-tpg.c627
-rw-r--r--drivers/media/platform/xilinx/xilinx-vip.c177
-rw-r--r--drivers/media/platform/xilinx/xilinx-vip.h14
-rw-r--r--drivers/media/platform/xilinx/xilinx-vipp.c62
-rw-r--r--drivers/media/platform/xilinx/xilinx-vipp.h5
-rw-r--r--drivers/media/platform/xilinx/xilinx-vpss-csc.c1169
-rw-r--r--drivers/media/platform/xilinx/xilinx-vpss-scaler.c1878
-rw-r--r--drivers/media/platform/xilinx/xilinx-vtc.c18
-rw-r--r--drivers/media/platform/xilinx/xilinx-vtc.h1
34 files changed, 25534 insertions, 250 deletions
diff --git a/drivers/media/platform/xilinx/Kconfig b/drivers/media/platform/xilinx/Kconfig
index a2773ad7c185..f21796d175a2 100644
--- a/drivers/media/platform/xilinx/Kconfig
+++ b/drivers/media/platform/xilinx/Kconfig
@@ -4,23 +4,153 @@ config VIDEO_XILINX
tristate "Xilinx Video IP (EXPERIMENTAL)"
depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && OF && HAS_DMA
select VIDEOBUF2_DMA_CONTIG
+ select XILINX_FRMBUF
select V4L2_FWNODE
help
Driver for Xilinx Video IP Pipelines
if VIDEO_XILINX
+config VIDEO_XILINX_AXI4S_SWITCH
+ tristate "Xilinx AXI4-Stream Video Switch"
+ depends on VIDEO_XILINX
+ ---help---
+ Driver for the Xilinx AXI4-Stream Video Switch. This is a
+ V4L sub device based driver. It supports fixed (TDEST based)
+ as well as dynamic (control register based) routing.
+ Say M to modularize. Say N if unsure.
+
+config VIDEO_XILINX_CFA
+ tristate "Xilinx Video Color Filter Array"
+ depends on VIDEO_XILINX
+ ---help---
+ Driver for the Xilinx Color Filter Array
+
+config VIDEO_XILINX_CRESAMPLE
+ tristate "Xilinx Video Chroma Resampler"
+ depends on VIDEO_XILINX
+ ---help---
+ Driver for the Xilinx Chroma Resampler
+
+config VIDEO_XILINX_DEMOSAIC
+ tristate "Xilinx Video Demosaic IP"
+ depends on VIDEO_XILINX
+ ---help---
+ Driver for Xilinx Video Demosaic IP. This is a V4L sub-device
+ based driver for the Demosaic IP that takes input a Bayer video
+ stream format as input and generates an RGB video output.
+ Say M to modularize. Say N if unsure.
+
+config VIDEO_XILINX_GAMMA
+ tristate "Xilinx Gamma Correction LUT"
+ depends on VIDEO_XILINX
+ ---help---
+ Driver for Xilinx Gamma Correction LUT IP. This is a V4L sub-device
+ based driver that exposes V4L controls to adjust Red, Blue and Green
+ Gamma Correction.
+
+ Say M to modularize. Say N if unsure.
+
+config VIDEO_XILINX_HLS
+ tristate "Xilinx Video HLS Core"
+ depends on VIDEO_XILINX
+ ---help---
+ Driver for the Xilinx Video HLS Cores
+
+config VIDEO_XILINX_REMAPPER
+ tristate "Xilinx Video Remapper"
+ depends on VIDEO_XILINX
+ ---help---
+ Driver for the Xilinx Video Remapper
+
+config VIDEO_XILINX_RGB2YUV
+ tristate "Xilinx Video RGB to YUV Convertor"
+ depends on VIDEO_XILINX
+ ---help---
+ Driver for the Xilinx Video RGB to YUV Convertor
+
+config VIDEO_XILINX_SCALER
+ tristate "Xilinx Video Scaler"
+ depends on VIDEO_XILINX
+ ---help---
+ Driver for the Xilinx Video Scaler
+
+config VIDEO_XILINX_MULTISCALER
+ tristate "Xilinx Video Multiscaler"
+ depends on VIDEO_XILINX
+ depends on VIDEO_DEV && VIDEO_V4L2
+ select V4L2_MEM2MEM_DEV
+ select VIDEOBUF2_DMA_CONTIG
+ ---help---
+ Driver for the Xilinx Video Multi Scaler. This is a V4L2 memory to
+ memory based driver. Multi-Scaler has max 8 channels which can be
+ programed for different scaling ratio.
+
+config VIDEO_XILINX_SDIRXSS
+ tristate "Xilinx SDI Rx Subsystem"
+ depends on VIDEO_XILINX
+ ---help---
+ Driver for Xilinx SDI Rx Subsystem
+
+config VIDEO_XILINX_SWITCH
+ tristate "Xilinx Video Switch"
+ depends on VIDEO_XILINX
+ ---help---
+ Driver for the Xilinx Video Switch
+
config VIDEO_XILINX_TPG
tristate "Xilinx Video Test Pattern Generator"
depends on VIDEO_XILINX
select VIDEO_XILINX_VTC
help
- Driver for the Xilinx Video Test Pattern Generator
+ Driver for the Xilinx Video Test Pattern Generator
+
+config VIDEO_XILINX_VPSS_CSC
+ tristate "Xilinx VPSS CSC"
+ depends on VIDEO_XILINX
+ ---help---
+ Driver for the Xilinx Video Processing Sub-System (VPSS)
+ Color Space Conversion. The driver provides RGB to YUV444
+ conversion and provides video controls like Brightness,
+ Contrast, Color Gains that can be applied to video.
+ Say N if unsure. Say M to modularize.
+
+config VIDEO_XILINX_VPSS_SCALER
+ tristate "Xilinx Video VPSS Scaler"
+ depends on VIDEO_XILINX
+ ---help---
+ Driver for Xilinx Video Processing Sub-System(VPSS) Scaler.
+ It allows upscaling and downscaling of video. It also supports
+ limited Color Space Conversion.
+ Say N if unsure.
config VIDEO_XILINX_VTC
tristate "Xilinx Video Timing Controller"
depends on VIDEO_XILINX
help
- Driver for the Xilinx Video Timing Controller
+ Driver for the Xilinx Video Timing Controller
+
+config VIDEO_XILINX_CSI2RXSS
+ tristate "Xilinx CSI2 Rx Subsystem"
+ depends on VIDEO_XILINX
+ ---help---
+ Driver for Xilinx MIPI CSI2 Rx Subsystem
+
+config VIDEO_XILINX_SCD
+ tristate "Xilinx Scene Change Detect"
+ depends on VIDEO_XILINX
+ ---help---
+ Driver for Xilinx Scene Change Detection Controller.
+ The driver allows applications to pass video buffers and
+ provides if scene change detection is present between
+ adjacent frames.
+
+config VIDEO_XILINX_M2M
+ tristate "Xilinx Video mem2mem"
+ depends on VIDEO_XILINX
+ select V4L2_MEM2MEM_DEV
+ ---help---
+ Driver for Xilinx V4L2 mem2mem pipeline operation to achieve memory
+ copy between two different physical memories using DMA transfers.
endif #VIDEO_XILINX
diff --git a/drivers/media/platform/xilinx/Makefile b/drivers/media/platform/xilinx/Makefile
index 4cdc0b1ec7a5..f7838c307405 100644
--- a/drivers/media/platform/xilinx/Makefile
+++ b/drivers/media/platform/xilinx/Makefile
@@ -1,7 +1,26 @@
# SPDX-License-Identifier: GPL-2.0
xilinx-video-objs += xilinx-dma.o xilinx-vip.o xilinx-vipp.o
+xilinx-scd-objs += xilinx-scenechange.o xilinx-scenechange-channel.o \
+ xilinx-scenechange-dma.o
obj-$(CONFIG_VIDEO_XILINX) += xilinx-video.o
+obj-$(CONFIG_VIDEO_XILINX_AXI4S_SWITCH) += xilinx-axis-switch.o
+obj-$(CONFIG_VIDEO_XILINX_CFA) += xilinx-cfa.o
+obj-$(CONFIG_VIDEO_XILINX_CRESAMPLE) += xilinx-cresample.o
+obj-$(CONFIG_VIDEO_XILINX_CSI2RXSS) += xilinx-csi2rxss.o
+obj-$(CONFIG_VIDEO_XILINX_DEMOSAIC) += xilinx-demosaic.o
+obj-$(CONFIG_VIDEO_XILINX_GAMMA) += xilinx-gamma.o
+obj-$(CONFIG_VIDEO_XILINX_HLS) += xilinx-hls.o
+obj-$(CONFIG_VIDEO_XILINX_M2M) += xilinx-m2m.o
+obj-$(CONFIG_VIDEO_XILINX_MULTISCALER) += xilinx-multi-scaler.o
+obj-$(CONFIG_VIDEO_XILINX_REMAPPER) += xilinx-remapper.o
+obj-$(CONFIG_VIDEO_XILINX_RGB2YUV) += xilinx-rgb2yuv.o
+obj-$(CONFIG_VIDEO_XILINX_SCALER) += xilinx-scaler.o
+obj-$(CONFIG_VIDEO_XILINX_SCD) += xilinx-scd.o
+obj-$(CONFIG_VIDEO_XILINX_SDIRXSS) += xilinx-sdirxss.o
+obj-$(CONFIG_VIDEO_XILINX_SWITCH) += xilinx-switch.o
obj-$(CONFIG_VIDEO_XILINX_TPG) += xilinx-tpg.o
+obj-$(CONFIG_VIDEO_XILINX_VPSS_CSC) += xilinx-vpss-csc.o
+obj-$(CONFIG_VIDEO_XILINX_VPSS_SCALER) += xilinx-vpss-scaler.o
obj-$(CONFIG_VIDEO_XILINX_VTC) += xilinx-vtc.o
diff --git a/drivers/media/platform/xilinx/xilinx-axis-switch.c b/drivers/media/platform/xilinx/xilinx-axis-switch.c
new file mode 100644
index 000000000000..3963e364570a
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-axis-switch.c
@@ -0,0 +1,588 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Xilinx AXI4-Stream Video Switch
+ *
+ * Copyright (C) 2018 Xilinx, Inc.
+ *
+ * Author: Vishal Sagar <vishal.sagar@xilinx.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include <media/media-device.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-subdev.h>
+
+#include "xilinx-vip.h"
+
+#define XVSW_CTRL_REG 0x00
+#define XVSW_CTRL_REG_UPDATE_MASK BIT(1)
+
+#define XVSW_MI_MUX_REG_BASE 0x40
+#define XVSW_MI_MUX_VAL_MASK 0xF
+#define XVSW_MI_MUX_DISABLE_MASK BIT(31)
+
+#define MIN_VSW_SINKS 1
+#define MAX_VSW_SINKS 16
+#define MIN_VSW_SRCS 1
+#define MAX_VSW_SRCS 16
+
+/**
+ * struct xvswitch_device - Xilinx AXI4-Stream Switch device structure
+ * @dev: Platform structure
+ * @iomem: Base address of IP
+ * @subdev: The v4l2 subdev structure
+ * @pads: media pads
+ * @routing: sink pad connected to each source pad (-1 if none)
+ * @formats: active V4L2 media bus formats on sink pads
+ * @nsinks: number of sink pads (1 to 8)
+ * @nsources: number of source pads (2 to 8)
+ * @tdest_routing: Whether TDEST routing is enabled
+ * @aclk: Video clock
+ * @saxi_ctlclk: AXI-Lite control clock
+ */
+struct xvswitch_device {
+ struct device *dev;
+ void __iomem *iomem;
+ struct v4l2_subdev subdev;
+ struct media_pad *pads;
+ int routing[MAX_VSW_SRCS];
+ struct v4l2_mbus_framefmt *formats;
+ u32 nsinks;
+ u32 nsources;
+ bool tdest_routing;
+ struct clk *aclk;
+ struct clk *saxi_ctlclk;
+};
+
+static inline struct xvswitch_device *to_xvsw(struct v4l2_subdev *subdev)
+{
+ return container_of(subdev, struct xvswitch_device, subdev);
+}
+
+static inline u32 xvswitch_read(struct xvswitch_device *xvsw, u32 addr)
+{
+ return ioread32(xvsw->iomem + addr);
+}
+
+static inline void xvswitch_write(struct xvswitch_device *xvsw, u32 addr,
+ u32 value)
+{
+ iowrite32(value, xvsw->iomem + addr);
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Video Operations
+ */
+
+static int xvsw_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+ struct xvswitch_device *xvsw = to_xvsw(subdev);
+ unsigned int i;
+
+ /* Nothing to be done in case of TDEST routing */
+ if (xvsw->tdest_routing)
+ return 0;
+
+ if (!enable) {
+ /* In control reg routing, disable all master ports */
+ for (i = 0; i < xvsw->nsources; i++) {
+ xvswitch_write(xvsw, XVSW_MI_MUX_REG_BASE + (i * 4),
+ XVSW_MI_MUX_DISABLE_MASK);
+ }
+ xvswitch_write(xvsw, XVSW_CTRL_REG, XVSW_CTRL_REG_UPDATE_MASK);
+ return 0;
+ }
+
+ /*
+ * In case of control reg routing,
+ * from routing table write the values into respective reg
+ * and enable
+ */
+ for (i = 0; i < MAX_VSW_SRCS; i++) {
+ u32 val;
+
+ if (xvsw->routing[i] != -1)
+ val = xvsw->routing[i];
+ else
+ val = XVSW_MI_MUX_DISABLE_MASK;
+
+ xvswitch_write(xvsw, XVSW_MI_MUX_REG_BASE + (i * 4),
+ val);
+ }
+
+ xvswitch_write(xvsw, XVSW_CTRL_REG, XVSW_CTRL_REG_UPDATE_MASK);
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Pad Operations
+ */
+
+static struct v4l2_mbus_framefmt *
+xvsw_get_pad_format(struct xvswitch_device *xvsw,
+ struct v4l2_subdev_pad_config *cfg,
+ unsigned int pad, u32 which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_format(&xvsw->subdev, cfg, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &xvsw->formats[pad];
+ default:
+ return NULL;
+ }
+}
+
+static int xvsw_get_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xvswitch_device *xvsw = to_xvsw(subdev);
+ int pad = fmt->pad;
+
+ /*
+ * If control reg routing and pad is source pad then
+ * get corresponding sink pad. if no sink pad then
+ * clear the format and return
+ */
+
+ if (!xvsw->tdest_routing && pad >= xvsw->nsinks) {
+ pad = xvsw->routing[pad - xvsw->nsinks];
+ if (pad < 0) {
+ memset(&fmt->format, 0, sizeof(fmt->format));
+ return 0;
+ }
+ }
+
+ fmt->format = *xvsw_get_pad_format(xvsw, cfg, pad, fmt->which);
+
+ return 0;
+}
+
+static int xvsw_set_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xvswitch_device *xvsw = to_xvsw(subdev);
+ struct v4l2_mbus_framefmt *format;
+
+ if (!xvsw->tdest_routing && fmt->pad >= xvsw->nsinks) {
+ /*
+ * In case of control reg routing,
+ * get the corresponding sink pad to source pad passed.
+ *
+ * The source pad format is always identical to the
+ * sink pad format and can't be modified.
+ *
+ * If sink pad found then get_format for that pad
+ * else clear the fmt->format as the source pad
+ * isn't connected and return.
+ */
+ return xvsw_get_format(subdev, cfg, fmt);
+ }
+
+ /*
+ * In TDEST routing mode, one can set any format on the pad as
+ * it can't be checked which pad's data will travel to
+ * which pad. E.g. In a system with 2 slaves and 4 masters,
+ * S0 or S1 data can reach M0 thru M3 based on TDEST
+ * S0 may have RBG and S1 may have YUV. M0, M1 stream RBG
+ * and M2, M3 stream YUV based on TDEST.
+ *
+ * In Control reg routing mode, set format only for sink pads.
+ */
+ format = xvsw_get_pad_format(xvsw, cfg, fmt->pad, fmt->which);
+
+ format->code = fmt->format.code;
+ format->width = clamp_t(unsigned int, fmt->format.width,
+ XVIP_MIN_WIDTH, XVIP_MAX_WIDTH);
+ format->height = clamp_t(unsigned int, fmt->format.height,
+ XVIP_MIN_HEIGHT, XVIP_MAX_HEIGHT);
+ format->field = V4L2_FIELD_NONE;
+ format->colorspace = V4L2_COLORSPACE_SRGB;
+
+ fmt->format = *format;
+
+ return 0;
+}
+
+static int xvsw_get_routing(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_routing *route)
+{
+ struct xvswitch_device *xvsw = to_xvsw(subdev);
+ unsigned int i;
+ u32 min;
+
+ /* In case of tdest routing, we can't get routing */
+ if (xvsw->tdest_routing)
+ return -EINVAL;
+
+ mutex_lock(&subdev->entity.graph_obj.mdev->graph_mutex);
+
+ if (xvsw->nsources < route->num_routes)
+ min = xvsw->nsources;
+ else
+ min = route->num_routes;
+
+ for (i = 0; i < min; ++i) {
+ route->routes[i].sink = xvsw->routing[i];
+ route->routes[i].source = i;
+ }
+
+ route->num_routes = xvsw->nsources;
+
+ mutex_unlock(&subdev->entity.graph_obj.mdev->graph_mutex);
+
+ return 0;
+}
+
+static int xvsw_set_routing(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_routing *route)
+{
+ struct xvswitch_device *xvsw = to_xvsw(subdev);
+ unsigned int i;
+ int ret = 0;
+
+ /* In case of tdest routing, we can't set routing */
+ if (xvsw->tdest_routing)
+ return -EINVAL;
+
+ mutex_lock(&subdev->entity.graph_obj.mdev->graph_mutex);
+
+ if (subdev->entity.stream_count) {
+ ret = -EBUSY;
+ goto done;
+ }
+
+ for (i = 0; i < xvsw->nsources; ++i)
+ xvsw->routing[i] = -1;
+
+ for (i = 0; i < route->num_routes; ++i)
+ xvsw->routing[route->routes[i].source - xvsw->nsinks] =
+ route->routes[i].sink;
+
+done:
+ mutex_unlock(&subdev->entity.graph_obj.mdev->graph_mutex);
+ return ret;
+}
+
+static int xvsw_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ return 0;
+}
+
+static int xvsw_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ return 0;
+}
+
+static struct v4l2_subdev_video_ops xvsw_video_ops = {
+ .s_stream = xvsw_s_stream,
+};
+
+static struct v4l2_subdev_pad_ops xvsw_pad_ops = {
+ .enum_mbus_code = xvip_enum_mbus_code,
+ .enum_frame_size = xvip_enum_frame_size,
+ .get_fmt = xvsw_get_format,
+ .set_fmt = xvsw_set_format,
+ .get_routing = xvsw_get_routing,
+ .set_routing = xvsw_set_routing,
+};
+
+static struct v4l2_subdev_ops xvsw_ops = {
+ .video = &xvsw_video_ops,
+ .pad = &xvsw_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops xvsw_internal_ops = {
+ .open = xvsw_open,
+ .close = xvsw_close,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media Operations
+ */
+
+static bool xvsw_has_route(struct media_entity *entity, unsigned int pad0,
+ unsigned int pad1)
+{
+ struct xvswitch_device *xvsw =
+ container_of(entity, struct xvswitch_device, subdev.entity);
+ unsigned int sink0, sink1;
+
+ /* Two sinks are never connected together. */
+ if (pad0 < xvsw->nsinks && pad1 < xvsw->nsinks)
+ return false;
+
+ /* In TDEST routing, assume all sinks and sources are connected */
+ if (xvsw->tdest_routing)
+ return true;
+
+ sink0 = pad0 < xvsw->nsinks ? pad0 : xvsw->routing[pad0 - xvsw->nsinks];
+ sink1 = pad1 < xvsw->nsinks ? pad1 : xvsw->routing[pad1 - xvsw->nsinks];
+
+ return sink0 == sink1;
+}
+
+static const struct media_entity_operations xvsw_media_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+ .has_route = xvsw_has_route,
+};
+
+/* -----------------------------------------------------------------------------
+ * Platform Device Driver
+ */
+
+static int xvsw_parse_of(struct xvswitch_device *xvsw)
+{
+ struct device_node *node = xvsw->dev->of_node;
+ struct device_node *ports;
+ struct device_node *port;
+ unsigned int nports = 0;
+ u32 routing_mode;
+ int ret;
+
+ ret = of_property_read_u32(node, "xlnx,num-si-slots", &xvsw->nsinks);
+ if (ret < 0 || xvsw->nsinks < MIN_VSW_SINKS ||
+ xvsw->nsinks > MAX_VSW_SINKS) {
+ dev_err(xvsw->dev, "missing or invalid xlnx,num-si-slots property\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32(node, "xlnx,num-mi-slots", &xvsw->nsources);
+ if (ret < 0 || xvsw->nsources < MIN_VSW_SRCS ||
+ xvsw->nsources > MAX_VSW_SRCS) {
+ dev_err(xvsw->dev, "missing or invalid xlnx,num-mi-slots property\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32(node, "xlnx,routing-mode", &routing_mode);
+ if (ret < 0 || routing_mode < 0 || routing_mode > 1) {
+ dev_err(xvsw->dev, "missing or invalid xlnx,routing property\n");
+ return ret;
+ }
+
+ if (!routing_mode)
+ xvsw->tdest_routing = true;
+
+ xvsw->aclk = devm_clk_get(xvsw->dev, "aclk");
+ if (IS_ERR(xvsw->aclk)) {
+ ret = PTR_ERR(xvsw->aclk);
+ dev_err(xvsw->dev, "failed to get ap_clk (%d)\n", ret);
+ return ret;
+ }
+
+ if (!xvsw->tdest_routing) {
+ xvsw->saxi_ctlclk = devm_clk_get(xvsw->dev,
+ "s_axi_ctl_clk");
+ if (IS_ERR(xvsw->saxi_ctlclk)) {
+ ret = PTR_ERR(xvsw->saxi_ctlclk);
+ dev_err(xvsw->dev,
+ "failed to get s_axi_ctl_clk (%d)\n",
+ ret);
+ return ret;
+ }
+ }
+
+ if (xvsw->tdest_routing && xvsw->nsinks > 1) {
+ dev_err(xvsw->dev, "sinks = %d. Driver Limitation max 1 sink in TDEST routing mode\n",
+ xvsw->nsinks);
+ return -EINVAL;
+ }
+
+ ports = of_get_child_by_name(node, "ports");
+ if (!ports)
+ ports = node;
+
+ for_each_child_of_node(ports, port) {
+ struct device_node *endpoint;
+
+ if (!port->name || of_node_cmp(port->name, "port"))
+ continue;
+
+ endpoint = of_get_next_child(port, NULL);
+ if (!endpoint) {
+ dev_err(xvsw->dev, "No port at\n");
+ return -EINVAL;
+ }
+
+ /* Count the number of ports. */
+ nports++;
+ }
+
+ /* validate number of ports */
+ if (nports != (xvsw->nsinks + xvsw->nsources)) {
+ dev_err(xvsw->dev, "invalid number of ports %u\n", nports);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int xvsw_probe(struct platform_device *pdev)
+{
+ struct v4l2_subdev *subdev;
+ struct xvswitch_device *xvsw;
+ struct resource *res;
+ unsigned int npads;
+ unsigned int i, padcount;
+ int ret;
+
+ xvsw = devm_kzalloc(&pdev->dev, sizeof(*xvsw), GFP_KERNEL);
+ if (!xvsw)
+ return -ENOMEM;
+
+ xvsw->dev = &pdev->dev;
+
+ ret = xvsw_parse_of(xvsw);
+ if (ret < 0)
+ return ret;
+
+ /* ioremap only if control reg based routing */
+ if (!xvsw->tdest_routing) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ xvsw->iomem = devm_ioremap_resource(xvsw->dev, res);
+ if (IS_ERR(xvsw->iomem))
+ return PTR_ERR(xvsw->iomem);
+ }
+
+ /*
+ * Initialize V4L2 subdevice and media entity. Pad numbers depend on the
+ * number of pads.
+ */
+ npads = xvsw->nsinks + xvsw->nsources;
+ xvsw->pads = devm_kzalloc(&pdev->dev, npads * sizeof(*xvsw->pads),
+ GFP_KERNEL);
+ if (!xvsw->pads)
+ return -ENOMEM;
+
+ for (i = 0; i < xvsw->nsinks; ++i)
+ xvsw->pads[i].flags = MEDIA_PAD_FL_SINK;
+
+ for (; i < npads; ++i)
+ xvsw->pads[i].flags = MEDIA_PAD_FL_SOURCE;
+
+ padcount = xvsw->tdest_routing ? npads : xvsw->nsinks;
+
+ /*
+ * In case of tdest routing, allocate format per pad.
+ * source pad format has to match one of the sink pads in tdest routing.
+ *
+ * Otherwise only allocate for sinks as sources will
+ * get the same pad format and corresponding sink.
+ * set format on src pad will return corresponding sinks data.
+ */
+ xvsw->formats = devm_kzalloc(&pdev->dev,
+ padcount * sizeof(*xvsw->formats),
+ GFP_KERNEL);
+ if (!xvsw->formats) {
+ dev_err(xvsw->dev, "No memory to allocate formats!\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < padcount; i++) {
+ xvsw->formats[i].code = MEDIA_BUS_FMT_RGB888_1X24;
+ xvsw->formats[i].field = V4L2_FIELD_NONE;
+ xvsw->formats[i].colorspace = V4L2_COLORSPACE_SRGB;
+ xvsw->formats[i].width = XVIP_MAX_WIDTH;
+ xvsw->formats[i].height = XVIP_MAX_HEIGHT;
+ }
+
+ /*
+ * Initialize the routing table if none are connected.
+ * Routing table is valid only incase routing is not TDEST based.
+ */
+ for (i = 0; i < MAX_VSW_SRCS; ++i)
+ xvsw->routing[i] = -1;
+
+ ret = clk_prepare_enable(xvsw->aclk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable aclk (%d)\n",
+ ret);
+ return ret;
+ }
+
+ if (!xvsw->tdest_routing) {
+ ret = clk_prepare_enable(xvsw->saxi_ctlclk);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "failed to enable s_axi_ctl_clk (%d)\n",
+ ret);
+ clk_disable_unprepare(xvsw->aclk);
+ return ret;
+ }
+ }
+
+ subdev = &xvsw->subdev;
+ v4l2_subdev_init(subdev, &xvsw_ops);
+ subdev->dev = &pdev->dev;
+ subdev->internal_ops = &xvsw_internal_ops;
+ strlcpy(subdev->name, dev_name(&pdev->dev), sizeof(subdev->name));
+ v4l2_set_subdevdata(subdev, xvsw);
+ subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ subdev->entity.ops = &xvsw_media_ops;
+
+ ret = media_entity_pads_init(&subdev->entity, npads, xvsw->pads);
+ if (ret < 0)
+ goto clk_error;
+
+ platform_set_drvdata(pdev, xvsw);
+
+ ret = v4l2_async_register_subdev(subdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to register subdev\n");
+ goto error;
+ }
+
+ dev_info(xvsw->dev, "Xilinx AXI4-Stream Switch found!\n");
+
+ return 0;
+
+error:
+ media_entity_cleanup(&subdev->entity);
+clk_error:
+ if (!xvsw->tdest_routing)
+ clk_disable_unprepare(xvsw->saxi_ctlclk);
+ clk_disable_unprepare(xvsw->aclk);
+ return ret;
+}
+
+static int xvsw_remove(struct platform_device *pdev)
+{
+ struct xvswitch_device *xvsw = platform_get_drvdata(pdev);
+ struct v4l2_subdev *subdev = &xvsw->subdev;
+
+ v4l2_async_unregister_subdev(subdev);
+ media_entity_cleanup(&subdev->entity);
+ if (!xvsw->tdest_routing)
+ clk_disable_unprepare(xvsw->saxi_ctlclk);
+ clk_disable_unprepare(xvsw->aclk);
+ return 0;
+}
+
+static const struct of_device_id xvsw_of_id_table[] = {
+ { .compatible = "xlnx,axis-switch-1.1" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, xvsw_of_id_table);
+
+static struct platform_driver xvsw_driver = {
+ .driver = {
+ .name = "xilinx-axis-switch",
+ .of_match_table = xvsw_of_id_table,
+ },
+ .probe = xvsw_probe,
+ .remove = xvsw_remove,
+};
+
+module_platform_driver(xvsw_driver);
+
+MODULE_AUTHOR("Vishal Sagar <vishal.sagar@xilinx.com>");
+MODULE_DESCRIPTION("Xilinx AXI4-Stream Switch Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/xilinx/xilinx-cfa.c b/drivers/media/platform/xilinx/xilinx-cfa.c
new file mode 100644
index 000000000000..832fb7306563
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-cfa.c
@@ -0,0 +1,394 @@
+/*
+ * Xilinx Color Filter Array
+ *
+ * Copyright (C) 2013-2015 Ideas on Board
+ * Copyright (C) 2013-2015 Xilinx, Inc.
+ *
+ * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
+ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include <media/v4l2-async.h>
+#include <media/v4l2-subdev.h>
+
+#include "xilinx-vip.h"
+
+#define XCFA_BAYER_PHASE 0x100
+#define XCFA_BAYER_PHASE_RGGB 0
+#define XCFA_BAYER_PHASE_GRBG 1
+#define XCFA_BAYER_PHASE_GBRG 2
+#define XCFA_BAYER_PHASE_BGGR 3
+
+/**
+ * struct xcfa_device - Xilinx CFA device structure
+ * @xvip: Xilinx Video IP device
+ * @pads: media pads
+ * @formats: V4L2 media bus formats
+ * @default_formats: default V4L2 media bus formats
+ * @vip_formats: Xilinx Video IP formats
+ */
+struct xcfa_device {
+ struct xvip_device xvip;
+
+ struct media_pad pads[2];
+
+ struct v4l2_mbus_framefmt formats[2];
+ struct v4l2_mbus_framefmt default_formats[2];
+ const struct xvip_video_format *vip_formats[2];
+};
+
+static inline struct xcfa_device *to_cfa(struct v4l2_subdev *subdev)
+{
+ return container_of(subdev, struct xcfa_device, xvip.subdev);
+}
+
+/*
+ * V4L2 Subdevice Video Operations
+ */
+
+static int xcfa_get_bayer_phase(const unsigned int code)
+{
+ switch (code) {
+ case MEDIA_BUS_FMT_SRGGB8_1X8:
+ return XCFA_BAYER_PHASE_RGGB;
+ case MEDIA_BUS_FMT_SGRBG8_1X8:
+ return XCFA_BAYER_PHASE_GRBG;
+ case MEDIA_BUS_FMT_SGBRG8_1X8:
+ return XCFA_BAYER_PHASE_GBRG;
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
+ return XCFA_BAYER_PHASE_BGGR;
+ }
+
+ return -EINVAL;
+}
+
+static int xcfa_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+ struct xcfa_device *xcfa = to_cfa(subdev);
+ const unsigned int code = xcfa->formats[XVIP_PAD_SINK].code;
+ u32 bayer_phase;
+
+ if (!enable) {
+ xvip_stop(&xcfa->xvip);
+ return 0;
+ }
+
+ /* This always returns the valid bayer phase value */
+ bayer_phase = xcfa_get_bayer_phase(code);
+
+ xvip_write(&xcfa->xvip, XCFA_BAYER_PHASE, bayer_phase);
+
+ xvip_set_frame_size(&xcfa->xvip, &xcfa->formats[XVIP_PAD_SINK]);
+
+ xvip_start(&xcfa->xvip);
+
+ return 0;
+}
+
+/*
+ * V4L2 Subdevice Pad Operations
+ */
+
+static struct v4l2_mbus_framefmt *
+__xcfa_get_pad_format(struct xcfa_device *xcfa,
+ struct v4l2_subdev_pad_config *cfg,
+ unsigned int pad, u32 which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_format(&xcfa->xvip.subdev, cfg, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &xcfa->formats[pad];
+ default:
+ return NULL;
+ }
+}
+
+static int xcfa_get_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xcfa_device *xcfa = to_cfa(subdev);
+
+ fmt->format = *__xcfa_get_pad_format(xcfa, cfg, fmt->pad, fmt->which);
+
+ return 0;
+}
+
+static int xcfa_set_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xcfa_device *xcfa = to_cfa(subdev);
+ struct v4l2_mbus_framefmt *format;
+ int bayer_phase;
+
+ format = __xcfa_get_pad_format(xcfa, cfg, fmt->pad, fmt->which);
+
+ if (fmt->pad == XVIP_PAD_SOURCE) {
+ fmt->format = *format;
+ return 0;
+ }
+
+ bayer_phase = xcfa_get_bayer_phase(fmt->format.code);
+ if (bayer_phase >= 0) {
+ xcfa->vip_formats[XVIP_PAD_SINK] =
+ xvip_get_format_by_code(fmt->format.code);
+ format->code = fmt->format.code;
+ }
+
+ xvip_set_format_size(format, fmt);
+
+ fmt->format = *format;
+
+ /* Propagate the format to the source pad */
+ format = __xcfa_get_pad_format(xcfa, cfg, XVIP_PAD_SOURCE, fmt->which);
+
+ xvip_set_format_size(format, fmt);
+
+ return 0;
+}
+
+/*
+ * V4L2 Subdevice Operations
+ */
+
+static int xcfa_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ struct xcfa_device *xcfa = to_cfa(subdev);
+ struct v4l2_mbus_framefmt *format;
+
+ /* Initialize with default formats */
+ format = v4l2_subdev_get_try_format(subdev, fh->pad, XVIP_PAD_SINK);
+ *format = xcfa->default_formats[XVIP_PAD_SINK];
+
+ format = v4l2_subdev_get_try_format(subdev, fh->pad, XVIP_PAD_SOURCE);
+ *format = xcfa->default_formats[XVIP_PAD_SOURCE];
+
+ return 0;
+}
+
+static int xcfa_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ return 0;
+}
+
+static struct v4l2_subdev_video_ops xcfa_video_ops = {
+ .s_stream = xcfa_s_stream,
+};
+
+static struct v4l2_subdev_pad_ops xcfa_pad_ops = {
+ .enum_mbus_code = xvip_enum_mbus_code,
+ .enum_frame_size = xvip_enum_frame_size,
+ .get_fmt = xcfa_get_format,
+ .set_fmt = xcfa_set_format,
+};
+
+static struct v4l2_subdev_ops xcfa_ops = {
+ .video = &xcfa_video_ops,
+ .pad = &xcfa_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops xcfa_internal_ops = {
+ .open = xcfa_open,
+ .close = xcfa_close,
+};
+
+/*
+ * Media Operations
+ */
+
+static const struct media_entity_operations xcfa_media_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+/*
+ * Power Management
+ */
+
+static int __maybe_unused xcfa_pm_suspend(struct device *dev)
+{
+ struct xcfa_device *xcfa = dev_get_drvdata(dev);
+
+ xvip_suspend(&xcfa->xvip);
+
+ return 0;
+}
+
+static int __maybe_unused xcfa_pm_resume(struct device *dev)
+{
+ struct xcfa_device *xcfa = dev_get_drvdata(dev);
+
+ xvip_resume(&xcfa->xvip);
+
+ return 0;
+}
+
+/*
+ * Platform Device Driver
+ */
+
+static int xcfa_parse_of(struct xcfa_device *xcfa)
+{
+ struct device *dev = xcfa->xvip.dev;
+ struct device_node *node = xcfa->xvip.dev->of_node;
+ struct device_node *ports;
+ struct device_node *port;
+ u32 port_id;
+ int ret;
+
+ ports = of_get_child_by_name(node, "ports");
+ if (ports == NULL)
+ ports = node;
+
+ /* Get the format description for each pad */
+ for_each_child_of_node(ports, port) {
+ if (port->name && (of_node_cmp(port->name, "port") == 0)) {
+ const struct xvip_video_format *vip_format;
+
+ vip_format = xvip_of_get_format(port);
+ if (IS_ERR(vip_format)) {
+ dev_err(dev, "invalid format in DT");
+ return PTR_ERR(vip_format);
+ }
+
+ ret = of_property_read_u32(port, "reg", &port_id);
+ if (ret < 0) {
+ dev_err(dev, "no reg in DT");
+ return ret;
+ }
+
+ if (port_id != 0 && port_id != 1) {
+ dev_err(dev, "invalid reg in DT");
+ return -EINVAL;
+ }
+
+ xcfa->vip_formats[port_id] = vip_format;
+ }
+ }
+
+ return 0;
+}
+
+static int xcfa_probe(struct platform_device *pdev)
+{
+ struct xcfa_device *xcfa;
+ struct v4l2_subdev *subdev;
+ struct v4l2_mbus_framefmt *default_format;
+ int ret;
+
+ xcfa = devm_kzalloc(&pdev->dev, sizeof(*xcfa), GFP_KERNEL);
+ if (!xcfa)
+ return -ENOMEM;
+
+ xcfa->xvip.dev = &pdev->dev;
+
+ ret = xcfa_parse_of(xcfa);
+ if (ret < 0)
+ return ret;
+
+ ret = xvip_init_resources(&xcfa->xvip);
+ if (ret < 0)
+ return ret;
+
+ /* Reset and initialize the core */
+ xvip_reset(&xcfa->xvip);
+
+ /* Initialize V4L2 subdevice and media entity */
+ subdev = &xcfa->xvip.subdev;
+ v4l2_subdev_init(subdev, &xcfa_ops);
+ subdev->dev = &pdev->dev;
+ subdev->internal_ops = &xcfa_internal_ops;
+ strlcpy(subdev->name, dev_name(&pdev->dev), sizeof(subdev->name));
+ v4l2_set_subdevdata(subdev, xcfa);
+ subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ /* Initialize default and active formats */
+ default_format = &xcfa->default_formats[XVIP_PAD_SINK];
+ default_format->code = xcfa->vip_formats[XVIP_PAD_SINK]->code;
+ default_format->field = V4L2_FIELD_NONE;
+ default_format->colorspace = V4L2_COLORSPACE_SRGB;
+ xvip_get_frame_size(&xcfa->xvip, default_format);
+
+ xcfa->formats[XVIP_PAD_SINK] = *default_format;
+
+ default_format = &xcfa->default_formats[XVIP_PAD_SOURCE];
+ *default_format = xcfa->default_formats[XVIP_PAD_SINK];
+ default_format->code = xcfa->vip_formats[XVIP_PAD_SOURCE]->code;
+
+ xcfa->formats[XVIP_PAD_SOURCE] = *default_format;
+
+ xcfa->pads[XVIP_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ xcfa->pads[XVIP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ subdev->entity.ops = &xcfa_media_ops;
+ ret = media_entity_pads_init(&subdev->entity, 2, xcfa->pads);
+ if (ret < 0)
+ goto error;
+
+ platform_set_drvdata(pdev, xcfa);
+
+ xvip_print_version(&xcfa->xvip);
+
+ ret = v4l2_async_register_subdev(subdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to register subdev\n");
+ goto error;
+ }
+
+ return 0;
+
+error:
+ media_entity_cleanup(&subdev->entity);
+ xvip_cleanup_resources(&xcfa->xvip);
+ return ret;
+}
+
+static int xcfa_remove(struct platform_device *pdev)
+{
+ struct xcfa_device *xcfa = platform_get_drvdata(pdev);
+ struct v4l2_subdev *subdev = &xcfa->xvip.subdev;
+
+ v4l2_async_unregister_subdev(subdev);
+ media_entity_cleanup(&subdev->entity);
+
+ xvip_cleanup_resources(&xcfa->xvip);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(xcfa_pm_ops, xcfa_pm_suspend, xcfa_pm_resume);
+
+static const struct of_device_id xcfa_of_id_table[] = {
+ { .compatible = "xlnx,v-cfa-7.0" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, xcfa_of_id_table);
+
+static struct platform_driver xcfa_driver = {
+ .driver = {
+ .name = "xilinx-cfa",
+ .pm = &xcfa_pm_ops,
+ .of_match_table = xcfa_of_id_table,
+ },
+ .probe = xcfa_probe,
+ .remove = xcfa_remove,
+};
+
+module_platform_driver(xcfa_driver);
+
+MODULE_DESCRIPTION("Xilinx Color Filter Array Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/xilinx/xilinx-cresample.c b/drivers/media/platform/xilinx/xilinx-cresample.c
new file mode 100644
index 000000000000..05335c10a388
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-cresample.c
@@ -0,0 +1,447 @@
+/*
+ * Xilinx Chroma Resampler
+ *
+ * Copyright (C) 2013-2015 Ideas on Board
+ * Copyright (C) 2013-2015 Xilinx, Inc.
+ *
+ * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
+ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/xilinx-v4l2-controls.h>
+
+#include <media/v4l2-async.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
+
+#include "xilinx-vip.h"
+
+#define XCRESAMPLE_ENCODING 0x100
+#define XCRESAMPLE_ENCODING_FIELD (1 << 7)
+#define XCRESAMPLE_ENCODING_CHROMA (1 << 8)
+
+/**
+ * struct xcresample_device - Xilinx CRESAMPLE device structure
+ * @xvip: Xilinx Video IP device
+ * @pads: media pads
+ * @formats: V4L2 media bus formats at the sink and source pads
+ * @default_formats: default V4L2 media bus formats
+ * @vip_formats: Xilinx Video IP formats
+ * @ctrl_handler: control handler
+ */
+struct xcresample_device {
+ struct xvip_device xvip;
+
+ struct media_pad pads[2];
+
+ struct v4l2_mbus_framefmt formats[2];
+ struct v4l2_mbus_framefmt default_formats[2];
+ const struct xvip_video_format *vip_formats[2];
+
+ struct v4l2_ctrl_handler ctrl_handler;
+};
+
+static inline struct xcresample_device *to_cresample(struct v4l2_subdev *subdev)
+{
+ return container_of(subdev, struct xcresample_device, xvip.subdev);
+}
+
+/*
+ * V4L2 Subdevice Video Operations
+ */
+
+static int xcresample_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+ struct xcresample_device *xcresample = to_cresample(subdev);
+
+ if (!enable) {
+ xvip_stop(&xcresample->xvip);
+ return 0;
+ }
+
+ xvip_set_frame_size(&xcresample->xvip,
+ &xcresample->formats[XVIP_PAD_SINK]);
+
+ xvip_start(&xcresample->xvip);
+
+ return 0;
+}
+
+/*
+ * V4L2 Subdevice Pad Operations
+ */
+
+static struct v4l2_mbus_framefmt *
+__xcresample_get_pad_format(struct xcresample_device *xcresample,
+ struct v4l2_subdev_pad_config *cfg,
+ unsigned int pad, u32 which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_format(&xcresample->xvip.subdev, cfg,
+ pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &xcresample->formats[pad];
+ default:
+ return NULL;
+ }
+}
+
+static int xcresample_get_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xcresample_device *xcresample = to_cresample(subdev);
+
+ fmt->format = *__xcresample_get_pad_format(xcresample, cfg, fmt->pad,
+ fmt->which);
+
+ return 0;
+}
+
+static int xcresample_set_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xcresample_device *xcresample = to_cresample(subdev);
+ struct v4l2_mbus_framefmt *format;
+
+ format = __xcresample_get_pad_format(xcresample, cfg, fmt->pad,
+ fmt->which);
+
+ if (fmt->pad == XVIP_PAD_SOURCE) {
+ fmt->format = *format;
+ return 0;
+ }
+
+ xvip_set_format_size(format, fmt);
+
+ fmt->format = *format;
+
+ /* Propagate the format to the source pad. */
+ format = __xcresample_get_pad_format(xcresample, cfg, XVIP_PAD_SOURCE,
+ fmt->which);
+
+ xvip_set_format_size(format, fmt);
+
+ return 0;
+}
+
+/*
+ * V4L2 Subdevice Operations
+ */
+
+static int xcresample_open(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh)
+{
+ struct xcresample_device *xcresample = to_cresample(subdev);
+ struct v4l2_mbus_framefmt *format;
+
+ /* Initialize with default formats */
+ format = v4l2_subdev_get_try_format(subdev, fh->pad, XVIP_PAD_SINK);
+ *format = xcresample->default_formats[XVIP_PAD_SINK];
+
+ format = v4l2_subdev_get_try_format(subdev, fh->pad, XVIP_PAD_SOURCE);
+ *format = xcresample->default_formats[XVIP_PAD_SOURCE];
+
+ return 0;
+}
+
+static int xcresample_close(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh)
+{
+ return 0;
+}
+
+static int xcresample_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct xcresample_device *xcresample =
+ container_of(ctrl->handler, struct xcresample_device,
+ ctrl_handler);
+ switch (ctrl->id) {
+ case V4L2_CID_XILINX_CRESAMPLE_FIELD_PARITY:
+ xvip_clr_or_set(&xcresample->xvip, XCRESAMPLE_ENCODING,
+ XCRESAMPLE_ENCODING_FIELD, ctrl->val);
+ return 0;
+ case V4L2_CID_XILINX_CRESAMPLE_CHROMA_PARITY:
+ xvip_clr_or_set(&xcresample->xvip, XCRESAMPLE_ENCODING,
+ XCRESAMPLE_ENCODING_CHROMA, ctrl->val);
+ return 0;
+ }
+
+ return -EINVAL;
+
+}
+
+static const struct v4l2_ctrl_ops xcresample_ctrl_ops = {
+ .s_ctrl = xcresample_s_ctrl,
+};
+
+static struct v4l2_subdev_video_ops xcresample_video_ops = {
+ .s_stream = xcresample_s_stream,
+};
+
+static struct v4l2_subdev_pad_ops xcresample_pad_ops = {
+ .enum_mbus_code = xvip_enum_mbus_code,
+ .enum_frame_size = xvip_enum_frame_size,
+ .get_fmt = xcresample_get_format,
+ .set_fmt = xcresample_set_format,
+};
+
+static struct v4l2_subdev_ops xcresample_ops = {
+ .video = &xcresample_video_ops,
+ .pad = &xcresample_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops xcresample_internal_ops = {
+ .open = xcresample_open,
+ .close = xcresample_close,
+};
+
+/*
+ * Control Configs
+ */
+
+static const char *const xcresample_parity_string[] = {
+ "Even",
+ "Odd",
+};
+
+static struct v4l2_ctrl_config xcresample_field = {
+ .ops = &xcresample_ctrl_ops,
+ .id = V4L2_CID_XILINX_CRESAMPLE_FIELD_PARITY,
+ .name = "Chroma Resampler: Encoding Field Parity",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .min = 0,
+ .max = 1,
+ .qmenu = xcresample_parity_string,
+};
+
+static struct v4l2_ctrl_config xcresample_chroma = {
+ .ops = &xcresample_ctrl_ops,
+ .id = V4L2_CID_XILINX_CRESAMPLE_CHROMA_PARITY,
+ .name = "Chroma Resampler: Encoding Chroma Parity",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .min = 0,
+ .max = 1,
+ .qmenu = xcresample_parity_string,
+};
+
+/*
+ * Media Operations
+ */
+
+static const struct media_entity_operations xcresample_media_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+/*
+ * Power Management
+ */
+
+static int __maybe_unused xcresample_pm_suspend(struct device *dev)
+{
+ struct xcresample_device *xcresample = dev_get_drvdata(dev);
+
+ xvip_suspend(&xcresample->xvip);
+
+ return 0;
+}
+
+static int __maybe_unused xcresample_pm_resume(struct device *dev)
+{
+ struct xcresample_device *xcresample = dev_get_drvdata(dev);
+
+ xvip_resume(&xcresample->xvip);
+
+ return 0;
+}
+
+/*
+ * Platform Device Driver
+ */
+
+static int xcresample_parse_of(struct xcresample_device *xcresample)
+{
+ struct device *dev = xcresample->xvip.dev;
+ struct device_node *node = xcresample->xvip.dev->of_node;
+ struct device_node *ports;
+ struct device_node *port;
+ u32 port_id;
+ int ret;
+
+ ports = of_get_child_by_name(node, "ports");
+ if (ports == NULL)
+ ports = node;
+
+ /* Get the format description for each pad */
+ for_each_child_of_node(ports, port) {
+ if (port->name && (of_node_cmp(port->name, "port") == 0)) {
+ const struct xvip_video_format *vip_format;
+
+ vip_format = xvip_of_get_format(port);
+ if (IS_ERR(vip_format)) {
+ dev_err(dev, "invalid format in DT");
+ return PTR_ERR(vip_format);
+ }
+
+ ret = of_property_read_u32(port, "reg", &port_id);
+ if (ret < 0) {
+ dev_err(dev, "no reg in DT");
+ return ret;
+ }
+
+ if (port_id != 0 && port_id != 1) {
+ dev_err(dev, "invalid reg in DT");
+ return -EINVAL;
+ }
+
+ xcresample->vip_formats[port_id] = vip_format;
+ }
+ }
+
+ return 0;
+}
+
+static int xcresample_probe(struct platform_device *pdev)
+{
+ struct xcresample_device *xcresample;
+ struct v4l2_subdev *subdev;
+ struct v4l2_mbus_framefmt *default_format;
+ int ret;
+
+ xcresample = devm_kzalloc(&pdev->dev, sizeof(*xcresample), GFP_KERNEL);
+ if (!xcresample)
+ return -ENOMEM;
+
+ xcresample->xvip.dev = &pdev->dev;
+
+ ret = xcresample_parse_of(xcresample);
+ if (ret < 0)
+ return ret;
+
+ ret = xvip_init_resources(&xcresample->xvip);
+ if (ret < 0)
+ return ret;
+
+ /* Reset and initialize the core */
+ xvip_reset(&xcresample->xvip);
+
+ /* Initialize V4L2 subdevice and media entity */
+ subdev = &xcresample->xvip.subdev;
+ v4l2_subdev_init(subdev, &xcresample_ops);
+ subdev->dev = &pdev->dev;
+ subdev->internal_ops = &xcresample_internal_ops;
+ strlcpy(subdev->name, dev_name(&pdev->dev), sizeof(subdev->name));
+ v4l2_set_subdevdata(subdev, xcresample);
+ subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ /* Initialize default and active formats */
+ default_format = &xcresample->default_formats[XVIP_PAD_SINK];
+ default_format->code = xcresample->vip_formats[XVIP_PAD_SINK]->code;
+ default_format->field = V4L2_FIELD_NONE;
+ default_format->colorspace = V4L2_COLORSPACE_SRGB;
+ xvip_get_frame_size(&xcresample->xvip, default_format);
+
+ xcresample->formats[XVIP_PAD_SINK] = *default_format;
+
+ default_format = &xcresample->default_formats[XVIP_PAD_SOURCE];
+ *default_format = xcresample->default_formats[XVIP_PAD_SINK];
+ default_format->code = xcresample->vip_formats[XVIP_PAD_SOURCE]->code;
+
+ xcresample->formats[XVIP_PAD_SOURCE] = *default_format;
+
+ xcresample->pads[XVIP_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ xcresample->pads[XVIP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ subdev->entity.ops = &xcresample_media_ops;
+ ret = media_entity_pads_init(&subdev->entity, 2, xcresample->pads);
+ if (ret < 0)
+ goto error;
+
+ v4l2_ctrl_handler_init(&xcresample->ctrl_handler, 2);
+ xcresample_field.def =
+ (xvip_read(&xcresample->xvip, XCRESAMPLE_ENCODING) &
+ XCRESAMPLE_ENCODING_FIELD) ? 1 : 0;
+ v4l2_ctrl_new_custom(&xcresample->ctrl_handler, &xcresample_field,
+ NULL);
+ xcresample_chroma.def =
+ (xvip_read(&xcresample->xvip, XCRESAMPLE_ENCODING) &
+ XCRESAMPLE_ENCODING_CHROMA) ? 1 : 0;
+ v4l2_ctrl_new_custom(&xcresample->ctrl_handler, &xcresample_chroma,
+ NULL);
+ if (xcresample->ctrl_handler.error) {
+ dev_err(&pdev->dev, "failed to add controls\n");
+ ret = xcresample->ctrl_handler.error;
+ goto error;
+ }
+ subdev->ctrl_handler = &xcresample->ctrl_handler;
+
+ platform_set_drvdata(pdev, xcresample);
+
+ xvip_print_version(&xcresample->xvip);
+
+ ret = v4l2_async_register_subdev(subdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to register subdev\n");
+ goto error;
+ }
+
+ return 0;
+
+error:
+ v4l2_ctrl_handler_free(&xcresample->ctrl_handler);
+ media_entity_cleanup(&subdev->entity);
+ xvip_cleanup_resources(&xcresample->xvip);
+ return ret;
+}
+
+static int xcresample_remove(struct platform_device *pdev)
+{
+ struct xcresample_device *xcresample = platform_get_drvdata(pdev);
+ struct v4l2_subdev *subdev = &xcresample->xvip.subdev;
+
+ v4l2_async_unregister_subdev(subdev);
+ v4l2_ctrl_handler_free(&xcresample->ctrl_handler);
+ media_entity_cleanup(&subdev->entity);
+
+ xvip_cleanup_resources(&xcresample->xvip);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(xcresample_pm_ops, xcresample_pm_suspend,
+ xcresample_pm_resume);
+
+static const struct of_device_id xcresample_of_id_table[] = {
+ { .compatible = "xlnx,v-cresample-4.0" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, xcresample_of_id_table);
+
+static struct platform_driver xcresample_driver = {
+ .driver = {
+ .name = "xilinx-cresample",
+ .pm = &xcresample_pm_ops,
+ .of_match_table = xcresample_of_id_table,
+ },
+ .probe = xcresample_probe,
+ .remove = xcresample_remove,
+};
+
+module_platform_driver(xcresample_driver);
+
+MODULE_DESCRIPTION("Xilinx Chroma Resampler Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/xilinx/xilinx-csi2rxss.c b/drivers/media/platform/xilinx/xilinx-csi2rxss.c
new file mode 100644
index 000000000000..fc58a5268a9e
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-csi2rxss.c
@@ -0,0 +1,2023 @@
+/*
+ * Xilinx MIPI CSI2 Subsystem
+ *
+ * Copyright (C) 2016 Xilinx, Inc.
+ *
+ * Contacts: Vishal Sagar <vsagar@xilinx.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/media/xilinx-vip.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/compiler.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/spinlock_types.h>
+#include <linux/types.h>
+#include <linux/v4l2-subdev.h>
+#include <linux/xilinx-csi2rxss.h>
+#include <linux/xilinx-v4l2-controls.h>
+#include <media/media-entity.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+#include "xilinx-vip.h"
+
+/*
+ * MIPI CSI2 Rx register map, bitmask and offsets
+ */
+#define XCSI_CCR_OFFSET 0x00000000
+#define XCSI_CCR_SOFTRESET_SHIFT 1
+#define XCSI_CCR_COREENB_SHIFT 0
+#define XCSI_CCR_SOFTRESET_MASK BIT(XCSI_CCR_SOFTRESET_SHIFT)
+#define XCSI_CCR_COREENB_MASK BIT(XCSI_CCR_COREENB_SHIFT)
+
+#define XCSI_PCR_OFFSET 0x00000004
+#define XCSI_PCR_MAXLANES_MASK 0x00000018
+#define XCSI_PCR_ACTLANES_MASK 0x00000003
+#define XCSI_PCR_MAXLANES_SHIFT 3
+#define XCSI_PCR_ACTLANES_SHIFT 0
+
+#define XCSI_CSR_OFFSET 0x00000010
+#define XCSI_CSR_PKTCOUNT_SHIFT 16
+#define XCSI_CSR_SPFIFOFULL_SHIFT 3
+#define XCSI_CSR_SPFIFONE_SHIFT 2
+#define XCSI_CSR_SLBF_SHIFT 1
+#define XCSI_CSR_RIPCD_SHIFT 0
+#define XCSI_CSR_PKTCOUNT_MASK 0xFFFF0000
+#define XCSI_CSR_SPFIFOFULL_MASK BIT(XCSI_CSR_SPFIFOFULL_SHIFT)
+#define XCSI_CSR_SPFIFONE_MASK BIT(XCSI_CSR_SPFIFONE_SHIFT)
+#define XCSI_CSR_SLBF_MASK BIT(XCSI_CSR_SLBF_SHIFT)
+#define XCSI_CSR_RIPCD_MASK BIT(XCSI_CSR_RIPCD_SHIFT)
+
+#define XCSI_GIER_OFFSET 0x00000020
+#define XCSI_GIER_GIE_SHIFT 0
+#define XCSI_GIER_GIE_MASK BIT(XCSI_GIER_GIE_SHIFT)
+#define XCSI_GIER_SET 1
+#define XCSI_GIER_RESET 0
+
+#define XCSI_ISR_OFFSET 0x00000024
+#define XCSI_ISR_FR_SHIFT 31
+#define XCSI_ISR_VCX_SHIFT 30
+#define XCSI_ISR_ILC_SHIFT 21
+#define XCSI_ISR_SPFIFOF_SHIFT 20
+#define XCSI_ISR_SPFIFONE_SHIFT 19
+#define XCSI_ISR_SLBF_SHIFT 18
+#define XCSI_ISR_STOP_SHIFT 17
+#define XCSI_ISR_SOTERR_SHIFT 13
+#define XCSI_ISR_SOTSYNCERR_SHIFT 12
+#define XCSI_ISR_ECC2BERR_SHIFT 11
+#define XCSI_ISR_ECC1BERR_SHIFT 10
+#define XCSI_ISR_CRCERR_SHIFT 9
+#define XCSI_ISR_DATAIDERR_SHIFT 8
+#define XCSI_ISR_VC3FSYNCERR_SHIFT 7
+#define XCSI_ISR_VC3FLVLERR_SHIFT 6
+#define XCSI_ISR_VC2FSYNCERR_SHIFT 5
+#define XCSI_ISR_VC2FLVLERR_SHIFT 4
+#define XCSI_ISR_VC1FSYNCERR_SHIFT 3
+#define XCSI_ISR_VC1FLVLERR_SHIFT 2
+#define XCSI_ISR_VC0FSYNCERR_SHIFT 1
+#define XCSI_ISR_VC0FLVLERR_SHIFT 0
+#define XCSI_ISR_FR_MASK BIT(XCSI_ISR_FR_SHIFT)
+#define XCSI_ISR_VCX_MASK BIT(XCSI_ISR_VCX_SHIFT)
+#define XCSI_ISR_ILC_MASK BIT(XCSI_ISR_ILC_SHIFT)
+#define XCSI_ISR_SPFIFOF_MASK BIT(XCSI_ISR_SPFIFOF_SHIFT)
+#define XCSI_ISR_SPFIFONE_MASK BIT(XCSI_ISR_SPFIFONE_SHIFT)
+#define XCSI_ISR_SLBF_MASK BIT(XCSI_ISR_SLBF_SHIFT)
+#define XCSI_ISR_STOP_MASK BIT(XCSI_ISR_STOP_SHIFT)
+#define XCSI_ISR_SOTERR_MASK BIT(XCSI_ISR_SOTERR_SHIFT)
+#define XCSI_ISR_SOTSYNCERR_MASK BIT(XCSI_ISR_SOTSYNCERR_SHIFT)
+#define XCSI_ISR_ECC2BERR_MASK BIT(XCSI_ISR_ECC2BERR_SHIFT)
+#define XCSI_ISR_ECC1BERR_MASK BIT(XCSI_ISR_ECC1BERR_SHIFT)
+#define XCSI_ISR_CRCERR_MASK BIT(XCSI_ISR_CRCERR_SHIFT)
+#define XCSI_ISR_DATAIDERR_MASK BIT(XCSI_ISR_DATAIDERR_SHIFT)
+#define XCSI_ISR_VC3FSYNCERR_MASK BIT(XCSI_ISR_VC3FSYNCERR_SHIFT)
+#define XCSI_ISR_VC3FLVLERR_MASK BIT(XCSI_ISR_VC3FLVLERR_SHIFT)
+#define XCSI_ISR_VC2FSYNCERR_MASK BIT(XCSI_ISR_VC2FSYNCERR_SHIFT)
+#define XCSI_ISR_VC2FLVLERR_MASK BIT(XCSI_ISR_VC2FLVLERR_SHIFT)
+#define XCSI_ISR_VC1FSYNCERR_MASK BIT(XCSI_ISR_VC1FSYNCERR_SHIFT)
+#define XCSI_ISR_VC1FLVLERR_MASK BIT(XCSI_ISR_VC1FLVLERR_SHIFT)
+#define XCSI_ISR_VC0FSYNCERR_MASK BIT(XCSI_ISR_VC0FSYNCERR_SHIFT)
+#define XCSI_ISR_VC0FLVLERR_MASK BIT(XCSI_ISR_VC0FLVLERR_SHIFT)
+#define XCSI_ISR_ALLINTR_MASK 0xC03FFFFF
+
+#define XCSI_INTR_PROT_MASK (XCSI_ISR_VC3FSYNCERR_MASK | \
+ XCSI_ISR_VC3FLVLERR_MASK | \
+ XCSI_ISR_VC2FSYNCERR_MASK | \
+ XCSI_ISR_VC2FLVLERR_MASK | \
+ XCSI_ISR_VC1FSYNCERR_MASK | \
+ XCSI_ISR_VC1FLVLERR_MASK | \
+ XCSI_ISR_VC0FSYNCERR_MASK | \
+ XCSI_ISR_VC0FLVLERR_MASK | \
+ XCSI_ISR_VCX_MASK)
+
+#define XCSI_INTR_PKTLVL_MASK (XCSI_ISR_ECC2BERR_MASK | \
+ XCSI_ISR_ECC1BERR_MASK | \
+ XCSI_ISR_CRCERR_MASK | \
+ XCSI_ISR_DATAIDERR_MASK)
+
+#define XCSI_INTR_DPHY_MASK (XCSI_ISR_SOTERR_MASK | \
+ XCSI_ISR_SOTSYNCERR_MASK)
+
+#define XCSI_INTR_SPKT_MASK (XCSI_ISR_SPFIFOF_MASK | \
+ XCSI_ISR_SPFIFONE_MASK)
+
+#define XCSI_INTR_FRAMERCVD_MASK (XCSI_ISR_FR_MASK)
+
+#define XCSI_INTR_ERR_MASK (XCSI_ISR_ILC_MASK | \
+ XCSI_ISR_SLBF_MASK | \
+ XCSI_ISR_STOP_MASK)
+
+#define XCSI_IER_OFFSET 0x00000028
+#define XCSI_IER_FR_SHIFT 31
+#define XCSI_IER_VCX_SHIFT 30
+#define XCSI_IER_ILC_SHIFT 21
+#define XCSI_IER_SPFIFOF_SHIFT 20
+#define XCSI_IER_SPFIFONE_SHIFT 19
+#define XCSI_IER_SLBF_SHIFT 18
+#define XCSI_IER_STOP_SHIFT 17
+#define XCSI_IER_SOTERR_SHIFT 13
+#define XCSI_IER_SOTSYNCERR_SHIFT 12
+#define XCSI_IER_ECC2BERR_SHIFT 11
+#define XCSI_IER_ECC1BERR_SHIFT 10
+#define XCSI_IER_CRCERR_SHIFT 9
+#define XCSI_IER_DATAIDERR_SHIFT 8
+#define XCSI_IER_VC3FSYNCERR_SHIFT 7
+#define XCSI_IER_VC3FLVLERR_SHIFT 6
+#define XCSI_IER_VC2FSYNCERR_SHIFT 5
+#define XCSI_IER_VC2FLVLERR_SHIFT 4
+#define XCSI_IER_VC1FSYNCERR_SHIFT 3
+#define XCSI_IER_VC1FLVLERR_SHIFT 2
+#define XCSI_IER_VC0FSYNCERR_SHIFT 1
+#define XCSI_IER_VC0FLVLERR_SHIFT 0
+#define XCSI_IER_FR_MASK BIT(XCSI_IER_FR_SHIFT)
+#define XCSI_IER_VCX_MASK BIT(XCSI_IER_VCX_SHIFT)
+#define XCSI_IER_ILC_MASK BIT(XCSI_IER_ILC_SHIFT)
+#define XCSI_IER_SPFIFOF_MASK BIT(XCSI_IER_SPFIFOF_SHIFT)
+#define XCSI_IER_SPFIFONE_MASK BIT(XCSI_IER_SPFIFONE_SHIFT)
+#define XCSI_IER_SLBF_MASK BIT(XCSI_IER_SLBF_SHIFT)
+#define XCSI_IER_STOP_MASK BIT(XCSI_IER_STOP_SHIFT)
+#define XCSI_IER_SOTERR_MASK BIT(XCSI_IER_SOTERR_SHIFT)
+#define XCSI_IER_SOTSYNCERR_MASK BIT(XCSI_IER_SOTSYNCERR_SHIFT)
+#define XCSI_IER_ECC2BERR_MASK BIT(XCSI_IER_ECC2BERR_SHIFT)
+#define XCSI_IER_ECC1BERR_MASK BIT(XCSI_IER_ECC1BERR_SHIFT)
+#define XCSI_IER_CRCERR_MASK BIT(XCSI_IER_CRCERR_SHIFT)
+#define XCSI_IER_DATAIDERR_MASK BIT(XCSI_IER_DATAIDERR_SHIFT)
+#define XCSI_IER_VC3FSYNCERR_MASK BIT(XCSI_IER_VC3FSYNCERR_SHIFT)
+#define XCSI_IER_VC3FLVLERR_MASK BIT(XCSI_IER_VC3FLVLERR_SHIFT)
+#define XCSI_IER_VC2FSYNCERR_MASK BIT(XCSI_IER_VC2FSYNCERR_SHIFT)
+#define XCSI_IER_VC2FLVLERR_MASK BIT(XCSI_IER_VC2FLVLERR_SHIFT)
+#define XCSI_IER_VC1FSYNCERR_MASK BIT(XCSI_IER_VC1FSYNCERR_SHIFT)
+#define XCSI_IER_VC1FLVLERR_MASK BIT(XCSI_IER_VC1FLVLERR_SHIFT)
+#define XCSI_IER_VC0FSYNCERR_MASK BIT(XCSI_IER_VC0FSYNCERR_SHIFT)
+#define XCSI_IER_VC0FLVLERR_MASK BIT(XCSI_IER_VC0FLVLERR_SHIFT)
+#define XCSI_IER_ALLINTR_MASK 0xC03FFFFF
+
+#define XCSI_SPKTR_OFFSET 0x00000030
+#define XCSI_SPKTR_DATA_SHIFT 8
+#define XCSI_SPKTR_VC_SHIFT 6
+#define XCSI_SPKTR_DT_SHIFT 0
+#define XCSI_SPKTR_DATA_MASK 0x00FFFF00
+#define XCSI_SPKTR_VC_MASK 0x000000C0
+#define XCSI_SPKTR_DT_MASK 0x0000003F
+
+#define XCSI_VCXR_OFFSET 0x00000034
+#define XCSI_VCXR_VC15FSYNCERR_MASK BIT(23)
+#define XCSI_VCXR_VC15FLVLERR_MASK BIT(22)
+#define XCSI_VCXR_VC14FSYNCERR_MASK BIT(21)
+#define XCSI_VCXR_VC14FLVLERR_MASK BIT(20)
+#define XCSI_VCXR_VC13FSYNCERR_MASK BIT(19)
+#define XCSI_VCXR_VC13FLVLERR_MASK BIT(18)
+#define XCSI_VCXR_VC12FSYNCERR_MASK BIT(17)
+#define XCSI_VCXR_VC12FLVLERR_MASK BIT(16)
+#define XCSI_VCXR_VC11FSYNCERR_MASK BIT(15)
+#define XCSI_VCXR_VC11FLVLERR_MASK BIT(14)
+#define XCSI_VCXR_VC10FSYNCERR_MASK BIT(13)
+#define XCSI_VCXR_VC10FLVLERR_MASK BIT(12)
+#define XCSI_VCXR_VC9FSYNCERR_MASK BIT(11)
+#define XCSI_VCXR_VC9FLVLERR_MASK BIT(10)
+#define XCSI_VCXR_VC8FSYNCERR_MASK BIT(9)
+#define XCSI_VCXR_VC8FLVLERR_MASK BIT(8)
+#define XCSI_VCXR_VC7FSYNCERR_MASK BIT(7)
+#define XCSI_VCXR_VC7FLVLERR_MASK BIT(6)
+#define XCSI_VCXR_VC6FSYNCERR_MASK BIT(5)
+#define XCSI_VCXR_VC6FLVLERR_MASK BIT(4)
+#define XCSI_VCXR_VC5FSYNCERR_MASK BIT(3)
+#define XCSI_VCXR_VC5FLVLERR_MASK BIT(2)
+#define XCSI_VCXR_VC4FSYNCERR_MASK BIT(1)
+#define XCSI_VCXR_VC4FLVLERR_MASK BIT(0)
+#define XCSI_VCXR_MASK 0x00FFFFFF
+
+#define XCSI_CLKINFR_OFFSET 0x0000003C
+#define XCSI_CLKINFR_STOP_SHIFT 1
+#define XCSI_CLKINFR_STOP_MASK BIT(XCSI_CLKINFR_STOP_SHIFT)
+
+#define XCSI_L0INFR_OFFSET 0x00000040
+#define XCSI_L1INFR_OFFSET 0x00000044
+#define XCSI_L2INFR_OFFSET 0x00000048
+#define XCSI_L3INFR_OFFSET 0x0000004C
+#define XCSI_LXINFR_STOP_SHIFT 5
+#define XCSI_LXINFR_SOTERR_SHIFT 1
+#define XCSI_LXINFR_SOTSYNCERR_SHIFT 0
+#define XCSI_LXINFR_STOP_MASK BIT(XCSI_LXINFR_STOP_SHIFT)
+#define XCSI_LXINFR_SOTERR_MASK BIT(XCSI_LXINFR_SOTERR_SHIFT)
+#define XCSI_LXINFR_SOTSYNCERR_MASK BIT(XCSI_LXINFR_SOTSYNCERR_SHIFT)
+
+#define XCSI_VC0INF1R_OFFSET 0x00000060
+#define XCSI_VC1INF1R_OFFSET 0x00000068
+#define XCSI_VC2INF1R_OFFSET 0x00000070
+#define XCSI_VC3INF1R_OFFSET 0x00000078
+#define XCSI_VC4INF1R_OFFSET 0x00000080
+#define XCSI_VC5INF1R_OFFSET 0x00000088
+#define XCSI_VC6INF1R_OFFSET 0x00000090
+#define XCSI_VC7INF1R_OFFSET 0x00000098
+#define XCSI_VC8INF1R_OFFSET 0x000000A0
+#define XCSI_VC9INF1R_OFFSET 0x000000A8
+#define XCSI_VC10INF1R_OFFSET 0x000000B0
+#define XCSI_VC11INF1R_OFFSET 0x000000B8
+#define XCSI_VC12INF1R_OFFSET 0x000000C0
+#define XCSI_VC13INF1R_OFFSET 0x000000C8
+#define XCSI_VC14INF1R_OFFSET 0x000000D0
+#define XCSI_VC15INF1R_OFFSET 0x000000D8
+#define XCSI_VCXINF1R_LINECOUNT_SHIFT 16
+#define XCSI_VCXINF1R_BYTECOUNT_SHIFT 0
+#define XCSI_VCXINF1R_LINECOUNT_MASK 0xFFFF0000
+#define XCSI_VCXINF1R_BYTECOUNT_MASK 0x0000FFFF
+
+#define XCSI_VC0INF2R_OFFSET 0x00000064
+#define XCSI_VC1INF2R_OFFSET 0x0000006C
+#define XCSI_VC2INF2R_OFFSET 0x00000074
+#define XCSI_VC3INF2R_OFFSET 0x0000007C
+#define XCSI_VC4INF2R_OFFSET 0x00000084
+#define XCSI_VC5INF2R_OFFSET 0x0000008C
+#define XCSI_VC6INF2R_OFFSET 0x00000094
+#define XCSI_VC7INF2R_OFFSET 0x0000009C
+#define XCSI_VC8INF2R_OFFSET 0x000000A4
+#define XCSI_VC9INF2R_OFFSET 0x000000AC
+#define XCSI_VC10INF2R_OFFSET 0x000000B4
+#define XCSI_VC11INF2R_OFFSET 0x000000BC
+#define XCSI_VC12INF2R_OFFSET 0x000000C4
+#define XCSI_VC13INF2R_OFFSET 0x000000CC
+#define XCSI_VC14INF2R_OFFSET 0x000000D4
+#define XCSI_VC15INF2R_OFFSET 0x000000DC
+#define XCSI_VCXINF2R_DATATYPE_SHIFT 0
+#define XCSI_VCXINF2R_DATATYPE_MASK 0x0000003F
+
+#define XDPHY_CTRLREG_OFFSET 0x0
+#define XDPHY_CTRLREG_DPHYEN_SHIFT 1
+#define XDPHY_CTRLREG_DPHYEN_MASK BIT(XDPHY_CTRLREG_DPHYEN_SHIFT)
+
+#define XDPHY_CLKSTATREG_OFFSET 0x18
+#define XDPHY_CLKSTATREG_MODE_SHIFT 0
+#define XDPHY_CLKSTATREG_MODE_MASK 0x3
+#define XDPHY_LOW_POWER_MODE 0x0
+#define XDPHY_HI_SPEED_MODE 0x1
+#define XDPHY_ESC_MODE 0x2
+
+/*
+ * Interrupt mask
+ */
+#define XCSI_INTR_MASK (XCSI_ISR_ALLINTR_MASK & ~XCSI_ISR_STOP_MASK)
+/*
+ * Timeout for reset
+ */
+#define XCSI_TIMEOUT_VAL (1000) /* us */
+
+/*
+ * Max string length for CSI Data type string
+ */
+#define MAX_XIL_CSIDT_STR_LENGTH 64
+
+/*
+ * Maximum number of short packet events per file handle.
+ */
+#define XCSI_MAX_SPKT (512)
+
+/* Number of media pads */
+#define XILINX_CSI_MEDIA_PADS (2)
+
+#define XCSI_DEFAULT_WIDTH (1920)
+#define XCSI_DEFAULT_HEIGHT (1080)
+
+#define XCSI_DPHY_CLK_MIN 197000000000UL
+#define XCSI_DPHY_CLK_MAX 203000000000UL
+#define XCSI_DPHY_CLK_REQ 200000000000UL
+
+/*
+ * Macro to return "true" or "false" string if bit is set
+ */
+#define XCSI_GET_BITSET_STR(val, mask) (val) & (mask) ? "true" : "false"
+
+#define XCSI_CLK_PROP BIT(0)
+
+/**
+ * struct xcsi2rxss_feature - dt or IP property structure
+ * @flags: Bitmask of properties enabled in IP or dt
+ */
+struct xcsi2rxss_feature {
+ u32 flags;
+};
+
+enum CSI_DataTypes {
+ MIPI_CSI_DT_FRAME_START_CODE = 0x00,
+ MIPI_CSI_DT_FRAME_END_CODE,
+ MIPI_CSI_DT_LINE_START_CODE,
+ MIPI_CSI_DT_LINE_END_CODE,
+ MIPI_CSI_DT_SYNC_RSVD_04,
+ MIPI_CSI_DT_SYNC_RSVD_05,
+ MIPI_CSI_DT_SYNC_RSVD_06,
+ MIPI_CSI_DT_SYNC_RSVD_07,
+ MIPI_CSI_DT_GSPKT_08,
+ MIPI_CSI_DT_GSPKT_09,
+ MIPI_CSI_DT_GSPKT_0A,
+ MIPI_CSI_DT_GSPKT_0B,
+ MIPI_CSI_DT_GSPKT_0C,
+ MIPI_CSI_DT_GSPKT_0D,
+ MIPI_CSI_DT_GSPKT_0E,
+ MIPI_CSI_DT_GSPKT_0F,
+ MIPI_CSI_DT_GLPKT_10,
+ MIPI_CSI_DT_GLPKT_11,
+ MIPI_CSI_DT_GLPKT_12,
+ MIPI_CSI_DT_GLPKT_13,
+ MIPI_CSI_DT_GLPKT_14,
+ MIPI_CSI_DT_GLPKT_15,
+ MIPI_CSI_DT_GLPKT_16,
+ MIPI_CSI_DT_GLPKT_17,
+ MIPI_CSI_DT_YUV_420_8B,
+ MIPI_CSI_DT_YUV_420_10B,
+ MIPI_CSI_DT_YUV_420_8B_LEGACY,
+ MIPI_CSI_DT_YUV_RSVD,
+ MIPI_CSI_DT_YUV_420_8B_CSPS,
+ MIPI_CSI_DT_YUV_420_10B_CSPS,
+ MIPI_CSI_DT_YUV_422_8B,
+ MIPI_CSI_DT_YUV_422_10B,
+ MIPI_CSI_DT_RGB_444,
+ MIPI_CSI_DT_RGB_555,
+ MIPI_CSI_DT_RGB_565,
+ MIPI_CSI_DT_RGB_666,
+ MIPI_CSI_DT_RGB_888,
+ MIPI_CSI_DT_RGB_RSVD_25,
+ MIPI_CSI_DT_RGB_RSVD_26,
+ MIPI_CSI_DT_RGB_RSVD_27,
+ MIPI_CSI_DT_RAW_6,
+ MIPI_CSI_DT_RAW_7,
+ MIPI_CSI_DT_RAW_8,
+ MIPI_CSI_DT_RAW_10,
+ MIPI_CSI_DT_RAW_12,
+ MIPI_CSI_DT_RAW_14,
+ MIPI_CSI_DT_RAW_16,
+ MIPI_CSI_DT_RAW_20,
+ MIPI_CSI_DT_USER_30,
+ MIPI_CSI_DT_USER_31,
+ MIPI_CSI_DT_USER_32,
+ MIPI_CSI_DT_USER_33,
+ MIPI_CSI_DT_USER_34,
+ MIPI_CSI_DT_USER_35,
+ MIPI_CSI_DT_USER_36,
+ MIPI_CSI_DT_USER_37,
+ MIPI_CSI_DT_RSVD_38,
+ MIPI_CSI_DT_RSVD_39,
+ MIPI_CSI_DT_RSVD_3A,
+ MIPI_CSI_DT_RSVD_3B,
+ MIPI_CSI_DT_RSVD_3C,
+ MIPI_CSI_DT_RSVD_3D,
+ MIPI_CSI_DT_RSVD_3E,
+ MIPI_CSI_DT_RSVD_3F
+};
+
+/**
+ * struct pixel_format - Data Type to string name structure
+ * @PixelFormat: MIPI CSI2 Data type
+ * @PixelFormatStr: String name of Data Type
+ */
+struct pixel_format {
+ enum CSI_DataTypes PixelFormat;
+ char PixelFormatStr[MAX_XIL_CSIDT_STR_LENGTH];
+};
+
+/**
+ * struct xcsi2rxss_event - Event log structure
+ * @mask: Event mask
+ * @name: Name of the event
+ * @counter: Count number of events
+ */
+struct xcsi2rxss_event {
+ u32 mask;
+ const char * const name;
+ unsigned int counter;
+};
+
+/*
+ * struct xcsi2rxss_core - Core configuration CSI2 Rx Subsystem device structure
+ * @dev: Platform structure
+ * @iomem: Base address of subsystem
+ * @irq: requested irq number
+ * @dphy_present: Flag for DPHY register interface presence
+ * @dphy_offset: DPHY registers offset
+ * @enable_active_lanes: If number of active lanes can be modified
+ * @max_num_lanes: Maximum number of lanes present
+ * @vfb: Video Format Bridge enabled or not
+ * @ppc: pixels per clock
+ * @vc: Virtual Channel
+ * @axis_tdata_width: AXI Stream data width
+ * @datatype: Data type filter
+ * @pxlformat: String with CSI pixel format from IP
+ * @num_lanes: Number of lanes requested from application
+ * @events: Structure to maintain event logs
+ * @vcx_events: Structure to maintain VCX event logs
+ * @en_vcx: If more than 4 VC are enabled.
+ * @cfg: Pointer to csi2rxss config structure
+ * @lite_aclk: AXI4-Lite interface clock
+ * @video_aclk: Video clock
+ * @dphy_clk_200M: 200MHz DPHY clock
+ */
+struct xcsi2rxss_core {
+ struct device *dev;
+ void __iomem *iomem;
+ int irq;
+ u32 dphy_offset;
+ bool dphy_present;
+ bool enable_active_lanes;
+ u32 max_num_lanes;
+ bool vfb;
+ u32 ppc;
+ u32 vc;
+ u32 axis_tdata_width;
+ u32 datatype;
+ const char *pxlformat;
+ u32 num_lanes;
+ struct xcsi2rxss_event *events;
+ struct xcsi2rxss_event *vcx_events;
+ bool en_vcx;
+ const struct xcsi2rxss_feature *cfg;
+ struct clk *lite_aclk;
+ struct clk *video_aclk;
+ struct clk *dphy_clk_200M;
+};
+
+/**
+ * struct xcsi2rxss_state - CSI2 Rx Subsystem device structure
+ * @core: Core structure for MIPI CSI2 Rx Subsystem
+ * @subdev: The v4l2 subdev structure
+ * @ctrl_handler: control handler
+ * @formats: Active V4L2 formats on each pad
+ * @default_format: default V4L2 media bus format
+ * @vip_format: format information corresponding to the active format
+ * @event: Holds the short packet event
+ * @lock: mutex for serializing operations
+ * @pads: media pads
+ * @npads: number of pads
+ * @streaming: Flag for storing streaming state
+ * @suspended: Flag for storing suspended state
+ *
+ * This structure contains the device driver related parameters
+ */
+struct xcsi2rxss_state {
+ struct xcsi2rxss_core core;
+ struct v4l2_subdev subdev;
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_mbus_framefmt formats[2];
+ struct v4l2_mbus_framefmt default_format;
+ const struct xvip_video_format *vip_format;
+ struct v4l2_event event;
+ struct mutex lock;
+ struct media_pad pads[XILINX_CSI_MEDIA_PADS];
+ unsigned int npads;
+ bool streaming;
+ bool suspended;
+};
+
+static const struct xcsi2rxss_feature xlnx_csi2rxss_v4_0 = {
+ .flags = XCSI_CLK_PROP,
+};
+
+static const struct xcsi2rxss_feature xlnx_csi2rxss_v2_0 = {
+ .flags = 0,
+};
+
+static const struct of_device_id xcsi2rxss_of_id_table[] = {
+ { .compatible = "xlnx,mipi-csi2-rx-subsystem-2.0",
+ .data = &xlnx_csi2rxss_v2_0 },
+ { .compatible = "xlnx,mipi-csi2-rx-subsystem-3.0",
+ .data = &xlnx_csi2rxss_v2_0 },
+ { .compatible = "xlnx,mipi-csi2-rx-subsystem-4.0",
+ .data = &xlnx_csi2rxss_v4_0 },
+ { }
+};
+MODULE_DEVICE_TABLE(of, xcsi2rxss_of_id_table);
+
+static inline struct xcsi2rxss_state *
+to_xcsi2rxssstate(struct v4l2_subdev *subdev)
+{
+ return container_of(subdev, struct xcsi2rxss_state, subdev);
+}
+
+/*
+ * Regsiter related operations
+ */
+static inline u32 xcsi2rxss_read(struct xcsi2rxss_core *xcsi2rxss,
+ u32 addr)
+{
+ return ioread32(xcsi2rxss->iomem + addr);
+}
+
+static inline void xcsi2rxss_write(struct xcsi2rxss_core *xcsi2rxss,
+ u32 addr,
+ u32 value)
+{
+ iowrite32(value, xcsi2rxss->iomem + addr);
+}
+
+static inline void xcsi2rxss_clr(struct xcsi2rxss_core *xcsi2rxss,
+ u32 addr,
+ u32 clr)
+{
+ xcsi2rxss_write(xcsi2rxss,
+ addr,
+ xcsi2rxss_read(xcsi2rxss, addr) & ~clr);
+}
+
+static inline void xcsi2rxss_set(struct xcsi2rxss_core *xcsi2rxss,
+ u32 addr,
+ u32 set)
+{
+ xcsi2rxss_write(xcsi2rxss,
+ addr,
+ xcsi2rxss_read(xcsi2rxss, addr) | set);
+}
+
+static const struct pixel_format pixel_formats[] = {
+ { MIPI_CSI_DT_YUV_420_8B, "YUV420_8bit" },
+ { MIPI_CSI_DT_YUV_420_10B, "YUV420_10bit" },
+ { MIPI_CSI_DT_YUV_420_8B_LEGACY, "Legacy_YUV420_8bit" },
+ { MIPI_CSI_DT_YUV_420_8B_CSPS, "YUV420_8bit_CSPS" },
+ { MIPI_CSI_DT_YUV_420_10B_CSPS, "YUV420_10bit_CSPS" },
+ { MIPI_CSI_DT_YUV_422_8B, "YUV422_8bit" },
+ { MIPI_CSI_DT_YUV_422_10B, "YUV422_10bit" },
+ { MIPI_CSI_DT_RGB_444, "RGB444" },
+ { MIPI_CSI_DT_RGB_555, "RGB555" },
+ { MIPI_CSI_DT_RGB_565, "RGB565" },
+ { MIPI_CSI_DT_RGB_666, "RGB666" },
+ { MIPI_CSI_DT_RGB_888, "RGB888" },
+ { MIPI_CSI_DT_RAW_6, "RAW6" },
+ { MIPI_CSI_DT_RAW_7, "RAW7" },
+ { MIPI_CSI_DT_RAW_8, "RAW8" },
+ { MIPI_CSI_DT_RAW_10, "RAW10" },
+ { MIPI_CSI_DT_RAW_12, "RAW12" },
+ { MIPI_CSI_DT_RAW_14, "RAW14"},
+ { MIPI_CSI_DT_RAW_16, "RAW16"},
+ { MIPI_CSI_DT_RAW_20, "RAW20"}
+};
+
+static struct xcsi2rxss_event xcsi2rxss_events[] = {
+ { XCSI_ISR_FR_MASK, "Frame Received", 0 },
+ { XCSI_ISR_VCX_MASK, "VCX Frame Errors", 0 },
+ { XCSI_ISR_ILC_MASK, "Invalid Lane Count Error", 0 },
+ { XCSI_ISR_SPFIFOF_MASK, "Short Packet FIFO OverFlow Error", 0 },
+ { XCSI_ISR_SPFIFONE_MASK, "Short Packet FIFO Not Empty", 0 },
+ { XCSI_ISR_SLBF_MASK, "Streamline Buffer Full Error", 0 },
+ { XCSI_ISR_STOP_MASK, "Lane Stop State", 0 },
+ { XCSI_ISR_SOTERR_MASK, "SOT Error", 0 },
+ { XCSI_ISR_SOTSYNCERR_MASK, "SOT Sync Error", 0 },
+ { XCSI_ISR_ECC2BERR_MASK, "2 Bit ECC Unrecoverable Error", 0 },
+ { XCSI_ISR_ECC1BERR_MASK, "1 Bit ECC Recoverable Error", 0 },
+ { XCSI_ISR_CRCERR_MASK, "CRC Error", 0 },
+ { XCSI_ISR_DATAIDERR_MASK, "Data Id Error", 0 },
+ { XCSI_ISR_VC3FSYNCERR_MASK, "Virtual Channel 3 Frame Sync Error", 0 },
+ { XCSI_ISR_VC3FLVLERR_MASK, "Virtual Channel 3 Frame Level Error", 0 },
+ { XCSI_ISR_VC2FSYNCERR_MASK, "Virtual Channel 2 Frame Sync Error", 0 },
+ { XCSI_ISR_VC2FLVLERR_MASK, "Virtual Channel 2 Frame Level Error", 0 },
+ { XCSI_ISR_VC1FSYNCERR_MASK, "Virtual Channel 1 Frame Sync Error", 0 },
+ { XCSI_ISR_VC1FLVLERR_MASK, "Virtual Channel 1 Frame Level Error", 0 },
+ { XCSI_ISR_VC0FSYNCERR_MASK, "Virtual Channel 0 Frame Sync Error", 0 },
+ { XCSI_ISR_VC0FLVLERR_MASK, "Virtual Channel 0 Frame Level Error", 0 }
+};
+
+#define XMIPICSISS_NUM_EVENTS ARRAY_SIZE(xcsi2rxss_events)
+
+#define XMIPICSISS_VCX_START (4)
+#define XMIPICSISS_MAX_VC (4)
+#define XMIPICSISS_MAX_VCX (16)
+
+/* There are 2 events frame sync and frame level error per VC */
+#define XMIPICSISS_VCX_NUM_EVENTS ((XMIPICSISS_MAX_VCX -\
+ XMIPICSISS_MAX_VC) * 2)
+
+/**
+ * xcsi2rxss_clr_and_set - Clear and set the register with a bitmask
+ * @xcsi2rxss: Xilinx MIPI CSI2 Rx Subsystem subdev core struct
+ * @addr: address of register
+ * @clr: bitmask to be cleared
+ * @set: bitmask to be set
+ *
+ * Clear a bit(s) of mask @clr in the register at address @addr, then set
+ * a bit(s) of mask @set in the register after.
+ */
+static void xcsi2rxss_clr_and_set(struct xcsi2rxss_core *xcsi2rxss,
+ u32 addr, u32 clr, u32 set)
+{
+ u32 reg;
+
+ reg = xcsi2rxss_read(xcsi2rxss, addr);
+ reg &= ~clr;
+ reg |= set;
+ xcsi2rxss_write(xcsi2rxss, addr, reg);
+}
+
+/**
+ * xcsi2rxss_pxlfmtstrtodt - Convert pixel format string got from dts
+ * to data type.
+ * @pxlfmtstr: String obtained while parsing device node
+ *
+ * This function takes a CSI pixel format string obtained while parsing
+ * device tree node and converts it to data type.
+ *
+ * Eg. "RAW8" string is converted to 0x2A.
+ * Refer to MIPI CSI2 specification for details.
+ *
+ * Return: Equivalent pixel format value from table
+ */
+static u32 xcsi2rxss_pxlfmtstrtodt(const char *pxlfmtstr)
+{
+ u32 Index;
+ u32 MaxEntries = ARRAY_SIZE(pixel_formats);
+
+ for (Index = 0; Index < MaxEntries; Index++) {
+ if (!strncmp(pixel_formats[Index].PixelFormatStr,
+ pxlfmtstr, MAX_XIL_CSIDT_STR_LENGTH))
+ return pixel_formats[Index].PixelFormat;
+ }
+
+ return -EINVAL;
+}
+
+/**
+ * xcsi2rxss_pxlfmtdttostr - Convert pixel format data type to string.
+ * @datatype: MIPI CSI-2 Data Type
+ *
+ * This function takes a CSI pixel format data type and returns a
+ * pointer to the string name.
+ *
+ * Eg. 0x2A returns "RAW8" string.
+ * Refer to MIPI CSI2 specification for details.
+ *
+ * Return: Equivalent pixel format string from table
+ */
+static const char *xcsi2rxss_pxlfmtdttostr(u32 datatype)
+{
+ u32 Index;
+ u32 MaxEntries = ARRAY_SIZE(pixel_formats);
+
+ for (Index = 0; Index < MaxEntries; Index++) {
+ if (pixel_formats[Index].PixelFormat == datatype)
+ return pixel_formats[Index].PixelFormatStr;
+ }
+
+ return NULL;
+}
+
+/**
+ * xcsi2rxss_enable - Enable or disable the CSI Core
+ * @core: Core Xilinx CSI2 Rx Subsystem structure pointer
+ * @flag: true for enabling, false for disabling
+ *
+ * This function enables/disables the MIPI CSI2 Rx Subsystem core.
+ * After enabling the CSI2 Rx core, the DPHY is enabled in case the
+ * register interface for it is present.
+ */
+static void xcsi2rxss_enable(struct xcsi2rxss_core *core, bool flag)
+{
+ u32 DphyCtrlRegOffset = core->dphy_offset + XDPHY_CTRLREG_OFFSET;
+
+ if (flag) {
+ xcsi2rxss_write(core, XCSI_CCR_OFFSET, XCSI_CCR_COREENB_MASK);
+ if (core->dphy_present)
+ xcsi2rxss_write(core, DphyCtrlRegOffset,
+ XDPHY_CTRLREG_DPHYEN_MASK);
+ } else {
+ xcsi2rxss_write(core, XCSI_CCR_OFFSET, 0);
+ if (core->dphy_present)
+ xcsi2rxss_write(core, DphyCtrlRegOffset, 0);
+ }
+
+}
+
+/**
+ * xcsi2rxss_interrupts_enable - Enable or disable CSI interrupts
+ * @core: Core Xilinx CSI2 Rx Subsystem structure pointer
+ * @flag: true for enabling, false for disabling
+ *
+ * This function enables/disables the interrupts for the MIPI CSI2
+ * Rx Subsystem.
+ */
+static void xcsi2rxss_interrupts_enable(struct xcsi2rxss_core *core, bool flag)
+{
+ if (flag) {
+ xcsi2rxss_clr(core, XCSI_GIER_OFFSET, XCSI_GIER_GIE_MASK);
+ xcsi2rxss_write(core, XCSI_IER_OFFSET, XCSI_INTR_MASK);
+ xcsi2rxss_set(core, XCSI_GIER_OFFSET, XCSI_GIER_GIE_MASK);
+ } else {
+ xcsi2rxss_clr(core, XCSI_IER_OFFSET, XCSI_INTR_MASK);
+ xcsi2rxss_clr(core, XCSI_GIER_OFFSET, XCSI_GIER_GIE_MASK);
+ }
+}
+
+/**
+ * xcsi2rxss_reset - Does a soft reset of the MIPI CSI2 Rx Subsystem
+ * @core: Core Xilinx CSI2 Rx Subsystem structure pointer
+ *
+ * Return: 0 - on success OR -ETIME if reset times out
+ */
+static int xcsi2rxss_reset(struct xcsi2rxss_core *core)
+{
+ u32 Timeout = XCSI_TIMEOUT_VAL;
+
+ xcsi2rxss_set(core, XCSI_CCR_OFFSET, XCSI_CCR_SOFTRESET_MASK);
+
+ while (xcsi2rxss_read(core, XCSI_CSR_OFFSET) & XCSI_CSR_RIPCD_MASK) {
+ if (Timeout == 0) {
+ dev_err(core->dev, "Xilinx CSI2 Rx Subsystem Soft Reset Timeout!\n");
+ return -ETIME;
+ }
+
+ Timeout--;
+ udelay(1);
+ }
+
+ xcsi2rxss_clr(core, XCSI_CCR_OFFSET, XCSI_CCR_SOFTRESET_MASK);
+ return 0;
+}
+
+/**
+ * xcsi2rxss_irq_handler - Interrupt handler for CSI-2
+ * @irq: IRQ number
+ * @dev_id: Pointer to device state
+ *
+ * In the interrupt handler, a list of event counters are updated for
+ * corresponding interrupts. This is useful to get status / debug.
+ * If the short packet FIFO not empty or overflow interrupt is received
+ * capture the short packet and notify of event occurrence
+ *
+ * Return: IRQ_HANDLED after handling interrupts
+ */
+static irqreturn_t xcsi2rxss_irq_handler(int irq, void *dev_id)
+{
+ struct xcsi2rxss_state *state = (struct xcsi2rxss_state *)dev_id;
+ struct xcsi2rxss_core *core = &state->core;
+ u32 status;
+
+ status = xcsi2rxss_read(core, XCSI_ISR_OFFSET) & XCSI_INTR_MASK;
+ dev_dbg(core->dev, "interrupt status = 0x%08x\n", status);
+
+ if (!status)
+ return IRQ_NONE;
+
+ if (status & XCSI_ISR_SPFIFONE_MASK) {
+
+ memset(&state->event, 0, sizeof(state->event));
+
+ state->event.type = V4L2_EVENT_XLNXCSIRX_SPKT;
+
+ *((u32 *)(&state->event.u.data)) =
+ xcsi2rxss_read(core, XCSI_SPKTR_OFFSET);
+
+ v4l2_subdev_notify_event(&state->subdev, &state->event);
+ }
+
+ if (status & XCSI_ISR_SPFIFOF_MASK) {
+ dev_alert(core->dev, "Short packet FIFO overflowed\n");
+
+ memset(&state->event, 0, sizeof(state->event));
+
+ state->event.type = V4L2_EVENT_XLNXCSIRX_SPKT_OVF;
+
+ v4l2_subdev_notify_event(&state->subdev, &state->event);
+ }
+
+ if (status & XCSI_ISR_SLBF_MASK) {
+ dev_alert(core->dev, "Stream Line Buffer Full!\n");
+
+ memset(&state->event, 0, sizeof(state->event));
+
+ state->event.type = V4L2_EVENT_XLNXCSIRX_SLBF;
+
+ v4l2_subdev_notify_event(&state->subdev, &state->event);
+ }
+
+ if (status & XCSI_ISR_ALLINTR_MASK) {
+ unsigned int i;
+
+ for (i = 0; i < XMIPICSISS_NUM_EVENTS; i++) {
+ if (!(status & core->events[i].mask))
+ continue;
+ core->events[i].counter++;
+ dev_dbg(core->dev, "%s: %d\n", core->events[i].name,
+ core->events[i].counter);
+ }
+
+ if (status & XCSI_ISR_VCX_MASK && core->en_vcx) {
+ u32 vcxstatus;
+
+ vcxstatus = xcsi2rxss_read(core, XCSI_VCXR_OFFSET);
+ vcxstatus &= XCSI_VCXR_MASK;
+ for (i = 0; i < XMIPICSISS_VCX_NUM_EVENTS; i++) {
+ if (!(vcxstatus & core->vcx_events[i].mask))
+ continue;
+ core->vcx_events[i].counter++;
+ }
+ xcsi2rxss_write(core, XCSI_VCXR_OFFSET, vcxstatus);
+ }
+ }
+
+ xcsi2rxss_write(core, XCSI_ISR_OFFSET, status);
+
+ return IRQ_HANDLED;
+}
+
+static void xcsi2rxss_reset_event_counters(struct xcsi2rxss_state *state)
+{
+ int i;
+
+ for (i = 0; i < XMIPICSISS_NUM_EVENTS; i++)
+ state->core.events[i].counter = 0;
+
+ if (!state->core.en_vcx)
+ return;
+
+ for (i = 0; i < XMIPICSISS_VCX_NUM_EVENTS; i++)
+ state->core.vcx_events[i].counter = 0;
+}
+
+/**
+ * xcsi2rxss_log_counters - Print out the event counters.
+ * @state: Pointer to device state
+ *
+ */
+static void xcsi2rxss_log_counters(struct xcsi2rxss_state *state)
+{
+ int i;
+
+ for (i = 0; i < XMIPICSISS_NUM_EVENTS; i++) {
+ if (state->core.events[i].counter > 0)
+ v4l2_info(&state->subdev, "%s events: %d\n",
+ state->core.events[i].name,
+ state->core.events[i].counter);
+ }
+
+ if (!state->core.en_vcx)
+ return;
+
+ for (i = 0; i < XMIPICSISS_VCX_NUM_EVENTS; i++) {
+ if (state->core.vcx_events[i].counter > 0)
+ v4l2_info(&state->subdev,
+ "VC %d Frame %s error vcx events: %d\n",
+ (i / 2) + XMIPICSISS_VCX_START,
+ i & 1 ? "Sync" : "Level",
+ state->core.vcx_events[i].counter);
+ }
+}
+
+/**
+ * xcsi2rxss_log_status - Logs the status of the CSI-2 Receiver
+ * @sd: Pointer to V4L2 subdevice structure
+ *
+ * This function prints the current status of Xilinx MIPI CSI-2
+ *
+ * Return: 0 on success
+ */
+static int xcsi2rxss_log_status(struct v4l2_subdev *sd)
+{
+ struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd);
+ struct xcsi2rxss_core *core = &xcsi2rxss->core;
+ u32 reg, data, i, max_vc;
+
+ mutex_lock(&xcsi2rxss->lock);
+
+ xcsi2rxss_log_counters(xcsi2rxss);
+
+ v4l2_info(sd, "***** Core Status *****\n");
+ data = xcsi2rxss_read(core, XCSI_CSR_OFFSET);
+ v4l2_info(sd, "Short Packet FIFO Full = %s\n",
+ XCSI_GET_BITSET_STR(data, XCSI_CSR_SPFIFOFULL_MASK));
+ v4l2_info(sd, "Short Packet FIFO Not Empty = %s\n",
+ XCSI_GET_BITSET_STR(data, XCSI_CSR_SPFIFONE_MASK));
+ v4l2_info(sd, "Stream line buffer full = %s\n",
+ XCSI_GET_BITSET_STR(data, XCSI_CSR_SLBF_MASK));
+ v4l2_info(sd, "Soft reset/Core disable in progress = %s\n",
+ XCSI_GET_BITSET_STR(data, XCSI_CSR_RIPCD_MASK));
+
+ /* Clk & Lane Info */
+ v4l2_info(sd, "******** Clock Lane Info *********\n");
+ data = xcsi2rxss_read(core, XCSI_CLKINFR_OFFSET);
+ v4l2_info(sd, "Clock Lane in Stop State = %s\n",
+ XCSI_GET_BITSET_STR(data, XCSI_CLKINFR_STOP_MASK));
+
+ v4l2_info(sd, "******** Data Lane Info *********\n");
+ v4l2_info(sd, "Lane\tSoT Error\tSoT Sync Error\tStop State\n");
+ reg = XCSI_L0INFR_OFFSET;
+ for (i = 0; i < 4; i++) {
+ data = xcsi2rxss_read(core, reg);
+
+ v4l2_info(sd, "%d\t%s\t\t%s\t\t%s\n",
+ i,
+ XCSI_GET_BITSET_STR(data, XCSI_LXINFR_SOTERR_MASK),
+ XCSI_GET_BITSET_STR(data, XCSI_LXINFR_SOTSYNCERR_MASK),
+ XCSI_GET_BITSET_STR(data, XCSI_LXINFR_STOP_MASK));
+
+ reg += 4;
+ }
+
+ /* Virtual Channel Image Information */
+ v4l2_info(sd, "********** Virtual Channel Info ************\n");
+ v4l2_info(sd, "VC\tLine Count\tByte Count\tData Type\n");
+ if (core->en_vcx)
+ max_vc = XMIPICSISS_MAX_VCX;
+ else
+ max_vc = XMIPICSISS_MAX_VC;
+
+ reg = XCSI_VC0INF1R_OFFSET;
+ for (i = 0; i < max_vc; i++) {
+ u32 line_count, byte_count, data_type;
+ char *datatypestr;
+
+ /* Get line and byte count from VCXINFR1 Register */
+ data = xcsi2rxss_read(core, reg);
+ byte_count = (data & XCSI_VCXINF1R_BYTECOUNT_MASK) >>
+ XCSI_VCXINF1R_BYTECOUNT_SHIFT;
+ line_count = (data & XCSI_VCXINF1R_LINECOUNT_MASK) >>
+ XCSI_VCXINF1R_LINECOUNT_SHIFT;
+
+ /* Get data type from VCXINFR2 Register */
+ reg += 4;
+ data = xcsi2rxss_read(core, reg);
+ data_type = (data & XCSI_VCXINF2R_DATATYPE_MASK) >>
+ XCSI_VCXINF2R_DATATYPE_SHIFT;
+ datatypestr = (char *)xcsi2rxss_pxlfmtdttostr(data_type);
+
+ v4l2_info(sd, "%d\t%d\t\t%d\t\t%s\n",
+ i, line_count, byte_count, datatypestr);
+
+ /* Move to next pair of VC Info registers */
+ reg += 4;
+ }
+
+ mutex_unlock(&xcsi2rxss->lock);
+
+ return 0;
+}
+
+/*
+ * xcsi2rxss_subscribe_event - Subscribe to the custom short packet
+ * receive event.
+ * @sd: V4L2 Sub device
+ * @fh: V4L2 File Handle
+ * @sub: Subcribe event structure
+ *
+ * There are two types of events to be subscribed.
+ *
+ * First is to register for receiving a short packet.
+ * The short packets received are queued up in a FIFO.
+ * On reception of a short packet, an event will be generated
+ * with the short packet contents copied to its data area.
+ * Application subscribed to this event will poll for POLLPRI.
+ * On getting the event, the app dequeues the event to get the short packet
+ * data.
+ *
+ * Second is to register for Short packet FIFO overflow
+ * In case the rate of receiving short packets is high and
+ * the short packet FIFO overflows, this event will be triggered.
+ *
+ * Return: 0 on success, errors otherwise
+ */
+static int xcsi2rxss_subscribe_event(struct v4l2_subdev *sd,
+ struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ int ret;
+ struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd);
+
+ mutex_lock(&xcsi2rxss->lock);
+
+ switch (sub->type) {
+ case V4L2_EVENT_XLNXCSIRX_SPKT:
+ case V4L2_EVENT_XLNXCSIRX_SPKT_OVF:
+ case V4L2_EVENT_XLNXCSIRX_SLBF:
+ ret = v4l2_event_subscribe(fh, sub, XCSI_MAX_SPKT, NULL);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ mutex_unlock(&xcsi2rxss->lock);
+
+ return ret;
+}
+
+/**
+ * xcsi2rxss_unsubscribe_event - Unsubscribe from all events registered
+ * @sd: V4L2 Sub device
+ * @fh: V4L2 file handle
+ * @sub: pointer to Event unsubscription structure
+ *
+ * Return: zero on success, else a negative error code.
+ */
+static int xcsi2rxss_unsubscribe_event(struct v4l2_subdev *sd,
+ struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ int ret = 0;
+ struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd);
+
+ mutex_lock(&xcsi2rxss->lock);
+ ret = v4l2_event_unsubscribe(fh, sub);
+ mutex_unlock(&xcsi2rxss->lock);
+
+ return ret;
+}
+
+/**
+ * xcsi2rxss_s_ctrl - This is used to set the Xilinx MIPI CSI-2 V4L2 controls
+ * @ctrl: V4L2 control to be set
+ *
+ * This function is used to set the V4L2 controls for the Xilinx MIPI
+ * CSI-2 Rx Subsystem. It is used to set the active lanes in the system.
+ * The event counters can be reset.
+ *
+ * Return: 0 on success, errors otherwise
+ */
+static int xcsi2rxss_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ int ret = 0;
+ u32 Timeout = XCSI_TIMEOUT_VAL;
+ u32 active_lanes = 1;
+
+ struct xcsi2rxss_state *xcsi2rxss =
+ container_of(ctrl->handler,
+ struct xcsi2rxss_state, ctrl_handler);
+ struct xcsi2rxss_core *core = &xcsi2rxss->core;
+
+ mutex_lock(&xcsi2rxss->lock);
+
+ switch (ctrl->id) {
+ case V4L2_CID_XILINX_MIPICSISS_ACT_LANES:
+ /*
+ * This will be called only when "Enable Active Lanes" parameter
+ * is set in design
+ */
+ xcsi2rxss_clr_and_set(core, XCSI_PCR_OFFSET,
+ XCSI_PCR_ACTLANES_MASK, ctrl->val - 1);
+
+ /*
+ * If the core is enabled, wait for active lanes to be
+ * set.
+ *
+ * If core is disabled or there is no clock from DPHY Tx
+ * then the read back won't reflect the updated value
+ * as the PPI clock will not be present.
+ */
+
+ if (core->dphy_present) {
+ u32 dphyclkstatregoffset = core->dphy_offset +
+ XDPHY_CLKSTATREG_OFFSET;
+
+ u32 dphyclkstat =
+ xcsi2rxss_read(core, dphyclkstatregoffset) &
+ XDPHY_CLKSTATREG_MODE_MASK;
+
+ u32 coreenable =
+ xcsi2rxss_read(core, XCSI_CCR_OFFSET) &
+ XCSI_CCR_COREENB_MASK;
+
+ char lpmstr[] = "Low Power";
+ char hsmstr[] = "High Speed";
+ char esmstr[] = "Escape";
+ char *modestr;
+
+ switch (dphyclkstat) {
+ case 0:
+ modestr = lpmstr;
+ break;
+ case 1:
+ modestr = hsmstr;
+ break;
+ case 2:
+ modestr = esmstr;
+ break;
+ default:
+ modestr = NULL;
+ break;
+ }
+
+ dev_dbg(core->dev, "DPHY Clock Lane in %s mode\n",
+ modestr);
+
+ if ((dphyclkstat == XDPHY_HI_SPEED_MODE) &&
+ coreenable) {
+
+ /* Wait for core to apply new active lanes */
+ while (Timeout--)
+ udelay(1);
+
+ active_lanes =
+ xcsi2rxss_read(core, XCSI_PCR_OFFSET);
+ active_lanes &= XCSI_PCR_ACTLANES_MASK;
+ active_lanes++;
+
+ if (active_lanes != ctrl->val) {
+ dev_err(core->dev, "Failed to set active lanes!\n");
+ ret = -EAGAIN;
+ }
+ }
+ } else {
+ dev_dbg(core->dev, "No read back as no DPHY present.\n");
+ }
+
+ dev_dbg(core->dev, "Set active lanes: requested = %d, active = %d\n",
+ ctrl->val, active_lanes);
+ break;
+ case V4L2_CID_XILINX_MIPICSISS_RESET_COUNTERS:
+ xcsi2rxss_reset_event_counters(xcsi2rxss);
+ break;
+ default:
+ break;
+ }
+
+ mutex_unlock(&xcsi2rxss->lock);
+
+ return ret;
+}
+
+/**
+ * xcsi2rxss_g_volatile_ctrl - get the Xilinx MIPI CSI-2 Rx controls
+ * @ctrl: Pointer to V4L2 control
+ *
+ * This is used to get the number of frames received by the Xilinx
+ * MIPI CSI-2 Rx.
+ *
+ * Return: 0 on success, errors otherwise
+ */
+static int xcsi2rxss_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ int ret = 0;
+ struct xcsi2rxss_state *xcsi2rxss =
+ container_of(ctrl->handler,
+ struct xcsi2rxss_state, ctrl_handler);
+
+ mutex_lock(&xcsi2rxss->lock);
+
+ switch (ctrl->id) {
+ case V4L2_CID_XILINX_MIPICSISS_FRAME_COUNTER:
+ ctrl->val = xcsi2rxss->core.events[0].counter;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ mutex_unlock(&xcsi2rxss->lock);
+
+ return ret;
+}
+
+static int xcsi2rxss_start_stream(struct xcsi2rxss_state *xcsi2rxss)
+{
+ int ret;
+
+ xcsi2rxss_enable(&xcsi2rxss->core, true);
+
+ ret = xcsi2rxss_reset(&xcsi2rxss->core);
+ if (ret < 0)
+ return ret;
+
+ xcsi2rxss_interrupts_enable(&xcsi2rxss->core, true);
+
+ return 0;
+}
+
+static void xcsi2rxss_stop_stream(struct xcsi2rxss_state *xcsi2rxss)
+{
+ xcsi2rxss_interrupts_enable(&xcsi2rxss->core, false);
+ xcsi2rxss_enable(&xcsi2rxss->core, false);
+}
+
+/**
+ * xcsi2rxss_s_stream - It is used to start/stop the streaming.
+ * @sd: V4L2 Sub device
+ * @enable: Flag (True / False)
+ *
+ * This function controls the start or stop of streaming for the
+ * Xilinx MIPI CSI-2 Rx Subsystem provided the device isn't in
+ * suspended state.
+ *
+ * Return: 0 on success, errors otherwise
+ */
+static int xcsi2rxss_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ int ret = 0;
+ struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd);
+
+ mutex_lock(&xcsi2rxss->lock);
+
+ if (xcsi2rxss->suspended) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ if (enable) {
+ if (!xcsi2rxss->streaming) {
+ /* reset the event counters */
+ xcsi2rxss_reset_event_counters(xcsi2rxss);
+
+ ret = xcsi2rxss_start_stream(xcsi2rxss);
+ if (ret == 0)
+ xcsi2rxss->streaming = true;
+ }
+ } else {
+ if (xcsi2rxss->streaming) {
+ xcsi2rxss_stop_stream(xcsi2rxss);
+ xcsi2rxss->streaming = false;
+ }
+ }
+unlock:
+ mutex_unlock(&xcsi2rxss->lock);
+ return ret;
+}
+
+static struct v4l2_mbus_framefmt *
+__xcsi2rxss_get_pad_format(struct xcsi2rxss_state *xcsi2rxss,
+ struct v4l2_subdev_pad_config *cfg,
+ unsigned int pad, u32 which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_format(&xcsi2rxss->subdev, cfg, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &xcsi2rxss->formats[pad];
+ default:
+ return NULL;
+ }
+}
+
+/**
+ * xcsi2rxss_get_format - Get the pad format
+ * @sd: Pointer to V4L2 Sub device structure
+ * @cfg: Pointer to sub device pad information structure
+ * @fmt: Pointer to pad level media bus format
+ *
+ * This function is used to get the pad format information.
+ *
+ * Return: 0 on success
+ */
+static int xcsi2rxss_get_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+
+ struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd);
+
+ mutex_lock(&xcsi2rxss->lock);
+ fmt->format = *__xcsi2rxss_get_pad_format(xcsi2rxss, cfg,
+ fmt->pad, fmt->which);
+ mutex_unlock(&xcsi2rxss->lock);
+
+ return 0;
+}
+
+/**
+ * xcsi2rxss_set_format - This is used to set the pad format
+ * @sd: Pointer to V4L2 Sub device structure
+ * @cfg: Pointer to sub device pad information structure
+ * @fmt: Pointer to pad level media bus format
+ *
+ * This function is used to set the pad format.
+ * Since the pad format is fixed in hardware, it can't be
+ * modified on run time. So when a format set is requested by
+ * application, all parameters except the format type is
+ * saved for the pad and the original pad format is sent
+ * back to the application.
+ *
+ * Return: 0 on success
+ */
+static int xcsi2rxss_set_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct v4l2_mbus_framefmt *__format;
+ struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd);
+ struct xcsi2rxss_core *core = &xcsi2rxss->core;
+ u32 code;
+
+ mutex_lock(&xcsi2rxss->lock);
+
+ /*
+ * Only the format->code parameter matters for CSI as the
+ * CSI format cannot be changed at runtime.
+ * Ensure that format to set is copied to over to CSI pad format
+ */
+ __format = __xcsi2rxss_get_pad_format(xcsi2rxss, cfg,
+ fmt->pad, fmt->which);
+
+ /* Save the pad format code */
+ code = __format->code;
+
+ /* If the bayer pattern to be set is SXXXX8 then only 1x8 type
+ * is supported and core's data type doesn't matter.
+ * In case the bayer pattern being set is SXXX10 then only
+ * 1x10 type are supported and core should be configured for RAW10.
+ * In case the bayer pattern being set is SXXX12 then only
+ * 1x12 type are supported and core should be configured for RAW12.
+ *
+ * Otherwise don't allow change.
+ */
+ if (((fmt->format.code == MEDIA_BUS_FMT_SBGGR8_1X8) ||
+ (fmt->format.code == MEDIA_BUS_FMT_SGBRG8_1X8) ||
+ (fmt->format.code == MEDIA_BUS_FMT_SGRBG8_1X8) ||
+ (fmt->format.code == MEDIA_BUS_FMT_SRGGB8_1X8))
+ || ((core->datatype == MIPI_CSI_DT_RAW_10) &&
+ ((fmt->format.code == MEDIA_BUS_FMT_SBGGR10_1X10) ||
+ (fmt->format.code == MEDIA_BUS_FMT_SGBRG10_1X10) ||
+ (fmt->format.code == MEDIA_BUS_FMT_SGRBG10_1X10) ||
+ (fmt->format.code == MEDIA_BUS_FMT_SRGGB10_1X10)))
+ || ((core->datatype == MIPI_CSI_DT_RAW_12) &&
+ ((fmt->format.code == MEDIA_BUS_FMT_SBGGR12_1X12) ||
+ (fmt->format.code == MEDIA_BUS_FMT_SGBRG12_1X12) ||
+ (fmt->format.code == MEDIA_BUS_FMT_SGRBG12_1X12) ||
+ (fmt->format.code == MEDIA_BUS_FMT_SRGGB12_1X12))) ||
+ ((core->datatype == MIPI_CSI_DT_RAW_16) &&
+ ((fmt->format.code == MEDIA_BUS_FMT_SBGGR16_1X16) ||
+ (fmt->format.code == MEDIA_BUS_FMT_SGBRG16_1X16) ||
+ (fmt->format.code == MEDIA_BUS_FMT_SGRBG16_1X16) ||
+ (fmt->format.code == MEDIA_BUS_FMT_SRGGB16_1X16))))
+
+ /* Copy over the format to be set */
+ *__format = fmt->format;
+ else {
+ /* Restore the original pad format code */
+ fmt->format.code = code;
+ __format->code = code;
+ __format->width = fmt->format.width;
+ __format->height = fmt->format.height;
+ }
+
+ mutex_unlock(&xcsi2rxss->lock);
+
+ return 0;
+}
+
+/**
+ * xcsi2rxss_open - Called on v4l2_open()
+ * @sd: Pointer to V4L2 sub device structure
+ * @fh: Pointer to V4L2 File handle
+ *
+ * This function is called on v4l2_open(). It sets the default format
+ * for both pads.
+ *
+ * Return: 0 on success
+ */
+static int xcsi2rxss_open(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ struct v4l2_mbus_framefmt *format;
+ struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd);
+
+ format = v4l2_subdev_get_try_format(sd, fh->pad, 0);
+ *format = xcsi2rxss->default_format;
+
+ format = v4l2_subdev_get_try_format(sd, fh->pad, 1);
+ *format = xcsi2rxss->default_format;
+
+ return 0;
+}
+
+static int xcsi2rxss_close(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Media Operations
+ */
+
+static const struct media_entity_operations xcsi2rxss_media_ops = {
+ .link_validate = v4l2_subdev_link_validate
+};
+
+static const struct v4l2_ctrl_ops xcsi2rxss_ctrl_ops = {
+ .g_volatile_ctrl = xcsi2rxss_g_volatile_ctrl,
+ .s_ctrl = xcsi2rxss_s_ctrl
+};
+
+static struct v4l2_ctrl_config xcsi2rxss_ctrls[] = {
+ {
+ .ops = &xcsi2rxss_ctrl_ops,
+ .id = V4L2_CID_XILINX_MIPICSISS_ACT_LANES,
+ .name = "MIPI CSI2 Rx Subsystem: Active Lanes",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 1,
+ .max = 4,
+ .step = 1,
+ .def = 1,
+ }, {
+ .ops = &xcsi2rxss_ctrl_ops,
+ .id = V4L2_CID_XILINX_MIPICSISS_FRAME_COUNTER,
+ .name = "MIPI CSI2 Rx Subsystem: Frames Received Counter",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = 0xFFFFFFFF,
+ .step = 1,
+ .def = 0,
+ .flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
+ }, {
+ .ops = &xcsi2rxss_ctrl_ops,
+ .id = V4L2_CID_XILINX_MIPICSISS_RESET_COUNTERS,
+ .name = "MIPI CSI2 Rx Subsystem: Reset Counters",
+ .type = V4L2_CTRL_TYPE_BUTTON,
+ .min = 0,
+ .max = 1,
+ .step = 1,
+ .def = 0,
+ .flags = V4L2_CTRL_FLAG_WRITE_ONLY,
+ }
+};
+
+static const struct v4l2_subdev_core_ops xcsi2rxss_core_ops = {
+ .log_status = xcsi2rxss_log_status,
+ .subscribe_event = xcsi2rxss_subscribe_event,
+ .unsubscribe_event = xcsi2rxss_unsubscribe_event
+};
+
+static struct v4l2_subdev_video_ops xcsi2rxss_video_ops = {
+ .s_stream = xcsi2rxss_s_stream
+};
+
+static struct v4l2_subdev_pad_ops xcsi2rxss_pad_ops = {
+ .get_fmt = xcsi2rxss_get_format,
+ .set_fmt = xcsi2rxss_set_format,
+};
+
+static struct v4l2_subdev_ops xcsi2rxss_ops = {
+ .core = &xcsi2rxss_core_ops,
+ .video = &xcsi2rxss_video_ops,
+ .pad = &xcsi2rxss_pad_ops
+};
+
+static const struct v4l2_subdev_internal_ops xcsi2rxss_internal_ops = {
+ .open = xcsi2rxss_open,
+ .close = xcsi2rxss_close
+};
+
+/* -----------------------------------------------------------------------------
+ * Power Management
+ */
+
+/*
+ * xcsi2rxss_pm_suspend - Function called on Power Suspend
+ * @dev: Pointer to device structure
+ *
+ * On power suspend the CSI-2 Core is disabled if the device isn't
+ * in suspended state and is streaming.
+ *
+ * Return: 0 on success
+ */
+static int __maybe_unused xcsi2rxss_pm_suspend(struct device *dev)
+{
+ struct xcsi2rxss_state *xcsi2rxss = dev_get_drvdata(dev);
+
+ mutex_lock(&xcsi2rxss->lock);
+
+ if (!xcsi2rxss->suspended && xcsi2rxss->streaming)
+ xcsi2rxss_clr(&xcsi2rxss->core,
+ XCSI_CCR_OFFSET, XCSI_CCR_COREENB_MASK);
+
+ xcsi2rxss->suspended = true;
+
+ mutex_unlock(&xcsi2rxss->lock);
+
+ return 0;
+}
+
+/*
+ * xcsi2rxss_pm_resume - Function called on Power Resume
+ * @dev: Pointer to device structure
+ *
+ * On power resume the CSI-2 Core is enabled when it is in suspended state
+ * and prior to entering suspended state it was streaming.
+ *
+ * Return: 0 on success
+ */
+static int __maybe_unused xcsi2rxss_pm_resume(struct device *dev)
+{
+ struct xcsi2rxss_state *xcsi2rxss = dev_get_drvdata(dev);
+
+ mutex_lock(&xcsi2rxss->lock);
+
+ if ((xcsi2rxss->suspended) && (xcsi2rxss->streaming))
+ xcsi2rxss_set(&xcsi2rxss->core,
+ XCSI_CCR_OFFSET, XCSI_CCR_COREENB_MASK);
+
+ xcsi2rxss->suspended = false;
+
+ mutex_unlock(&xcsi2rxss->lock);
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Platform Device Driver
+ */
+
+static int xcsi2rxss_parse_of(struct xcsi2rxss_state *xcsi2rxss)
+{
+ struct device_node *node = xcsi2rxss->core.dev->of_node;
+ struct device_node *ports = NULL;
+ struct device_node *port = NULL;
+ unsigned int nports = 0;
+ struct xcsi2rxss_core *core = &xcsi2rxss->core;
+ int ret;
+ bool iic_present;
+
+ if (core->cfg->flags & XCSI_CLK_PROP) {
+ core->lite_aclk = devm_clk_get(core->dev, "lite_aclk");
+ if (IS_ERR(core->lite_aclk)) {
+ ret = PTR_ERR(core->lite_aclk);
+ dev_err(core->dev, "failed to get lite_aclk (%d)\n",
+ ret);
+ return ret;
+ }
+
+ core->video_aclk = devm_clk_get(core->dev, "video_aclk");
+ if (IS_ERR(core->video_aclk)) {
+ ret = PTR_ERR(core->video_aclk);
+ dev_err(core->dev, "failed to get video_aclk (%d)\n",
+ ret);
+ return ret;
+ }
+
+ core->dphy_clk_200M = devm_clk_get(core->dev, "dphy_clk_200M");
+ if (IS_ERR(core->dphy_clk_200M)) {
+ ret = PTR_ERR(core->dphy_clk_200M);
+ dev_err(core->dev, "failed to get dphy_clk_200M (%d)\n",
+ ret);
+ return ret;
+ }
+ } else {
+ dev_info(core->dev, "assuming all required clocks are enabled!\n");
+ }
+
+ core->dphy_present = of_property_read_bool(node, "xlnx,dphy-present");
+ dev_dbg(core->dev, "DPHY present property = %s\n",
+ core->dphy_present ? "Present" : "Absent");
+
+ iic_present = of_property_read_bool(node, "xlnx,iic-present");
+ dev_dbg(core->dev, "IIC present property = %s\n",
+ iic_present ? "Present" : "Absent");
+
+ if (core->dphy_present) {
+ if (iic_present)
+ core->dphy_offset = 0x20000;
+ else
+ core->dphy_offset = 0x10000;
+ }
+
+ ret = of_property_read_u32(node, "xlnx,max-lanes",
+ &core->max_num_lanes);
+ if (ret < 0) {
+ dev_err(core->dev, "missing xlnx,max-lanes property\n");
+ return ret;
+ }
+
+ if ((core->max_num_lanes > 4) || (core->max_num_lanes < 1)) {
+ dev_err(core->dev, "%d max lanes : invalid xlnx,max-lanes property\n",
+ core->max_num_lanes);
+ return -EINVAL;
+ }
+
+ core->en_vcx = of_property_read_bool(node, "xlnx,en-vcx");
+
+ ret = of_property_read_u32(node, "xlnx,vc", &core->vc);
+ if (ret < 0) {
+ dev_err(core->dev, "missing xlnx,vc property\n");
+ return ret;
+ }
+ if ((core->vc > XMIPICSISS_MAX_VC && !core->en_vcx) ||
+ (core->vc > XMIPICSISS_MAX_VCX && core->en_vcx)) {
+ dev_err(core->dev, "invalid virtual channel property value.\n");
+ return -EINVAL;
+ }
+
+ core->enable_active_lanes =
+ of_property_read_bool(node, "xlnx,en-active-lanes");
+ dev_dbg(core->dev, "Enable active lanes property = %s\n",
+ core->enable_active_lanes ? "Present" : "Absent");
+
+ ret = of_property_read_string(node, "xlnx,csi-pxl-format",
+ &core->pxlformat);
+ if (ret < 0) {
+ dev_err(core->dev, "missing xlnx,csi-pxl-format property\n");
+ return ret;
+ }
+
+ core->datatype = xcsi2rxss_pxlfmtstrtodt(core->pxlformat);
+ if ((core->datatype < MIPI_CSI_DT_YUV_420_8B) ||
+ (core->datatype > MIPI_CSI_DT_RAW_20)) {
+ dev_err(core->dev, "Invalid xlnx,csi-pxl-format string\n");
+ return -EINVAL;
+ }
+
+ core->vfb = of_property_read_bool(node, "xlnx,vfb");
+ dev_dbg(core->dev, "Video Format Bridge property = %s\n",
+ core->vfb ? "Present" : "Absent");
+
+ if (core->vfb) {
+ ret = of_property_read_u32(node, "xlnx,ppc", &core->ppc);
+ if ((ret < 0) || !((core->ppc == 1) ||
+ (core->ppc == 2) || (core->ppc == 4))) {
+ dev_err(core->dev, "Invalid xlnx,ppc property ret = %d ppc = %d\n",
+ ret, core->ppc);
+ return -EINVAL;
+ }
+ }
+
+ ports = of_get_child_by_name(node, "ports");
+ if (ports == NULL)
+ ports = node;
+
+ for_each_child_of_node(ports, port) {
+ int ret;
+ const struct xvip_video_format *format;
+ struct device_node *endpoint;
+ struct v4l2_fwnode_endpoint v4lendpoint;
+
+ if (!port->name || of_node_cmp(port->name, "port"))
+ continue;
+
+ /*
+ * Currently only a subset of VFB enabled formats present in
+ * xvip are supported in the driver.
+ *
+ * If the VFB is disabled, the pixels per clock don't matter.
+ * The data width is either 32 or 64 bit as selected in design.
+ *
+ * For e.g. If Data Type is RGB888, VFB is disabled and
+ * data width is 32 bits.
+ *
+ * Clk Cycle | Byte 0 | Byte 1 | Byte 2 | Byte 3
+ * -----------+----------+----------+----------+----------
+ * 1 | B0 | G0 | R0 | B1
+ * 2 | G1 | R1 | B2 | G2
+ * 3 | R2 | B3 | G3 | R3
+ */
+ format = xvip_of_get_format(port);
+ if (IS_ERR(format)) {
+ dev_err(core->dev, "invalid format in DT");
+ return PTR_ERR(format);
+ }
+
+ if (core->vfb &&
+ (format->vf_code != XVIP_VF_YUV_422) &&
+ (format->vf_code != XVIP_VF_RBG) &&
+ (format->vf_code != XVIP_VF_MONO_SENSOR)) {
+ dev_err(core->dev, "Invalid UG934 video format set.\n");
+ return -EINVAL;
+ }
+
+ /* Get and check the format description */
+ if (!xcsi2rxss->vip_format) {
+ xcsi2rxss->vip_format = format;
+ } else if (xcsi2rxss->vip_format != format) {
+ dev_err(core->dev, "in/out format mismatch in DT");
+ return -EINVAL;
+ }
+
+ endpoint = of_get_next_child(port, NULL);
+ if (!endpoint) {
+ dev_err(core->dev, "No port at\n");
+ return -EINVAL;
+ }
+
+ ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(endpoint),
+ &v4lendpoint);
+ if (ret) {
+ of_node_put(endpoint);
+ return ret;
+ }
+
+ of_node_put(endpoint);
+ dev_dbg(core->dev, "%s : port %d bus type = %d\n",
+ __func__, nports, v4lendpoint.bus_type);
+
+ if (v4lendpoint.bus_type == V4L2_MBUS_CSI2_DPHY) {
+ dev_dbg(core->dev, "%s : base.port = %d base.id = %d\n",
+ __func__,
+ v4lendpoint.base.port,
+ v4lendpoint.base.id);
+
+ dev_dbg(core->dev, "%s : mipi number lanes = %d\n",
+ __func__,
+ v4lendpoint.bus.mipi_csi2.num_data_lanes);
+ } else {
+ dev_dbg(core->dev, "%s : Not a CSI2 bus\n", __func__);
+ }
+
+ /* Count the number of ports. */
+ nports++;
+ }
+
+ if (nports != 2) {
+ dev_err(core->dev, "invalid number of ports %u\n", nports);
+ return -EINVAL;
+ }
+ xcsi2rxss->npads = nports;
+
+ /*Register interrupt handler */
+ core->irq = irq_of_parse_and_map(node, 0);
+
+ ret = devm_request_irq(core->dev, core->irq, xcsi2rxss_irq_handler,
+ IRQF_SHARED, "xilinx-csi2rxss", xcsi2rxss);
+ if (ret) {
+ dev_err(core->dev, "Err = %d Interrupt handler reg failed!\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int xcsi2rxss_probe(struct platform_device *pdev)
+{
+ struct v4l2_subdev *subdev;
+ struct xcsi2rxss_state *xcsi2rxss;
+ struct resource *res;
+ const struct of_device_id *match;
+ struct device_node *node = pdev->dev.of_node;
+ u32 i;
+ int ret;
+ int num_ctrls;
+
+ xcsi2rxss = devm_kzalloc(&pdev->dev, sizeof(*xcsi2rxss), GFP_KERNEL);
+ if (!xcsi2rxss)
+ return -ENOMEM;
+
+ mutex_init(&xcsi2rxss->lock);
+
+ xcsi2rxss->core.dev = &pdev->dev;
+
+ match = of_match_node(xcsi2rxss_of_id_table, node);
+ if (!match)
+ return -ENODEV;
+
+ xcsi2rxss->core.cfg = match->data;
+
+ ret = xcsi2rxss_parse_of(xcsi2rxss);
+ if (ret < 0)
+ return ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ xcsi2rxss->core.iomem = devm_ioremap_resource(xcsi2rxss->core.dev, res);
+ if (IS_ERR(xcsi2rxss->core.iomem))
+ return PTR_ERR(xcsi2rxss->core.iomem);
+
+ if (xcsi2rxss->core.cfg->flags & XCSI_CLK_PROP) {
+ unsigned long rate;
+
+ ret = clk_prepare_enable(xcsi2rxss->core.lite_aclk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable lite_aclk (%d)\n",
+ ret);
+ goto clk_err;
+ }
+
+ ret = clk_prepare_enable(xcsi2rxss->core.video_aclk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable video_aclk (%d)\n",
+ ret);
+ goto video_aclk_err;
+ }
+
+ ret = clk_prepare_enable(xcsi2rxss->core.dphy_clk_200M);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable dphy clk (%d)\n",
+ ret);
+ goto dphy_clk_err;
+ }
+
+ ret = clk_set_rate(xcsi2rxss->core.dphy_clk_200M,
+ XCSI_DPHY_CLK_REQ);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to set dphy clk rate (%d)\n",
+ ret);
+
+ goto all_clk_err;
+ }
+
+ rate = clk_get_rate(xcsi2rxss->core.dphy_clk_200M);
+ if (rate < XCSI_DPHY_CLK_MIN && rate > XCSI_DPHY_CLK_MAX) {
+ dev_err(&pdev->dev, "Err DPHY Clock = %lu\n",
+ rate);
+ ret = -EINVAL;
+ goto all_clk_err;
+ }
+ }
+
+ /*
+ * Reset and initialize the core.
+ */
+ xcsi2rxss_reset(&xcsi2rxss->core);
+
+ xcsi2rxss->core.events = (struct xcsi2rxss_event *)&xcsi2rxss_events;
+
+ if (xcsi2rxss->core.en_vcx) {
+ u32 alloc_size;
+
+ alloc_size = sizeof(struct xcsi2rxss_event) *
+ XMIPICSISS_VCX_NUM_EVENTS;
+ xcsi2rxss->core.vcx_events = devm_kzalloc(&pdev->dev,
+ alloc_size,
+ GFP_KERNEL);
+ if (!xcsi2rxss->core.vcx_events) {
+ mutex_destroy(&xcsi2rxss->lock);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < XMIPICSISS_VCX_NUM_EVENTS; i++)
+ xcsi2rxss->core.vcx_events[i].mask = 1 << i;
+ }
+
+ /* Initialize V4L2 subdevice and media entity */
+ xcsi2rxss->pads[0].flags = MEDIA_PAD_FL_SOURCE;
+ xcsi2rxss->pads[1].flags = MEDIA_PAD_FL_SINK;
+
+ /* Initialize the default format */
+ memset(&xcsi2rxss->default_format, 0,
+ sizeof(xcsi2rxss->default_format));
+ xcsi2rxss->default_format.code = xcsi2rxss->vip_format->code;
+ xcsi2rxss->default_format.field = V4L2_FIELD_NONE;
+ xcsi2rxss->default_format.colorspace = V4L2_COLORSPACE_SRGB;
+ xcsi2rxss->default_format.width = XCSI_DEFAULT_WIDTH;
+ xcsi2rxss->default_format.height = XCSI_DEFAULT_HEIGHT;
+
+ xcsi2rxss->formats[0] = xcsi2rxss->default_format;
+ xcsi2rxss->formats[1] = xcsi2rxss->default_format;
+
+ /* Initialize V4L2 subdevice and media entity */
+ subdev = &xcsi2rxss->subdev;
+ v4l2_subdev_init(subdev, &xcsi2rxss_ops);
+
+ subdev->dev = &pdev->dev;
+ subdev->internal_ops = &xcsi2rxss_internal_ops;
+ strlcpy(subdev->name, dev_name(&pdev->dev), sizeof(subdev->name));
+
+ subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ subdev->entity.ops = &xcsi2rxss_media_ops;
+
+ v4l2_set_subdevdata(subdev, xcsi2rxss);
+
+ ret = media_entity_pads_init(&subdev->entity, 2, xcsi2rxss->pads);
+ if (ret < 0)
+ goto error;
+
+ /*
+ * In case the Enable Active Lanes config parameter is not set,
+ * dynamic lane reconfiguration is not allowed.
+ * So V4L2_CID_XILINX_MIPICSISS_ACT_LANES ctrl will not be registered.
+ * Accordingly allocate the number of controls
+ */
+ num_ctrls = ARRAY_SIZE(xcsi2rxss_ctrls);
+
+ if (!xcsi2rxss->core.enable_active_lanes)
+ num_ctrls--;
+
+ dev_dbg(xcsi2rxss->core.dev, "# of ctrls = %d\n", num_ctrls);
+
+ v4l2_ctrl_handler_init(&xcsi2rxss->ctrl_handler, num_ctrls);
+
+ for (i = 0; i < ARRAY_SIZE(xcsi2rxss_ctrls); i++) {
+ struct v4l2_ctrl *ctrl;
+
+ if (xcsi2rxss_ctrls[i].id ==
+ V4L2_CID_XILINX_MIPICSISS_ACT_LANES) {
+
+ if (xcsi2rxss->core.enable_active_lanes) {
+ xcsi2rxss_ctrls[i].max =
+ xcsi2rxss->core.max_num_lanes;
+ } else {
+ /* Don't register control */
+ dev_dbg(xcsi2rxss->core.dev,
+ "Skip active lane control\n");
+ continue;
+ }
+ }
+
+ dev_dbg(xcsi2rxss->core.dev, "%d ctrl = 0x%x\n",
+ i, xcsi2rxss_ctrls[i].id);
+ ctrl = v4l2_ctrl_new_custom(&xcsi2rxss->ctrl_handler,
+ &xcsi2rxss_ctrls[i], NULL);
+ if (!ctrl) {
+ dev_err(xcsi2rxss->core.dev, "Failed for %s ctrl\n",
+ xcsi2rxss_ctrls[i].name);
+ goto error;
+ }
+ }
+
+ dev_dbg(xcsi2rxss->core.dev, "# v4l2 ctrls registered = %d\n", i - 1);
+
+ if (xcsi2rxss->ctrl_handler.error) {
+ dev_err(&pdev->dev, "failed to add controls\n");
+ ret = xcsi2rxss->ctrl_handler.error;
+ goto error;
+ }
+
+ subdev->ctrl_handler = &xcsi2rxss->ctrl_handler;
+
+ ret = v4l2_ctrl_handler_setup(&xcsi2rxss->ctrl_handler);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to set controls\n");
+ goto error;
+ }
+
+ platform_set_drvdata(pdev, xcsi2rxss);
+
+ dev_info(xcsi2rxss->core.dev, "Xilinx CSI2 Rx Subsystem device found!\n");
+
+ ret = v4l2_async_register_subdev(subdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to register subdev\n");
+ goto error;
+ }
+
+ /* default states for streaming and suspend */
+ xcsi2rxss->streaming = false;
+ xcsi2rxss->suspended = false;
+ return 0;
+
+error:
+ v4l2_ctrl_handler_free(&xcsi2rxss->ctrl_handler);
+ media_entity_cleanup(&subdev->entity);
+ mutex_destroy(&xcsi2rxss->lock);
+
+all_clk_err:
+ clk_disable_unprepare(xcsi2rxss->core.dphy_clk_200M);
+dphy_clk_err:
+ clk_disable_unprepare(xcsi2rxss->core.video_aclk);
+video_aclk_err:
+ clk_disable_unprepare(xcsi2rxss->core.lite_aclk);
+clk_err:
+ return ret;
+}
+
+static int xcsi2rxss_remove(struct platform_device *pdev)
+{
+ struct xcsi2rxss_state *xcsi2rxss = platform_get_drvdata(pdev);
+ struct v4l2_subdev *subdev = &xcsi2rxss->subdev;
+
+ v4l2_async_unregister_subdev(subdev);
+ v4l2_ctrl_handler_free(&xcsi2rxss->ctrl_handler);
+ media_entity_cleanup(&subdev->entity);
+ mutex_destroy(&xcsi2rxss->lock);
+ clk_disable_unprepare(xcsi2rxss->core.dphy_clk_200M);
+ clk_disable_unprepare(xcsi2rxss->core.video_aclk);
+ clk_disable_unprepare(xcsi2rxss->core.lite_aclk);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(xcsi2rxss_pm_ops,
+ xcsi2rxss_pm_suspend, xcsi2rxss_pm_resume);
+
+static struct platform_driver xcsi2rxss_driver = {
+ .driver = {
+ .name = "xilinx-csi2rxss",
+ .pm = &xcsi2rxss_pm_ops,
+ .of_match_table = xcsi2rxss_of_id_table,
+ },
+ .probe = xcsi2rxss_probe,
+ .remove = xcsi2rxss_remove,
+};
+
+module_platform_driver(xcsi2rxss_driver);
+
+MODULE_AUTHOR("Vishal Sagar <vsagar@xilinx.com>");
+MODULE_DESCRIPTION("Xilinx MIPI CSI2 Rx Subsystem Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/xilinx/xilinx-demosaic.c b/drivers/media/platform/xilinx/xilinx-demosaic.c
new file mode 100644
index 000000000000..a519c2c9719b
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-demosaic.c
@@ -0,0 +1,418 @@
+/*
+ * Xilinx Video Demosaic IP
+ *
+ * Copyright (C) 2017 Xilinx, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include <media/v4l2-async.h>
+#include <media/v4l2-subdev.h>
+
+#include "xilinx-vip.h"
+
+#define XDEMOSAIC_AP_CTRL (0x00)
+#define XDEMOSAIC_WIDTH (0x10)
+#define XDEMOSAIC_HEIGHT (0x18)
+#define XDEMOSAIC_INPUT_BAYER_FORMAT (0x28)
+
+#define XDEMOSAIC_MIN_HEIGHT (64)
+#define XDEMOSAIC_MAX_HEIGHT (4320)
+#define XDEMOSAIC_DEF_HEIGHT (720)
+#define XDEMOSAIC_MIN_WIDTH (64)
+#define XDEMOSAIC_MAX_WIDTH (8192)
+#define XDEMOSAIC_DEF_WIDTH (1280)
+
+#define XDEMOSAIC_RESET_DEASSERT (0)
+#define XDEMOSAIC_RESET_ASSERT (1)
+#define XDEMOSAIC_START BIT(0)
+#define XDEMOSAIC_AUTO_RESTART BIT(7)
+#define XDEMOSAIC_STREAM_ON (XDEMOSAIC_AUTO_RESTART | XDEMOSAIC_START)
+
+enum xdmsc_bayer_format {
+ XDEMOSAIC_RGGB = 0,
+ XDEMOSAIC_GRBG,
+ XDEMOSAIC_GBRG,
+ XDEMOSAIC_BGGR,
+};
+
+struct xdmsc_dev {
+ struct xvip_device xvip;
+ struct media_pad pads[2];
+ struct v4l2_mbus_framefmt formats[2];
+ struct v4l2_mbus_framefmt default_formats[2];
+
+ enum xdmsc_bayer_format bayer_fmt;
+ struct gpio_desc *rst_gpio;
+ u32 max_width;
+ u32 max_height;
+};
+
+static inline u32 xdmsc_read(struct xdmsc_dev *xdmsc, u32 reg)
+{
+ u32 data;
+
+ data = xvip_read(&xdmsc->xvip, reg);
+ dev_dbg(xdmsc->xvip.dev,
+ "Reading 0x%x from reg offset 0x%x", data, reg);
+ return data;
+}
+
+static inline void xdmsc_write(struct xdmsc_dev *xdmsc, u32 reg, u32 data)
+{
+ xvip_write(&xdmsc->xvip, reg, data);
+ dev_dbg(xdmsc->xvip.dev,
+ "Writing 0x%x to reg offset 0x%x", data, reg);
+#ifdef DEBUG
+ if (xdmsc_read(xdmsc, reg) != data)
+ dev_err(xdmsc->xvip.dev,
+ "Wrote 0x%x does not match read back", data);
+#endif
+}
+
+static inline struct xdmsc_dev *to_xdmsc(struct v4l2_subdev *subdev)
+{
+ return container_of(subdev, struct xdmsc_dev, xvip.subdev);
+}
+
+static struct v4l2_mbus_framefmt
+*__xdmsc_get_pad_format(struct xdmsc_dev *xdmsc,
+ struct v4l2_subdev_pad_config *cfg,
+ unsigned int pad, u32 which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_format(&xdmsc->xvip.subdev,
+ cfg, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &xdmsc->formats[pad];
+ default:
+ return NULL;
+ }
+}
+
+static int xdmsc_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+ struct xdmsc_dev *xdmsc = to_xdmsc(subdev);
+
+ if (!enable) {
+ dev_dbg(xdmsc->xvip.dev, "%s : Off", __func__);
+ gpiod_set_value_cansleep(xdmsc->rst_gpio,
+ XDEMOSAIC_RESET_ASSERT);
+ gpiod_set_value_cansleep(xdmsc->rst_gpio,
+ XDEMOSAIC_RESET_DEASSERT);
+ return 0;
+ }
+
+ xdmsc_write(xdmsc, XDEMOSAIC_WIDTH,
+ xdmsc->formats[XVIP_PAD_SINK].width);
+ xdmsc_write(xdmsc, XDEMOSAIC_HEIGHT,
+ xdmsc->formats[XVIP_PAD_SINK].height);
+ xdmsc_write(xdmsc, XDEMOSAIC_INPUT_BAYER_FORMAT, xdmsc->bayer_fmt);
+
+ /* Start Demosaic Video IP */
+ xdmsc_write(xdmsc, XDEMOSAIC_AP_CTRL, XDEMOSAIC_STREAM_ON);
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops xdmsc_video_ops = {
+ .s_stream = xdmsc_s_stream,
+};
+
+static int xdmsc_get_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xdmsc_dev *xdmsc = to_xdmsc(subdev);
+
+ fmt->format = *__xdmsc_get_pad_format(xdmsc, cfg, fmt->pad, fmt->which);
+ return 0;
+}
+
+static bool
+xdmsc_is_format_bayer(struct xdmsc_dev *xdmsc, u32 code)
+{
+ switch (code) {
+ case MEDIA_BUS_FMT_SRGGB8_1X8:
+ case MEDIA_BUS_FMT_SRGGB10_1X10:
+ case MEDIA_BUS_FMT_SRGGB12_1X12:
+ case MEDIA_BUS_FMT_SRGGB16_1X16:
+ xdmsc->bayer_fmt = XDEMOSAIC_RGGB;
+ break;
+ case MEDIA_BUS_FMT_SGRBG8_1X8:
+ case MEDIA_BUS_FMT_SGRBG10_1X10:
+ case MEDIA_BUS_FMT_SGRBG12_1X12:
+ case MEDIA_BUS_FMT_SGRBG16_1X16:
+ xdmsc->bayer_fmt = XDEMOSAIC_GRBG;
+ break;
+ case MEDIA_BUS_FMT_SGBRG8_1X8:
+ case MEDIA_BUS_FMT_SGBRG10_1X10:
+ case MEDIA_BUS_FMT_SGBRG12_1X12:
+ case MEDIA_BUS_FMT_SGBRG16_1X16:
+ xdmsc->bayer_fmt = XDEMOSAIC_GBRG;
+ break;
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
+ case MEDIA_BUS_FMT_SBGGR10_1X10:
+ case MEDIA_BUS_FMT_SBGGR12_1X12:
+ case MEDIA_BUS_FMT_SBGGR16_1X16:
+ xdmsc->bayer_fmt = XDEMOSAIC_BGGR;
+ break;
+ default:
+ dev_dbg(xdmsc->xvip.dev, "Unsupported format for Sink Pad");
+ return false;
+ }
+ return true;
+}
+
+static int xdmsc_set_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xdmsc_dev *xdmsc = to_xdmsc(subdev);
+ struct v4l2_mbus_framefmt *__format;
+
+ __format = __xdmsc_get_pad_format(xdmsc, cfg, fmt->pad, fmt->which);
+ *__format = fmt->format;
+
+ __format->width = clamp_t(unsigned int, fmt->format.width,
+ XDEMOSAIC_MIN_WIDTH, xdmsc->max_width);
+ __format->height = clamp_t(unsigned int, fmt->format.height,
+ XDEMOSAIC_MIN_HEIGHT, xdmsc->max_height);
+
+ if (fmt->pad == XVIP_PAD_SOURCE) {
+ if (__format->code != MEDIA_BUS_FMT_RBG888_1X24 &&
+ __format->code != MEDIA_BUS_FMT_RBG101010_1X30 &&
+ __format->code != MEDIA_BUS_FMT_RBG121212_1X36 &&
+ __format->code != MEDIA_BUS_FMT_RBG161616_1X48) {
+ dev_dbg(xdmsc->xvip.dev,
+ "%s : Unsupported source media bus code format",
+ __func__);
+ __format->code = MEDIA_BUS_FMT_RBG888_1X24;
+ }
+ }
+
+ if (fmt->pad == XVIP_PAD_SINK) {
+ if (!xdmsc_is_format_bayer(xdmsc, __format->code)) {
+ dev_dbg(xdmsc->xvip.dev,
+ "Unsupported Sink Pad Media format, defaulting to RGGB");
+ __format->code = MEDIA_BUS_FMT_SRGGB8_1X8;
+ }
+ }
+
+ fmt->format = *__format;
+ return 0;
+}
+
+static int xdmsc_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ struct xdmsc_dev *xdmsc = to_xdmsc(subdev);
+ struct v4l2_mbus_framefmt *format;
+
+ format = v4l2_subdev_get_try_format(subdev, fh->pad, XVIP_PAD_SINK);
+ *format = xdmsc->default_formats[XVIP_PAD_SINK];
+
+ format = v4l2_subdev_get_try_format(subdev, fh->pad, XVIP_PAD_SOURCE);
+ *format = xdmsc->default_formats[XVIP_PAD_SOURCE];
+ return 0;
+}
+
+static int xdmsc_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ return 0;
+}
+
+static const struct v4l2_subdev_internal_ops xdmsc_internal_ops = {
+ .open = xdmsc_open,
+ .close = xdmsc_close,
+};
+
+static const struct v4l2_subdev_pad_ops xdmsc_pad_ops = {
+ .enum_mbus_code = xvip_enum_mbus_code,
+ .enum_frame_size = xvip_enum_frame_size,
+ .get_fmt = xdmsc_get_format,
+ .set_fmt = xdmsc_set_format,
+};
+
+static const struct v4l2_subdev_ops xdmsc_ops = {
+ .video = &xdmsc_video_ops,
+ .pad = &xdmsc_pad_ops,
+};
+
+static const struct media_entity_operations xdmsc_media_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+static int xdmsc_parse_of(struct xdmsc_dev *xdmsc)
+{
+ struct device *dev = xdmsc->xvip.dev;
+ struct device_node *node = dev->of_node;
+ struct device_node *ports;
+ struct device_node *port;
+ u32 port_id = 0;
+ int rval;
+
+ rval = of_property_read_u32(node, "xlnx,max-height",
+ &xdmsc->max_height);
+ if (rval < 0) {
+ dev_err(dev, "missing xlnx,max-height property!");
+ return -EINVAL;
+ } else if (xdmsc->max_height > XDEMOSAIC_MAX_HEIGHT ||
+ xdmsc->max_height < XDEMOSAIC_MIN_HEIGHT) {
+ dev_err(dev, "Invalid height in dt");
+ return -EINVAL;
+ }
+
+ rval = of_property_read_u32(node, "xlnx,max-width",
+ &xdmsc->max_width);
+ if (rval < 0) {
+ dev_err(dev, "missing xlnx,max-width property!");
+ return -EINVAL;
+ } else if (xdmsc->max_width > XDEMOSAIC_MAX_WIDTH ||
+ xdmsc->max_width < XDEMOSAIC_MIN_WIDTH) {
+ dev_err(dev, "Invalid width in dt");
+ return -EINVAL;
+ }
+
+ ports = of_get_child_by_name(node, "ports");
+ if (!ports)
+ ports = node;
+ /* Get the format description for each pad */
+ for_each_child_of_node(ports, port) {
+ if (port->name && (of_node_cmp(port->name, "port") == 0)) {
+ rval = of_property_read_u32(port, "reg", &port_id);
+ if (rval < 0) {
+ dev_err(dev, "No reg in DT");
+ return rval;
+ }
+
+ if (port_id != 0 && port_id != 1) {
+ dev_err(dev, "Invalid reg in DT");
+ return -EINVAL;
+ }
+ }
+ }
+
+ xdmsc->rst_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(xdmsc->rst_gpio)) {
+ if (PTR_ERR(xdmsc->rst_gpio) != -EPROBE_DEFER)
+ dev_err(dev, "Reset GPIO not setup in DT");
+ return PTR_ERR(xdmsc->rst_gpio);
+ }
+ return 0;
+}
+
+static int xdmsc_probe(struct platform_device *pdev)
+{
+ struct xdmsc_dev *xdmsc;
+ struct v4l2_subdev *subdev;
+ struct v4l2_mbus_framefmt *def_fmt;
+ int rval;
+
+ xdmsc = devm_kzalloc(&pdev->dev, sizeof(*xdmsc), GFP_KERNEL);
+ if (!xdmsc)
+ return -ENOMEM;
+ xdmsc->xvip.dev = &pdev->dev;
+ rval = xdmsc_parse_of(xdmsc);
+ if (rval < 0)
+ return rval;
+ rval = xvip_init_resources(&xdmsc->xvip);
+
+ /* Reset Demosaic IP */
+ gpiod_set_value_cansleep(xdmsc->rst_gpio,
+ XDEMOSAIC_RESET_DEASSERT);
+
+ /* Init V4L2 subdev */
+ subdev = &xdmsc->xvip.subdev;
+ v4l2_subdev_init(subdev, &xdmsc_ops);
+ subdev->dev = &pdev->dev;
+ subdev->internal_ops = &xdmsc_internal_ops;
+ strlcpy(subdev->name, dev_name(&pdev->dev), sizeof(subdev->name));
+ subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ /* Default Formats Initialization */
+ def_fmt = &xdmsc->default_formats[XVIP_PAD_SINK];
+ def_fmt->field = V4L2_FIELD_NONE;
+ def_fmt->colorspace = V4L2_COLORSPACE_SRGB;
+ def_fmt->width = XDEMOSAIC_DEF_WIDTH;
+ def_fmt->height = XDEMOSAIC_DEF_HEIGHT;
+
+ /*
+ * Sink Pad can be any Bayer format.
+ * Default Sink Pad format is RGGB.
+ */
+ def_fmt->code = MEDIA_BUS_FMT_SRGGB8_1X8;
+ xdmsc->formats[XVIP_PAD_SINK] = *def_fmt;
+
+ def_fmt = &xdmsc->default_formats[XVIP_PAD_SOURCE];
+ *def_fmt = xdmsc->default_formats[XVIP_PAD_SINK];
+
+ /* Source Pad has a fixed media bus format of RGB */
+ def_fmt->code = MEDIA_BUS_FMT_RBG888_1X24;
+ xdmsc->formats[XVIP_PAD_SOURCE] = *def_fmt;
+
+ xdmsc->pads[XVIP_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ xdmsc->pads[XVIP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+ /* Init Media Entity */
+ subdev->entity.ops = &xdmsc_media_ops;
+ rval = media_entity_pads_init(&subdev->entity, 2, xdmsc->pads);
+ if (rval < 0)
+ goto media_error;
+
+ platform_set_drvdata(pdev, xdmsc);
+ rval = v4l2_async_register_subdev(subdev);
+ if (rval < 0) {
+ dev_err(&pdev->dev, "failed to register subdev");
+ goto v4l2_subdev_error;
+ }
+ dev_info(&pdev->dev,
+ "Xilinx Video Demosaic Probe Successful");
+ return 0;
+
+v4l2_subdev_error:
+ media_entity_cleanup(&subdev->entity);
+media_error:
+ xvip_cleanup_resources(&xdmsc->xvip);
+ return rval;
+}
+
+static int xdmsc_remove(struct platform_device *pdev)
+{
+ struct xdmsc_dev *xdmsc = platform_get_drvdata(pdev);
+ struct v4l2_subdev *subdev = &xdmsc->xvip.subdev;
+
+ v4l2_async_unregister_subdev(subdev);
+ media_entity_cleanup(&subdev->entity);
+ xvip_cleanup_resources(&xdmsc->xvip);
+ return 0;
+}
+
+static const struct of_device_id xdmsc_of_id_table[] = {
+ {.compatible = "xlnx,v-demosaic"},
+ { }
+};
+MODULE_DEVICE_TABLE(of, xdmsc_of_id_table);
+
+static struct platform_driver xdmsc_driver = {
+ .driver = {
+ .name = "xilinx-demosaic",
+ .of_match_table = xdmsc_of_id_table,
+ },
+ .probe = xdmsc_probe,
+ .remove = xdmsc_remove,
+
+};
+
+module_platform_driver(xdmsc_driver);
+MODULE_DESCRIPTION("Xilinx Demosaic IP Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c
index c9d5fdb2d407..e8090721d25b 100644
--- a/drivers/media/platform/xilinx/xilinx-dma.c
+++ b/drivers/media/platform/xilinx/xilinx-dma.c
@@ -10,11 +10,13 @@
*/
#include <linux/dma/xilinx_dma.h>
+#include <linux/dma/xilinx_frmbuf.h>
#include <linux/lcm.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/slab.h>
+#include <linux/xilinx-v4l2-controls.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-fh.h>
@@ -36,6 +38,11 @@
#define XVIP_DMA_MIN_HEIGHT 1U
#define XVIP_DMA_MAX_HEIGHT 8191U
+struct xventity_list {
+ struct list_head list;
+ struct media_entity *entity;
+};
+
/* -----------------------------------------------------------------------------
* Helper functions
*/
@@ -60,9 +67,10 @@ static int xvip_dma_verify_format(struct xvip_dma *dma)
struct v4l2_subdev_format fmt;
struct v4l2_subdev *subdev;
int ret;
+ int width, height;
subdev = xvip_dma_remote_subdev(&dma->pad, &fmt.pad);
- if (subdev == NULL)
+ if (!subdev)
return -EPIPE;
fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
@@ -70,10 +78,18 @@ static int xvip_dma_verify_format(struct xvip_dma *dma)
if (ret < 0)
return ret == -ENOIOCTLCMD ? -EINVAL : ret;
- if (dma->fmtinfo->code != fmt.format.code ||
- dma->format.height != fmt.format.height ||
- dma->format.width != fmt.format.width ||
- dma->format.colorspace != fmt.format.colorspace)
+ if (dma->fmtinfo->code != fmt.format.code)
+ return -EINVAL;
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(dma->format.type)) {
+ width = dma->format.fmt.pix_mp.width;
+ height = dma->format.fmt.pix_mp.height;
+ } else {
+ width = dma->format.fmt.pix.width;
+ height = dma->format.fmt.pix.height;
+ }
+
+ if (width != fmt.format.width || height != fmt.format.height)
return -EINVAL;
return 0;
@@ -83,44 +99,135 @@ static int xvip_dma_verify_format(struct xvip_dma *dma)
* Pipeline Stream Management
*/
+static int xvip_entity_start_stop(struct xvip_composite_device *xdev,
+ struct media_entity *entity, bool start)
+{
+ struct v4l2_subdev *subdev;
+ bool is_streaming;
+ int ret = 0;
+
+ dev_dbg(xdev->dev, "%s entity %s\n",
+ start ? "Starting" : "Stopping", entity->name);
+ subdev = media_entity_to_v4l2_subdev(entity);
+
+ /* This is to maintain list of stream on/off devices */
+ is_streaming = xvip_subdev_set_streaming(xdev, subdev, start);
+
+ /*
+ * start or stop the subdev only once in case if they are
+ * shared between sub-graphs
+ */
+ if (start && !is_streaming) {
+ /* power-on subdevice */
+ ret = v4l2_subdev_call(subdev, core, s_power, 1);
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
+ dev_err(xdev->dev,
+ "s_power on failed on subdev\n");
+ xvip_subdev_set_streaming(xdev, subdev, 0);
+ return ret;
+ }
+
+ /* stream-on subdevice */
+ ret = v4l2_subdev_call(subdev, video, s_stream, 1);
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
+ dev_err(xdev->dev,
+ "s_stream on failed on subdev\n");
+ v4l2_subdev_call(subdev, core, s_power, 0);
+ xvip_subdev_set_streaming(xdev, subdev, 0);
+ }
+ } else if (!start && is_streaming) {
+ /* stream-off subdevice */
+ ret = v4l2_subdev_call(subdev, video, s_stream, 0);
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
+ dev_err(xdev->dev,
+ "s_stream off failed on subdev\n");
+ xvip_subdev_set_streaming(xdev, subdev, 1);
+ }
+
+ /* power-off subdevice */
+ ret = v4l2_subdev_call(subdev, core, s_power, 0);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ dev_err(xdev->dev,
+ "s_power off failed on subdev\n");
+ }
+
+ return ret;
+}
+
/**
* xvip_pipeline_start_stop - Start ot stop streaming on a pipeline
- * @pipe: The pipeline
+ * @xdev: Composite video device
+ * @dma: xvip dma
* @start: Start (when true) or stop (when false) the pipeline
*
- * Walk the entities chain starting at the pipeline output video node and start
- * or stop all of them.
+ * Walk the entities chain starting @dma and start or stop all of them
*
* Return: 0 if successful, or the return value of the failed video::s_stream
* operation otherwise.
*/
-static int xvip_pipeline_start_stop(struct xvip_pipeline *pipe, bool start)
+static int xvip_pipeline_start_stop(struct xvip_composite_device *xdev,
+ struct xvip_dma *dma, bool start)
{
- struct xvip_dma *dma = pipe->output;
- struct media_entity *entity;
- struct media_pad *pad;
- struct v4l2_subdev *subdev;
- int ret;
+ struct media_graph graph;
+ struct media_entity *entity = &dma->video.entity;
+ struct media_device *mdev = entity->graph_obj.mdev;
+ struct xventity_list *temp, *_temp;
+ LIST_HEAD(ent_list);
+ int ret = 0;
+
+ mutex_lock(&mdev->graph_mutex);
+
+ /* Walk the graph to locate the subdev nodes */
+ ret = media_graph_walk_init(&graph, mdev);
+ if (ret)
+ goto error;
- entity = &dma->video.entity;
- while (1) {
- pad = &entity->pads[0];
- if (!(pad->flags & MEDIA_PAD_FL_SINK))
- break;
+ media_graph_walk_start(&graph, entity);
- pad = media_entity_remote_pad(pad);
- if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
- break;
+ /* get the list of entities */
+ while ((entity = media_graph_walk_next(&graph))) {
+ struct xventity_list *ele;
- entity = pad->entity;
- subdev = media_entity_to_v4l2_subdev(entity);
+ /* We want to stream on/off only subdevs */
+ if (!is_media_entity_v4l2_subdev(entity))
+ continue;
- ret = v4l2_subdev_call(subdev, video, s_stream, start);
- if (start && ret < 0 && ret != -ENOIOCTLCMD)
- return ret;
+ /* Maintain the pipeline sequence in a list */
+ ele = kzalloc(sizeof(*ele), GFP_KERNEL);
+ if (!ele) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ele->entity = entity;
+ list_add(&ele->list, &ent_list);
}
- return 0;
+ if (start) {
+ list_for_each_entry_safe(temp, _temp, &ent_list, list) {
+ /* Enable all subdevs from sink to source */
+ ret = xvip_entity_start_stop(xdev, temp->entity, start);
+ if (ret < 0) {
+ dev_err(xdev->dev, "ret = %d for entity %s\n",
+ ret, temp->entity->name);
+ break;
+ }
+ }
+ } else {
+ list_for_each_entry_safe_reverse(temp, _temp, &ent_list, list)
+ /* Enable all subdevs from source to sink */
+ xvip_entity_start_stop(xdev, temp->entity, start);
+ }
+
+ list_for_each_entry_safe(temp, _temp, &ent_list, list) {
+ list_del(&temp->list);
+ kfree(temp);
+ }
+
+error:
+ mutex_unlock(&mdev->graph_mutex);
+ media_graph_walk_cleanup(&graph);
+ return ret;
}
/**
@@ -133,7 +240,8 @@ static int xvip_pipeline_start_stop(struct xvip_pipeline *pipe, bool start)
* independently, pipelines have a shared stream state that enable or disable
* all entities in the pipeline. For this reason the pipeline uses a streaming
* counter that tracks the number of DMA engines that have requested the stream
- * to be enabled.
+ * to be enabled. This will walk the graph starting from each DMA and enable or
+ * disable the entities in the path.
*
* When called with the @on argument set to true, this function will increment
* the pipeline streaming count. If the streaming count reaches the number of
@@ -150,20 +258,31 @@ static int xvip_pipeline_start_stop(struct xvip_pipeline *pipe, bool start)
*/
static int xvip_pipeline_set_stream(struct xvip_pipeline *pipe, bool on)
{
+ struct xvip_composite_device *xdev;
+ struct xvip_dma *dma;
int ret = 0;
mutex_lock(&pipe->lock);
+ xdev = pipe->xdev;
if (on) {
if (pipe->stream_count == pipe->num_dmas - 1) {
- ret = xvip_pipeline_start_stop(pipe, true);
- if (ret < 0)
- goto done;
+ /*
+ * This will iterate the DMAs and the stream-on of
+ * subdevs may not be sequential due to multiple
+ * sub-graph path
+ */
+ list_for_each_entry(dma, &xdev->dmas, list) {
+ ret = xvip_pipeline_start_stop(xdev, dma, true);
+ if (ret < 0)
+ goto done;
+ }
}
pipe->stream_count++;
} else {
if (--pipe->stream_count == 0)
- xvip_pipeline_start_stop(pipe, false);
+ list_for_each_entry(dma, &xdev->dmas, list)
+ xvip_pipeline_start_stop(xdev, dma, false);
}
done:
@@ -200,23 +319,22 @@ static int xvip_pipeline_validate(struct xvip_pipeline *pipe,
dma = to_xvip_dma(media_entity_to_video_device(entity));
- if (dma->pad.flags & MEDIA_PAD_FL_SINK) {
- pipe->output = dma;
+ if (dma->pad.flags & MEDIA_PAD_FL_SINK)
num_outputs++;
- } else {
+ else
num_inputs++;
- }
}
mutex_unlock(&mdev->graph_mutex);
media_graph_walk_cleanup(&graph);
- /* We need exactly one output and zero or one input. */
- if (num_outputs != 1 || num_inputs > 1)
+ /* We need at least one DMA to proceed */
+ if (num_outputs == 0 && num_inputs == 0)
return -EPIPE;
pipe->num_dmas = num_inputs + num_outputs;
+ pipe->xdev = start->xdev;
return 0;
}
@@ -224,7 +342,6 @@ static int xvip_pipeline_validate(struct xvip_pipeline *pipe,
static void __xvip_pipeline_cleanup(struct xvip_pipeline *pipe)
{
pipe->num_dmas = 0;
- pipe->output = NULL;
}
/**
@@ -287,11 +404,13 @@ done:
* @buf: vb2 buffer base object
* @queue: buffer list entry in the DMA engine queued buffers list
* @dma: DMA channel that uses the buffer
+ * @desc: Descriptor associated with this structure
*/
struct xvip_dma_buffer {
struct vb2_v4l2_buffer buf;
struct list_head queue;
struct xvip_dma *dma;
+ struct dma_async_tx_descriptor *desc;
};
#define to_xvip_dma_buffer(vb) container_of(vb, struct xvip_dma_buffer, buf)
@@ -300,6 +419,9 @@ static void xvip_dma_complete(void *param)
{
struct xvip_dma_buffer *buf = param;
struct xvip_dma *dma = buf->dma;
+ int i, sizeimage;
+ u32 fid;
+ int status;
spin_lock(&dma->queued_lock);
list_del(&buf->queue);
@@ -308,7 +430,38 @@ static void xvip_dma_complete(void *param)
buf->buf.field = V4L2_FIELD_NONE;
buf->buf.sequence = dma->sequence++;
buf->buf.vb2_buf.timestamp = ktime_get_ns();
- vb2_set_plane_payload(&buf->buf.vb2_buf, 0, dma->format.sizeimage);
+
+ status = xilinx_xdma_get_fid(dma->dma, buf->desc, &fid);
+ if (!status) {
+ if (((V4L2_TYPE_IS_MULTIPLANAR(dma->format.type)) &&
+ dma->format.fmt.pix_mp.field == V4L2_FIELD_ALTERNATE) ||
+ dma->format.fmt.pix.field == V4L2_FIELD_ALTERNATE) {
+ /*
+ * fid = 1 is odd field i.e. V4L2_FIELD_TOP.
+ * fid = 0 is even field i.e. V4L2_FIELD_BOTTOM.
+ */
+ buf->buf.field = fid ?
+ V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM;
+
+ if (fid == dma->prev_fid)
+ buf->buf.sequence = dma->sequence++;
+
+ buf->buf.sequence >>= 1;
+ dma->prev_fid = fid;
+ }
+ }
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(dma->format.type)) {
+ for (i = 0; i < dma->fmtinfo->buffers; i++) {
+ sizeimage =
+ dma->format.fmt.pix_mp.plane_fmt[i].sizeimage;
+ vb2_set_plane_payload(&buf->buf.vb2_buf, i, sizeimage);
+ }
+ } else {
+ sizeimage = dma->format.fmt.pix.sizeimage;
+ vb2_set_plane_payload(&buf->buf.vb2_buf, 0, sizeimage);
+ }
+
vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_DONE);
}
@@ -318,13 +471,39 @@ xvip_dma_queue_setup(struct vb2_queue *vq,
unsigned int sizes[], struct device *alloc_devs[])
{
struct xvip_dma *dma = vb2_get_drv_priv(vq);
+ u8 i;
+ int sizeimage;
+
+ /* Multi planar case: Make sure the image size is large enough */
+ if (V4L2_TYPE_IS_MULTIPLANAR(dma->format.type)) {
+ if (*nplanes) {
+ if (*nplanes != dma->format.fmt.pix_mp.num_planes)
+ return -EINVAL;
+
+ for (i = 0; i < *nplanes; i++) {
+ sizeimage =
+ dma->format.fmt.pix_mp.plane_fmt[i].sizeimage;
+ if (sizes[i] < sizeimage)
+ return -EINVAL;
+ }
+ } else {
+ *nplanes = dma->fmtinfo->buffers;
+ for (i = 0; i < dma->fmtinfo->buffers; i++) {
+ sizeimage =
+ dma->format.fmt.pix_mp.plane_fmt[i].sizeimage;
+ sizes[i] = sizeimage;
+ }
+ }
+ return 0;
+ }
- /* Make sure the image size is large enough. */
- if (*nplanes)
- return sizes[0] < dma->format.sizeimage ? -EINVAL : 0;
+ /* Single planar case: Make sure the image size is large enough */
+ sizeimage = dma->format.fmt.pix.sizeimage;
+ if (*nplanes == 1)
+ return sizes[0] < sizeimage ? -EINVAL : 0;
*nplanes = 1;
- sizes[0] = dma->format.sizeimage;
+ sizes[0] = sizeimage;
return 0;
}
@@ -348,14 +527,19 @@ static void xvip_dma_buffer_queue(struct vb2_buffer *vb)
struct dma_async_tx_descriptor *desc;
dma_addr_t addr = vb2_dma_contig_plane_dma_addr(vb, 0);
u32 flags;
+ u32 luma_size;
+ u32 padding_factor_nume, padding_factor_deno, bpl_nume, bpl_deno;
+ u32 fid = ~0;
- if (dma->queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ if (dma->queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ dma->queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
dma->xt.dir = DMA_DEV_TO_MEM;
dma->xt.src_sgl = false;
dma->xt.dst_sgl = true;
dma->xt.dst_start = addr;
- } else {
+ } else if (dma->queue.type == V4L2_BUF_TYPE_VIDEO_OUTPUT ||
+ dma->queue.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
dma->xt.dir = DMA_MEM_TO_DEV;
dma->xt.src_sgl = true;
@@ -363,10 +547,66 @@ static void xvip_dma_buffer_queue(struct vb2_buffer *vb)
dma->xt.src_start = addr;
}
- dma->xt.frame_size = 1;
- dma->sgl[0].size = dma->format.width * dma->fmtinfo->bpp;
- dma->sgl[0].icg = dma->format.bytesperline - dma->sgl[0].size;
- dma->xt.numf = dma->format.height;
+ /*
+ * DMA IP supports only 2 planes, so one datachunk is sufficient
+ * to get start address of 2nd plane
+ */
+ if (V4L2_TYPE_IS_MULTIPLANAR(dma->format.type)) {
+ struct v4l2_pix_format_mplane *pix_mp;
+
+ pix_mp = &dma->format.fmt.pix_mp;
+ xilinx_xdma_v4l2_config(dma->dma, pix_mp->pixelformat);
+ xvip_width_padding_factor(pix_mp->pixelformat,
+ &padding_factor_nume,
+ &padding_factor_deno);
+ xvip_bpl_scaling_factor(pix_mp->pixelformat, &bpl_nume,
+ &bpl_deno);
+ dma->xt.frame_size = dma->fmtinfo->num_planes;
+ dma->sgl[0].size = (pix_mp->width * dma->fmtinfo->bpl_factor *
+ padding_factor_nume * bpl_nume) /
+ (padding_factor_deno * bpl_deno);
+ dma->sgl[0].icg = pix_mp->plane_fmt[0].bytesperline -
+ dma->sgl[0].size;
+ dma->xt.numf = pix_mp->height;
+
+ /*
+ * dst_icg is the number of bytes to jump after last luma addr
+ * and before first chroma addr
+ */
+
+ /* Handling contiguous data with mplanes */
+ if (dma->fmtinfo->buffers == 1) {
+ dma->sgl[0].dst_icg = 0;
+ } else {
+ /* Handling non-contiguous data with mplanes */
+ if (dma->fmtinfo->buffers == 2) {
+ dma_addr_t chroma_addr =
+ vb2_dma_contig_plane_dma_addr(vb, 1);
+ luma_size = pix_mp->plane_fmt[0].bytesperline *
+ dma->xt.numf;
+ if (chroma_addr > addr)
+ dma->sgl[0].dst_icg = chroma_addr -
+ addr - luma_size;
+ }
+ }
+ } else {
+ struct v4l2_pix_format *pix;
+
+ pix = &dma->format.fmt.pix;
+ xilinx_xdma_v4l2_config(dma->dma, pix->pixelformat);
+ xvip_width_padding_factor(pix->pixelformat,
+ &padding_factor_nume,
+ &padding_factor_deno);
+ xvip_bpl_scaling_factor(pix->pixelformat, &bpl_nume,
+ &bpl_deno);
+ dma->xt.frame_size = dma->fmtinfo->num_planes;
+ dma->sgl[0].size = (pix->width * dma->fmtinfo->bpl_factor *
+ padding_factor_nume * bpl_nume) /
+ (padding_factor_deno * bpl_deno);
+ dma->sgl[0].icg = pix->bytesperline - dma->sgl[0].size;
+ dma->xt.numf = pix->height;
+ dma->sgl[0].dst_icg = 0;
+ }
desc = dmaengine_prep_interleaved_dma(dma->dma, &dma->xt, flags);
if (!desc) {
@@ -376,6 +616,28 @@ static void xvip_dma_buffer_queue(struct vb2_buffer *vb)
}
desc->callback = xvip_dma_complete;
desc->callback_param = buf;
+ buf->desc = desc;
+
+ if (buf->buf.field == V4L2_FIELD_TOP)
+ fid = 1;
+ else if (buf->buf.field == V4L2_FIELD_BOTTOM)
+ fid = 0;
+ else if (buf->buf.field == V4L2_FIELD_NONE)
+ fid = 0;
+
+ xilinx_xdma_set_fid(dma->dma, desc, fid);
+
+ /* Set low latency capture mode */
+ if (dma->earlycb_mode) {
+ int ret;
+
+ ret = xilinx_xdma_set_earlycb(dma->dma, desc,
+ dma->earlycb_mode);
+ if (ret < 0) {
+ dev_err(dma->xdev->dev,
+ "Failed enable low latency mode\n");
+ }
+ }
spin_lock_irq(&dma->queued_lock);
list_add_tail(&buf->queue, &dma->queued_bufs);
@@ -395,6 +657,7 @@ static int xvip_dma_start_streaming(struct vb2_queue *vq, unsigned int count)
int ret;
dma->sequence = 0;
+ dma->prev_fid = ~0;
/*
* Start streaming on the pipeline. No link touching an entity in the
@@ -403,10 +666,12 @@ static int xvip_dma_start_streaming(struct vb2_queue *vq, unsigned int count)
* Use the pipeline object embedded in the first DMA object that starts
* streaming.
*/
+ mutex_lock(&dma->xdev->lock);
pipe = dma->video.entity.pipe
? to_xvip_pipeline(&dma->video.entity) : &dma->pipe;
ret = media_pipeline_start(&dma->video.entity, &pipe->pipe);
+ mutex_unlock(&dma->xdev->lock);
if (ret < 0)
goto error;
@@ -427,7 +692,9 @@ static int xvip_dma_start_streaming(struct vb2_queue *vq, unsigned int count)
dma_async_issue_pending(dma->dma);
/* Start the pipeline. */
- xvip_pipeline_set_stream(pipe, true);
+ ret = xvip_pipeline_set_stream(pipe, true);
+ if (ret < 0)
+ goto error_stop;
return 0;
@@ -435,6 +702,7 @@ error_stop:
media_pipeline_stop(&dma->video.entity);
error:
+ dmaengine_terminate_all(dma->dma);
/* Give back all queued buffers to videobuf2. */
spin_lock_irq(&dma->queued_lock);
list_for_each_entry_safe(buf, nbuf, &dma->queued_bufs, queue) {
@@ -493,10 +761,20 @@ xvip_dma_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
cap->device_caps = V4L2_CAP_STREAMING;
- if (dma->queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ switch (dma->queue.type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE;
- else
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ cap->device_caps |= V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
cap->device_caps |= V4L2_CAP_VIDEO_OUTPUT;
+ break;
+ }
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS
| dma->xdev->v4l2_caps;
@@ -509,6 +787,61 @@ xvip_dma_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
return 0;
}
+static int xvip_xdma_enum_fmt(struct xvip_dma *dma, struct v4l2_fmtdesc *f,
+ struct v4l2_subdev_format *v4l_fmt)
+{
+ const struct xvip_video_format *fmt;
+ int ret;
+ u32 i, fmt_cnt, *fmts;
+
+ ret = xilinx_xdma_get_v4l2_vid_fmts(dma->dma, &fmt_cnt, &fmts);
+ if (ret)
+ return ret;
+
+ /* Has media pad value changed? */
+ if (v4l_fmt->format.code != dma->remote_subdev_med_bus ||
+ !dma->remote_subdev_med_bus) {
+ /* Re-generate legal list of fourcc codes */
+ dma->poss_v4l2_fmt_cnt = 0;
+ dma->remote_subdev_med_bus = v4l_fmt->format.code;
+
+ if (!dma->poss_v4l2_fmts) {
+ dma->poss_v4l2_fmts =
+ devm_kzalloc(&dma->video.dev,
+ sizeof(u32) * fmt_cnt,
+ GFP_KERNEL);
+ if (!dma->poss_v4l2_fmts)
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < fmt_cnt; i++) {
+ fmt = xvip_get_format_by_fourcc(fmts[i]);
+ if (IS_ERR(fmt))
+ return PTR_ERR(fmt);
+
+ if (fmt->code != dma->remote_subdev_med_bus)
+ continue;
+
+ dma->poss_v4l2_fmts[dma->poss_v4l2_fmt_cnt++] = fmts[i];
+ }
+ }
+
+ /* Return err if index is greater than count of legal values */
+ if (f->index >= dma->poss_v4l2_fmt_cnt)
+ return -EINVAL;
+
+ /* Else return pix format in table */
+ fmt = xvip_get_format_by_fourcc(dma->poss_v4l2_fmts[f->index]);
+ if (IS_ERR(fmt))
+ return PTR_ERR(fmt);
+
+ f->pixelformat = fmt->fourcc;
+ strlcpy(f->description, fmt->description,
+ sizeof(f->description));
+
+ return 0;
+}
+
/* FIXME: without this callback function, some applications are not configured
* with correct formats, and it results in frames in wrong format. Whether this
* callback needs to be required is not clearly defined, so it should be
@@ -519,12 +852,49 @@ xvip_dma_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f)
{
struct v4l2_fh *vfh = file->private_data;
struct xvip_dma *dma = to_xvip_dma(vfh->vdev);
+ struct v4l2_subdev *subdev;
+ struct v4l2_subdev_format v4l_fmt;
+ const struct xvip_video_format *fmt;
+ int err, ret;
+
+ /* Establish media pad format */
+ subdev = xvip_dma_remote_subdev(&dma->pad, &v4l_fmt.pad);
+ if (!subdev)
+ return -EPIPE;
+
+ v4l_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &v4l_fmt);
+ if (ret < 0)
+ return ret == -ENOIOCTLCMD ? -EINVAL : ret;
+
+ /*
+ * In case of frmbuf DMA, this will invoke frambuf driver specific APIs
+ * to enumerate formats otherwise return the pix format corresponding
+ * to subdev's media bus format. This kind of separation would be
+ * helpful for clean up and upstreaming.
+ */
+ err = xvip_xdma_enum_fmt(dma, f, &v4l_fmt);
+ if (!err)
+ return err;
+ /*
+ * This logic will just return one pix format based on subdev's
+ * media bus format
+ */
if (f->index > 0)
return -EINVAL;
- f->pixelformat = dma->format.pixelformat;
- strscpy(f->description, dma->fmtinfo->description,
+ if (V4L2_TYPE_IS_MULTIPLANAR(dma->format.type))
+ f->pixelformat = dma->format.fmt.pix_mp.pixelformat;
+ else
+ f->pixelformat = dma->format.fmt.pix.pixelformat;
+
+ fmt = xvip_get_format_by_code(v4l_fmt.format.code);
+ if (IS_ERR(fmt))
+ return PTR_ERR(fmt);
+
+ f->pixelformat = fmt->fourcc;
+ strlcpy(f->description, fmt->description,
sizeof(f->description));
return 0;
@@ -536,13 +906,17 @@ xvip_dma_get_format(struct file *file, void *fh, struct v4l2_format *format)
struct v4l2_fh *vfh = file->private_data;
struct xvip_dma *dma = to_xvip_dma(vfh->vdev);
- format->fmt.pix = dma->format;
+ if (V4L2_TYPE_IS_MULTIPLANAR(dma->format.type))
+ format->fmt.pix_mp = dma->format.fmt.pix_mp;
+ else
+ format->fmt.pix = dma->format.fmt.pix;
return 0;
}
static void
-__xvip_dma_try_format(struct xvip_dma *dma, struct v4l2_pix_format *pix,
+__xvip_dma_try_format(struct xvip_dma *dma,
+ struct v4l2_format *format,
const struct xvip_video_format **fmtinfo)
{
const struct xvip_video_format *info;
@@ -553,40 +927,144 @@ __xvip_dma_try_format(struct xvip_dma *dma, struct v4l2_pix_format *pix,
unsigned int width;
unsigned int align;
unsigned int bpl;
+ unsigned int i, hsub, vsub, plane_width, plane_height;
+ unsigned int fourcc;
+ unsigned int padding_factor_nume, padding_factor_deno;
+ unsigned int bpl_nume, bpl_deno;
+ struct v4l2_subdev_format fmt;
+ struct v4l2_subdev *subdev;
+ int ret;
+
+ subdev = xvip_dma_remote_subdev(&dma->pad, &fmt.pad);
+ if (!subdev)
+ return;
+
+ fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
+ if (ret < 0)
+ return;
+
+ if (fmt.format.field == V4L2_FIELD_ALTERNATE) {
+ if (V4L2_TYPE_IS_MULTIPLANAR(dma->format.type))
+ dma->format.fmt.pix_mp.field = V4L2_FIELD_ALTERNATE;
+ else
+ dma->format.fmt.pix.field = V4L2_FIELD_ALTERNATE;
+ } else {
+ if (V4L2_TYPE_IS_MULTIPLANAR(dma->format.type))
+ dma->format.fmt.pix_mp.field = V4L2_FIELD_NONE;
+ else
+ dma->format.fmt.pix.field = V4L2_FIELD_NONE;
+ }
/* Retrieve format information and select the default format if the
* requested format isn't supported.
*/
- info = xvip_get_format_by_fourcc(pix->pixelformat);
+ if (V4L2_TYPE_IS_MULTIPLANAR(dma->format.type))
+ fourcc = format->fmt.pix_mp.pixelformat;
+ else
+ fourcc = format->fmt.pix.pixelformat;
+
+ info = xvip_get_format_by_fourcc(fourcc);
+
if (IS_ERR(info))
info = xvip_get_format_by_fourcc(XVIP_DMA_DEF_FORMAT);
- pix->pixelformat = info->fourcc;
- pix->field = V4L2_FIELD_NONE;
+ xvip_width_padding_factor(info->fourcc, &padding_factor_nume,
+ &padding_factor_deno);
+ xvip_bpl_scaling_factor(info->fourcc, &bpl_nume, &bpl_deno);
/* The transfer alignment requirements are expressed in bytes. Compute
* the minimum and maximum values, clamp the requested width and convert
* it back to pixels.
*/
- align = lcm(dma->align, info->bpp);
+ align = lcm(dma->align, info->bpp >> 3);
min_width = roundup(XVIP_DMA_MIN_WIDTH, align);
max_width = rounddown(XVIP_DMA_MAX_WIDTH, align);
- width = rounddown(pix->width * info->bpp, align);
-
- pix->width = clamp(width, min_width, max_width) / info->bpp;
- pix->height = clamp(pix->height, XVIP_DMA_MIN_HEIGHT,
- XVIP_DMA_MAX_HEIGHT);
- /* Clamp the requested bytes per line value. If the maximum bytes per
- * line value is zero, the module doesn't support user configurable line
- * sizes. Override the requested value with the minimum in that case.
- */
- min_bpl = pix->width * info->bpp;
- max_bpl = rounddown(XVIP_DMA_MAX_WIDTH, dma->align);
- bpl = rounddown(pix->bytesperline, dma->align);
-
- pix->bytesperline = clamp(bpl, min_bpl, max_bpl);
- pix->sizeimage = pix->bytesperline * pix->height;
+ if (V4L2_TYPE_IS_MULTIPLANAR(dma->format.type)) {
+ struct v4l2_pix_format_mplane *pix_mp;
+ struct v4l2_plane_pix_format *plane_fmt;
+
+ pix_mp = &format->fmt.pix_mp;
+ plane_fmt = pix_mp->plane_fmt;
+ pix_mp->field = dma->format.fmt.pix_mp.field;
+ width = rounddown(pix_mp->width * info->bpl_factor, align);
+ pix_mp->width = clamp(width, min_width, max_width) /
+ info->bpl_factor;
+ pix_mp->height = clamp(pix_mp->height, XVIP_DMA_MIN_HEIGHT,
+ XVIP_DMA_MAX_HEIGHT);
+
+ /*
+ * Clamp the requested bytes per line value. If the maximum
+ * bytes per line value is zero, the module doesn't support
+ * user configurable line sizes. Override the requested value
+ * with the minimum in that case.
+ */
+
+ max_bpl = rounddown(XVIP_DMA_MAX_WIDTH, dma->align);
+
+ /* Handling contiguous data with mplanes */
+ if (info->buffers == 1) {
+ min_bpl = (pix_mp->width * info->bpl_factor *
+ padding_factor_nume * bpl_nume) /
+ (padding_factor_deno * bpl_deno);
+ min_bpl = roundup(min_bpl, dma->align);
+ bpl = roundup(plane_fmt[0].bytesperline, dma->align);
+ plane_fmt[0].bytesperline = clamp(bpl, min_bpl,
+ max_bpl);
+
+ if (info->num_planes == 1) {
+ /* Single plane formats */
+ plane_fmt[0].sizeimage =
+ plane_fmt[0].bytesperline *
+ pix_mp->height;
+ } else {
+ /* Multi plane formats */
+ plane_fmt[0].sizeimage =
+ DIV_ROUND_UP(plane_fmt[0].bytesperline *
+ pix_mp->height *
+ info->bpp, 8);
+ }
+ } else {
+ /* Handling non-contiguous data with mplanes */
+ hsub = info->hsub;
+ vsub = info->vsub;
+ for (i = 0; i < info->num_planes; i++) {
+ plane_width = pix_mp->width / (i ? hsub : 1);
+ plane_height = pix_mp->height / (i ? vsub : 1);
+ min_bpl = (plane_width * info->bpl_factor *
+ padding_factor_nume * bpl_nume) /
+ (padding_factor_deno * bpl_deno);
+ min_bpl = roundup(min_bpl, dma->align);
+ bpl = rounddown(plane_fmt[i].bytesperline,
+ dma->align);
+ plane_fmt[i].bytesperline =
+ clamp(bpl, min_bpl, max_bpl);
+ plane_fmt[i].sizeimage =
+ plane_fmt[i].bytesperline *
+ plane_height;
+ }
+ }
+ } else {
+ struct v4l2_pix_format *pix;
+
+ pix = &format->fmt.pix;
+ pix->field = dma->format.fmt.pix.field;
+ width = rounddown(pix->width * info->bpl_factor, align);
+ pix->width = clamp(width, min_width, max_width) /
+ info->bpl_factor;
+ pix->height = clamp(pix->height, XVIP_DMA_MIN_HEIGHT,
+ XVIP_DMA_MAX_HEIGHT);
+
+ min_bpl = (pix->width * info->bpl_factor *
+ padding_factor_nume * bpl_nume) /
+ (padding_factor_deno * bpl_deno);
+ min_bpl = roundup(min_bpl, dma->align);
+ max_bpl = rounddown(XVIP_DMA_MAX_WIDTH, dma->align);
+ bpl = rounddown(pix->bytesperline, dma->align);
+ pix->bytesperline = clamp(bpl, min_bpl, max_bpl);
+ pix->sizeimage = pix->width * pix->height * info->bpp / 8;
+ }
if (fmtinfo)
*fmtinfo = info;
@@ -598,7 +1076,7 @@ xvip_dma_try_format(struct file *file, void *fh, struct v4l2_format *format)
struct v4l2_fh *vfh = file->private_data;
struct xvip_dma *dma = to_xvip_dma(vfh->vdev);
- __xvip_dma_try_format(dma, &format->fmt.pix, NULL);
+ __xvip_dma_try_format(dma, format, NULL);
return 0;
}
@@ -609,26 +1087,59 @@ xvip_dma_set_format(struct file *file, void *fh, struct v4l2_format *format)
struct xvip_dma *dma = to_xvip_dma(vfh->vdev);
const struct xvip_video_format *info;
- __xvip_dma_try_format(dma, &format->fmt.pix, &info);
+ __xvip_dma_try_format(dma, format, &info);
if (vb2_is_busy(&dma->queue))
return -EBUSY;
- dma->format = format->fmt.pix;
+ if (V4L2_TYPE_IS_MULTIPLANAR(dma->format.type))
+ dma->format.fmt.pix_mp = format->fmt.pix_mp;
+ else
+ dma->format.fmt.pix = format->fmt.pix;
+
dma->fmtinfo = info;
return 0;
}
+static int
+xvip_dma_set_ctrl(struct file *file, void *fh, struct v4l2_control *ctl)
+{
+ struct v4l2_fh *vfh = file->private_data;
+ struct xvip_dma *dma = to_xvip_dma(vfh->vdev);
+
+ if (vb2_is_busy(&dma->queue))
+ return -EBUSY;
+
+ if (ctl->id == V4L2_CID_XILINX_LOW_LATENCY) {
+ if (ctl->value)
+ dma->earlycb_mode = EARLY_CALLBACK_LOW_LATENCY;
+ else
+ dma->earlycb_mode = 0;
+ }
+
+ return 0;
+}
+
static const struct v4l2_ioctl_ops xvip_dma_ioctl_ops = {
.vidioc_querycap = xvip_dma_querycap,
.vidioc_enum_fmt_vid_cap = xvip_dma_enum_format,
+ .vidioc_enum_fmt_vid_cap_mplane = xvip_dma_enum_format,
+ .vidioc_enum_fmt_vid_out = xvip_dma_enum_format,
+ .vidioc_enum_fmt_vid_out_mplane = xvip_dma_enum_format,
.vidioc_g_fmt_vid_cap = xvip_dma_get_format,
+ .vidioc_g_fmt_vid_cap_mplane = xvip_dma_get_format,
.vidioc_g_fmt_vid_out = xvip_dma_get_format,
+ .vidioc_g_fmt_vid_out_mplane = xvip_dma_get_format,
.vidioc_s_fmt_vid_cap = xvip_dma_set_format,
+ .vidioc_s_fmt_vid_cap_mplane = xvip_dma_set_format,
.vidioc_s_fmt_vid_out = xvip_dma_set_format,
+ .vidioc_s_fmt_vid_out_mplane = xvip_dma_set_format,
+ .vidioc_s_ctrl = xvip_dma_set_ctrl,
.vidioc_try_fmt_vid_cap = xvip_dma_try_format,
+ .vidioc_try_fmt_vid_cap_mplane = xvip_dma_try_format,
.vidioc_try_fmt_vid_out = xvip_dma_try_format,
+ .vidioc_try_fmt_vid_out_mplane = xvip_dma_try_format,
.vidioc_reqbufs = vb2_ioctl_reqbufs,
.vidioc_querybuf = vb2_ioctl_querybuf,
.vidioc_qbuf = vb2_ioctl_qbuf,
@@ -661,6 +1172,7 @@ int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma,
{
char name[16];
int ret;
+ u32 i, hsub, vsub, width, height;
dma->xdev = xdev;
dma->port = port;
@@ -670,17 +1182,56 @@ int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma,
spin_lock_init(&dma->queued_lock);
dma->fmtinfo = xvip_get_format_by_fourcc(XVIP_DMA_DEF_FORMAT);
- dma->format.pixelformat = dma->fmtinfo->fourcc;
- dma->format.colorspace = V4L2_COLORSPACE_SRGB;
- dma->format.field = V4L2_FIELD_NONE;
- dma->format.width = XVIP_DMA_DEF_WIDTH;
- dma->format.height = XVIP_DMA_DEF_HEIGHT;
- dma->format.bytesperline = dma->format.width * dma->fmtinfo->bpp;
- dma->format.sizeimage = dma->format.bytesperline * dma->format.height;
+ dma->format.type = type;
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+ struct v4l2_pix_format_mplane *pix_mp;
+
+ pix_mp = &dma->format.fmt.pix_mp;
+ pix_mp->pixelformat = dma->fmtinfo->fourcc;
+ pix_mp->colorspace = V4L2_COLORSPACE_SRGB;
+ pix_mp->field = V4L2_FIELD_NONE;
+ pix_mp->width = XVIP_DMA_DEF_WIDTH;
+
+ /* Handling contiguous data with mplanes */
+ if (dma->fmtinfo->buffers == 1) {
+ pix_mp->plane_fmt[0].bytesperline =
+ pix_mp->width * dma->fmtinfo->bpl_factor;
+ pix_mp->plane_fmt[0].sizeimage =
+ pix_mp->width * pix_mp->height *
+ dma->fmtinfo->bpp / 8;
+ } else {
+ /* Handling non-contiguous data with mplanes */
+ hsub = dma->fmtinfo->hsub;
+ vsub = dma->fmtinfo->vsub;
+ for (i = 0; i < dma->fmtinfo->buffers; i++) {
+ width = pix_mp->width / (i ? hsub : 1);
+ height = pix_mp->height / (i ? vsub : 1);
+ pix_mp->plane_fmt[i].bytesperline =
+ width * dma->fmtinfo->bpl_factor;
+ pix_mp->plane_fmt[i].sizeimage = width * height;
+ }
+ }
+ } else {
+ struct v4l2_pix_format *pix;
+
+ pix = &dma->format.fmt.pix;
+ pix->pixelformat = dma->fmtinfo->fourcc;
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+ pix->field = V4L2_FIELD_NONE;
+ pix->width = XVIP_DMA_DEF_WIDTH;
+ pix->height = XVIP_DMA_DEF_HEIGHT;
+ pix->bytesperline = pix->width * dma->fmtinfo->bpl_factor;
+ pix->sizeimage =
+ pix->width * pix->height * dma->fmtinfo->bpp / 8;
+ }
/* Initialize the media entity... */
- dma->pad.flags = type == V4L2_BUF_TYPE_VIDEO_CAPTURE
- ? MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
+ if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ dma->pad.flags = MEDIA_PAD_FL_SINK;
+ else
+ dma->pad.flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_pads_init(&dma->video.entity, 1, &dma->pad);
if (ret < 0)
@@ -692,11 +1243,18 @@ int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma,
dma->video.queue = &dma->queue;
snprintf(dma->video.name, sizeof(dma->video.name), "%pOFn %s %u",
xdev->dev->of_node,
- type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? "output" : "input",
+ (type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ ? "output" : "input",
port);
+
dma->video.vfl_type = VFL_TYPE_GRABBER;
- dma->video.vfl_dir = type == V4L2_BUF_TYPE_VIDEO_CAPTURE
- ? VFL_DIR_RX : VFL_DIR_TX;
+ if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ dma->video.vfl_dir = VFL_DIR_RX;
+ else
+ dma->video.vfl_dir = VFL_DIR_TX;
+
dma->video.release = video_device_release_empty;
dma->video.ioctl_ops = &xvip_dma_ioctl_ops;
dma->video.lock = &dma->lock;
@@ -729,10 +1287,12 @@ int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma,
/* ... and the DMA channel. */
snprintf(name, sizeof(name), "port%u", port);
- dma->dma = dma_request_slave_channel(dma->xdev->dev, name);
- if (dma->dma == NULL) {
- dev_err(dma->xdev->dev, "no VDMA channel found\n");
- ret = -ENODEV;
+ dma->dma = dma_request_chan(dma->xdev->dev, name);
+ if (IS_ERR(dma->dma)) {
+ ret = PTR_ERR(dma->dma);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dma->xdev->dev,
+ "No Video DMA channel found");
goto error;
}
@@ -756,7 +1316,7 @@ void xvip_dma_cleanup(struct xvip_dma *dma)
if (video_is_registered(&dma->video))
video_unregister_device(&dma->video);
- if (dma->dma)
+ if (!IS_ERR(dma->dma))
dma_release_channel(dma->dma);
media_entity_cleanup(&dma->video.entity);
diff --git a/drivers/media/platform/xilinx/xilinx-dma.h b/drivers/media/platform/xilinx/xilinx-dma.h
index 5aec4d17eb21..61c26ab103f7 100644
--- a/drivers/media/platform/xilinx/xilinx-dma.h
+++ b/drivers/media/platform/xilinx/xilinx-dma.h
@@ -32,7 +32,7 @@ struct xvip_video_format;
* @use_count: number of DMA engines using the pipeline
* @stream_count: number of DMA engines currently streaming
* @num_dmas: number of DMA engines in the pipeline
- * @output: DMA engine at the output of the pipeline
+ * @xdev: Composite device the pipe belongs to
*/
struct xvip_pipeline {
struct media_pipeline pipe;
@@ -42,7 +42,7 @@ struct xvip_pipeline {
unsigned int stream_count;
unsigned int num_dmas;
- struct xvip_dma *output;
+ struct xvip_composite_device *xdev;
};
static inline struct xvip_pipeline *to_xvip_pipeline(struct media_entity *e)
@@ -55,12 +55,15 @@ static inline struct xvip_pipeline *to_xvip_pipeline(struct media_entity *e)
* @list: list entry in a composite device dmas list
* @video: V4L2 video device associated with the DMA channel
* @pad: media pad for the video device entity
+ * @remote_subdev_med_bus: media bus format of sub-device
* @xdev: composite device the DMA channel belongs to
* @pipe: pipeline belonging to the DMA channel
* @port: composite device DT node port number for the DMA channel
* @lock: protects the @format, @fmtinfo and @queue fields
* @format: active V4L2 pixel format
* @fmtinfo: format information corresponding to the active @format
+ * @poss_v4l2_fmts: All possible v4l formats supported
+ * @poss_v4l2_fmt_cnt: number of supported v4l formats
* @queue: vb2 buffers queue
* @sequence: V4L2 buffers sequence number
* @queued_bufs: list of queued buffers
@@ -69,19 +72,23 @@ static inline struct xvip_pipeline *to_xvip_pipeline(struct media_entity *e)
* @align: transfer alignment required by the DMA channel (in bytes)
* @xt: dma interleaved template for dma configuration
* @sgl: data chunk structure for dma_interleaved_template
+ * @prev_fid: Previous Field ID
*/
struct xvip_dma {
struct list_head list;
struct video_device video;
struct media_pad pad;
+ u32 remote_subdev_med_bus;
struct xvip_composite_device *xdev;
struct xvip_pipeline pipe;
unsigned int port;
struct mutex lock;
- struct v4l2_pix_format format;
+ struct v4l2_format format;
const struct xvip_video_format *fmtinfo;
+ u32 *poss_v4l2_fmts;
+ u32 poss_v4l2_fmt_cnt;
struct vb2_queue queue;
unsigned int sequence;
@@ -93,6 +100,9 @@ struct xvip_dma {
unsigned int align;
struct dma_interleaved_template xt;
struct data_chunk sgl[1];
+
+ u32 prev_fid;
+ u32 earlycb_mode;
};
#define to_xvip_dma(vdev) container_of(vdev, struct xvip_dma, video)
diff --git a/drivers/media/platform/xilinx/xilinx-gamma-coeff.h b/drivers/media/platform/xilinx/xilinx-gamma-coeff.h
new file mode 100644
index 000000000000..344260008a47
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-gamma-coeff.h
@@ -0,0 +1,5385 @@
+/*
+ * Xilinx Gamma Correction IP
+ *
+ * Copyright (C) 2017 Xilinx, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __XILINX_GAMMA_COEFF_H__
+#define __XILINX_GAMMA_COEFF_H__
+
+#define GAMMA_CURVE_LENGTH (40)
+
+#define GAMMA_BPC_8 (8)
+#define GAMMA8_TABLE_LENGTH BIT(GAMMA_BPC_8)
+static const u16 xgamma8_01[GAMMA8_TABLE_LENGTH] = {
+ 0, 147, 157, 164, 168, 172, 175, 178,
+ 180, 183, 184, 186, 188, 189, 191, 192,
+ 193, 195, 196, 197, 198, 199, 200, 200,
+ 201, 202, 203, 204, 204, 205, 206, 207,
+ 207, 208, 208, 209, 210, 210, 211, 211,
+ 212, 212, 213, 213, 214, 214, 215, 215,
+ 216, 216, 217, 217, 218, 218, 218, 219,
+ 219, 220, 220, 220, 221, 221, 221, 222,
+ 222, 222, 223, 223, 223, 224, 224, 224,
+ 225, 225, 225, 226, 226, 226, 227, 227,
+ 227, 227, 228, 228, 228, 228, 229, 229,
+ 229, 230, 230, 230, 230, 231, 231, 231,
+ 231, 232, 232, 232, 232, 232, 233, 233,
+ 233, 233, 234, 234, 234, 234, 234, 235,
+ 235, 235, 235, 235, 236, 236, 236, 236,
+ 236, 237, 237, 237, 237, 237, 238, 238,
+ 238, 238, 238, 239, 239, 239, 239, 239,
+ 239, 240, 240, 240, 240, 240, 240, 241,
+ 241, 241, 241, 241, 241, 242, 242, 242,
+ 242, 242, 242, 243, 243, 243, 243, 243,
+ 243, 244, 244, 244, 244, 244, 244, 244,
+ 245, 245, 245, 245, 245, 245, 245, 246,
+ 246, 246, 246, 246, 246, 246, 247, 247,
+ 247, 247, 247, 247, 247, 247, 248, 248,
+ 248, 248, 248, 248, 248, 249, 249, 249,
+ 249, 249, 249, 249, 249, 249, 250, 250,
+ 250, 250, 250, 250, 250, 250, 251, 251,
+ 251, 251, 251, 251, 251, 251, 251, 252,
+ 252, 252, 252, 252, 252, 252, 252, 252,
+ 253, 253, 253, 253, 253, 253, 253, 253,
+ 253, 254, 254, 254, 254, 254, 254, 254,
+ 254, 254, 254, 255, 255, 255, 255, 255,
+};
+
+static const u16 xgamma8_02[GAMMA8_TABLE_LENGTH] = {
+ 0, 84, 97, 105, 111, 116, 120, 124,
+ 128, 131, 133, 136, 138, 141, 143, 145,
+ 147, 148, 150, 152, 153, 155, 156, 158,
+ 159, 160, 162, 163, 164, 165, 166, 167,
+ 168, 169, 170, 171, 172, 173, 174, 175,
+ 176, 177, 178, 179, 179, 180, 181, 182,
+ 183, 183, 184, 185, 186, 186, 187, 188,
+ 188, 189, 190, 190, 191, 192, 192, 193,
+ 193, 194, 195, 195, 196, 196, 197, 197,
+ 198, 199, 199, 200, 200, 201, 201, 202,
+ 202, 203, 203, 204, 204, 205, 205, 206,
+ 206, 207, 207, 208, 208, 208, 209, 209,
+ 210, 210, 211, 211, 211, 212, 212, 213,
+ 213, 214, 214, 214, 215, 215, 216, 216,
+ 216, 217, 217, 217, 218, 218, 219, 219,
+ 219, 220, 220, 220, 221, 221, 221, 222,
+ 222, 223, 223, 223, 224, 224, 224, 225,
+ 225, 225, 226, 226, 226, 227, 227, 227,
+ 227, 228, 228, 228, 229, 229, 229, 230,
+ 230, 230, 231, 231, 231, 231, 232, 232,
+ 232, 233, 233, 233, 233, 234, 234, 234,
+ 235, 235, 235, 235, 236, 236, 236, 237,
+ 237, 237, 237, 238, 238, 238, 238, 239,
+ 239, 239, 239, 240, 240, 240, 240, 241,
+ 241, 241, 241, 242, 242, 242, 242, 243,
+ 243, 243, 243, 244, 244, 244, 244, 245,
+ 245, 245, 245, 246, 246, 246, 246, 246,
+ 247, 247, 247, 247, 248, 248, 248, 248,
+ 248, 249, 249, 249, 249, 250, 250, 250,
+ 250, 250, 251, 251, 251, 251, 252, 252,
+ 252, 252, 252, 253, 253, 253, 253, 253,
+ 254, 254, 254, 254, 254, 255, 255, 255,
+};
+
+static const u16 xgamma8_03[GAMMA8_TABLE_LENGTH] = {
+ 0, 48, 60, 67, 73, 78, 83, 87,
+ 90, 94, 97, 99, 102, 104, 107, 109,
+ 111, 113, 115, 117, 119, 121, 122, 124,
+ 125, 127, 129, 130, 131, 133, 134, 136,
+ 137, 138, 139, 141, 142, 143, 144, 145,
+ 146, 147, 148, 149, 151, 152, 153, 154,
+ 155, 155, 156, 157, 158, 159, 160, 161,
+ 162, 163, 164, 164, 165, 166, 167, 168,
+ 168, 169, 170, 171, 172, 172, 173, 174,
+ 174, 175, 176, 177, 177, 178, 179, 179,
+ 180, 181, 181, 182, 183, 183, 184, 185,
+ 185, 186, 187, 187, 188, 188, 189, 190,
+ 190, 191, 191, 192, 193, 193, 194, 194,
+ 195, 195, 196, 197, 197, 198, 198, 199,
+ 199, 200, 200, 201, 201, 202, 202, 203,
+ 203, 204, 204, 205, 205, 206, 206, 207,
+ 207, 208, 208, 209, 209, 210, 210, 211,
+ 211, 212, 212, 213, 213, 213, 214, 214,
+ 215, 215, 216, 216, 217, 217, 217, 218,
+ 218, 219, 219, 220, 220, 220, 221, 221,
+ 222, 222, 223, 223, 223, 224, 224, 225,
+ 225, 225, 226, 226, 227, 227, 227, 228,
+ 228, 229, 229, 229, 230, 230, 230, 231,
+ 231, 232, 232, 232, 233, 233, 233, 234,
+ 234, 235, 235, 235, 236, 236, 236, 237,
+ 237, 237, 238, 238, 238, 239, 239, 240,
+ 240, 240, 241, 241, 241, 242, 242, 242,
+ 243, 243, 243, 244, 244, 244, 245, 245,
+ 245, 246, 246, 246, 247, 247, 247, 248,
+ 248, 248, 249, 249, 249, 249, 250, 250,
+ 250, 251, 251, 251, 252, 252, 252, 253,
+ 253, 253, 253, 254, 254, 254, 255, 255,
+};
+
+static const u16 xgamma8_04[GAMMA8_TABLE_LENGTH] = {
+ 0, 28, 37, 43, 48, 53, 57, 61,
+ 64, 67, 70, 73, 75, 78, 80, 82,
+ 84, 86, 88, 90, 92, 94, 96, 97,
+ 99, 101, 102, 104, 105, 107, 108, 110,
+ 111, 113, 114, 115, 117, 118, 119, 120,
+ 122, 123, 124, 125, 126, 127, 129, 130,
+ 131, 132, 133, 134, 135, 136, 137, 138,
+ 139, 140, 141, 142, 143, 144, 145, 146,
+ 147, 148, 149, 149, 150, 151, 152, 153,
+ 154, 155, 155, 156, 157, 158, 159, 160,
+ 160, 161, 162, 163, 164, 164, 165, 166,
+ 167, 167, 168, 169, 170, 170, 171, 172,
+ 173, 173, 174, 175, 175, 176, 177, 177,
+ 178, 179, 179, 180, 181, 182, 182, 183,
+ 183, 184, 185, 185, 186, 187, 187, 188,
+ 189, 189, 190, 190, 191, 192, 192, 193,
+ 194, 194, 195, 195, 196, 197, 197, 198,
+ 198, 199, 199, 200, 201, 201, 202, 202,
+ 203, 203, 204, 205, 205, 206, 206, 207,
+ 207, 208, 208, 209, 209, 210, 211, 211,
+ 212, 212, 213, 213, 214, 214, 215, 215,
+ 216, 216, 217, 217, 218, 218, 219, 219,
+ 220, 220, 221, 221, 222, 222, 223, 223,
+ 224, 224, 225, 225, 226, 226, 227, 227,
+ 228, 228, 229, 229, 230, 230, 230, 231,
+ 231, 232, 232, 233, 233, 234, 234, 235,
+ 235, 235, 236, 236, 237, 237, 238, 238,
+ 239, 239, 240, 240, 240, 241, 241, 242,
+ 242, 243, 243, 243, 244, 244, 245, 245,
+ 246, 246, 246, 247, 247, 248, 248, 248,
+ 249, 249, 250, 250, 251, 251, 251, 252,
+ 252, 253, 253, 253, 254, 254, 255, 255,
+};
+
+static const u16 xgamma8_05[GAMMA8_TABLE_LENGTH] = {
+ 0, 16, 23, 28, 32, 36, 39, 42,
+ 45, 48, 50, 53, 55, 58, 60, 62,
+ 64, 66, 68, 70, 71, 73, 75, 77,
+ 78, 80, 81, 83, 84, 86, 87, 89,
+ 90, 92, 93, 94, 96, 97, 98, 100,
+ 101, 102, 103, 105, 106, 107, 108, 109,
+ 111, 112, 113, 114, 115, 116, 117, 118,
+ 119, 121, 122, 123, 124, 125, 126, 127,
+ 128, 129, 130, 131, 132, 133, 134, 135,
+ 135, 136, 137, 138, 139, 140, 141, 142,
+ 143, 144, 145, 145, 146, 147, 148, 149,
+ 150, 151, 151, 152, 153, 154, 155, 156,
+ 156, 157, 158, 159, 160, 160, 161, 162,
+ 163, 164, 164, 165, 166, 167, 167, 168,
+ 169, 170, 170, 171, 172, 173, 173, 174,
+ 175, 176, 176, 177, 178, 179, 179, 180,
+ 181, 181, 182, 183, 183, 184, 185, 186,
+ 186, 187, 188, 188, 189, 190, 190, 191,
+ 192, 192, 193, 194, 194, 195, 196, 196,
+ 197, 198, 198, 199, 199, 200, 201, 201,
+ 202, 203, 203, 204, 204, 205, 206, 206,
+ 207, 208, 208, 209, 209, 210, 211, 211,
+ 212, 212, 213, 214, 214, 215, 215, 216,
+ 217, 217, 218, 218, 219, 220, 220, 221,
+ 221, 222, 222, 223, 224, 224, 225, 225,
+ 226, 226, 227, 228, 228, 229, 229, 230,
+ 230, 231, 231, 232, 233, 233, 234, 234,
+ 235, 235, 236, 236, 237, 237, 238, 238,
+ 239, 240, 240, 241, 241, 242, 242, 243,
+ 243, 244, 244, 245, 245, 246, 246, 247,
+ 247, 248, 248, 249, 249, 250, 250, 251,
+ 251, 252, 252, 253, 253, 254, 254, 255,
+};
+
+static const u16 xgamma8_06[GAMMA8_TABLE_LENGTH] = {
+ 0, 9, 14, 18, 21, 24, 27, 29,
+ 32, 34, 37, 39, 41, 43, 45, 47,
+ 48, 50, 52, 54, 55, 57, 59, 60,
+ 62, 63, 65, 66, 68, 69, 71, 72,
+ 73, 75, 76, 77, 79, 80, 81, 83,
+ 84, 85, 86, 88, 89, 90, 91, 92,
+ 94, 95, 96, 97, 98, 99, 100, 102,
+ 103, 104, 105, 106, 107, 108, 109, 110,
+ 111, 112, 113, 114, 115, 116, 117, 118,
+ 119, 120, 121, 122, 123, 124, 125, 126,
+ 127, 128, 129, 130, 131, 132, 133, 134,
+ 135, 136, 137, 137, 138, 139, 140, 141,
+ 142, 143, 144, 145, 145, 146, 147, 148,
+ 149, 150, 151, 151, 152, 153, 154, 155,
+ 156, 156, 157, 158, 159, 160, 161, 161,
+ 162, 163, 164, 165, 165, 166, 167, 168,
+ 169, 169, 170, 171, 172, 173, 173, 174,
+ 175, 176, 176, 177, 178, 179, 179, 180,
+ 181, 182, 182, 183, 184, 185, 185, 186,
+ 187, 188, 188, 189, 190, 191, 191, 192,
+ 193, 194, 194, 195, 196, 196, 197, 198,
+ 199, 199, 200, 201, 201, 202, 203, 203,
+ 204, 205, 206, 206, 207, 208, 208, 209,
+ 210, 210, 211, 212, 212, 213, 214, 214,
+ 215, 216, 216, 217, 218, 218, 219, 220,
+ 220, 221, 222, 222, 223, 224, 224, 225,
+ 226, 226, 227, 228, 228, 229, 230, 230,
+ 231, 231, 232, 233, 233, 234, 235, 235,
+ 236, 237, 237, 238, 238, 239, 240, 240,
+ 241, 242, 242, 243, 243, 244, 245, 245,
+ 246, 247, 247, 248, 248, 249, 250, 250,
+ 251, 251, 252, 253, 253, 254, 254, 255,
+};
+
+static const u16 xgamma8_07[GAMMA8_TABLE_LENGTH] = {
+ 0, 5, 9, 11, 14, 16, 18, 21,
+ 23, 25, 26, 28, 30, 32, 33, 35,
+ 37, 38, 40, 41, 43, 44, 46, 47,
+ 49, 50, 52, 53, 54, 56, 57, 58,
+ 60, 61, 62, 64, 65, 66, 67, 69,
+ 70, 71, 72, 73, 75, 76, 77, 78,
+ 79, 80, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90, 92, 93, 94, 95, 96,
+ 97, 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110, 111, 112,
+ 113, 114, 115, 116, 117, 118, 119, 120,
+ 121, 122, 123, 124, 125, 126, 127, 128,
+ 129, 130, 131, 131, 132, 133, 134, 135,
+ 136, 137, 138, 139, 140, 141, 142, 142,
+ 143, 144, 145, 146, 147, 148, 149, 150,
+ 150, 151, 152, 153, 154, 155, 156, 157,
+ 157, 158, 159, 160, 161, 162, 163, 163,
+ 164, 165, 166, 167, 168, 168, 169, 170,
+ 171, 172, 173, 173, 174, 175, 176, 177,
+ 178, 178, 179, 180, 181, 182, 182, 183,
+ 184, 185, 186, 186, 187, 188, 189, 190,
+ 190, 191, 192, 193, 194, 194, 195, 196,
+ 197, 197, 198, 199, 200, 201, 201, 202,
+ 203, 204, 204, 205, 206, 207, 208, 208,
+ 209, 210, 211, 211, 212, 213, 214, 214,
+ 215, 216, 217, 217, 218, 219, 220, 220,
+ 221, 222, 223, 223, 224, 225, 226, 226,
+ 227, 228, 228, 229, 230, 231, 231, 232,
+ 233, 234, 234, 235, 236, 237, 237, 238,
+ 239, 239, 240, 241, 242, 242, 243, 244,
+ 244, 245, 246, 247, 247, 248, 249, 249,
+ 250, 251, 251, 252, 253, 254, 254, 255,
+};
+
+static const u16 xgamma8_08[GAMMA8_TABLE_LENGTH] = {
+ 0, 3, 5, 7, 9, 11, 13, 14,
+ 16, 18, 19, 21, 22, 24, 25, 26,
+ 28, 29, 31, 32, 33, 35, 36, 37,
+ 39, 40, 41, 42, 44, 45, 46, 47,
+ 48, 50, 51, 52, 53, 54, 56, 57,
+ 58, 59, 60, 61, 63, 64, 65, 66,
+ 67, 68, 69, 70, 71, 73, 74, 75,
+ 76, 77, 78, 79, 80, 81, 82, 83,
+ 84, 85, 86, 88, 89, 90, 91, 92,
+ 93, 94, 95, 96, 97, 98, 99, 100,
+ 101, 102, 103, 104, 105, 106, 107, 108,
+ 109, 110, 111, 112, 113, 114, 115, 116,
+ 117, 118, 119, 120, 121, 122, 123, 123,
+ 124, 125, 126, 127, 128, 129, 130, 131,
+ 132, 133, 134, 135, 136, 137, 138, 139,
+ 140, 140, 141, 142, 143, 144, 145, 146,
+ 147, 148, 149, 150, 151, 151, 152, 153,
+ 154, 155, 156, 157, 158, 159, 160, 161,
+ 161, 162, 163, 164, 165, 166, 167, 168,
+ 169, 169, 170, 171, 172, 173, 174, 175,
+ 176, 177, 177, 178, 179, 180, 181, 182,
+ 183, 183, 184, 185, 186, 187, 188, 189,
+ 190, 190, 191, 192, 193, 194, 195, 196,
+ 196, 197, 198, 199, 200, 201, 202, 202,
+ 203, 204, 205, 206, 207, 207, 208, 209,
+ 210, 211, 212, 212, 213, 214, 215, 216,
+ 217, 217, 218, 219, 220, 221, 222, 222,
+ 223, 224, 225, 226, 227, 227, 228, 229,
+ 230, 231, 232, 232, 233, 234, 235, 236,
+ 236, 237, 238, 239, 240, 240, 241, 242,
+ 243, 244, 245, 245, 246, 247, 248, 249,
+ 249, 250, 251, 252, 253, 253, 254, 255,
+};
+
+static const u16 xgamma8_09[GAMMA8_TABLE_LENGTH] = {
+ 0, 2, 3, 5, 6, 7, 9, 10,
+ 11, 13, 14, 15, 16, 18, 19, 20,
+ 21, 22, 23, 25, 26, 27, 28, 29,
+ 30, 32, 33, 34, 35, 36, 37, 38,
+ 39, 40, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 54, 55, 56,
+ 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72,
+ 73, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 87, 88, 89,
+ 90, 91, 92, 93, 94, 95, 96, 97,
+ 98, 99, 100, 101, 102, 103, 104, 105,
+ 106, 107, 108, 109, 110, 111, 112, 113,
+ 114, 115, 116, 117, 118, 119, 120, 121,
+ 122, 123, 124, 125, 126, 126, 127, 128,
+ 129, 130, 131, 132, 133, 134, 135, 136,
+ 137, 138, 139, 140, 141, 142, 143, 144,
+ 145, 146, 147, 148, 149, 150, 151, 152,
+ 152, 153, 154, 155, 156, 157, 158, 159,
+ 160, 161, 162, 163, 164, 165, 166, 167,
+ 168, 169, 170, 170, 171, 172, 173, 174,
+ 175, 176, 177, 178, 179, 180, 181, 182,
+ 183, 184, 185, 185, 186, 187, 188, 189,
+ 190, 191, 192, 193, 194, 195, 196, 197,
+ 198, 198, 199, 200, 201, 202, 203, 204,
+ 205, 206, 207, 208, 209, 210, 210, 211,
+ 212, 213, 214, 215, 216, 217, 218, 219,
+ 220, 221, 221, 222, 223, 224, 225, 226,
+ 227, 228, 229, 230, 231, 231, 232, 233,
+ 234, 235, 236, 237, 238, 239, 240, 241,
+ 241, 242, 243, 244, 245, 246, 247, 248,
+ 249, 250, 250, 251, 252, 253, 254, 255,
+};
+
+static const u16 xgamma8_10[GAMMA8_TABLE_LENGTH] = {
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103,
+ 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127,
+ 128, 129, 130, 131, 132, 133, 134, 135,
+ 136, 137, 138, 139, 140, 141, 142, 143,
+ 144, 145, 146, 147, 148, 149, 150, 151,
+ 152, 153, 154, 155, 156, 157, 158, 159,
+ 160, 161, 162, 163, 164, 165, 166, 167,
+ 168, 169, 170, 171, 172, 173, 174, 175,
+ 176, 177, 178, 179, 180, 181, 182, 183,
+ 184, 185, 186, 187, 188, 189, 190, 191,
+ 192, 193, 194, 195, 196, 197, 198, 199,
+ 200, 201, 202, 203, 204, 205, 206, 207,
+ 208, 209, 210, 211, 212, 213, 214, 215,
+ 216, 217, 218, 219, 220, 221, 222, 223,
+ 224, 225, 226, 227, 228, 229, 230, 231,
+ 232, 233, 234, 235, 236, 237, 238, 239,
+ 240, 241, 242, 243, 244, 245, 246, 247,
+ 248, 249, 250, 251, 252, 253, 254, 255,
+};
+
+static const u16 xgamma8_11[GAMMA8_TABLE_LENGTH] = {
+ 0, 1, 1, 2, 3, 3, 4, 5,
+ 6, 6, 7, 8, 9, 10, 10, 11,
+ 12, 13, 14, 15, 16, 16, 17, 18,
+ 19, 20, 21, 22, 22, 23, 24, 25,
+ 26, 27, 28, 29, 30, 31, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 62,
+ 63, 64, 65, 66, 67, 68, 69, 70,
+ 71, 72, 73, 74, 75, 76, 77, 78,
+ 79, 80, 81, 82, 83, 84, 85, 86,
+ 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, 96, 97, 98, 99, 100, 101, 102,
+ 103, 104, 105, 106, 107, 108, 109, 110,
+ 111, 112, 113, 114, 115, 116, 117, 118,
+ 119, 121, 122, 123, 124, 125, 126, 127,
+ 128, 129, 130, 131, 132, 133, 134, 135,
+ 136, 137, 138, 139, 140, 141, 142, 143,
+ 144, 145, 146, 147, 149, 150, 151, 152,
+ 153, 154, 155, 156, 157, 158, 159, 160,
+ 161, 162, 163, 164, 165, 166, 167, 169,
+ 170, 171, 172, 173, 174, 175, 176, 177,
+ 178, 179, 180, 181, 182, 183, 184, 186,
+ 187, 188, 189, 190, 191, 192, 193, 194,
+ 195, 196, 197, 198, 199, 201, 202, 203,
+ 204, 205, 206, 207, 208, 209, 210, 211,
+ 212, 214, 215, 216, 217, 218, 219, 220,
+ 221, 222, 223, 224, 225, 227, 228, 229,
+ 230, 231, 232, 233, 234, 235, 236, 237,
+ 239, 240, 241, 242, 243, 244, 245, 246,
+ 247, 248, 250, 251, 252, 253, 254, 255,
+};
+
+static const u16 xgamma8_12[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 1, 1, 2, 2, 3, 3,
+ 4, 5, 5, 6, 7, 7, 8, 9,
+ 9, 10, 11, 11, 12, 13, 13, 14,
+ 15, 16, 16, 17, 18, 19, 20, 20,
+ 21, 22, 23, 24, 24, 25, 26, 27,
+ 28, 28, 29, 30, 31, 32, 33, 34,
+ 34, 35, 36, 37, 38, 39, 40, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 62,
+ 63, 64, 65, 66, 67, 68, 69, 70,
+ 71, 72, 73, 74, 75, 76, 77, 78,
+ 79, 80, 81, 82, 83, 84, 85, 86,
+ 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, 96, 97, 98, 99, 100, 101, 102,
+ 103, 104, 105, 106, 107, 108, 109, 110,
+ 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127,
+ 128, 130, 131, 132, 133, 134, 135, 136,
+ 137, 138, 139, 140, 141, 142, 144, 145,
+ 146, 147, 148, 149, 150, 151, 152, 153,
+ 155, 156, 157, 158, 159, 160, 161, 162,
+ 163, 165, 166, 167, 168, 169, 170, 171,
+ 172, 173, 175, 176, 177, 178, 179, 180,
+ 181, 183, 184, 185, 186, 187, 188, 189,
+ 191, 192, 193, 194, 195, 196, 197, 199,
+ 200, 201, 202, 203, 204, 205, 207, 208,
+ 209, 210, 211, 212, 214, 215, 216, 217,
+ 218, 219, 221, 222, 223, 224, 225, 226,
+ 228, 229, 230, 231, 232, 234, 235, 236,
+ 237, 238, 239, 241, 242, 243, 244, 245,
+ 247, 248, 249, 250, 251, 253, 254, 255,
+};
+
+static const u16 xgamma8_13[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 0, 1, 1, 2, 2, 2,
+ 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 8, 8, 9, 9, 10, 11, 11,
+ 12, 12, 13, 14, 14, 15, 16, 16,
+ 17, 18, 19, 19, 20, 21, 21, 22,
+ 23, 24, 24, 25, 26, 27, 28, 28,
+ 29, 30, 31, 31, 32, 33, 34, 35,
+ 36, 36, 37, 38, 39, 40, 41, 41,
+ 42, 43, 44, 45, 46, 47, 47, 48,
+ 49, 50, 51, 52, 53, 54, 55, 56,
+ 57, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 76, 77, 78,
+ 79, 80, 81, 82, 83, 84, 85, 86,
+ 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103,
+ 104, 105, 106, 107, 108, 109, 110, 112,
+ 113, 114, 115, 116, 117, 118, 119, 120,
+ 121, 122, 124, 125, 126, 127, 128, 129,
+ 130, 131, 132, 133, 135, 136, 137, 138,
+ 139, 140, 141, 143, 144, 145, 146, 147,
+ 148, 149, 151, 152, 153, 154, 155, 156,
+ 157, 159, 160, 161, 162, 163, 164, 166,
+ 167, 168, 169, 170, 172, 173, 174, 175,
+ 176, 178, 179, 180, 181, 182, 184, 185,
+ 186, 187, 188, 190, 191, 192, 193, 194,
+ 196, 197, 198, 199, 201, 202, 203, 204,
+ 206, 207, 208, 209, 210, 212, 213, 214,
+ 215, 217, 218, 219, 220, 222, 223, 224,
+ 226, 227, 228, 229, 231, 232, 233, 234,
+ 236, 237, 238, 240, 241, 242, 243, 245,
+ 246, 247, 249, 250, 251, 252, 254, 255,
+};
+
+static const u16 xgamma8_14[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 0, 1, 1, 1, 1, 2,
+ 2, 2, 3, 3, 4, 4, 4, 5,
+ 5, 6, 6, 7, 7, 8, 8, 9,
+ 9, 10, 10, 11, 12, 12, 13, 13,
+ 14, 15, 15, 16, 16, 17, 18, 18,
+ 19, 20, 20, 21, 22, 22, 23, 24,
+ 25, 25, 26, 27, 28, 28, 29, 30,
+ 31, 31, 32, 33, 34, 34, 35, 36,
+ 37, 38, 38, 39, 40, 41, 42, 43,
+ 43, 44, 45, 46, 47, 48, 49, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57,
+ 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 78, 79, 80,
+ 81, 82, 83, 84, 85, 86, 87, 88,
+ 89, 90, 91, 92, 93, 94, 95, 96,
+ 97, 98, 99, 100, 101, 103, 104, 105,
+ 106, 107, 108, 109, 110, 111, 112, 113,
+ 115, 116, 117, 118, 119, 120, 121, 122,
+ 124, 125, 126, 127, 128, 129, 130, 132,
+ 133, 134, 135, 136, 137, 139, 140, 141,
+ 142, 143, 145, 146, 147, 148, 149, 151,
+ 152, 153, 154, 155, 157, 158, 159, 160,
+ 161, 163, 164, 165, 166, 168, 169, 170,
+ 171, 173, 174, 175, 176, 178, 179, 180,
+ 181, 183, 184, 185, 187, 188, 189, 190,
+ 192, 193, 194, 196, 197, 198, 200, 201,
+ 202, 203, 205, 206, 207, 209, 210, 211,
+ 213, 214, 215, 217, 218, 219, 221, 222,
+ 223, 225, 226, 227, 229, 230, 232, 233,
+ 234, 236, 237, 238, 240, 241, 242, 244,
+ 245, 247, 248, 249, 251, 252, 254, 255,
+};
+
+static const u16 xgamma8_15[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 1, 1, 1, 1,
+ 1, 2, 2, 2, 3, 3, 3, 4,
+ 4, 4, 5, 5, 6, 6, 6, 7,
+ 7, 8, 8, 9, 9, 10, 10, 11,
+ 11, 12, 12, 13, 14, 14, 15, 15,
+ 16, 16, 17, 18, 18, 19, 20, 20,
+ 21, 21, 22, 23, 23, 24, 25, 26,
+ 26, 27, 28, 28, 29, 30, 31, 31,
+ 32, 33, 34, 34, 35, 36, 37, 37,
+ 38, 39, 40, 41, 41, 42, 43, 44,
+ 45, 46, 46, 47, 48, 49, 50, 51,
+ 52, 53, 53, 54, 55, 56, 57, 58,
+ 59, 60, 61, 62, 63, 64, 65, 65,
+ 66, 67, 68, 69, 70, 71, 72, 73,
+ 74, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 88, 89, 90,
+ 91, 92, 93, 94, 95, 96, 97, 98,
+ 99, 100, 102, 103, 104, 105, 106, 107,
+ 108, 109, 110, 112, 113, 114, 115, 116,
+ 117, 119, 120, 121, 122, 123, 124, 126,
+ 127, 128, 129, 130, 132, 133, 134, 135,
+ 136, 138, 139, 140, 141, 142, 144, 145,
+ 146, 147, 149, 150, 151, 152, 154, 155,
+ 156, 158, 159, 160, 161, 163, 164, 165,
+ 167, 168, 169, 171, 172, 173, 174, 176,
+ 177, 178, 180, 181, 182, 184, 185, 187,
+ 188, 189, 191, 192, 193, 195, 196, 197,
+ 199, 200, 202, 203, 204, 206, 207, 209,
+ 210, 211, 213, 214, 216, 217, 218, 220,
+ 221, 223, 224, 226, 227, 228, 230, 231,
+ 233, 234, 236, 237, 239, 240, 242, 243,
+ 245, 246, 248, 249, 251, 252, 254, 255,
+};
+
+static const u16 xgamma8_16[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 1, 1,
+ 1, 1, 1, 2, 2, 2, 2, 3,
+ 3, 3, 4, 4, 4, 5, 5, 5,
+ 6, 6, 7, 7, 7, 8, 8, 9,
+ 9, 10, 10, 11, 11, 12, 12, 13,
+ 13, 14, 14, 15, 15, 16, 16, 17,
+ 18, 18, 19, 19, 20, 21, 21, 22,
+ 23, 23, 24, 25, 25, 26, 27, 27,
+ 28, 29, 29, 30, 31, 31, 32, 33,
+ 34, 34, 35, 36, 37, 38, 38, 39,
+ 40, 41, 42, 42, 43, 44, 45, 46,
+ 46, 47, 48, 49, 50, 51, 52, 53,
+ 53, 54, 55, 56, 57, 58, 59, 60,
+ 61, 62, 63, 64, 64, 65, 66, 67,
+ 68, 69, 70, 71, 72, 73, 74, 75,
+ 76, 77, 78, 79, 80, 81, 83, 84,
+ 85, 86, 87, 88, 89, 90, 91, 92,
+ 93, 94, 95, 97, 98, 99, 100, 101,
+ 102, 103, 104, 106, 107, 108, 109, 110,
+ 111, 113, 114, 115, 116, 117, 119, 120,
+ 121, 122, 123, 125, 126, 127, 128, 130,
+ 131, 132, 133, 135, 136, 137, 138, 140,
+ 141, 142, 143, 145, 146, 147, 149, 150,
+ 151, 153, 154, 155, 157, 158, 159, 161,
+ 162, 163, 165, 166, 167, 169, 170, 171,
+ 173, 174, 176, 177, 178, 180, 181, 183,
+ 184, 185, 187, 188, 190, 191, 193, 194,
+ 196, 197, 198, 200, 201, 203, 204, 206,
+ 207, 209, 210, 212, 213, 215, 216, 218,
+ 219, 221, 222, 224, 225, 227, 228, 230,
+ 231, 233, 235, 236, 238, 239, 241, 242,
+ 244, 245, 247, 249, 250, 252, 253, 255,
+};
+
+static const u16 xgamma8_17[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1, 2, 2, 2,
+ 2, 3, 3, 3, 3, 4, 4, 4,
+ 5, 5, 5, 6, 6, 6, 7, 7,
+ 7, 8, 8, 9, 9, 10, 10, 10,
+ 11, 11, 12, 12, 13, 13, 14, 14,
+ 15, 15, 16, 17, 17, 18, 18, 19,
+ 19, 20, 21, 21, 22, 22, 23, 24,
+ 24, 25, 26, 26, 27, 28, 28, 29,
+ 30, 30, 31, 32, 33, 33, 34, 35,
+ 36, 36, 37, 38, 39, 39, 40, 41,
+ 42, 43, 43, 44, 45, 46, 47, 48,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 56, 57, 58, 59, 60, 61, 62,
+ 63, 64, 65, 66, 67, 68, 69, 70,
+ 71, 72, 73, 74, 75, 76, 77, 78,
+ 79, 80, 81, 82, 83, 84, 85, 86,
+ 88, 89, 90, 91, 92, 93, 94, 95,
+ 97, 98, 99, 100, 101, 102, 103, 105,
+ 106, 107, 108, 109, 111, 112, 113, 114,
+ 115, 117, 118, 119, 120, 122, 123, 124,
+ 125, 127, 128, 129, 131, 132, 133, 134,
+ 136, 137, 138, 140, 141, 142, 144, 145,
+ 146, 148, 149, 151, 152, 153, 155, 156,
+ 157, 159, 160, 162, 163, 164, 166, 167,
+ 169, 170, 172, 173, 174, 176, 177, 179,
+ 180, 182, 183, 185, 186, 188, 189, 191,
+ 192, 194, 195, 197, 198, 200, 201, 203,
+ 205, 206, 208, 209, 211, 212, 214, 216,
+ 217, 219, 220, 222, 224, 225, 227, 228,
+ 230, 232, 233, 235, 237, 238, 240, 242,
+ 243, 245, 247, 248, 250, 252, 253, 255,
+};
+
+static const u16 xgamma8_18[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 2,
+ 2, 2, 2, 2, 3, 3, 3, 3,
+ 4, 4, 4, 4, 5, 5, 5, 6,
+ 6, 6, 7, 7, 8, 8, 8, 9,
+ 9, 10, 10, 10, 11, 11, 12, 12,
+ 13, 13, 14, 14, 15, 15, 16, 16,
+ 17, 17, 18, 18, 19, 19, 20, 21,
+ 21, 22, 22, 23, 24, 24, 25, 26,
+ 26, 27, 28, 28, 29, 30, 30, 31,
+ 32, 32, 33, 34, 35, 35, 36, 37,
+ 38, 38, 39, 40, 41, 41, 42, 43,
+ 44, 45, 46, 46, 47, 48, 49, 50,
+ 51, 52, 53, 53, 54, 55, 56, 57,
+ 58, 59, 60, 61, 62, 63, 64, 65,
+ 66, 67, 68, 69, 70, 71, 72, 73,
+ 74, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 86, 87, 88, 89, 90,
+ 91, 92, 93, 95, 96, 97, 98, 99,
+ 100, 102, 103, 104, 105, 107, 108, 109,
+ 110, 111, 113, 114, 115, 116, 118, 119,
+ 120, 122, 123, 124, 126, 127, 128, 129,
+ 131, 132, 134, 135, 136, 138, 139, 140,
+ 142, 143, 145, 146, 147, 149, 150, 152,
+ 153, 154, 156, 157, 159, 160, 162, 163,
+ 165, 166, 168, 169, 171, 172, 174, 175,
+ 177, 178, 180, 181, 183, 184, 186, 188,
+ 189, 191, 192, 194, 195, 197, 199, 200,
+ 202, 204, 205, 207, 208, 210, 212, 213,
+ 215, 217, 218, 220, 222, 224, 225, 227,
+ 229, 230, 232, 234, 236, 237, 239, 241,
+ 243, 244, 246, 248, 250, 251, 253, 255,
+};
+
+static const u16 xgamma8_19[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 1, 1, 1, 1,
+ 1, 1, 2, 2, 2, 2, 2, 3,
+ 3, 3, 3, 4, 4, 4, 4, 5,
+ 5, 5, 6, 6, 6, 7, 7, 7,
+ 8, 8, 8, 9, 9, 9, 10, 10,
+ 11, 11, 12, 12, 12, 13, 13, 14,
+ 14, 15, 15, 16, 16, 17, 17, 18,
+ 18, 19, 20, 20, 21, 21, 22, 22,
+ 23, 24, 24, 25, 26, 26, 27, 28,
+ 28, 29, 30, 30, 31, 32, 32, 33,
+ 34, 35, 35, 36, 37, 38, 38, 39,
+ 40, 41, 41, 42, 43, 44, 45, 46,
+ 46, 47, 48, 49, 50, 51, 52, 53,
+ 53, 54, 55, 56, 57, 58, 59, 60,
+ 61, 62, 63, 64, 65, 66, 67, 68,
+ 69, 70, 71, 72, 73, 74, 75, 76,
+ 77, 78, 79, 81, 82, 83, 84, 85,
+ 86, 87, 88, 90, 91, 92, 93, 94,
+ 95, 97, 98, 99, 100, 101, 103, 104,
+ 105, 106, 108, 109, 110, 112, 113, 114,
+ 115, 117, 118, 119, 121, 122, 123, 125,
+ 126, 127, 129, 130, 132, 133, 134, 136,
+ 137, 139, 140, 141, 143, 144, 146, 147,
+ 149, 150, 152, 153, 155, 156, 158, 159,
+ 161, 162, 164, 165, 167, 168, 170, 172,
+ 173, 175, 176, 178, 180, 181, 183, 184,
+ 186, 188, 189, 191, 193, 194, 196, 198,
+ 199, 201, 203, 204, 206, 208, 210, 211,
+ 213, 215, 217, 218, 220, 222, 224, 225,
+ 227, 229, 231, 233, 235, 236, 238, 240,
+ 242, 244, 246, 247, 249, 251, 253, 255,
+};
+
+static const u16 xgamma8_20[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 1, 1, 1,
+ 1, 1, 1, 1, 2, 2, 2, 2,
+ 2, 2, 3, 3, 3, 3, 4, 4,
+ 4, 4, 5, 5, 5, 5, 6, 6,
+ 6, 7, 7, 7, 8, 8, 8, 9,
+ 9, 9, 10, 10, 11, 11, 11, 12,
+ 12, 13, 13, 14, 14, 15, 15, 16,
+ 16, 17, 17, 18, 18, 19, 19, 20,
+ 20, 21, 21, 22, 23, 23, 24, 24,
+ 25, 26, 26, 27, 28, 28, 29, 30,
+ 30, 31, 32, 32, 33, 34, 35, 35,
+ 36, 37, 38, 38, 39, 40, 41, 42,
+ 42, 43, 44, 45, 46, 47, 47, 48,
+ 49, 50, 51, 52, 53, 54, 55, 56,
+ 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71,
+ 73, 74, 75, 76, 77, 78, 79, 80,
+ 81, 82, 84, 85, 86, 87, 88, 89,
+ 91, 92, 93, 94, 95, 97, 98, 99,
+ 100, 102, 103, 104, 105, 107, 108, 109,
+ 111, 112, 113, 115, 116, 117, 119, 120,
+ 121, 123, 124, 126, 127, 128, 130, 131,
+ 133, 134, 136, 137, 139, 140, 142, 143,
+ 145, 146, 148, 149, 151, 152, 154, 155,
+ 157, 158, 160, 162, 163, 165, 166, 168,
+ 170, 171, 173, 175, 176, 178, 180, 181,
+ 183, 185, 186, 188, 190, 192, 193, 195,
+ 197, 199, 200, 202, 204, 206, 207, 209,
+ 211, 213, 215, 217, 218, 220, 222, 224,
+ 226, 228, 230, 232, 233, 235, 237, 239,
+ 241, 243, 245, 247, 249, 251, 253, 255,
+};
+
+static const u16 xgamma8_21[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 2,
+ 2, 2, 2, 2, 2, 3, 3, 3,
+ 3, 3, 4, 4, 4, 4, 5, 5,
+ 5, 5, 6, 6, 6, 7, 7, 7,
+ 8, 8, 8, 9, 9, 9, 10, 10,
+ 11, 11, 11, 12, 12, 13, 13, 14,
+ 14, 14, 15, 15, 16, 16, 17, 17,
+ 18, 18, 19, 20, 20, 21, 21, 22,
+ 22, 23, 24, 24, 25, 25, 26, 27,
+ 27, 28, 29, 29, 30, 31, 31, 32,
+ 33, 33, 34, 35, 36, 36, 37, 38,
+ 39, 40, 40, 41, 42, 43, 44, 44,
+ 45, 46, 47, 48, 49, 50, 51, 51,
+ 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67,
+ 68, 69, 70, 71, 72, 73, 75, 76,
+ 77, 78, 79, 80, 81, 83, 84, 85,
+ 86, 87, 88, 90, 91, 92, 93, 95,
+ 96, 97, 98, 100, 101, 102, 104, 105,
+ 106, 107, 109, 110, 112, 113, 114, 116,
+ 117, 118, 120, 121, 123, 124, 126, 127,
+ 129, 130, 131, 133, 134, 136, 137, 139,
+ 141, 142, 144, 145, 147, 148, 150, 151,
+ 153, 155, 156, 158, 160, 161, 163, 165,
+ 166, 168, 170, 171, 173, 175, 176, 178,
+ 180, 182, 183, 185, 187, 189, 191, 192,
+ 194, 196, 198, 200, 202, 203, 205, 207,
+ 209, 211, 213, 215, 217, 219, 221, 223,
+ 225, 226, 228, 230, 232, 234, 236, 238,
+ 241, 243, 245, 247, 249, 251, 253, 255,
+};
+
+static const u16 xgamma8_22[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 4, 4, 4,
+ 4, 5, 5, 5, 5, 6, 6, 6,
+ 6, 7, 7, 7, 8, 8, 8, 9,
+ 9, 9, 10, 10, 11, 11, 11, 12,
+ 12, 13, 13, 13, 14, 14, 15, 15,
+ 16, 16, 17, 17, 18, 18, 19, 19,
+ 20, 20, 21, 22, 22, 23, 23, 24,
+ 25, 25, 26, 26, 27, 28, 28, 29,
+ 30, 30, 31, 32, 33, 33, 34, 35,
+ 35, 36, 37, 38, 39, 39, 40, 41,
+ 42, 43, 43, 44, 45, 46, 47, 48,
+ 49, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71,
+ 73, 74, 75, 76, 77, 78, 79, 81,
+ 82, 83, 84, 85, 87, 88, 89, 90,
+ 91, 93, 94, 95, 97, 98, 99, 100,
+ 102, 103, 105, 106, 107, 109, 110, 111,
+ 113, 114, 116, 117, 119, 120, 121, 123,
+ 124, 126, 127, 129, 130, 132, 133, 135,
+ 137, 138, 140, 141, 143, 145, 146, 148,
+ 149, 151, 153, 154, 156, 158, 159, 161,
+ 163, 165, 166, 168, 170, 172, 173, 175,
+ 177, 179, 181, 182, 184, 186, 188, 190,
+ 192, 194, 196, 197, 199, 201, 203, 205,
+ 207, 209, 211, 213, 215, 217, 219, 221,
+ 223, 225, 227, 229, 231, 234, 236, 238,
+ 240, 242, 244, 246, 248, 251, 253, 255,
+};
+
+static const u16 xgamma8_23[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 2, 2, 2, 2,
+ 2, 2, 2, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 5, 5, 5,
+ 5, 6, 6, 6, 7, 7, 7, 7,
+ 8, 8, 8, 9, 9, 10, 10, 10,
+ 11, 11, 11, 12, 12, 13, 13, 13,
+ 14, 14, 15, 15, 16, 16, 17, 17,
+ 18, 18, 19, 19, 20, 20, 21, 21,
+ 22, 23, 23, 24, 24, 25, 26, 26,
+ 27, 28, 28, 29, 30, 30, 31, 32,
+ 32, 33, 34, 35, 35, 36, 37, 38,
+ 38, 39, 40, 41, 42, 42, 43, 44,
+ 45, 46, 47, 48, 49, 49, 50, 51,
+ 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67,
+ 69, 70, 71, 72, 73, 74, 75, 76,
+ 78, 79, 80, 81, 82, 84, 85, 86,
+ 87, 89, 90, 91, 92, 94, 95, 96,
+ 98, 99, 100, 102, 103, 104, 106, 107,
+ 109, 110, 112, 113, 114, 116, 117, 119,
+ 120, 122, 123, 125, 126, 128, 130, 131,
+ 133, 134, 136, 138, 139, 141, 143, 144,
+ 146, 148, 149, 151, 153, 154, 156, 158,
+ 160, 161, 163, 165, 167, 169, 170, 172,
+ 174, 176, 178, 180, 182, 183, 185, 187,
+ 189, 191, 193, 195, 197, 199, 201, 203,
+ 205, 207, 209, 211, 213, 215, 218, 220,
+ 222, 224, 226, 228, 230, 233, 235, 237,
+ 239, 241, 244, 246, 248, 250, 253, 255,
+};
+
+static const u16 xgamma8_24[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 2,
+ 2, 2, 2, 2, 2, 2, 3, 3,
+ 3, 3, 3, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 6, 6, 6, 6,
+ 7, 7, 7, 8, 8, 8, 9, 9,
+ 9, 10, 10, 10, 11, 11, 11, 12,
+ 12, 13, 13, 14, 14, 14, 15, 15,
+ 16, 16, 17, 17, 18, 18, 19, 19,
+ 20, 20, 21, 22, 22, 23, 23, 24,
+ 24, 25, 26, 26, 27, 28, 28, 29,
+ 30, 30, 31, 32, 32, 33, 34, 35,
+ 35, 36, 37, 38, 39, 39, 40, 41,
+ 42, 43, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 52, 53, 53, 54, 55,
+ 56, 57, 58, 59, 60, 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, 71, 73,
+ 74, 75, 76, 77, 78, 80, 81, 82,
+ 83, 85, 86, 87, 88, 90, 91, 92,
+ 94, 95, 96, 98, 99, 100, 102, 103,
+ 105, 106, 108, 109, 111, 112, 114, 115,
+ 117, 118, 120, 121, 123, 124, 126, 127,
+ 129, 131, 132, 134, 136, 137, 139, 141,
+ 142, 144, 146, 148, 149, 151, 153, 155,
+ 156, 158, 160, 162, 164, 166, 167, 169,
+ 171, 173, 175, 177, 179, 181, 183, 185,
+ 187, 189, 191, 193, 195, 197, 199, 201,
+ 203, 205, 207, 210, 212, 214, 216, 218,
+ 220, 223, 225, 227, 229, 232, 234, 236,
+ 239, 241, 243, 246, 248, 250, 253, 255,
+};
+
+static const u16 xgamma8_25[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2,
+ 2, 3, 3, 3, 3, 3, 4, 4,
+ 4, 4, 4, 5, 5, 5, 5, 6,
+ 6, 6, 6, 7, 7, 7, 7, 8,
+ 8, 8, 9, 9, 9, 10, 10, 10,
+ 11, 11, 12, 12, 12, 13, 13, 14,
+ 14, 15, 15, 15, 16, 16, 17, 17,
+ 18, 18, 19, 19, 20, 20, 21, 22,
+ 22, 23, 23, 24, 25, 25, 26, 26,
+ 27, 28, 28, 29, 30, 30, 31, 32,
+ 33, 33, 34, 35, 36, 36, 37, 38,
+ 39, 40, 40, 41, 42, 43, 44, 45,
+ 46, 46, 47, 48, 49, 50, 51, 52,
+ 53, 54, 55, 56, 57, 58, 59, 60,
+ 61, 62, 63, 64, 65, 67, 68, 69,
+ 70, 71, 72, 73, 75, 76, 77, 78,
+ 80, 81, 82, 83, 85, 86, 87, 89,
+ 90, 91, 93, 94, 95, 97, 98, 99,
+ 101, 102, 104, 105, 107, 108, 110, 111,
+ 113, 114, 116, 117, 119, 121, 122, 124,
+ 125, 127, 129, 130, 132, 134, 135, 137,
+ 139, 141, 142, 144, 146, 148, 150, 151,
+ 153, 155, 157, 159, 161, 163, 165, 166,
+ 168, 170, 172, 174, 176, 178, 180, 182,
+ 184, 186, 189, 191, 193, 195, 197, 199,
+ 201, 204, 206, 208, 210, 212, 215, 217,
+ 219, 221, 224, 226, 228, 231, 233, 235,
+ 238, 240, 243, 245, 248, 250, 253, 255,
+};
+
+static const u16 xgamma8_26[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 2, 2, 2, 2,
+ 2, 2, 2, 2, 3, 3, 3, 3,
+ 3, 3, 4, 4, 4, 4, 5, 5,
+ 5, 5, 5, 6, 6, 6, 6, 7,
+ 7, 7, 8, 8, 8, 9, 9, 9,
+ 10, 10, 10, 11, 11, 11, 12, 12,
+ 13, 13, 13, 14, 14, 15, 15, 16,
+ 16, 17, 17, 18, 18, 19, 19, 20,
+ 20, 21, 21, 22, 22, 23, 24, 24,
+ 25, 25, 26, 27, 27, 28, 29, 29,
+ 30, 31, 31, 32, 33, 34, 34, 35,
+ 36, 37, 38, 38, 39, 40, 41, 42,
+ 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57,
+ 58, 59, 60, 61, 62, 63, 64, 65,
+ 66, 68, 69, 70, 71, 72, 73, 75,
+ 76, 77, 78, 80, 81, 82, 84, 85,
+ 86, 88, 89, 90, 92, 93, 94, 96,
+ 97, 99, 100, 102, 103, 105, 106, 108,
+ 109, 111, 112, 114, 115, 117, 119, 120,
+ 122, 124, 125, 127, 129, 130, 132, 134,
+ 136, 137, 139, 141, 143, 145, 146, 148,
+ 150, 152, 154, 156, 158, 160, 162, 164,
+ 166, 168, 170, 172, 174, 176, 178, 180,
+ 182, 184, 186, 188, 191, 193, 195, 197,
+ 199, 202, 204, 206, 209, 211, 213, 215,
+ 218, 220, 223, 225, 227, 230, 232, 235,
+ 237, 240, 242, 245, 247, 250, 252, 255,
+};
+
+static const u16 xgamma8_27[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 2,
+ 2, 2, 2, 2, 2, 2, 3, 3,
+ 3, 3, 3, 3, 3, 4, 4, 4,
+ 4, 4, 5, 5, 5, 5, 6, 6,
+ 6, 6, 7, 7, 7, 7, 8, 8,
+ 8, 9, 9, 9, 10, 10, 10, 11,
+ 11, 12, 12, 12, 13, 13, 14, 14,
+ 14, 15, 15, 16, 16, 17, 17, 18,
+ 18, 19, 19, 20, 20, 21, 21, 22,
+ 23, 23, 24, 24, 25, 26, 26, 27,
+ 28, 28, 29, 30, 30, 31, 32, 33,
+ 33, 34, 35, 36, 36, 37, 38, 39,
+ 40, 41, 41, 42, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 51, 52, 53,
+ 55, 56, 57, 58, 59, 60, 61, 62,
+ 63, 64, 65, 66, 68, 69, 70, 71,
+ 72, 74, 75, 76, 77, 79, 80, 81,
+ 83, 84, 85, 87, 88, 89, 91, 92,
+ 94, 95, 97, 98, 100, 101, 103, 104,
+ 106, 107, 109, 110, 112, 114, 115, 117,
+ 119, 120, 122, 124, 125, 127, 129, 131,
+ 132, 134, 136, 138, 140, 141, 143, 145,
+ 147, 149, 151, 153, 155, 157, 159, 161,
+ 163, 165, 167, 169, 171, 173, 175, 178,
+ 180, 182, 184, 186, 188, 191, 193, 195,
+ 198, 200, 202, 205, 207, 209, 212, 214,
+ 216, 219, 221, 224, 226, 229, 231, 234,
+ 237, 239, 242, 244, 247, 250, 252, 255,
+};
+
+static const u16 xgamma8_28[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2,
+ 2, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 5, 5, 5,
+ 5, 6, 6, 6, 6, 7, 7, 7,
+ 7, 8, 8, 8, 9, 9, 9, 10,
+ 10, 10, 11, 11, 11, 12, 12, 13,
+ 13, 13, 14, 14, 15, 15, 16, 16,
+ 17, 17, 18, 18, 19, 19, 20, 20,
+ 21, 21, 22, 22, 23, 24, 24, 25,
+ 25, 26, 27, 27, 28, 29, 29, 30,
+ 31, 32, 32, 33, 34, 35, 35, 36,
+ 37, 38, 39, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 50,
+ 51, 52, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 66, 67, 68,
+ 69, 70, 72, 73, 74, 75, 77, 78,
+ 79, 81, 82, 83, 85, 86, 87, 89,
+ 90, 92, 93, 95, 96, 98, 99, 101,
+ 102, 104, 105, 107, 109, 110, 112, 114,
+ 115, 117, 119, 120, 122, 124, 126, 127,
+ 129, 131, 133, 135, 137, 138, 140, 142,
+ 144, 146, 148, 150, 152, 154, 156, 158,
+ 160, 162, 164, 167, 169, 171, 173, 175,
+ 177, 180, 182, 184, 186, 189, 191, 193,
+ 196, 198, 200, 203, 205, 208, 210, 213,
+ 215, 218, 220, 223, 225, 228, 231, 233,
+ 236, 239, 241, 244, 247, 249, 252, 255,
+};
+
+static const u16 xgamma8_29[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 2, 2, 2, 2,
+ 2, 2, 2, 2, 3, 3, 3, 3,
+ 3, 3, 3, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 6, 6, 6, 6,
+ 7, 7, 7, 7, 8, 8, 8, 9,
+ 9, 9, 9, 10, 10, 11, 11, 11,
+ 12, 12, 12, 13, 13, 14, 14, 15,
+ 15, 15, 16, 16, 17, 17, 18, 18,
+ 19, 19, 20, 21, 21, 22, 22, 23,
+ 23, 24, 25, 25, 26, 27, 27, 28,
+ 29, 29, 30, 31, 32, 32, 33, 34,
+ 35, 35, 36, 37, 38, 39, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 52, 53, 54, 55, 56,
+ 57, 58, 59, 60, 61, 62, 64, 65,
+ 66, 67, 68, 70, 71, 72, 73, 75,
+ 76, 77, 79, 80, 81, 83, 84, 86,
+ 87, 88, 90, 91, 93, 94, 96, 97,
+ 99, 101, 102, 104, 105, 107, 109, 110,
+ 112, 114, 115, 117, 119, 121, 122, 124,
+ 126, 128, 130, 132, 134, 135, 137, 139,
+ 141, 143, 145, 147, 149, 151, 153, 155,
+ 158, 160, 162, 164, 166, 168, 171, 173,
+ 175, 177, 180, 182, 184, 187, 189, 191,
+ 194, 196, 199, 201, 204, 206, 209, 211,
+ 214, 216, 219, 222, 224, 227, 230, 232,
+ 235, 238, 241, 244, 246, 249, 252, 255,
+};
+
+static const u16 xgamma8_30[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 2,
+ 2, 2, 2, 2, 2, 2, 2, 3,
+ 3, 3, 3, 3, 3, 3, 4, 4,
+ 4, 4, 4, 5, 5, 5, 5, 6,
+ 6, 6, 6, 6, 7, 7, 7, 8,
+ 8, 8, 8, 9, 9, 9, 10, 10,
+ 10, 11, 11, 12, 12, 12, 13, 13,
+ 14, 14, 14, 15, 15, 16, 16, 17,
+ 17, 18, 18, 19, 19, 20, 20, 21,
+ 22, 22, 23, 23, 24, 25, 25, 26,
+ 27, 27, 28, 29, 29, 30, 31, 32,
+ 32, 33, 34, 35, 35, 36, 37, 38,
+ 39, 40, 40, 41, 42, 43, 44, 45,
+ 46, 47, 48, 49, 50, 51, 52, 53,
+ 54, 55, 56, 57, 58, 60, 61, 62,
+ 63, 64, 65, 67, 68, 69, 70, 72,
+ 73, 74, 76, 77, 78, 80, 81, 82,
+ 84, 85, 87, 88, 90, 91, 93, 94,
+ 96, 97, 99, 101, 102, 104, 105, 107,
+ 109, 111, 112, 114, 116, 118, 119, 121,
+ 123, 125, 127, 129, 131, 132, 134, 136,
+ 138, 140, 142, 144, 147, 149, 151, 153,
+ 155, 157, 159, 162, 164, 166, 168, 171,
+ 173, 175, 178, 180, 182, 185, 187, 190,
+ 192, 195, 197, 200, 202, 205, 207, 210,
+ 213, 215, 218, 221, 223, 226, 229, 232,
+ 235, 237, 240, 243, 246, 249, 252, 255,
+};
+
+static const u16 xgamma8_31[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 5, 5,
+ 5, 5, 6, 6, 6, 6, 6, 7,
+ 7, 7, 8, 8, 8, 8, 9, 9,
+ 9, 10, 10, 10, 11, 11, 12, 12,
+ 12, 13, 13, 14, 14, 14, 15, 15,
+ 16, 16, 17, 17, 18, 18, 19, 19,
+ 20, 20, 21, 22, 22, 23, 23, 24,
+ 25, 25, 26, 27, 27, 28, 29, 29,
+ 30, 31, 32, 32, 33, 34, 35, 36,
+ 36, 37, 38, 39, 40, 41, 42, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 53, 54, 56, 57, 58, 59,
+ 60, 61, 62, 64, 65, 66, 67, 69,
+ 70, 71, 73, 74, 75, 77, 78, 79,
+ 81, 82, 84, 85, 87, 88, 90, 91,
+ 93, 94, 96, 97, 99, 101, 102, 104,
+ 106, 108, 109, 111, 113, 115, 116, 118,
+ 120, 122, 124, 126, 128, 130, 132, 134,
+ 136, 138, 140, 142, 144, 146, 148, 150,
+ 152, 155, 157, 159, 161, 164, 166, 168,
+ 171, 173, 175, 178, 180, 183, 185, 188,
+ 190, 193, 195, 198, 201, 203, 206, 209,
+ 211, 214, 217, 220, 222, 225, 228, 231,
+ 234, 237, 240, 243, 246, 249, 252, 255,
+};
+
+static const u16 xgamma8_32[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 3, 3, 3,
+ 3, 3, 3, 4, 4, 4, 4, 4,
+ 4, 5, 5, 5, 5, 6, 6, 6,
+ 6, 6, 7, 7, 7, 8, 8, 8,
+ 8, 9, 9, 9, 10, 10, 10, 11,
+ 11, 12, 12, 12, 13, 13, 14, 14,
+ 14, 15, 15, 16, 16, 17, 17, 18,
+ 18, 19, 19, 20, 21, 21, 22, 22,
+ 23, 23, 24, 25, 25, 26, 27, 27,
+ 28, 29, 30, 30, 31, 32, 33, 33,
+ 34, 35, 36, 37, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 52, 53, 54, 55, 56,
+ 57, 59, 60, 61, 62, 63, 65, 66,
+ 67, 68, 70, 71, 72, 74, 75, 76,
+ 78, 79, 81, 82, 84, 85, 87, 88,
+ 90, 91, 93, 95, 96, 98, 99, 101,
+ 103, 105, 106, 108, 110, 112, 113, 115,
+ 117, 119, 121, 123, 125, 127, 129, 131,
+ 133, 135, 137, 139, 141, 143, 146, 148,
+ 150, 152, 154, 157, 159, 161, 164, 166,
+ 168, 171, 173, 176, 178, 181, 183, 186,
+ 188, 191, 194, 196, 199, 202, 204, 207,
+ 210, 213, 216, 219, 221, 224, 227, 230,
+ 233, 236, 239, 242, 246, 249, 252, 255,
+};
+
+static const u16 xgamma8_33[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 3,
+ 3, 3, 3, 3, 3, 3, 4, 4,
+ 4, 4, 4, 4, 5, 5, 5, 5,
+ 6, 6, 6, 6, 7, 7, 7, 7,
+ 8, 8, 8, 9, 9, 9, 9, 10,
+ 10, 11, 11, 11, 12, 12, 12, 13,
+ 13, 14, 14, 15, 15, 15, 16, 16,
+ 17, 17, 18, 18, 19, 19, 20, 21,
+ 21, 22, 22, 23, 24, 24, 25, 26,
+ 26, 27, 28, 28, 29, 30, 31, 31,
+ 32, 33, 34, 34, 35, 36, 37, 38,
+ 39, 40, 40, 41, 42, 43, 44, 45,
+ 46, 47, 48, 49, 50, 51, 53, 54,
+ 55, 56, 57, 58, 59, 61, 62, 63,
+ 64, 66, 67, 68, 70, 71, 72, 74,
+ 75, 76, 78, 79, 81, 82, 84, 85,
+ 87, 88, 90, 92, 93, 95, 97, 98,
+ 100, 102, 103, 105, 107, 109, 111, 113,
+ 114, 116, 118, 120, 122, 124, 126, 128,
+ 130, 132, 134, 136, 139, 141, 143, 145,
+ 147, 150, 152, 154, 157, 159, 161, 164,
+ 166, 169, 171, 174, 176, 179, 181, 184,
+ 187, 189, 192, 195, 198, 200, 203, 206,
+ 209, 212, 215, 217, 220, 223, 226, 230,
+ 233, 236, 239, 242, 245, 248, 252, 255,
+};
+
+static const u16 xgamma8_34[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 3, 3, 3, 3, 3, 3,
+ 3, 4, 4, 4, 4, 4, 5, 5,
+ 5, 5, 5, 6, 6, 6, 6, 7,
+ 7, 7, 7, 8, 8, 8, 9, 9,
+ 9, 10, 10, 10, 11, 11, 11, 12,
+ 12, 12, 13, 13, 14, 14, 15, 15,
+ 16, 16, 17, 17, 18, 18, 19, 19,
+ 20, 20, 21, 21, 22, 23, 23, 24,
+ 24, 25, 26, 26, 27, 28, 29, 29,
+ 30, 31, 32, 32, 33, 34, 35, 36,
+ 37, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 55, 56, 57, 58, 59, 60,
+ 62, 63, 64, 66, 67, 68, 70, 71,
+ 72, 74, 75, 77, 78, 80, 81, 83,
+ 84, 86, 87, 89, 90, 92, 94, 95,
+ 97, 99, 101, 102, 104, 106, 108, 110,
+ 112, 114, 115, 117, 119, 121, 123, 125,
+ 128, 130, 132, 134, 136, 138, 141, 143,
+ 145, 147, 150, 152, 154, 157, 159, 162,
+ 164, 167, 169, 172, 174, 177, 180, 182,
+ 185, 188, 190, 193, 196, 199, 202, 205,
+ 208, 210, 213, 216, 219, 223, 226, 229,
+ 232, 235, 238, 242, 245, 248, 252, 255,
+};
+
+static const u16 xgamma8_35[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 3, 3, 3,
+ 3, 3, 3, 4, 4, 4, 4, 4,
+ 4, 5, 5, 5, 5, 5, 6, 6,
+ 6, 6, 7, 7, 7, 7, 8, 8,
+ 8, 9, 9, 9, 10, 10, 10, 11,
+ 11, 11, 12, 12, 13, 13, 13, 14,
+ 14, 15, 15, 16, 16, 17, 17, 18,
+ 18, 19, 19, 20, 20, 21, 22, 22,
+ 23, 23, 24, 25, 25, 26, 27, 28,
+ 28, 29, 30, 30, 31, 32, 33, 34,
+ 35, 35, 36, 37, 38, 39, 40, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 56, 57, 58,
+ 59, 60, 62, 63, 64, 66, 67, 68,
+ 70, 71, 72, 74, 75, 77, 78, 80,
+ 81, 83, 85, 86, 88, 89, 91, 93,
+ 94, 96, 98, 100, 102, 103, 105, 107,
+ 109, 111, 113, 115, 117, 119, 121, 123,
+ 125, 127, 129, 131, 134, 136, 138, 140,
+ 143, 145, 147, 150, 152, 155, 157, 159,
+ 162, 165, 167, 170, 172, 175, 178, 180,
+ 183, 186, 189, 192, 194, 197, 200, 203,
+ 206, 209, 212, 215, 219, 222, 225, 228,
+ 231, 235, 238, 241, 245, 248, 252, 255,
+};
+
+static const u16 xgamma8_36[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 3,
+ 3, 3, 3, 3, 3, 3, 4, 4,
+ 4, 4, 4, 4, 5, 5, 5, 5,
+ 6, 6, 6, 6, 6, 7, 7, 7,
+ 8, 8, 8, 8, 9, 9, 9, 10,
+ 10, 10, 11, 11, 12, 12, 12, 13,
+ 13, 14, 14, 15, 15, 15, 16, 16,
+ 17, 17, 18, 18, 19, 20, 20, 21,
+ 21, 22, 23, 23, 24, 24, 25, 26,
+ 27, 27, 28, 29, 29, 30, 31, 32,
+ 33, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 42, 43, 44, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 56,
+ 57, 58, 59, 61, 62, 63, 64, 66,
+ 67, 69, 70, 71, 73, 74, 76, 77,
+ 79, 80, 82, 83, 85, 87, 88, 90,
+ 92, 94, 95, 97, 99, 101, 103, 104,
+ 106, 108, 110, 112, 114, 116, 118, 120,
+ 122, 125, 127, 129, 131, 133, 136, 138,
+ 140, 143, 145, 147, 150, 152, 155, 157,
+ 160, 162, 165, 168, 170, 173, 176, 179,
+ 181, 184, 187, 190, 193, 196, 199, 202,
+ 205, 208, 211, 214, 218, 221, 224, 227,
+ 231, 234, 237, 241, 244, 248, 251, 255,
+};
+
+static const u16 xgamma8_37[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 3, 3, 3, 3, 3, 3,
+ 3, 4, 4, 4, 4, 4, 5, 5,
+ 5, 5, 5, 6, 6, 6, 6, 7,
+ 7, 7, 7, 8, 8, 8, 9, 9,
+ 9, 10, 10, 10, 11, 11, 11, 12,
+ 12, 13, 13, 13, 14, 14, 15, 15,
+ 16, 16, 17, 17, 18, 18, 19, 19,
+ 20, 20, 21, 22, 22, 23, 24, 24,
+ 25, 26, 26, 27, 28, 28, 29, 30,
+ 31, 32, 32, 33, 34, 35, 36, 37,
+ 38, 39, 39, 40, 41, 42, 43, 44,
+ 45, 47, 48, 49, 50, 51, 52, 53,
+ 54, 56, 57, 58, 59, 61, 62, 63,
+ 65, 66, 67, 69, 70, 72, 73, 75,
+ 76, 78, 79, 81, 83, 84, 86, 88,
+ 89, 91, 93, 95, 96, 98, 100, 102,
+ 104, 106, 108, 110, 112, 114, 116, 118,
+ 120, 122, 124, 127, 129, 131, 133, 136,
+ 138, 140, 143, 145, 148, 150, 153, 155,
+ 158, 160, 163, 166, 169, 171, 174, 177,
+ 180, 183, 186, 188, 191, 194, 198, 201,
+ 204, 207, 210, 213, 217, 220, 223, 227,
+ 230, 233, 237, 241, 244, 248, 251, 255,
+};
+
+static const u16 xgamma8_38[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 3, 3, 3, 3,
+ 3, 3, 3, 4, 4, 4, 4, 4,
+ 4, 5, 5, 5, 5, 6, 6, 6,
+ 6, 6, 7, 7, 7, 8, 8, 8,
+ 8, 9, 9, 9, 10, 10, 10, 11,
+ 11, 12, 12, 12, 13, 13, 14, 14,
+ 15, 15, 15, 16, 16, 17, 18, 18,
+ 19, 19, 20, 20, 21, 21, 22, 23,
+ 23, 24, 25, 25, 26, 27, 28, 28,
+ 29, 30, 31, 31, 32, 33, 34, 35,
+ 36, 37, 38, 38, 39, 40, 41, 42,
+ 43, 44, 45, 47, 48, 49, 50, 51,
+ 52, 53, 55, 56, 57, 58, 60, 61,
+ 62, 64, 65, 66, 68, 69, 71, 72,
+ 74, 75, 77, 78, 80, 82, 83, 85,
+ 87, 88, 90, 92, 94, 96, 98, 99,
+ 101, 103, 105, 107, 109, 111, 113, 115,
+ 118, 120, 122, 124, 126, 129, 131, 133,
+ 136, 138, 141, 143, 146, 148, 151, 153,
+ 156, 158, 161, 164, 167, 169, 172, 175,
+ 178, 181, 184, 187, 190, 193, 196, 199,
+ 203, 206, 209, 212, 216, 219, 222, 226,
+ 229, 233, 237, 240, 244, 247, 251, 255,
+};
+
+static const u16 xgamma8_39[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 3, 3,
+ 3, 3, 3, 3, 3, 4, 4, 4,
+ 4, 4, 4, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 7, 7, 7, 7,
+ 8, 8, 8, 9, 9, 9, 10, 10,
+ 10, 11, 11, 11, 12, 12, 13, 13,
+ 13, 14, 14, 15, 15, 16, 16, 17,
+ 17, 18, 18, 19, 20, 20, 21, 21,
+ 22, 23, 23, 24, 25, 25, 26, 27,
+ 27, 28, 29, 30, 31, 31, 32, 33,
+ 34, 35, 36, 37, 38, 38, 39, 40,
+ 41, 42, 43, 45, 46, 47, 48, 49,
+ 50, 51, 52, 54, 55, 56, 57, 59,
+ 60, 61, 63, 64, 66, 67, 68, 70,
+ 71, 73, 74, 76, 78, 79, 81, 83,
+ 84, 86, 88, 90, 91, 93, 95, 97,
+ 99, 101, 103, 105, 107, 109, 111, 113,
+ 115, 117, 120, 122, 124, 126, 129, 131,
+ 133, 136, 138, 141, 143, 146, 149, 151,
+ 154, 157, 159, 162, 165, 168, 171, 173,
+ 176, 179, 182, 185, 189, 192, 195, 198,
+ 201, 205, 208, 211, 215, 218, 222, 225,
+ 229, 232, 236, 240, 243, 247, 251, 255,
+};
+
+static const u16 xgamma8_40[GAMMA8_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 5, 5, 5,
+ 5, 5, 6, 6, 6, 6, 7, 7,
+ 7, 7, 8, 8, 8, 9, 9, 9,
+ 9, 10, 10, 11, 11, 11, 12, 12,
+ 13, 13, 13, 14, 14, 15, 15, 16,
+ 16, 17, 17, 18, 18, 19, 19, 20,
+ 21, 21, 22, 23, 23, 24, 25, 25,
+ 26, 27, 27, 28, 29, 30, 31, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 52, 53, 54, 55, 57,
+ 58, 59, 61, 62, 63, 65, 66, 68,
+ 69, 71, 72, 74, 75, 77, 79, 80,
+ 82, 84, 85, 87, 89, 91, 93, 95,
+ 96, 98, 100, 102, 104, 107, 109, 111,
+ 113, 115, 117, 120, 122, 124, 126, 129,
+ 131, 134, 136, 139, 141, 144, 146, 149,
+ 152, 155, 157, 160, 163, 166, 169, 172,
+ 175, 178, 181, 184, 187, 190, 194, 197,
+ 200, 203, 207, 210, 214, 217, 221, 224,
+ 228, 232, 236, 239, 243, 247, 251, 255,
+};
+
+static const u16 *xgamma8_curves[GAMMA_CURVE_LENGTH] = {
+ &xgamma8_01[0],
+ &xgamma8_02[0],
+ &xgamma8_03[0],
+ &xgamma8_04[0],
+ &xgamma8_05[0],
+ &xgamma8_06[0],
+ &xgamma8_07[0],
+ &xgamma8_08[0],
+ &xgamma8_09[0],
+ &xgamma8_10[0],
+ &xgamma8_11[0],
+ &xgamma8_12[0],
+ &xgamma8_13[0],
+ &xgamma8_14[0],
+ &xgamma8_15[0],
+ &xgamma8_16[0],
+ &xgamma8_17[0],
+ &xgamma8_18[0],
+ &xgamma8_19[0],
+ &xgamma8_20[0],
+ &xgamma8_21[0],
+ &xgamma8_22[0],
+ &xgamma8_23[0],
+ &xgamma8_24[0],
+ &xgamma8_25[0],
+ &xgamma8_26[0],
+ &xgamma8_27[0],
+ &xgamma8_28[0],
+ &xgamma8_29[0],
+ &xgamma8_30[0],
+ &xgamma8_31[0],
+ &xgamma8_32[0],
+ &xgamma8_33[0],
+ &xgamma8_34[0],
+ &xgamma8_35[0],
+ &xgamma8_36[0],
+ &xgamma8_37[0],
+ &xgamma8_38[0],
+ &xgamma8_39[0],
+ &xgamma8_40[0],
+};
+
+#define GAMMA_BPC_10 (10)
+#define GAMMA10_TABLE_LENGTH BIT(GAMMA_BPC_10)
+static const u16 xgamma10_01[GAMMA10_TABLE_LENGTH] = {
+ 0, 512, 548, 571, 588, 601, 612, 621, 630, 637, 644,
+ 650, 656, 661, 666, 671, 675, 679, 683, 687, 690, 694,
+ 697, 700, 703, 706, 709, 711, 714, 716, 719, 721, 723,
+ 726, 728, 730, 732, 734, 736, 738, 740, 742, 743, 745,
+ 747, 749, 750, 752, 753, 755, 756, 758, 759, 761, 762,
+ 764, 765, 766, 768, 769, 770, 772, 773, 774, 775, 777,
+ 778, 779, 780, 781, 782, 783, 785, 786, 787, 788, 789,
+ 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 800,
+ 800, 801, 802, 803, 804, 805, 806, 807, 807, 808, 809,
+ 810, 811, 812, 812, 813, 814, 815, 815, 816, 817, 818,
+ 819, 819, 820, 821, 821, 822, 823, 824, 824, 825, 826,
+ 826, 827, 828, 828, 829, 830, 830, 831, 832, 832, 833,
+ 834, 834, 835, 835, 836, 837, 837, 838, 838, 839, 840,
+ 840, 841, 841, 842, 843, 843, 844, 844, 845, 845, 846,
+ 847, 847, 848, 848, 849, 849, 850, 850, 851, 851, 852,
+ 852, 853, 853, 854, 854, 855, 855, 856, 856, 857, 857,
+ 858, 858, 859, 859, 860, 860, 861, 861, 862, 862, 863,
+ 863, 864, 864, 864, 865, 865, 866, 866, 867, 867, 868,
+ 868, 869, 869, 869, 870, 870, 871, 871, 872, 872, 872,
+ 873, 873, 874, 874, 874, 875, 875, 876, 876, 876, 877,
+ 877, 878, 878, 878, 879, 879, 880, 880, 880, 881, 881,
+ 882, 882, 882, 883, 883, 883, 884, 884, 885, 885, 885,
+ 886, 886, 886, 887, 887, 887, 888, 888, 889, 889, 889,
+ 890, 890, 890, 891, 891, 891, 892, 892, 892, 893, 893,
+ 893, 894, 894, 894, 895, 895, 895, 896, 896, 896, 897,
+ 897, 897, 898, 898, 898, 899, 899, 899, 900, 900, 900,
+ 901, 901, 901, 902, 902, 902, 902, 903, 903, 903, 904,
+ 904, 904, 905, 905, 905, 906, 906, 906, 906, 907, 907,
+ 907, 908, 908, 908, 908, 909, 909, 909, 910, 910, 910,
+ 910, 911, 911, 911, 912, 912, 912, 912, 913, 913, 913,
+ 914, 914, 914, 914, 915, 915, 915, 915, 916, 916, 916,
+ 917, 917, 917, 917, 918, 918, 918, 918, 919, 919, 919,
+ 919, 920, 920, 920, 921, 921, 921, 921, 922, 922, 922,
+ 922, 923, 923, 923, 923, 924, 924, 924, 924, 925, 925,
+ 925, 925, 926, 926, 926, 926, 927, 927, 927, 927, 928,
+ 928, 928, 928, 928, 929, 929, 929, 929, 930, 930, 930,
+ 930, 931, 931, 931, 931, 932, 932, 932, 932, 932, 933,
+ 933, 933, 933, 934, 934, 934, 934, 935, 935, 935, 935,
+ 935, 936, 936, 936, 936, 937, 937, 937, 937, 937, 938,
+ 938, 938, 938, 939, 939, 939, 939, 939, 940, 940, 940,
+ 940, 940, 941, 941, 941, 941, 942, 942, 942, 942, 942,
+ 943, 943, 943, 943, 943, 944, 944, 944, 944, 944, 945,
+ 945, 945, 945, 945, 946, 946, 946, 946, 946, 947, 947,
+ 947, 947, 947, 948, 948, 948, 948, 948, 949, 949, 949,
+ 949, 949, 950, 950, 950, 950, 950, 951, 951, 951, 951,
+ 951, 952, 952, 952, 952, 952, 953, 953, 953, 953, 953,
+ 953, 954, 954, 954, 954, 954, 955, 955, 955, 955, 955,
+ 956, 956, 956, 956, 956, 956, 957, 957, 957, 957, 957,
+ 958, 958, 958, 958, 958, 958, 959, 959, 959, 959, 959,
+ 960, 960, 960, 960, 960, 960, 961, 961, 961, 961, 961,
+ 961, 962, 962, 962, 962, 962, 962, 963, 963, 963, 963,
+ 963, 964, 964, 964, 964, 964, 964, 965, 965, 965, 965,
+ 965, 965, 966, 966, 966, 966, 966, 966, 967, 967, 967,
+ 967, 967, 967, 968, 968, 968, 968, 968, 968, 969, 969,
+ 969, 969, 969, 969, 970, 970, 970, 970, 970, 970, 970,
+ 971, 971, 971, 971, 971, 971, 972, 972, 972, 972, 972,
+ 972, 973, 973, 973, 973, 973, 973, 974, 974, 974, 974,
+ 974, 974, 974, 975, 975, 975, 975, 975, 975, 976, 976,
+ 976, 976, 976, 976, 976, 977, 977, 977, 977, 977, 977,
+ 977, 978, 978, 978, 978, 978, 978, 979, 979, 979, 979,
+ 979, 979, 979, 980, 980, 980, 980, 980, 980, 980, 981,
+ 981, 981, 981, 981, 981, 981, 982, 982, 982, 982, 982,
+ 982, 982, 983, 983, 983, 983, 983, 983, 983, 984, 984,
+ 984, 984, 984, 984, 984, 985, 985, 985, 985, 985, 985,
+ 985, 986, 986, 986, 986, 986, 986, 986, 987, 987, 987,
+ 987, 987, 987, 987, 988, 988, 988, 988, 988, 988, 988,
+ 989, 989, 989, 989, 989, 989, 989, 989, 990, 990, 990,
+ 990, 990, 990, 990, 991, 991, 991, 991, 991, 991, 991,
+ 991, 992, 992, 992, 992, 992, 992, 992, 993, 993, 993,
+ 993, 993, 993, 993, 993, 994, 994, 994, 994, 994, 994,
+ 994, 994, 995, 995, 995, 995, 995, 995, 995, 996, 996,
+ 996, 996, 996, 996, 996, 996, 997, 997, 997, 997, 997,
+ 997, 997, 997, 998, 998, 998, 998, 998, 998, 998, 998,
+ 999, 999, 999, 999, 999, 999, 999, 999, 1000, 1000, 1000,
+ 1000, 1000, 1000, 1000, 1000, 1000, 1001, 1001, 1001, 1001, 1001,
+ 1001, 1001, 1001, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002,
+ 1003, 1003, 1003, 1003, 1003, 1003, 1003, 1003, 1004, 1004, 1004,
+ 1004, 1004, 1004, 1004, 1004, 1004, 1005, 1005, 1005, 1005, 1005,
+ 1005, 1005, 1005, 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006,
+ 1006, 1007, 1007, 1007, 1007, 1007, 1007, 1007, 1007, 1007, 1008,
+ 1008, 1008, 1008, 1008, 1008, 1008, 1008, 1009, 1009, 1009, 1009,
+ 1009, 1009, 1009, 1009, 1009, 1010, 1010, 1010, 1010, 1010, 1010,
+ 1010, 1010, 1010, 1011, 1011, 1011, 1011, 1011, 1011, 1011, 1011,
+ 1011, 1012, 1012, 1012, 1012, 1012, 1012, 1012, 1012, 1012, 1013,
+ 1013, 1013, 1013, 1013, 1013, 1013, 1013, 1013, 1014, 1014, 1014,
+ 1014, 1014, 1014, 1014, 1014, 1014, 1014, 1015, 1015, 1015, 1015,
+ 1015, 1015, 1015, 1015, 1015, 1016, 1016, 1016, 1016, 1016, 1016,
+ 1016, 1016, 1016, 1017, 1017, 1017, 1017, 1017, 1017, 1017, 1017,
+ 1017, 1017, 1018, 1018, 1018, 1018, 1018, 1018, 1018, 1018, 1018,
+ 1019, 1019, 1019, 1019, 1019, 1019, 1019, 1019, 1019, 1019, 1020,
+ 1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020, 1020, 1021, 1021,
+ 1021, 1021, 1021, 1021, 1021, 1021, 1021, 1021, 1022, 1022, 1022,
+ 1022, 1022, 1022, 1022, 1022, 1022, 1022, 1023, 1023, 1023, 1023,
+ 1023,
+};
+
+static const u16 xgamma10_02[GAMMA10_TABLE_LENGTH] = {
+ 0, 256, 294, 319, 338, 353, 366, 378, 388, 397, 405,
+ 413, 420, 427, 434, 440, 445, 451, 456, 461, 466, 470,
+ 475, 479, 483, 487, 491, 495, 498, 502, 505, 508, 512,
+ 515, 518, 521, 524, 527, 529, 532, 535, 538, 540, 543,
+ 545, 548, 550, 552, 555, 557, 559, 562, 564, 566, 568,
+ 570, 572, 574, 576, 578, 580, 582, 584, 586, 588, 589,
+ 591, 593, 595, 597, 598, 600, 602, 603, 605, 607, 608,
+ 610, 611, 613, 614, 616, 618, 619, 621, 622, 623, 625,
+ 626, 628, 629, 631, 632, 633, 635, 636, 637, 639, 640,
+ 641, 643, 644, 645, 646, 648, 649, 650, 651, 653, 654,
+ 655, 656, 657, 658, 660, 661, 662, 663, 664, 665, 666,
+ 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678,
+ 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689,
+ 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700,
+ 700, 701, 702, 703, 704, 705, 706, 707, 708, 708, 709,
+ 710, 711, 712, 713, 714, 714, 715, 716, 717, 718, 719,
+ 719, 720, 721, 722, 723, 723, 724, 725, 726, 727, 727,
+ 728, 729, 730, 731, 731, 732, 733, 734, 734, 735, 736,
+ 737, 737, 738, 739, 740, 740, 741, 742, 742, 743, 744,
+ 745, 745, 746, 747, 747, 748, 749, 750, 750, 751, 752,
+ 752, 753, 754, 754, 755, 756, 756, 757, 758, 758, 759,
+ 760, 760, 761, 762, 762, 763, 764, 764, 765, 765, 766,
+ 767, 767, 768, 769, 769, 770, 771, 771, 772, 772, 773,
+ 774, 774, 775, 775, 776, 777, 777, 778, 778, 779, 780,
+ 780, 781, 781, 782, 783, 783, 784, 784, 785, 785, 786,
+ 787, 787, 788, 788, 789, 789, 790, 791, 791, 792, 792,
+ 793, 793, 794, 794, 795, 796, 796, 797, 797, 798, 798,
+ 799, 799, 800, 800, 801, 801, 802, 803, 803, 804, 804,
+ 805, 805, 806, 806, 807, 807, 808, 808, 809, 809, 810,
+ 810, 811, 811, 812, 812, 813, 813, 814, 814, 815, 815,
+ 816, 816, 817, 817, 818, 818, 819, 819, 820, 820, 821,
+ 821, 822, 822, 823, 823, 824, 824, 825, 825, 825, 826,
+ 826, 827, 827, 828, 828, 829, 829, 830, 830, 831, 831,
+ 832, 832, 832, 833, 833, 834, 834, 835, 835, 836, 836,
+ 837, 837, 837, 838, 838, 839, 839, 840, 840, 841, 841,
+ 841, 842, 842, 843, 843, 844, 844, 844, 845, 845, 846,
+ 846, 847, 847, 847, 848, 848, 849, 849, 850, 850, 850,
+ 851, 851, 852, 852, 852, 853, 853, 854, 854, 855, 855,
+ 855, 856, 856, 857, 857, 857, 858, 858, 859, 859, 859,
+ 860, 860, 861, 861, 861, 862, 862, 863, 863, 863, 864,
+ 864, 865, 865, 865, 866, 866, 866, 867, 867, 868, 868,
+ 868, 869, 869, 870, 870, 870, 871, 871, 871, 872, 872,
+ 873, 873, 873, 874, 874, 875, 875, 875, 876, 876, 876,
+ 877, 877, 877, 878, 878, 879, 879, 879, 880, 880, 880,
+ 881, 881, 882, 882, 882, 883, 883, 883, 884, 884, 884,
+ 885, 885, 885, 886, 886, 887, 887, 887, 888, 888, 888,
+ 889, 889, 889, 890, 890, 890, 891, 891, 891, 892, 892,
+ 892, 893, 893, 894, 894, 894, 895, 895, 895, 896, 896,
+ 896, 897, 897, 897, 898, 898, 898, 899, 899, 899, 900,
+ 900, 900, 901, 901, 901, 902, 902, 902, 903, 903, 903,
+ 904, 904, 904, 905, 905, 905, 906, 906, 906, 907, 907,
+ 907, 908, 908, 908, 908, 909, 909, 909, 910, 910, 910,
+ 911, 911, 911, 912, 912, 912, 913, 913, 913, 914, 914,
+ 914, 914, 915, 915, 915, 916, 916, 916, 917, 917, 917,
+ 918, 918, 918, 919, 919, 919, 919, 920, 920, 920, 921,
+ 921, 921, 922, 922, 922, 923, 923, 923, 923, 924, 924,
+ 924, 925, 925, 925, 926, 926, 926, 926, 927, 927, 927,
+ 928, 928, 928, 928, 929, 929, 929, 930, 930, 930, 931,
+ 931, 931, 931, 932, 932, 932, 933, 933, 933, 933, 934,
+ 934, 934, 935, 935, 935, 935, 936, 936, 936, 937, 937,
+ 937, 937, 938, 938, 938, 939, 939, 939, 939, 940, 940,
+ 940, 941, 941, 941, 941, 942, 942, 942, 942, 943, 943,
+ 943, 944, 944, 944, 944, 945, 945, 945, 946, 946, 946,
+ 946, 947, 947, 947, 947, 948, 948, 948, 949, 949, 949,
+ 949, 950, 950, 950, 950, 951, 951, 951, 951, 952, 952,
+ 952, 953, 953, 953, 953, 954, 954, 954, 954, 955, 955,
+ 955, 955, 956, 956, 956, 956, 957, 957, 957, 958, 958,
+ 958, 958, 959, 959, 959, 959, 960, 960, 960, 960, 961,
+ 961, 961, 961, 962, 962, 962, 962, 963, 963, 963, 963,
+ 964, 964, 964, 964, 965, 965, 965, 965, 966, 966, 966,
+ 966, 967, 967, 967, 967, 968, 968, 968, 968, 969, 969,
+ 969, 969, 970, 970, 970, 970, 971, 971, 971, 971, 972,
+ 972, 972, 972, 973, 973, 973, 973, 974, 974, 974, 974,
+ 975, 975, 975, 975, 976, 976, 976, 976, 977, 977, 977,
+ 977, 978, 978, 978, 978, 978, 979, 979, 979, 979, 980,
+ 980, 980, 980, 981, 981, 981, 981, 982, 982, 982, 982,
+ 983, 983, 983, 983, 983, 984, 984, 984, 984, 985, 985,
+ 985, 985, 986, 986, 986, 986, 986, 987, 987, 987, 987,
+ 988, 988, 988, 988, 989, 989, 989, 989, 989, 990, 990,
+ 990, 990, 991, 991, 991, 991, 992, 992, 992, 992, 992,
+ 993, 993, 993, 993, 994, 994, 994, 994, 994, 995, 995,
+ 995, 995, 996, 996, 996, 996, 996, 997, 997, 997, 997,
+ 998, 998, 998, 998, 998, 999, 999, 999, 999, 1000, 1000,
+ 1000, 1000, 1000, 1001, 1001, 1001, 1001, 1002, 1002, 1002, 1002,
+ 1002, 1003, 1003, 1003, 1003, 1003, 1004, 1004, 1004, 1004, 1005,
+ 1005, 1005, 1005, 1005, 1006, 1006, 1006, 1006, 1006, 1007, 1007,
+ 1007, 1007, 1008, 1008, 1008, 1008, 1008, 1009, 1009, 1009, 1009,
+ 1009, 1010, 1010, 1010, 1010, 1010, 1011, 1011, 1011, 1011, 1012,
+ 1012, 1012, 1012, 1012, 1013, 1013, 1013, 1013, 1013, 1014, 1014,
+ 1014, 1014, 1014, 1015, 1015, 1015, 1015, 1015, 1016, 1016, 1016,
+ 1016, 1017, 1017, 1017, 1017, 1017, 1018, 1018, 1018, 1018, 1018,
+ 1019, 1019, 1019, 1019, 1019, 1020, 1020, 1020, 1020, 1020, 1021,
+ 1021, 1021, 1021, 1021, 1022, 1022, 1022, 1022, 1022, 1023, 1023,
+ 1023,
+};
+
+static const u16 xgamma10_03[GAMMA10_TABLE_LENGTH] = {
+ 0, 128, 157, 178, 194, 207, 219, 229, 239, 247, 255,
+ 263, 270, 276, 282, 288, 294, 299, 304, 309, 314, 319,
+ 323, 328, 332, 336, 340, 344, 348, 351, 355, 358, 362,
+ 365, 368, 372, 375, 378, 381, 384, 387, 390, 393, 395,
+ 398, 401, 403, 406, 409, 411, 414, 416, 419, 421, 423,
+ 426, 428, 430, 432, 435, 437, 439, 441, 443, 445, 447,
+ 450, 452, 454, 456, 458, 460, 461, 463, 465, 467, 469,
+ 471, 473, 474, 476, 478, 480, 482, 483, 485, 487, 488,
+ 490, 492, 493, 495, 497, 498, 500, 501, 503, 505, 506,
+ 508, 509, 511, 512, 514, 515, 517, 518, 520, 521, 523,
+ 524, 525, 527, 528, 530, 531, 532, 534, 535, 537, 538,
+ 539, 541, 542, 543, 544, 546, 547, 548, 550, 551, 552,
+ 553, 555, 556, 557, 558, 560, 561, 562, 563, 565, 566,
+ 567, 568, 569, 570, 572, 573, 574, 575, 576, 577, 579,
+ 580, 581, 582, 583, 584, 585, 586, 587, 589, 590, 591,
+ 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 602,
+ 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613,
+ 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624,
+ 625, 626, 627, 628, 629, 630, 631, 632, 633, 633, 634,
+ 635, 636, 637, 638, 639, 640, 641, 642, 642, 643, 644,
+ 645, 646, 647, 648, 649, 649, 650, 651, 652, 653, 654,
+ 655, 655, 656, 657, 658, 659, 660, 661, 661, 662, 663,
+ 664, 665, 665, 666, 667, 668, 669, 670, 670, 671, 672,
+ 673, 674, 674, 675, 676, 677, 677, 678, 679, 680, 681,
+ 681, 682, 683, 684, 684, 685, 686, 687, 688, 688, 689,
+ 690, 691, 691, 692, 693, 694, 694, 695, 696, 696, 697,
+ 698, 699, 699, 700, 701, 702, 702, 703, 704, 704, 705,
+ 706, 707, 707, 708, 709, 709, 710, 711, 712, 712, 713,
+ 714, 714, 715, 716, 716, 717, 718, 718, 719, 720, 721,
+ 721, 722, 723, 723, 724, 725, 725, 726, 727, 727, 728,
+ 729, 729, 730, 731, 731, 732, 733, 733, 734, 734, 735,
+ 736, 736, 737, 738, 738, 739, 740, 740, 741, 742, 742,
+ 743, 743, 744, 745, 745, 746, 747, 747, 748, 748, 749,
+ 750, 750, 751, 752, 752, 753, 753, 754, 755, 755, 756,
+ 756, 757, 758, 758, 759, 759, 760, 761, 761, 762, 762,
+ 763, 764, 764, 765, 765, 766, 767, 767, 768, 768, 769,
+ 770, 770, 771, 771, 772, 772, 773, 774, 774, 775, 775,
+ 776, 776, 777, 778, 778, 779, 779, 780, 780, 781, 782,
+ 782, 783, 783, 784, 784, 785, 785, 786, 787, 787, 788,
+ 788, 789, 789, 790, 790, 791, 792, 792, 793, 793, 794,
+ 794, 795, 795, 796, 796, 797, 797, 798, 799, 799, 800,
+ 800, 801, 801, 802, 802, 803, 803, 804, 804, 805, 805,
+ 806, 806, 807, 808, 808, 809, 809, 810, 810, 811, 811,
+ 812, 812, 813, 813, 814, 814, 815, 815, 816, 816, 817,
+ 817, 818, 818, 819, 819, 820, 820, 821, 821, 822, 822,
+ 823, 823, 824, 824, 825, 825, 826, 826, 827, 827, 828,
+ 828, 829, 829, 830, 830, 831, 831, 832, 832, 833, 833,
+ 834, 834, 835, 835, 836, 836, 836, 837, 837, 838, 838,
+ 839, 839, 840, 840, 841, 841, 842, 842, 843, 843, 844,
+ 844, 845, 845, 845, 846, 846, 847, 847, 848, 848, 849,
+ 849, 850, 850, 851, 851, 852, 852, 852, 853, 853, 854,
+ 854, 855, 855, 856, 856, 857, 857, 857, 858, 858, 859,
+ 859, 860, 860, 861, 861, 862, 862, 862, 863, 863, 864,
+ 864, 865, 865, 866, 866, 866, 867, 867, 868, 868, 869,
+ 869, 869, 870, 870, 871, 871, 872, 872, 873, 873, 873,
+ 874, 874, 875, 875, 876, 876, 876, 877, 877, 878, 878,
+ 879, 879, 879, 880, 880, 881, 881, 882, 882, 882, 883,
+ 883, 884, 884, 885, 885, 885, 886, 886, 887, 887, 887,
+ 888, 888, 889, 889, 890, 890, 890, 891, 891, 892, 892,
+ 892, 893, 893, 894, 894, 895, 895, 895, 896, 896, 897,
+ 897, 897, 898, 898, 899, 899, 899, 900, 900, 901, 901,
+ 901, 902, 902, 903, 903, 903, 904, 904, 905, 905, 905,
+ 906, 906, 907, 907, 907, 908, 908, 909, 909, 909, 910,
+ 910, 911, 911, 911, 912, 912, 913, 913, 913, 914, 914,
+ 915, 915, 915, 916, 916, 916, 917, 917, 918, 918, 918,
+ 919, 919, 920, 920, 920, 921, 921, 921, 922, 922, 923,
+ 923, 923, 924, 924, 925, 925, 925, 926, 926, 926, 927,
+ 927, 928, 928, 928, 929, 929, 929, 930, 930, 931, 931,
+ 931, 932, 932, 932, 933, 933, 934, 934, 934, 935, 935,
+ 935, 936, 936, 936, 937, 937, 938, 938, 938, 939, 939,
+ 939, 940, 940, 941, 941, 941, 942, 942, 942, 943, 943,
+ 943, 944, 944, 945, 945, 945, 946, 946, 946, 947, 947,
+ 947, 948, 948, 948, 949, 949, 950, 950, 950, 951, 951,
+ 951, 952, 952, 952, 953, 953, 953, 954, 954, 955, 955,
+ 955, 956, 956, 956, 957, 957, 957, 958, 958, 958, 959,
+ 959, 959, 960, 960, 960, 961, 961, 962, 962, 962, 963,
+ 963, 963, 964, 964, 964, 965, 965, 965, 966, 966, 966,
+ 967, 967, 967, 968, 968, 968, 969, 969, 969, 970, 970,
+ 970, 971, 971, 971, 972, 972, 972, 973, 973, 973, 974,
+ 974, 974, 975, 975, 975, 976, 976, 976, 977, 977, 977,
+ 978, 978, 978, 979, 979, 979, 980, 980, 980, 981, 981,
+ 981, 982, 982, 982, 983, 983, 983, 984, 984, 984, 985,
+ 985, 985, 986, 986, 986, 987, 987, 987, 988, 988, 988,
+ 989, 989, 989, 990, 990, 990, 991, 991, 991, 992, 992,
+ 992, 993, 993, 993, 994, 994, 994, 994, 995, 995, 995,
+ 996, 996, 996, 997, 997, 997, 998, 998, 998, 999, 999,
+ 999, 1000, 1000, 1000, 1001, 1001, 1001, 1001, 1002, 1002, 1002,
+ 1003, 1003, 1003, 1004, 1004, 1004, 1005, 1005, 1005, 1006, 1006,
+ 1006, 1006, 1007, 1007, 1007, 1008, 1008, 1008, 1009, 1009, 1009,
+ 1010, 1010, 1010, 1011, 1011, 1011, 1011, 1012, 1012, 1012, 1013,
+ 1013, 1013, 1014, 1014, 1014, 1015, 1015, 1015, 1015, 1016, 1016,
+ 1016, 1017, 1017, 1017, 1018, 1018, 1018, 1018, 1019, 1019, 1019,
+ 1020, 1020, 1020, 1021, 1021, 1021, 1021, 1022, 1022, 1022, 1023,
+ 1023,
+};
+
+static const u16 xgamma10_04[GAMMA10_TABLE_LENGTH] = {
+ 0, 64, 84, 99, 111, 122, 131, 139, 147, 154, 161,
+ 167, 173, 178, 184, 189, 194, 199, 203, 208, 212, 216,
+ 220, 224, 228, 232, 235, 239, 243, 246, 249, 253, 256,
+ 259, 262, 265, 268, 271, 274, 277, 280, 283, 285, 288,
+ 291, 293, 296, 298, 301, 303, 306, 308, 311, 313, 315,
+ 318, 320, 322, 325, 327, 329, 331, 333, 335, 338, 340,
+ 342, 344, 346, 348, 350, 352, 354, 356, 358, 360, 362,
+ 364, 365, 367, 369, 371, 373, 375, 376, 378, 380, 382,
+ 383, 385, 387, 389, 390, 392, 394, 395, 397, 399, 400,
+ 402, 404, 405, 407, 408, 410, 412, 413, 415, 416, 418,
+ 419, 421, 422, 424, 425, 427, 428, 430, 431, 433, 434,
+ 436, 437, 438, 440, 441, 443, 444, 445, 447, 448, 450,
+ 451, 452, 454, 455, 456, 458, 459, 460, 462, 463, 464,
+ 466, 467, 468, 470, 471, 472, 473, 475, 476, 477, 478,
+ 480, 481, 482, 483, 485, 486, 487, 488, 489, 491, 492,
+ 493, 494, 495, 497, 498, 499, 500, 501, 503, 504, 505,
+ 506, 507, 508, 509, 511, 512, 513, 514, 515, 516, 517,
+ 518, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529,
+ 530, 531, 533, 534, 535, 536, 537, 538, 539, 540, 541,
+ 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552,
+ 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563,
+ 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574,
+ 575, 576, 577, 578, 578, 579, 580, 581, 582, 583, 584,
+ 585, 586, 587, 588, 589, 590, 591, 591, 592, 593, 594,
+ 595, 596, 597, 598, 599, 600, 600, 601, 602, 603, 604,
+ 605, 606, 607, 607, 608, 609, 610, 611, 612, 613, 614,
+ 614, 615, 616, 617, 618, 619, 620, 620, 621, 622, 623,
+ 624, 625, 625, 626, 627, 628, 629, 630, 630, 631, 632,
+ 633, 634, 635, 635, 636, 637, 638, 639, 639, 640, 641,
+ 642, 643, 643, 644, 645, 646, 647, 647, 648, 649, 650,
+ 651, 651, 652, 653, 654, 655, 655, 656, 657, 658, 658,
+ 659, 660, 661, 662, 662, 663, 664, 665, 665, 666, 667,
+ 668, 668, 669, 670, 671, 671, 672, 673, 674, 674, 675,
+ 676, 677, 677, 678, 679, 680, 680, 681, 682, 683, 683,
+ 684, 685, 685, 686, 687, 688, 688, 689, 690, 691, 691,
+ 692, 693, 693, 694, 695, 696, 696, 697, 698, 698, 699,
+ 700, 701, 701, 702, 703, 703, 704, 705, 705, 706, 707,
+ 708, 708, 709, 710, 710, 711, 712, 712, 713, 714, 714,
+ 715, 716, 717, 717, 718, 719, 719, 720, 721, 721, 722,
+ 723, 723, 724, 725, 725, 726, 727, 727, 728, 729, 729,
+ 730, 731, 731, 732, 733, 733, 734, 735, 735, 736, 737,
+ 737, 738, 739, 739, 740, 740, 741, 742, 742, 743, 744,
+ 744, 745, 746, 746, 747, 748, 748, 749, 749, 750, 751,
+ 751, 752, 753, 753, 754, 755, 755, 756, 756, 757, 758,
+ 758, 759, 760, 760, 761, 761, 762, 763, 763, 764, 765,
+ 765, 766, 766, 767, 768, 768, 769, 769, 770, 771, 771,
+ 772, 773, 773, 774, 774, 775, 776, 776, 777, 777, 778,
+ 779, 779, 780, 780, 781, 782, 782, 783, 783, 784, 785,
+ 785, 786, 786, 787, 788, 788, 789, 789, 790, 791, 791,
+ 792, 792, 793, 793, 794, 795, 795, 796, 796, 797, 798,
+ 798, 799, 799, 800, 800, 801, 802, 802, 803, 803, 804,
+ 804, 805, 806, 806, 807, 807, 808, 808, 809, 810, 810,
+ 811, 811, 812, 812, 813, 814, 814, 815, 815, 816, 816,
+ 817, 818, 818, 819, 819, 820, 820, 821, 821, 822, 823,
+ 823, 824, 824, 825, 825, 826, 826, 827, 827, 828, 829,
+ 829, 830, 830, 831, 831, 832, 832, 833, 834, 834, 835,
+ 835, 836, 836, 837, 837, 838, 838, 839, 839, 840, 841,
+ 841, 842, 842, 843, 843, 844, 844, 845, 845, 846, 846,
+ 847, 847, 848, 849, 849, 850, 850, 851, 851, 852, 852,
+ 853, 853, 854, 854, 855, 855, 856, 856, 857, 857, 858,
+ 859, 859, 860, 860, 861, 861, 862, 862, 863, 863, 864,
+ 864, 865, 865, 866, 866, 867, 867, 868, 868, 869, 869,
+ 870, 870, 871, 871, 872, 872, 873, 873, 874, 874, 875,
+ 875, 876, 876, 877, 877, 878, 878, 879, 879, 880, 880,
+ 881, 881, 882, 882, 883, 883, 884, 884, 885, 885, 886,
+ 886, 887, 887, 888, 888, 889, 889, 890, 890, 891, 891,
+ 892, 892, 893, 893, 894, 894, 895, 895, 896, 896, 897,
+ 897, 898, 898, 899, 899, 900, 900, 901, 901, 902, 902,
+ 903, 903, 904, 904, 905, 905, 905, 906, 906, 907, 907,
+ 908, 908, 909, 909, 910, 910, 911, 911, 912, 912, 913,
+ 913, 914, 914, 915, 915, 915, 916, 916, 917, 917, 918,
+ 918, 919, 919, 920, 920, 921, 921, 922, 922, 923, 923,
+ 923, 924, 924, 925, 925, 926, 926, 927, 927, 928, 928,
+ 929, 929, 929, 930, 930, 931, 931, 932, 932, 933, 933,
+ 934, 934, 935, 935, 935, 936, 936, 937, 937, 938, 938,
+ 939, 939, 940, 940, 940, 941, 941, 942, 942, 943, 943,
+ 944, 944, 945, 945, 945, 946, 946, 947, 947, 948, 948,
+ 949, 949, 949, 950, 950, 951, 951, 952, 952, 953, 953,
+ 953, 954, 954, 955, 955, 956, 956, 957, 957, 957, 958,
+ 958, 959, 959, 960, 960, 961, 961, 961, 962, 962, 963,
+ 963, 964, 964, 965, 965, 965, 966, 966, 967, 967, 968,
+ 968, 968, 969, 969, 970, 970, 971, 971, 971, 972, 972,
+ 973, 973, 974, 974, 974, 975, 975, 976, 976, 977, 977,
+ 977, 978, 978, 979, 979, 980, 980, 980, 981, 981, 982,
+ 982, 983, 983, 983, 984, 984, 985, 985, 986, 986, 986,
+ 987, 987, 988, 988, 989, 989, 989, 990, 990, 991, 991,
+ 991, 992, 992, 993, 993, 994, 994, 994, 995, 995, 996,
+ 996, 996, 997, 997, 998, 998, 999, 999, 999, 1000, 1000,
+ 1001, 1001, 1001, 1002, 1002, 1003, 1003, 1004, 1004, 1004, 1005,
+ 1005, 1006, 1006, 1006, 1007, 1007, 1008, 1008, 1008, 1009, 1009,
+ 1010, 1010, 1010, 1011, 1011, 1012, 1012, 1013, 1013, 1013, 1014,
+ 1014, 1015, 1015, 1015, 1016, 1016, 1017, 1017, 1017, 1018, 1018,
+ 1019, 1019, 1019, 1020, 1020, 1021, 1021, 1021, 1022, 1022, 1023,
+ 1023,
+};
+
+static const u16 xgamma10_05[GAMMA10_TABLE_LENGTH] = {
+ 0, 32, 45, 55, 64, 72, 78, 85, 90, 96, 101,
+ 106, 111, 115, 120, 124, 128, 132, 136, 139, 143, 147,
+ 150, 153, 157, 160, 163, 166, 169, 172, 175, 178, 181,
+ 184, 186, 189, 192, 195, 197, 200, 202, 205, 207, 210,
+ 212, 215, 217, 219, 222, 224, 226, 228, 231, 233, 235,
+ 237, 239, 241, 244, 246, 248, 250, 252, 254, 256, 258,
+ 260, 262, 264, 266, 268, 270, 271, 273, 275, 277, 279,
+ 281, 282, 284, 286, 288, 290, 291, 293, 295, 297, 298,
+ 300, 302, 303, 305, 307, 308, 310, 312, 313, 315, 317,
+ 318, 320, 321, 323, 325, 326, 328, 329, 331, 332, 334,
+ 335, 337, 338, 340, 341, 343, 344, 346, 347, 349, 350,
+ 352, 353, 355, 356, 358, 359, 360, 362, 363, 365, 366,
+ 367, 369, 370, 372, 373, 374, 376, 377, 378, 380, 381,
+ 382, 384, 385, 386, 388, 389, 390, 392, 393, 394, 396,
+ 397, 398, 399, 401, 402, 403, 405, 406, 407, 408, 410,
+ 411, 412, 413, 415, 416, 417, 418, 419, 421, 422, 423,
+ 424, 426, 427, 428, 429, 430, 431, 433, 434, 435, 436,
+ 437, 439, 440, 441, 442, 443, 444, 445, 447, 448, 449,
+ 450, 451, 452, 453, 455, 456, 457, 458, 459, 460, 461,
+ 462, 463, 465, 466, 467, 468, 469, 470, 471, 472, 473,
+ 474, 475, 477, 478, 479, 480, 481, 482, 483, 484, 485,
+ 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 497,
+ 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508,
+ 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519,
+ 520, 521, 522, 523, 524, 525, 526, 527, 527, 528, 529,
+ 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540,
+ 541, 542, 543, 544, 545, 546, 547, 547, 548, 549, 550,
+ 551, 552, 553, 554, 555, 556, 557, 558, 559, 559, 560,
+ 561, 562, 563, 564, 565, 566, 567, 568, 569, 569, 570,
+ 571, 572, 573, 574, 575, 576, 577, 577, 578, 579, 580,
+ 581, 582, 583, 584, 585, 585, 586, 587, 588, 589, 590,
+ 591, 591, 592, 593, 594, 595, 596, 597, 598, 598, 599,
+ 600, 601, 602, 603, 603, 604, 605, 606, 607, 608, 609,
+ 609, 610, 611, 612, 613, 614, 614, 615, 616, 617, 618,
+ 619, 619, 620, 621, 622, 623, 623, 624, 625, 626, 627,
+ 628, 628, 629, 630, 631, 632, 632, 633, 634, 635, 636,
+ 636, 637, 638, 639, 640, 640, 641, 642, 643, 644, 644,
+ 645, 646, 647, 648, 648, 649, 650, 651, 652, 652, 653,
+ 654, 655, 655, 656, 657, 658, 659, 659, 660, 661, 662,
+ 662, 663, 664, 665, 666, 666, 667, 668, 669, 669, 670,
+ 671, 672, 672, 673, 674, 675, 675, 676, 677, 678, 678,
+ 679, 680, 681, 681, 682, 683, 684, 684, 685, 686, 687,
+ 687, 688, 689, 690, 690, 691, 692, 693, 693, 694, 695,
+ 696, 696, 697, 698, 699, 699, 700, 701, 701, 702, 703,
+ 704, 704, 705, 706, 707, 707, 708, 709, 709, 710, 711,
+ 712, 712, 713, 714, 714, 715, 716, 717, 717, 718, 719,
+ 719, 720, 721, 722, 722, 723, 724, 724, 725, 726, 727,
+ 727, 728, 729, 729, 730, 731, 731, 732, 733, 734, 734,
+ 735, 736, 736, 737, 738, 738, 739, 740, 740, 741, 742,
+ 743, 743, 744, 745, 745, 746, 747, 747, 748, 749, 749,
+ 750, 751, 751, 752, 753, 754, 754, 755, 756, 756, 757,
+ 758, 758, 759, 760, 760, 761, 762, 762, 763, 764, 764,
+ 765, 766, 766, 767, 768, 768, 769, 770, 770, 771, 772,
+ 772, 773, 774, 774, 775, 776, 776, 777, 778, 778, 779,
+ 780, 780, 781, 781, 782, 783, 783, 784, 785, 785, 786,
+ 787, 787, 788, 789, 789, 790, 791, 791, 792, 793, 793,
+ 794, 794, 795, 796, 796, 797, 798, 798, 799, 800, 800,
+ 801, 802, 802, 803, 803, 804, 805, 805, 806, 807, 807,
+ 808, 809, 809, 810, 810, 811, 812, 812, 813, 814, 814,
+ 815, 815, 816, 817, 817, 818, 819, 819, 820, 820, 821,
+ 822, 822, 823, 824, 824, 825, 825, 826, 827, 827, 828,
+ 829, 829, 830, 830, 831, 832, 832, 833, 833, 834, 835,
+ 835, 836, 836, 837, 838, 838, 839, 840, 840, 841, 841,
+ 842, 843, 843, 844, 844, 845, 846, 846, 847, 847, 848,
+ 849, 849, 850, 850, 851, 852, 852, 853, 853, 854, 855,
+ 855, 856, 856, 857, 858, 858, 859, 859, 860, 861, 861,
+ 862, 862, 863, 864, 864, 865, 865, 866, 867, 867, 868,
+ 868, 869, 869, 870, 871, 871, 872, 872, 873, 874, 874,
+ 875, 875, 876, 877, 877, 878, 878, 879, 879, 880, 881,
+ 881, 882, 882, 883, 883, 884, 885, 885, 886, 886, 887,
+ 888, 888, 889, 889, 890, 890, 891, 892, 892, 893, 893,
+ 894, 894, 895, 896, 896, 897, 897, 898, 898, 899, 900,
+ 900, 901, 901, 902, 902, 903, 904, 904, 905, 905, 906,
+ 906, 907, 907, 908, 909, 909, 910, 910, 911, 911, 912,
+ 913, 913, 914, 914, 915, 915, 916, 916, 917, 918, 918,
+ 919, 919, 920, 920, 921, 921, 922, 923, 923, 924, 924,
+ 925, 925, 926, 926, 927, 928, 928, 929, 929, 930, 930,
+ 931, 931, 932, 932, 933, 934, 934, 935, 935, 936, 936,
+ 937, 937, 938, 939, 939, 940, 940, 941, 941, 942, 942,
+ 943, 943, 944, 944, 945, 946, 946, 947, 947, 948, 948,
+ 949, 949, 950, 950, 951, 952, 952, 953, 953, 954, 954,
+ 955, 955, 956, 956, 957, 957, 958, 958, 959, 960, 960,
+ 961, 961, 962, 962, 963, 963, 964, 964, 965, 965, 966,
+ 966, 967, 967, 968, 969, 969, 970, 970, 971, 971, 972,
+ 972, 973, 973, 974, 974, 975, 975, 976, 976, 977, 977,
+ 978, 979, 979, 980, 980, 981, 981, 982, 982, 983, 983,
+ 984, 984, 985, 985, 986, 986, 987, 987, 988, 988, 989,
+ 989, 990, 990, 991, 992, 992, 993, 993, 994, 994, 995,
+ 995, 996, 996, 997, 997, 998, 998, 999, 999, 1000, 1000,
+ 1001, 1001, 1002, 1002, 1003, 1003, 1004, 1004, 1005, 1005, 1006,
+ 1006, 1007, 1007, 1008, 1008, 1009, 1009, 1010, 1010, 1011, 1011,
+ 1012, 1012, 1013, 1013, 1014, 1014, 1015, 1015, 1016, 1016, 1017,
+ 1017, 1018, 1018, 1019, 1019, 1020, 1020, 1021, 1021, 1022, 1022,
+ 1023,
+};
+
+static const u16 xgamma10_06[GAMMA10_TABLE_LENGTH] = {
+ 0, 16, 24, 31, 37, 42, 47, 51, 56, 60, 64,
+ 67, 71, 75, 78, 81, 84, 88, 91, 94, 97, 99,
+ 102, 105, 108, 110, 113, 116, 118, 121, 123, 126, 128,
+ 130, 133, 135, 137, 140, 142, 144, 146, 148, 151, 153,
+ 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175,
+ 177, 179, 181, 183, 185, 187, 188, 190, 192, 194, 196,
+ 198, 199, 201, 203, 205, 206, 208, 210, 212, 213, 215,
+ 217, 218, 220, 222, 223, 225, 227, 228, 230, 232, 233,
+ 235, 236, 238, 240, 241, 243, 244, 246, 247, 249, 250,
+ 252, 253, 255, 257, 258, 260, 261, 263, 264, 265, 267,
+ 268, 270, 271, 273, 274, 276, 277, 279, 280, 281, 283,
+ 284, 286, 287, 288, 290, 291, 293, 294, 295, 297, 298,
+ 299, 301, 302, 303, 305, 306, 308, 309, 310, 312, 313,
+ 314, 315, 317, 318, 319, 321, 322, 323, 325, 326, 327,
+ 328, 330, 331, 332, 334, 335, 336, 337, 339, 340, 341,
+ 342, 344, 345, 346, 347, 349, 350, 351, 352, 353, 355,
+ 356, 357, 358, 359, 361, 362, 363, 364, 365, 367, 368,
+ 369, 370, 371, 373, 374, 375, 376, 377, 378, 380, 381,
+ 382, 383, 384, 385, 387, 388, 389, 390, 391, 392, 393,
+ 394, 396, 397, 398, 399, 400, 401, 402, 403, 405, 406,
+ 407, 408, 409, 410, 411, 412, 413, 415, 416, 417, 418,
+ 419, 420, 421, 422, 423, 424, 425, 426, 428, 429, 430,
+ 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441,
+ 442, 443, 445, 446, 447, 448, 449, 450, 451, 452, 453,
+ 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464,
+ 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475,
+ 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486,
+ 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497,
+ 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 507,
+ 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518,
+ 519, 520, 521, 522, 523, 524, 525, 525, 526, 527, 528,
+ 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 538,
+ 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 548,
+ 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 558,
+ 559, 560, 561, 562, 563, 564, 565, 566, 566, 567, 568,
+ 569, 570, 571, 572, 573, 574, 574, 575, 576, 577, 578,
+ 579, 580, 581, 581, 582, 583, 584, 585, 586, 587, 588,
+ 588, 589, 590, 591, 592, 593, 594, 594, 595, 596, 597,
+ 598, 599, 600, 601, 601, 602, 603, 604, 605, 606, 606,
+ 607, 608, 609, 610, 611, 612, 612, 613, 614, 615, 616,
+ 617, 617, 618, 619, 620, 621, 622, 622, 623, 624, 625,
+ 626, 627, 627, 628, 629, 630, 631, 632, 632, 633, 634,
+ 635, 636, 637, 637, 638, 639, 640, 641, 642, 642, 643,
+ 644, 645, 646, 646, 647, 648, 649, 650, 650, 651, 652,
+ 653, 654, 655, 655, 656, 657, 658, 659, 659, 660, 661,
+ 662, 663, 663, 664, 665, 666, 667, 667, 668, 669, 670,
+ 671, 671, 672, 673, 674, 675, 675, 676, 677, 678, 678,
+ 679, 680, 681, 682, 682, 683, 684, 685, 686, 686, 687,
+ 688, 689, 689, 690, 691, 692, 693, 693, 694, 695, 696,
+ 696, 697, 698, 699, 700, 700, 701, 702, 703, 703, 704,
+ 705, 706, 707, 707, 708, 709, 710, 710, 711, 712, 713,
+ 713, 714, 715, 716, 716, 717, 718, 719, 719, 720, 721,
+ 722, 723, 723, 724, 725, 726, 726, 727, 728, 729, 729,
+ 730, 731, 732, 732, 733, 734, 735, 735, 736, 737, 738,
+ 738, 739, 740, 741, 741, 742, 743, 743, 744, 745, 746,
+ 746, 747, 748, 749, 749, 750, 751, 752, 752, 753, 754,
+ 755, 755, 756, 757, 758, 758, 759, 760, 760, 761, 762,
+ 763, 763, 764, 765, 766, 766, 767, 768, 768, 769, 770,
+ 771, 771, 772, 773, 774, 774, 775, 776, 776, 777, 778,
+ 779, 779, 780, 781, 781, 782, 783, 784, 784, 785, 786,
+ 786, 787, 788, 789, 789, 790, 791, 791, 792, 793, 794,
+ 794, 795, 796, 796, 797, 798, 799, 799, 800, 801, 801,
+ 802, 803, 803, 804, 805, 806, 806, 807, 808, 808, 809,
+ 810, 811, 811, 812, 813, 813, 814, 815, 815, 816, 817,
+ 818, 818, 819, 820, 820, 821, 822, 822, 823, 824, 824,
+ 825, 826, 827, 827, 828, 829, 829, 830, 831, 831, 832,
+ 833, 833, 834, 835, 835, 836, 837, 838, 838, 839, 840,
+ 840, 841, 842, 842, 843, 844, 844, 845, 846, 846, 847,
+ 848, 848, 849, 850, 851, 851, 852, 853, 853, 854, 855,
+ 855, 856, 857, 857, 858, 859, 859, 860, 861, 861, 862,
+ 863, 863, 864, 865, 865, 866, 867, 867, 868, 869, 869,
+ 870, 871, 871, 872, 873, 873, 874, 875, 875, 876, 877,
+ 877, 878, 879, 879, 880, 881, 881, 882, 883, 883, 884,
+ 885, 885, 886, 887, 887, 888, 889, 889, 890, 891, 891,
+ 892, 893, 893, 894, 895, 895, 896, 897, 897, 898, 898,
+ 899, 900, 900, 901, 902, 902, 903, 904, 904, 905, 906,
+ 906, 907, 908, 908, 909, 910, 910, 911, 911, 912, 913,
+ 913, 914, 915, 915, 916, 917, 917, 918, 919, 919, 920,
+ 921, 921, 922, 922, 923, 924, 924, 925, 926, 926, 927,
+ 928, 928, 929, 930, 930, 931, 931, 932, 933, 933, 934,
+ 935, 935, 936, 937, 937, 938, 938, 939, 940, 940, 941,
+ 942, 942, 943, 944, 944, 945, 945, 946, 947, 947, 948,
+ 949, 949, 950, 950, 951, 952, 952, 953, 954, 954, 955,
+ 956, 956, 957, 957, 958, 959, 959, 960, 961, 961, 962,
+ 962, 963, 964, 964, 965, 966, 966, 967, 967, 968, 969,
+ 969, 970, 970, 971, 972, 972, 973, 974, 974, 975, 975,
+ 976, 977, 977, 978, 979, 979, 980, 980, 981, 982, 982,
+ 983, 983, 984, 985, 985, 986, 987, 987, 988, 988, 989,
+ 990, 990, 991, 991, 992, 993, 993, 994, 995, 995, 996,
+ 996, 997, 998, 998, 999, 999, 1000, 1001, 1001, 1002, 1002,
+ 1003, 1004, 1004, 1005, 1006, 1006, 1007, 1007, 1008, 1009, 1009,
+ 1010, 1010, 1011, 1012, 1012, 1013, 1013, 1014, 1015, 1015, 1016,
+ 1016, 1017, 1018, 1018, 1019, 1019, 1020, 1021, 1021, 1022, 1022,
+ 1023,
+};
+
+static const u16 xgamma10_07[GAMMA10_TABLE_LENGTH] = {
+ 0, 8, 13, 17, 21, 25, 28, 31, 34, 37, 40,
+ 43, 46, 48, 51, 53, 56, 58, 60, 63, 65, 67,
+ 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90,
+ 92, 94, 96, 98, 100, 102, 104, 106, 108, 109, 111,
+ 113, 115, 117, 118, 120, 122, 124, 125, 127, 129, 131,
+ 132, 134, 136, 137, 139, 140, 142, 144, 145, 147, 149,
+ 150, 152, 153, 155, 157, 158, 160, 161, 163, 164, 166,
+ 167, 169, 170, 172, 173, 175, 176, 178, 179, 181, 182,
+ 184, 185, 187, 188, 190, 191, 192, 194, 195, 197, 198,
+ 199, 201, 202, 204, 205, 206, 208, 209, 211, 212, 213,
+ 215, 216, 217, 219, 220, 222, 223, 224, 226, 227, 228,
+ 230, 231, 232, 234, 235, 236, 237, 239, 240, 241, 243,
+ 244, 245, 247, 248, 249, 250, 252, 253, 254, 256, 257,
+ 258, 259, 261, 262, 263, 264, 266, 267, 268, 269, 271,
+ 272, 273, 274, 275, 277, 278, 279, 280, 282, 283, 284,
+ 285, 286, 288, 289, 290, 291, 292, 294, 295, 296, 297,
+ 298, 300, 301, 302, 303, 304, 306, 307, 308, 309, 310,
+ 311, 313, 314, 315, 316, 317, 318, 319, 321, 322, 323,
+ 324, 325, 326, 327, 329, 330, 331, 332, 333, 334, 335,
+ 337, 338, 339, 340, 341, 342, 343, 344, 346, 347, 348,
+ 349, 350, 351, 352, 353, 354, 355, 357, 358, 359, 360,
+ 361, 362, 363, 364, 365, 366, 368, 369, 370, 371, 372,
+ 373, 374, 375, 376, 377, 378, 379, 380, 382, 383, 384,
+ 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395,
+ 396, 397, 398, 400, 401, 402, 403, 404, 405, 406, 407,
+ 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418,
+ 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429,
+ 430, 431, 432, 433, 434, 435, 436, 437, 439, 440, 441,
+ 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452,
+ 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462,
+ 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473,
+ 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484,
+ 485, 486, 487, 488, 489, 490, 491, 492, 492, 493, 494,
+ 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505,
+ 506, 507, 508, 509, 510, 511, 511, 512, 513, 514, 515,
+ 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526,
+ 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536,
+ 537, 538, 538, 539, 540, 541, 542, 543, 544, 545, 546,
+ 547, 548, 549, 549, 550, 551, 552, 553, 554, 555, 556,
+ 557, 558, 559, 560, 560, 561, 562, 563, 564, 565, 566,
+ 567, 568, 569, 569, 570, 571, 572, 573, 574, 575, 576,
+ 577, 578, 578, 579, 580, 581, 582, 583, 584, 585, 586,
+ 586, 587, 588, 589, 590, 591, 592, 593, 594, 594, 595,
+ 596, 597, 598, 599, 600, 601, 601, 602, 603, 604, 605,
+ 606, 607, 608, 608, 609, 610, 611, 612, 613, 614, 615,
+ 615, 616, 617, 618, 619, 620, 621, 622, 622, 623, 624,
+ 625, 626, 627, 628, 628, 629, 630, 631, 632, 633, 634,
+ 634, 635, 636, 637, 638, 639, 640, 640, 641, 642, 643,
+ 644, 645, 646, 646, 647, 648, 649, 650, 651, 652, 652,
+ 653, 654, 655, 656, 657, 657, 658, 659, 660, 661, 662,
+ 663, 663, 664, 665, 666, 667, 668, 668, 669, 670, 671,
+ 672, 673, 673, 674, 675, 676, 677, 678, 678, 679, 680,
+ 681, 682, 683, 683, 684, 685, 686, 687, 688, 688, 689,
+ 690, 691, 692, 693, 693, 694, 695, 696, 697, 698, 698,
+ 699, 700, 701, 702, 703, 703, 704, 705, 706, 707, 707,
+ 708, 709, 710, 711, 712, 712, 713, 714, 715, 716, 716,
+ 717, 718, 719, 720, 721, 721, 722, 723, 724, 725, 725,
+ 726, 727, 728, 729, 729, 730, 731, 732, 733, 733, 734,
+ 735, 736, 737, 738, 738, 739, 740, 741, 742, 742, 743,
+ 744, 745, 746, 746, 747, 748, 749, 750, 750, 751, 752,
+ 753, 754, 754, 755, 756, 757, 758, 758, 759, 760, 761,
+ 761, 762, 763, 764, 765, 765, 766, 767, 768, 769, 769,
+ 770, 771, 772, 773, 773, 774, 775, 776, 777, 777, 778,
+ 779, 780, 780, 781, 782, 783, 784, 784, 785, 786, 787,
+ 788, 788, 789, 790, 791, 791, 792, 793, 794, 795, 795,
+ 796, 797, 798, 798, 799, 800, 801, 802, 802, 803, 804,
+ 805, 805, 806, 807, 808, 809, 809, 810, 811, 812, 812,
+ 813, 814, 815, 816, 816, 817, 818, 819, 819, 820, 821,
+ 822, 822, 823, 824, 825, 826, 826, 827, 828, 829, 829,
+ 830, 831, 832, 832, 833, 834, 835, 835, 836, 837, 838,
+ 839, 839, 840, 841, 842, 842, 843, 844, 845, 845, 846,
+ 847, 848, 848, 849, 850, 851, 851, 852, 853, 854, 854,
+ 855, 856, 857, 857, 858, 859, 860, 860, 861, 862, 863,
+ 864, 864, 865, 866, 867, 867, 868, 869, 870, 870, 871,
+ 872, 873, 873, 874, 875, 876, 876, 877, 878, 879, 879,
+ 880, 881, 881, 882, 883, 884, 884, 885, 886, 887, 887,
+ 888, 889, 890, 890, 891, 892, 893, 893, 894, 895, 896,
+ 896, 897, 898, 899, 899, 900, 901, 902, 902, 903, 904,
+ 904, 905, 906, 907, 907, 908, 909, 910, 910, 911, 912,
+ 913, 913, 914, 915, 916, 916, 917, 918, 918, 919, 920,
+ 921, 921, 922, 923, 924, 924, 925, 926, 927, 927, 928,
+ 929, 929, 930, 931, 932, 932, 933, 934, 935, 935, 936,
+ 937, 937, 938, 939, 940, 940, 941, 942, 943, 943, 944,
+ 945, 945, 946, 947, 948, 948, 949, 950, 950, 951, 952,
+ 953, 953, 954, 955, 956, 956, 957, 958, 958, 959, 960,
+ 961, 961, 962, 963, 963, 964, 965, 966, 966, 967, 968,
+ 968, 969, 970, 971, 971, 972, 973, 973, 974, 975, 976,
+ 976, 977, 978, 978, 979, 980, 981, 981, 982, 983, 983,
+ 984, 985, 986, 986, 987, 988, 988, 989, 990, 991, 991,
+ 992, 993, 993, 994, 995, 996, 996, 997, 998, 998, 999,
+ 1000, 1000, 1001, 1002, 1003, 1003, 1004, 1005, 1005, 1006, 1007,
+ 1008, 1008, 1009, 1010, 1010, 1011, 1012, 1012, 1013, 1014, 1015,
+ 1015, 1016, 1017, 1017, 1018, 1019, 1019, 1020, 1021, 1022, 1022,
+ 1023,
+};
+
+static const u16 xgamma10_08[GAMMA10_TABLE_LENGTH] = {
+ 0, 4, 7, 10, 12, 14, 17, 19, 21, 23, 25,
+ 27, 29, 31, 33, 35, 37, 39, 40, 42, 44, 46,
+ 47, 49, 51, 53, 54, 56, 58, 59, 61, 62, 64,
+ 66, 67, 69, 70, 72, 73, 75, 76, 78, 80, 81,
+ 83, 84, 86, 87, 89, 90, 91, 93, 94, 96, 97,
+ 99, 100, 102, 103, 104, 106, 107, 109, 110, 111, 113,
+ 114, 116, 117, 118, 120, 121, 122, 124, 125, 126, 128,
+ 129, 131, 132, 133, 135, 136, 137, 138, 140, 141, 142,
+ 144, 145, 146, 148, 149, 150, 152, 153, 154, 155, 157,
+ 158, 159, 160, 162, 163, 164, 166, 167, 168, 169, 171,
+ 172, 173, 174, 176, 177, 178, 179, 181, 182, 183, 184,
+ 185, 187, 188, 189, 190, 192, 193, 194, 195, 196, 198,
+ 199, 200, 201, 202, 204, 205, 206, 207, 208, 210, 211,
+ 212, 213, 214, 216, 217, 218, 219, 220, 221, 223, 224,
+ 225, 226, 227, 228, 230, 231, 232, 233, 234, 235, 237,
+ 238, 239, 240, 241, 242, 243, 245, 246, 247, 248, 249,
+ 250, 251, 253, 254, 255, 256, 257, 258, 259, 260, 262,
+ 263, 264, 265, 266, 267, 268, 269, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 281, 282, 283, 284, 285, 286,
+ 287, 288, 289, 290, 292, 293, 294, 295, 296, 297, 298,
+ 299, 300, 301, 302, 304, 305, 306, 307, 308, 309, 310,
+ 311, 312, 313, 314, 315, 316, 318, 319, 320, 321, 322,
+ 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333,
+ 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345,
+ 346, 347, 348, 349, 350, 351, 352, 353, 355, 356, 357,
+ 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368,
+ 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379,
+ 380, 381, 382, 383, 384, 385, 386, 388, 389, 390, 391,
+ 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402,
+ 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413,
+ 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424,
+ 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435,
+ 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446,
+ 447, 448, 449, 450, 451, 451, 452, 453, 454, 455, 456,
+ 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467,
+ 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478,
+ 479, 480, 481, 482, 483, 484, 485, 486, 486, 487, 488,
+ 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499,
+ 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 509,
+ 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520,
+ 521, 522, 523, 524, 525, 526, 527, 527, 528, 529, 530,
+ 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541,
+ 542, 543, 543, 544, 545, 546, 547, 548, 549, 550, 551,
+ 552, 553, 554, 555, 556, 557, 557, 558, 559, 560, 561,
+ 562, 563, 564, 565, 566, 567, 568, 569, 570, 570, 571,
+ 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582,
+ 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592,
+ 593, 594, 594, 595, 596, 597, 598, 599, 600, 601, 602,
+ 603, 604, 604, 605, 606, 607, 608, 609, 610, 611, 612,
+ 613, 614, 615, 615, 616, 617, 618, 619, 620, 621, 622,
+ 623, 624, 624, 625, 626, 627, 628, 629, 630, 631, 632,
+ 633, 634, 634, 635, 636, 637, 638, 639, 640, 641, 642,
+ 643, 643, 644, 645, 646, 647, 648, 649, 650, 651, 651,
+ 652, 653, 654, 655, 656, 657, 658, 659, 660, 660, 661,
+ 662, 663, 664, 665, 666, 667, 668, 668, 669, 670, 671,
+ 672, 673, 674, 675, 676, 676, 677, 678, 679, 680, 681,
+ 682, 683, 684, 684, 685, 686, 687, 688, 689, 690, 691,
+ 691, 692, 693, 694, 695, 696, 697, 698, 699, 699, 700,
+ 701, 702, 703, 704, 705, 706, 706, 707, 708, 709, 710,
+ 711, 712, 713, 713, 714, 715, 716, 717, 718, 719, 720,
+ 720, 721, 722, 723, 724, 725, 726, 727, 727, 728, 729,
+ 730, 731, 732, 733, 734, 734, 735, 736, 737, 738, 739,
+ 740, 740, 741, 742, 743, 744, 745, 746, 747, 747, 748,
+ 749, 750, 751, 752, 753, 753, 754, 755, 756, 757, 758,
+ 759, 759, 760, 761, 762, 763, 764, 765, 766, 766, 767,
+ 768, 769, 770, 771, 772, 772, 773, 774, 775, 776, 777,
+ 778, 778, 779, 780, 781, 782, 783, 784, 784, 785, 786,
+ 787, 788, 789, 790, 790, 791, 792, 793, 794, 795, 795,
+ 796, 797, 798, 799, 800, 801, 801, 802, 803, 804, 805,
+ 806, 807, 807, 808, 809, 810, 811, 812, 812, 813, 814,
+ 815, 816, 817, 818, 818, 819, 820, 821, 822, 823, 823,
+ 824, 825, 826, 827, 828, 829, 829, 830, 831, 832, 833,
+ 834, 834, 835, 836, 837, 838, 839, 839, 840, 841, 842,
+ 843, 844, 845, 845, 846, 847, 848, 849, 850, 850, 851,
+ 852, 853, 854, 855, 855, 856, 857, 858, 859, 860, 860,
+ 861, 862, 863, 864, 865, 865, 866, 867, 868, 869, 870,
+ 870, 871, 872, 873, 874, 875, 875, 876, 877, 878, 879,
+ 880, 880, 881, 882, 883, 884, 885, 885, 886, 887, 888,
+ 889, 890, 890, 891, 892, 893, 894, 895, 895, 896, 897,
+ 898, 899, 899, 900, 901, 902, 903, 904, 904, 905, 906,
+ 907, 908, 909, 909, 910, 911, 912, 913, 913, 914, 915,
+ 916, 917, 918, 918, 919, 920, 921, 922, 923, 923, 924,
+ 925, 926, 927, 927, 928, 929, 930, 931, 932, 932, 933,
+ 934, 935, 936, 936, 937, 938, 939, 940, 941, 941, 942,
+ 943, 944, 945, 945, 946, 947, 948, 949, 950, 950, 951,
+ 952, 953, 954, 954, 955, 956, 957, 958, 958, 959, 960,
+ 961, 962, 963, 963, 964, 965, 966, 967, 967, 968, 969,
+ 970, 971, 971, 972, 973, 974, 975, 976, 976, 977, 978,
+ 979, 980, 980, 981, 982, 983, 984, 984, 985, 986, 987,
+ 988, 988, 989, 990, 991, 992, 992, 993, 994, 995, 996,
+ 997, 997, 998, 999, 1000, 1001, 1001, 1002, 1003, 1004, 1005,
+ 1005, 1006, 1007, 1008, 1009, 1009, 1010, 1011, 1012, 1013, 1013,
+ 1014, 1015, 1016, 1017, 1017, 1018, 1019, 1020, 1021, 1021, 1022,
+ 1023,
+};
+
+static const u16 xgamma10_09[GAMMA10_TABLE_LENGTH] = {
+ 0, 2, 4, 5, 7, 9, 10, 12, 13, 14, 16,
+ 17, 19, 20, 22, 23, 24, 26, 27, 28, 30, 31,
+ 32, 34, 35, 36, 38, 39, 40, 41, 43, 44, 45,
+ 47, 48, 49, 50, 52, 53, 54, 55, 57, 58, 59,
+ 60, 62, 63, 64, 65, 66, 68, 69, 70, 71, 72,
+ 74, 75, 76, 77, 78, 80, 81, 82, 83, 84, 86,
+ 87, 88, 89, 90, 92, 93, 94, 95, 96, 97, 99,
+ 100, 101, 102, 103, 104, 106, 107, 108, 109, 110, 111,
+ 112, 114, 115, 116, 117, 118, 119, 120, 122, 123, 124,
+ 125, 126, 127, 128, 130, 131, 132, 133, 134, 135, 136,
+ 137, 139, 140, 141, 142, 143, 144, 145, 146, 148, 149,
+ 150, 151, 152, 153, 154, 155, 156, 158, 159, 160, 161,
+ 162, 163, 164, 165, 166, 168, 169, 170, 171, 172, 173,
+ 174, 175, 176, 177, 178, 180, 181, 182, 183, 184, 185,
+ 186, 187, 188, 189, 190, 192, 193, 194, 195, 196, 197,
+ 198, 199, 200, 201, 202, 203, 204, 206, 207, 208, 209,
+ 210, 211, 212, 213, 214, 215, 216, 217, 218, 220, 221,
+ 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232,
+ 233, 234, 235, 237, 238, 239, 240, 241, 242, 243, 244,
+ 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
+ 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267,
+ 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278,
+ 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290,
+ 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301,
+ 302, 303, 304, 305, 306, 307, 308, 309, 311, 312, 313,
+ 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324,
+ 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335,
+ 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346,
+ 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357,
+ 358, 359, 360, 361, 362, 363, 364, 365, 367, 368, 369,
+ 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380,
+ 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391,
+ 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402,
+ 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413,
+ 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424,
+ 425, 426, 427, 427, 428, 429, 430, 431, 432, 433, 434,
+ 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445,
+ 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456,
+ 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467,
+ 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478,
+ 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489,
+ 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499,
+ 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510,
+ 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521,
+ 522, 523, 524, 525, 525, 526, 527, 528, 529, 530, 531,
+ 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542,
+ 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553,
+ 554, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563,
+ 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574,
+ 575, 576, 577, 578, 579, 579, 580, 581, 582, 583, 584,
+ 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595,
+ 596, 597, 598, 599, 600, 601, 601, 602, 603, 604, 605,
+ 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616,
+ 617, 618, 619, 620, 621, 621, 622, 623, 624, 625, 626,
+ 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637,
+ 638, 639, 640, 640, 641, 642, 643, 644, 645, 646, 647,
+ 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658,
+ 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668,
+ 669, 670, 671, 672, 673, 674, 675, 675, 676, 677, 678,
+ 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689,
+ 690, 691, 691, 692, 693, 694, 695, 696, 697, 698, 699,
+ 700, 701, 702, 703, 704, 705, 706, 706, 707, 708, 709,
+ 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720,
+ 721, 721, 722, 723, 724, 725, 726, 727, 728, 729, 730,
+ 731, 732, 733, 734, 735, 735, 736, 737, 738, 739, 740,
+ 741, 742, 743, 744, 745, 746, 747, 748, 749, 749, 750,
+ 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761,
+ 762, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771,
+ 772, 773, 774, 775, 776, 776, 777, 778, 779, 780, 781,
+ 782, 783, 784, 785, 786, 787, 788, 788, 789, 790, 791,
+ 792, 793, 794, 795, 796, 797, 798, 799, 800, 801, 801,
+ 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812,
+ 813, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822,
+ 823, 824, 825, 825, 826, 827, 828, 829, 830, 831, 832,
+ 833, 834, 835, 836, 836, 837, 838, 839, 840, 841, 842,
+ 843, 844, 845, 846, 847, 848, 848, 849, 850, 851, 852,
+ 853, 854, 855, 856, 857, 858, 859, 859, 860, 861, 862,
+ 863, 864, 865, 866, 867, 868, 869, 870, 870, 871, 872,
+ 873, 874, 875, 876, 877, 878, 879, 880, 881, 881, 882,
+ 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 892,
+ 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 902,
+ 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 913,
+ 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923,
+ 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933,
+ 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943,
+ 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953,
+ 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 962,
+ 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 972,
+ 973, 974, 975, 976, 977, 978, 979, 980, 981, 982, 982,
+ 983, 984, 985, 986, 987, 988, 989, 990, 991, 991, 992,
+ 993, 994, 995, 996, 997, 998, 999, 1000, 1000, 1001, 1002,
+ 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1009, 1010, 1011, 1012,
+ 1013, 1014, 1015, 1016, 1017, 1018, 1018, 1019, 1020, 1021, 1022,
+ 1023,
+};
+
+static const u16 xgamma10_10[GAMMA10_TABLE_LENGTH] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
+ 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
+ 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,
+ 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
+ 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131,
+ 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142,
+ 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153,
+ 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
+ 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
+ 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186,
+ 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197,
+ 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208,
+ 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
+ 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230,
+ 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241,
+ 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252,
+ 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263,
+ 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285,
+ 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296,
+ 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307,
+ 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318,
+ 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329,
+ 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340,
+ 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351,
+ 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362,
+ 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373,
+ 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384,
+ 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395,
+ 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406,
+ 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417,
+ 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428,
+ 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439,
+ 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450,
+ 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461,
+ 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472,
+ 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483,
+ 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494,
+ 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505,
+ 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516,
+ 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527,
+ 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538,
+ 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549,
+ 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560,
+ 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571,
+ 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582,
+ 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593,
+ 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604,
+ 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615,
+ 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626,
+ 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637,
+ 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648,
+ 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659,
+ 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670,
+ 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681,
+ 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692,
+ 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703,
+ 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 714,
+ 715, 716, 717, 718, 719, 720, 721, 722, 723, 724, 725,
+ 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736,
+ 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747,
+ 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758,
+ 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769,
+ 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780,
+ 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791,
+ 792, 793, 794, 795, 796, 797, 798, 799, 800, 801, 802,
+ 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813,
+ 814, 815, 816, 817, 818, 819, 820, 821, 822, 823, 824,
+ 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835,
+ 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846,
+ 847, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857,
+ 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868,
+ 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879,
+ 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 890,
+ 891, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901,
+ 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912,
+ 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923,
+ 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934,
+ 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945,
+ 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956,
+ 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967,
+ 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978,
+ 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989,
+ 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000,
+ 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011,
+ 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022,
+ 1023,
+};
+
+static const u16 xgamma10_11[GAMMA10_TABLE_LENGTH] = {
+ 0, 1, 1, 2, 2, 3, 4, 4, 5, 6, 6,
+ 7, 8, 8, 9, 10, 11, 11, 12, 13, 13, 14,
+ 15, 16, 16, 17, 18, 19, 20, 20, 21, 22, 23,
+ 23, 24, 25, 26, 27, 27, 28, 29, 30, 31, 31,
+ 32, 33, 34, 35, 35, 36, 37, 38, 39, 39, 40,
+ 41, 42, 43, 44, 44, 45, 46, 47, 48, 49, 49,
+ 50, 51, 52, 53, 54, 54, 55, 56, 57, 58, 59,
+ 59, 60, 61, 62, 63, 64, 65, 65, 66, 67, 68,
+ 69, 70, 71, 71, 72, 73, 74, 75, 76, 77, 78,
+ 78, 79, 80, 81, 82, 83, 84, 84, 85, 86, 87,
+ 88, 89, 90, 91, 92, 92, 93, 94, 95, 96, 97,
+ 98, 99, 100, 100, 101, 102, 103, 104, 105, 106, 107,
+ 108, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
+ 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+ 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137,
+ 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147,
+ 148, 149, 149, 150, 151, 152, 153, 154, 155, 156, 157,
+ 158, 159, 160, 161, 161, 162, 163, 164, 165, 166, 167,
+ 168, 169, 170, 171, 172, 173, 174, 175, 175, 176, 177,
+ 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188,
+ 189, 190, 191, 191, 192, 193, 194, 195, 196, 197, 198,
+ 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
+ 210, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
+ 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230,
+ 231, 232, 232, 233, 234, 235, 236, 237, 238, 239, 240,
+ 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251,
+ 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 261,
+ 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272,
+ 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283,
+ 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
+ 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305,
+ 306, 307, 307, 308, 309, 310, 311, 312, 313, 314, 315,
+ 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326,
+ 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337,
+ 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348,
+ 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359,
+ 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370,
+ 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381,
+ 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392,
+ 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403,
+ 404, 405, 406, 407, 408, 409, 410, 411, 412, 414, 415,
+ 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426,
+ 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437,
+ 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448,
+ 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459,
+ 460, 461, 462, 463, 464, 465, 466, 468, 469, 470, 471,
+ 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482,
+ 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493,
+ 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 505,
+ 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516,
+ 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527,
+ 528, 529, 530, 531, 532, 533, 535, 536, 537, 538, 539,
+ 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550,
+ 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 562,
+ 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573,
+ 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584,
+ 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596,
+ 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 608,
+ 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619,
+ 620, 621, 622, 623, 624, 625, 626, 627, 629, 630, 631,
+ 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642,
+ 643, 644, 645, 646, 648, 649, 650, 651, 652, 653, 654,
+ 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665,
+ 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677,
+ 678, 679, 680, 681, 682, 683, 685, 686, 687, 688, 689,
+ 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700,
+ 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712,
+ 713, 714, 715, 716, 717, 719, 720, 721, 722, 723, 724,
+ 725, 726, 727, 728, 729, 730, 731, 732, 733, 735, 736,
+ 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747,
+ 748, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759,
+ 760, 761, 762, 763, 764, 766, 767, 768, 769, 770, 771,
+ 772, 773, 774, 775, 776, 777, 778, 779, 781, 782, 783,
+ 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 795,
+ 796, 797, 798, 799, 800, 801, 802, 803, 804, 805, 806,
+ 807, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818,
+ 819, 820, 821, 823, 824, 825, 826, 827, 828, 829, 830,
+ 831, 832, 833, 834, 835, 837, 838, 839, 840, 841, 842,
+ 843, 844, 845, 846, 847, 848, 850, 851, 852, 853, 854,
+ 855, 856, 857, 858, 859, 860, 861, 863, 864, 865, 866,
+ 867, 868, 869, 870, 871, 872, 873, 874, 876, 877, 878,
+ 879, 880, 881, 882, 883, 884, 885, 886, 887, 889, 890,
+ 891, 892, 893, 894, 895, 896, 897, 898, 899, 900, 902,
+ 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 914,
+ 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 926,
+ 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 938,
+ 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 950,
+ 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 962,
+ 963, 964, 965, 966, 967, 968, 969, 970, 971, 973, 974,
+ 975, 976, 977, 978, 979, 980, 981, 982, 983, 985, 986,
+ 987, 988, 989, 990, 991, 992, 993, 994, 996, 997, 998,
+ 999, 1000, 1001, 1002, 1003, 1004, 1005, 1007, 1008, 1009, 1010,
+ 1011, 1012, 1013, 1014, 1015, 1016, 1018, 1019, 1020, 1021, 1022,
+ 1023,
+};
+
+static const u16 xgamma10_12[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 1, 1, 1, 2, 2, 3, 3, 3, 4,
+ 4, 5, 5, 6, 6, 7, 7, 8, 9, 9, 10,
+ 10, 11, 11, 12, 12, 13, 14, 14, 15, 15, 16,
+ 17, 17, 18, 18, 19, 20, 20, 21, 22, 22, 23,
+ 23, 24, 25, 25, 26, 27, 27, 28, 29, 29, 30,
+ 31, 31, 32, 33, 33, 34, 35, 35, 36, 37, 37,
+ 38, 39, 40, 40, 41, 42, 42, 43, 44, 44, 45,
+ 46, 47, 47, 48, 49, 49, 50, 51, 52, 52, 53,
+ 54, 55, 55, 56, 57, 58, 58, 59, 60, 61, 61,
+ 62, 63, 64, 64, 65, 66, 67, 67, 68, 69, 70,
+ 70, 71, 72, 73, 74, 74, 75, 76, 77, 77, 78,
+ 79, 80, 81, 81, 82, 83, 84, 84, 85, 86, 87,
+ 88, 88, 89, 90, 91, 92, 92, 93, 94, 95, 96,
+ 96, 97, 98, 99, 100, 101, 101, 102, 103, 104, 105,
+ 105, 106, 107, 108, 109, 110, 110, 111, 112, 113, 114,
+ 115, 115, 116, 117, 118, 119, 120, 120, 121, 122, 123,
+ 124, 125, 125, 126, 127, 128, 129, 130, 131, 131, 132,
+ 133, 134, 135, 136, 137, 137, 138, 139, 140, 141, 142,
+ 143, 143, 144, 145, 146, 147, 148, 149, 150, 150, 151,
+ 152, 153, 154, 155, 156, 157, 157, 158, 159, 160, 161,
+ 162, 163, 164, 164, 165, 166, 167, 168, 169, 170, 171,
+ 172, 172, 173, 174, 175, 176, 177, 178, 179, 180, 180,
+ 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 190,
+ 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 200,
+ 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211,
+ 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221,
+ 222, 223, 224, 224, 225, 226, 227, 228, 229, 230, 231,
+ 232, 233, 234, 235, 236, 237, 238, 238, 239, 240, 241,
+ 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252,
+ 253, 254, 255, 256, 256, 257, 258, 259, 260, 261, 262,
+ 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273,
+ 274, 275, 276, 277, 278, 279, 280, 280, 281, 282, 283,
+ 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
+ 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305,
+ 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316,
+ 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327,
+ 328, 329, 330, 331, 332, 333, 334, 334, 335, 336, 337,
+ 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348,
+ 349, 350, 351, 353, 354, 355, 356, 357, 358, 359, 360,
+ 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371,
+ 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382,
+ 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393,
+ 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404,
+ 405, 406, 407, 408, 409, 411, 412, 413, 414, 415, 416,
+ 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427,
+ 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 439,
+ 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450,
+ 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 462,
+ 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473,
+ 474, 475, 476, 477, 478, 479, 481, 482, 483, 484, 485,
+ 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496,
+ 497, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508,
+ 509, 510, 511, 512, 513, 515, 516, 517, 518, 519, 520,
+ 521, 522, 523, 524, 525, 526, 527, 529, 530, 531, 532,
+ 533, 534, 535, 536, 537, 538, 539, 540, 541, 543, 544,
+ 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555,
+ 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567,
+ 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579,
+ 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591,
+ 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 604,
+ 605, 606, 607, 608, 609, 610, 611, 612, 613, 615, 616,
+ 617, 618, 619, 620, 621, 622, 623, 624, 626, 627, 628,
+ 629, 630, 631, 632, 633, 634, 636, 637, 638, 639, 640,
+ 641, 642, 643, 644, 646, 647, 648, 649, 650, 651, 652,
+ 653, 654, 656, 657, 658, 659, 660, 661, 662, 663, 664,
+ 666, 667, 668, 669, 670, 671, 672, 673, 675, 676, 677,
+ 678, 679, 680, 681, 682, 683, 685, 686, 687, 688, 689,
+ 690, 691, 692, 694, 695, 696, 697, 698, 699, 700, 701,
+ 703, 704, 705, 706, 707, 708, 709, 710, 712, 713, 714,
+ 715, 716, 717, 718, 720, 721, 722, 723, 724, 725, 726,
+ 727, 729, 730, 731, 732, 733, 734, 735, 737, 738, 739,
+ 740, 741, 742, 743, 745, 746, 747, 748, 749, 750, 751,
+ 752, 754, 755, 756, 757, 758, 759, 760, 762, 763, 764,
+ 765, 766, 767, 768, 770, 771, 772, 773, 774, 775, 776,
+ 778, 779, 780, 781, 782, 783, 785, 786, 787, 788, 789,
+ 790, 791, 793, 794, 795, 796, 797, 798, 799, 801, 802,
+ 803, 804, 805, 806, 808, 809, 810, 811, 812, 813, 814,
+ 816, 817, 818, 819, 820, 821, 823, 824, 825, 826, 827,
+ 828, 830, 831, 832, 833, 834, 835, 836, 838, 839, 840,
+ 841, 842, 843, 845, 846, 847, 848, 849, 850, 852, 853,
+ 854, 855, 856, 857, 859, 860, 861, 862, 863, 864, 866,
+ 867, 868, 869, 870, 871, 873, 874, 875, 876, 877, 878,
+ 880, 881, 882, 883, 884, 885, 887, 888, 889, 890, 891,
+ 892, 894, 895, 896, 897, 898, 900, 901, 902, 903, 904,
+ 905, 907, 908, 909, 910, 911, 912, 914, 915, 916, 917,
+ 918, 920, 921, 922, 923, 924, 925, 927, 928, 929, 930,
+ 931, 932, 934, 935, 936, 937, 938, 940, 941, 942, 943,
+ 944, 946, 947, 948, 949, 950, 951, 953, 954, 955, 956,
+ 957, 959, 960, 961, 962, 963, 964, 966, 967, 968, 969,
+ 970, 972, 973, 974, 975, 976, 978, 979, 980, 981, 982,
+ 984, 985, 986, 987, 988, 989, 991, 992, 993, 994, 995,
+ 997, 998, 999, 1000, 1001, 1003, 1004, 1005, 1006, 1007, 1009,
+ 1010, 1011, 1012, 1013, 1015, 1016, 1017, 1018, 1019, 1021, 1022,
+ 1023,
+};
+
+static const u16 xgamma10_13[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 7,
+ 7, 7, 8, 8, 9, 9, 10, 10, 10, 11, 11,
+ 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17,
+ 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
+ 23, 23, 24, 25, 25, 26, 26, 27, 27, 28, 28,
+ 29, 30, 30, 31, 31, 32, 32, 33, 34, 34, 35,
+ 35, 36, 37, 37, 38, 38, 39, 40, 40, 41, 42,
+ 42, 43, 43, 44, 45, 45, 46, 47, 47, 48, 48,
+ 49, 50, 50, 51, 52, 52, 53, 54, 54, 55, 56,
+ 56, 57, 58, 58, 59, 60, 60, 61, 62, 62, 63,
+ 64, 64, 65, 66, 67, 67, 68, 69, 69, 70, 71,
+ 71, 72, 73, 74, 74, 75, 76, 76, 77, 78, 79,
+ 79, 80, 81, 81, 82, 83, 84, 84, 85, 86, 87,
+ 87, 88, 89, 89, 90, 91, 92, 92, 93, 94, 95,
+ 95, 96, 97, 98, 98, 99, 100, 101, 102, 102, 103,
+ 104, 105, 105, 106, 107, 108, 108, 109, 110, 111, 112,
+ 112, 113, 114, 115, 115, 116, 117, 118, 119, 119, 120,
+ 121, 122, 123, 123, 124, 125, 126, 127, 127, 128, 129,
+ 130, 131, 131, 132, 133, 134, 135, 135, 136, 137, 138,
+ 139, 140, 140, 141, 142, 143, 144, 145, 145, 146, 147,
+ 148, 149, 149, 150, 151, 152, 153, 154, 155, 155, 156,
+ 157, 158, 159, 160, 160, 161, 162, 163, 164, 165, 166,
+ 166, 167, 168, 169, 170, 171, 172, 172, 173, 174, 175,
+ 176, 177, 178, 178, 179, 180, 181, 182, 183, 184, 185,
+ 185, 186, 187, 188, 189, 190, 191, 192, 192, 193, 194,
+ 195, 196, 197, 198, 199, 200, 200, 201, 202, 203, 204,
+ 205, 206, 207, 208, 209, 209, 210, 211, 212, 213, 214,
+ 215, 216, 217, 218, 218, 219, 220, 221, 222, 223, 224,
+ 225, 226, 227, 228, 229, 229, 230, 231, 232, 233, 234,
+ 235, 236, 237, 238, 239, 240, 241, 242, 242, 243, 244,
+ 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
+ 256, 257, 257, 258, 259, 260, 261, 262, 263, 264, 265,
+ 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276,
+ 277, 278, 278, 279, 280, 281, 282, 283, 284, 285, 286,
+ 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297,
+ 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308,
+ 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319,
+ 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330,
+ 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341,
+ 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352,
+ 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363,
+ 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374,
+ 375, 376, 377, 378, 379, 380, 381, 383, 384, 385, 386,
+ 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397,
+ 398, 399, 400, 401, 402, 403, 404, 405, 407, 408, 409,
+ 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420,
+ 421, 422, 423, 424, 426, 427, 428, 429, 430, 431, 432,
+ 433, 434, 435, 436, 437, 438, 439, 440, 442, 443, 444,
+ 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455,
+ 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467,
+ 468, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479,
+ 480, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491,
+ 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 504,
+ 505, 506, 507, 508, 509, 510, 511, 512, 513, 515, 516,
+ 517, 518, 519, 520, 521, 522, 523, 525, 526, 527, 528,
+ 529, 530, 531, 532, 534, 535, 536, 537, 538, 539, 540,
+ 541, 542, 544, 545, 546, 547, 548, 549, 550, 551, 553,
+ 554, 555, 556, 557, 558, 559, 561, 562, 563, 564, 565,
+ 566, 567, 568, 570, 571, 572, 573, 574, 575, 576, 578,
+ 579, 580, 581, 582, 583, 584, 586, 587, 588, 589, 590,
+ 591, 592, 594, 595, 596, 597, 598, 599, 600, 602, 603,
+ 604, 605, 606, 607, 608, 610, 611, 612, 613, 614, 615,
+ 617, 618, 619, 620, 621, 622, 624, 625, 626, 627, 628,
+ 629, 630, 632, 633, 634, 635, 636, 637, 639, 640, 641,
+ 642, 643, 644, 646, 647, 648, 649, 650, 652, 653, 654,
+ 655, 656, 657, 659, 660, 661, 662, 663, 664, 666, 667,
+ 668, 669, 670, 671, 673, 674, 675, 676, 677, 679, 680,
+ 681, 682, 683, 684, 686, 687, 688, 689, 690, 692, 693,
+ 694, 695, 696, 698, 699, 700, 701, 702, 704, 705, 706,
+ 707, 708, 709, 711, 712, 713, 714, 715, 717, 718, 719,
+ 720, 721, 723, 724, 725, 726, 727, 729, 730, 731, 732,
+ 733, 735, 736, 737, 738, 739, 741, 742, 743, 744, 746,
+ 747, 748, 749, 750, 752, 753, 754, 755, 756, 758, 759,
+ 760, 761, 762, 764, 765, 766, 767, 769, 770, 771, 772,
+ 773, 775, 776, 777, 778, 780, 781, 782, 783, 784, 786,
+ 787, 788, 789, 791, 792, 793, 794, 795, 797, 798, 799,
+ 800, 802, 803, 804, 805, 807, 808, 809, 810, 811, 813,
+ 814, 815, 816, 818, 819, 820, 821, 823, 824, 825, 826,
+ 827, 829, 830, 831, 832, 834, 835, 836, 837, 839, 840,
+ 841, 842, 844, 845, 846, 847, 849, 850, 851, 852, 854,
+ 855, 856, 857, 859, 860, 861, 862, 864, 865, 866, 867,
+ 869, 870, 871, 872, 874, 875, 876, 877, 879, 880, 881,
+ 882, 884, 885, 886, 887, 889, 890, 891, 892, 894, 895,
+ 896, 897, 899, 900, 901, 903, 904, 905, 906, 908, 909,
+ 910, 911, 913, 914, 915, 916, 918, 919, 920, 922, 923,
+ 924, 925, 927, 928, 929, 930, 932, 933, 934, 935, 937,
+ 938, 939, 941, 942, 943, 944, 946, 947, 948, 950, 951,
+ 952, 953, 955, 956, 957, 958, 960, 961, 962, 964, 965,
+ 966, 967, 969, 970, 971, 973, 974, 975, 976, 978, 979,
+ 980, 982, 983, 984, 985, 987, 988, 989, 991, 992, 993,
+ 994, 996, 997, 998, 1000, 1001, 1002, 1004, 1005, 1006, 1007,
+ 1009, 1010, 1011, 1013, 1014, 1015, 1017, 1018, 1019, 1020, 1022,
+ 1023,
+};
+
+static const u16 xgamma10_14[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2,
+ 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4,
+ 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8,
+ 8, 9, 9, 9, 10, 10, 11, 11, 11, 12, 12,
+ 12, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17,
+ 17, 18, 18, 18, 19, 19, 20, 20, 21, 21, 22,
+ 22, 23, 23, 23, 24, 24, 25, 25, 26, 26, 27,
+ 27, 28, 28, 29, 29, 30, 30, 31, 31, 32, 32,
+ 33, 34, 34, 35, 35, 36, 36, 37, 37, 38, 38,
+ 39, 39, 40, 41, 41, 42, 42, 43, 43, 44, 45,
+ 45, 46, 46, 47, 47, 48, 49, 49, 50, 50, 51,
+ 52, 52, 53, 53, 54, 55, 55, 56, 56, 57, 58,
+ 58, 59, 59, 60, 61, 61, 62, 63, 63, 64, 64,
+ 65, 66, 66, 67, 68, 68, 69, 70, 70, 71, 72,
+ 72, 73, 74, 74, 75, 76, 76, 77, 78, 78, 79,
+ 80, 80, 81, 82, 82, 83, 84, 84, 85, 86, 86,
+ 87, 88, 88, 89, 90, 91, 91, 92, 93, 93, 94,
+ 95, 95, 96, 97, 98, 98, 99, 100, 100, 101, 102,
+ 103, 103, 104, 105, 106, 106, 107, 108, 109, 109, 110,
+ 111, 111, 112, 113, 114, 114, 115, 116, 117, 117, 118,
+ 119, 120, 120, 121, 122, 123, 124, 124, 125, 126, 127,
+ 127, 128, 129, 130, 130, 131, 132, 133, 134, 134, 135,
+ 136, 137, 138, 138, 139, 140, 141, 141, 142, 143, 144,
+ 145, 145, 146, 147, 148, 149, 150, 150, 151, 152, 153,
+ 154, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162,
+ 163, 163, 164, 165, 166, 167, 168, 168, 169, 170, 171,
+ 172, 173, 173, 174, 175, 176, 177, 178, 179, 179, 180,
+ 181, 182, 183, 184, 185, 185, 186, 187, 188, 189, 190,
+ 191, 191, 192, 193, 194, 195, 196, 197, 198, 198, 199,
+ 200, 201, 202, 203, 204, 205, 205, 206, 207, 208, 209,
+ 210, 211, 212, 213, 213, 214, 215, 216, 217, 218, 219,
+ 220, 221, 222, 222, 223, 224, 225, 226, 227, 228, 229,
+ 230, 231, 232, 232, 233, 234, 235, 236, 237, 238, 239,
+ 240, 241, 242, 243, 244, 244, 245, 246, 247, 248, 249,
+ 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 259,
+ 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270,
+ 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281,
+ 282, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291,
+ 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302,
+ 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313,
+ 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324,
+ 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335,
+ 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346,
+ 347, 348, 349, 351, 352, 353, 354, 355, 356, 357, 358,
+ 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369,
+ 370, 371, 372, 373, 374, 375, 377, 378, 379, 380, 381,
+ 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392,
+ 393, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404,
+ 405, 406, 407, 408, 410, 411, 412, 413, 414, 415, 416,
+ 417, 418, 419, 420, 421, 423, 424, 425, 426, 427, 428,
+ 429, 430, 431, 432, 433, 435, 436, 437, 438, 439, 440,
+ 441, 442, 443, 444, 446, 447, 448, 449, 450, 451, 452,
+ 453, 454, 456, 457, 458, 459, 460, 461, 462, 463, 464,
+ 466, 467, 468, 469, 470, 471, 472, 473, 475, 476, 477,
+ 478, 479, 480, 481, 482, 484, 485, 486, 487, 488, 489,
+ 490, 491, 493, 494, 495, 496, 497, 498, 499, 501, 502,
+ 503, 504, 505, 506, 507, 509, 510, 511, 512, 513, 514,
+ 515, 517, 518, 519, 520, 521, 522, 524, 525, 526, 527,
+ 528, 529, 531, 532, 533, 534, 535, 536, 537, 539, 540,
+ 541, 542, 543, 544, 546, 547, 548, 549, 550, 552, 553,
+ 554, 555, 556, 557, 559, 560, 561, 562, 563, 564, 566,
+ 567, 568, 569, 570, 572, 573, 574, 575, 576, 578, 579,
+ 580, 581, 582, 583, 585, 586, 587, 588, 589, 591, 592,
+ 593, 594, 595, 597, 598, 599, 600, 601, 603, 604, 605,
+ 606, 607, 609, 610, 611, 612, 613, 615, 616, 617, 618,
+ 620, 621, 622, 623, 624, 626, 627, 628, 629, 630, 632,
+ 633, 634, 635, 637, 638, 639, 640, 641, 643, 644, 645,
+ 646, 648, 649, 650, 651, 653, 654, 655, 656, 657, 659,
+ 660, 661, 662, 664, 665, 666, 667, 669, 670, 671, 672,
+ 674, 675, 676, 677, 679, 680, 681, 682, 684, 685, 686,
+ 687, 689, 690, 691, 692, 694, 695, 696, 697, 699, 700,
+ 701, 702, 704, 705, 706, 707, 709, 710, 711, 712, 714,
+ 715, 716, 717, 719, 720, 721, 723, 724, 725, 726, 728,
+ 729, 730, 731, 733, 734, 735, 737, 738, 739, 740, 742,
+ 743, 744, 745, 747, 748, 749, 751, 752, 753, 754, 756,
+ 757, 758, 760, 761, 762, 763, 765, 766, 767, 769, 770,
+ 771, 772, 774, 775, 776, 778, 779, 780, 782, 783, 784,
+ 785, 787, 788, 789, 791, 792, 793, 794, 796, 797, 798,
+ 800, 801, 802, 804, 805, 806, 808, 809, 810, 811, 813,
+ 814, 815, 817, 818, 819, 821, 822, 823, 825, 826, 827,
+ 829, 830, 831, 833, 834, 835, 836, 838, 839, 840, 842,
+ 843, 844, 846, 847, 848, 850, 851, 852, 854, 855, 856,
+ 858, 859, 860, 862, 863, 864, 866, 867, 868, 870, 871,
+ 872, 874, 875, 876, 878, 879, 880, 882, 883, 884, 886,
+ 887, 888, 890, 891, 893, 894, 895, 897, 898, 899, 901,
+ 902, 903, 905, 906, 907, 909, 910, 911, 913, 914, 915,
+ 917, 918, 920, 921, 922, 924, 925, 926, 928, 929, 930,
+ 932, 933, 935, 936, 937, 939, 940, 941, 943, 944, 945,
+ 947, 948, 950, 951, 952, 954, 955, 956, 958, 959, 961,
+ 962, 963, 965, 966, 967, 969, 970, 972, 973, 974, 976,
+ 977, 978, 980, 981, 983, 984, 985, 987, 988, 990, 991,
+ 992, 994, 995, 996, 998, 999, 1001, 1002, 1003, 1005, 1006,
+ 1008, 1009, 1010, 1012, 1013, 1015, 1016, 1017, 1019, 1020, 1022,
+ 1023,
+};
+
+static const u16 xgamma10_15[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
+ 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3,
+ 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6,
+ 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9,
+ 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 12,
+ 13, 13, 13, 14, 14, 15, 15, 15, 16, 16, 16,
+ 17, 17, 18, 18, 18, 19, 19, 20, 20, 20, 21,
+ 21, 22, 22, 22, 23, 23, 24, 24, 25, 25, 25,
+ 26, 26, 27, 27, 28, 28, 28, 29, 29, 30, 30,
+ 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36,
+ 36, 37, 37, 38, 38, 39, 39, 40, 40, 41, 41,
+ 42, 42, 43, 43, 44, 44, 45, 45, 46, 46, 47,
+ 47, 48, 48, 49, 50, 50, 51, 51, 52, 52, 53,
+ 53, 54, 55, 55, 56, 56, 57, 57, 58, 59, 59,
+ 60, 60, 61, 62, 62, 63, 63, 64, 64, 65, 66,
+ 66, 67, 67, 68, 69, 69, 70, 71, 71, 72, 72,
+ 73, 74, 74, 75, 76, 76, 77, 77, 78, 79, 79,
+ 80, 81, 81, 82, 83, 83, 84, 84, 85, 86, 86,
+ 87, 88, 88, 89, 90, 90, 91, 92, 92, 93, 94,
+ 94, 95, 96, 97, 97, 98, 99, 99, 100, 101, 101,
+ 102, 103, 103, 104, 105, 106, 106, 107, 108, 108, 109,
+ 110, 110, 111, 112, 113, 113, 114, 115, 116, 116, 117,
+ 118, 118, 119, 120, 121, 121, 122, 123, 124, 124, 125,
+ 126, 127, 127, 128, 129, 130, 130, 131, 132, 133, 133,
+ 134, 135, 136, 136, 137, 138, 139, 139, 140, 141, 142,
+ 143, 143, 144, 145, 146, 146, 147, 148, 149, 150, 150,
+ 151, 152, 153, 154, 154, 155, 156, 157, 158, 158, 159,
+ 160, 161, 162, 162, 163, 164, 165, 166, 167, 167, 168,
+ 169, 170, 171, 171, 172, 173, 174, 175, 176, 176, 177,
+ 178, 179, 180, 181, 181, 182, 183, 184, 185, 186, 187,
+ 187, 188, 189, 190, 191, 192, 193, 193, 194, 195, 196,
+ 197, 198, 199, 199, 200, 201, 202, 203, 204, 205, 206,
+ 206, 207, 208, 209, 210, 211, 212, 213, 214, 214, 215,
+ 216, 217, 218, 219, 220, 221, 222, 223, 223, 224, 225,
+ 226, 227, 228, 229, 230, 231, 232, 233, 233, 234, 235,
+ 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 245,
+ 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256,
+ 257, 258, 259, 260, 261, 261, 262, 263, 264, 265, 266,
+ 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277,
+ 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288,
+ 289, 290, 291, 292, 293, 293, 294, 295, 296, 297, 298,
+ 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309,
+ 310, 311, 312, 314, 315, 316, 317, 318, 319, 320, 321,
+ 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332,
+ 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343,
+ 344, 345, 346, 347, 349, 350, 351, 352, 353, 354, 355,
+ 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366,
+ 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378,
+ 379, 380, 381, 383, 384, 385, 386, 387, 388, 389, 390,
+ 391, 392, 393, 395, 396, 397, 398, 399, 400, 401, 402,
+ 403, 404, 405, 407, 408, 409, 410, 411, 412, 413, 414,
+ 415, 417, 418, 419, 420, 421, 422, 423, 424, 425, 427,
+ 428, 429, 430, 431, 432, 433, 434, 436, 437, 438, 439,
+ 440, 441, 442, 444, 445, 446, 447, 448, 449, 450, 451,
+ 453, 454, 455, 456, 457, 458, 460, 461, 462, 463, 464,
+ 465, 466, 468, 469, 470, 471, 472, 473, 475, 476, 477,
+ 478, 479, 480, 482, 483, 484, 485, 486, 487, 489, 490,
+ 491, 492, 493, 494, 496, 497, 498, 499, 500, 501, 503,
+ 504, 505, 506, 507, 509, 510, 511, 512, 513, 515, 516,
+ 517, 518, 519, 521, 522, 523, 524, 525, 527, 528, 529,
+ 530, 531, 533, 534, 535, 536, 537, 539, 540, 541, 542,
+ 543, 545, 546, 547, 548, 550, 551, 552, 553, 554, 556,
+ 557, 558, 559, 561, 562, 563, 564, 565, 567, 568, 569,
+ 570, 572, 573, 574, 575, 577, 578, 579, 580, 582, 583,
+ 584, 585, 587, 588, 589, 590, 591, 593, 594, 595, 596,
+ 598, 599, 600, 602, 603, 604, 605, 607, 608, 609, 610,
+ 612, 613, 614, 615, 617, 618, 619, 620, 622, 623, 624,
+ 626, 627, 628, 629, 631, 632, 633, 634, 636, 637, 638,
+ 640, 641, 642, 643, 645, 646, 647, 649, 650, 651, 652,
+ 654, 655, 656, 658, 659, 660, 662, 663, 664, 665, 667,
+ 668, 669, 671, 672, 673, 675, 676, 677, 678, 680, 681,
+ 682, 684, 685, 686, 688, 689, 690, 692, 693, 694, 696,
+ 697, 698, 700, 701, 702, 703, 705, 706, 707, 709, 710,
+ 711, 713, 714, 715, 717, 718, 719, 721, 722, 723, 725,
+ 726, 727, 729, 730, 731, 733, 734, 735, 737, 738, 740,
+ 741, 742, 744, 745, 746, 748, 749, 750, 752, 753, 754,
+ 756, 757, 758, 760, 761, 763, 764, 765, 767, 768, 769,
+ 771, 772, 773, 775, 776, 778, 779, 780, 782, 783, 784,
+ 786, 787, 789, 790, 791, 793, 794, 795, 797, 798, 800,
+ 801, 802, 804, 805, 806, 808, 809, 811, 812, 813, 815,
+ 816, 818, 819, 820, 822, 823, 825, 826, 827, 829, 830,
+ 832, 833, 834, 836, 837, 839, 840, 841, 843, 844, 846,
+ 847, 848, 850, 851, 853, 854, 855, 857, 858, 860, 861,
+ 863, 864, 865, 867, 868, 870, 871, 872, 874, 875, 877,
+ 878, 880, 881, 882, 884, 885, 887, 888, 890, 891, 892,
+ 894, 895, 897, 898, 900, 901, 902, 904, 905, 907, 908,
+ 910, 911, 913, 914, 915, 917, 918, 920, 921, 923, 924,
+ 926, 927, 929, 930, 931, 933, 934, 936, 937, 939, 940,
+ 942, 943, 945, 946, 947, 949, 950, 952, 953, 955, 956,
+ 958, 959, 961, 962, 964, 965, 967, 968, 969, 971, 972,
+ 974, 975, 977, 978, 980, 981, 983, 984, 986, 987, 989,
+ 990, 992, 993, 995, 996, 998, 999, 1001, 1002, 1004, 1005,
+ 1007, 1008, 1010, 1011, 1013, 1014, 1016, 1017, 1019, 1020, 1022,
+ 1023,
+};
+
+static const u16 xgamma10_16[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+ 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4,
+ 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6,
+ 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9,
+ 10, 10, 10, 10, 11, 11, 11, 12, 12, 12, 12,
+ 13, 13, 13, 14, 14, 14, 15, 15, 15, 16, 16,
+ 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 20,
+ 20, 21, 21, 21, 22, 22, 22, 23, 23, 24, 24,
+ 24, 25, 25, 26, 26, 26, 27, 27, 28, 28, 28,
+ 29, 29, 30, 30, 31, 31, 31, 32, 32, 33, 33,
+ 34, 34, 35, 35, 35, 36, 36, 37, 37, 38, 38,
+ 39, 39, 40, 40, 41, 41, 41, 42, 42, 43, 43,
+ 44, 44, 45, 45, 46, 46, 47, 47, 48, 48, 49,
+ 49, 50, 50, 51, 52, 52, 53, 53, 54, 54, 55,
+ 55, 56, 56, 57, 57, 58, 58, 59, 60, 60, 61,
+ 61, 62, 62, 63, 63, 64, 65, 65, 66, 66, 67,
+ 67, 68, 69, 69, 70, 70, 71, 72, 72, 73, 73,
+ 74, 75, 75, 76, 76, 77, 78, 78, 79, 79, 80,
+ 81, 81, 82, 82, 83, 84, 84, 85, 86, 86, 87,
+ 87, 88, 89, 89, 90, 91, 91, 92, 93, 93, 94,
+ 95, 95, 96, 97, 97, 98, 99, 99, 100, 101, 101,
+ 102, 103, 103, 104, 105, 105, 106, 107, 107, 108, 109,
+ 109, 110, 111, 111, 112, 113, 114, 114, 115, 116, 116,
+ 117, 118, 119, 119, 120, 121, 121, 122, 123, 124, 124,
+ 125, 126, 126, 127, 128, 129, 129, 130, 131, 132, 132,
+ 133, 134, 135, 135, 136, 137, 138, 138, 139, 140, 141,
+ 141, 142, 143, 144, 144, 145, 146, 147, 148, 148, 149,
+ 150, 151, 151, 152, 153, 154, 155, 155, 156, 157, 158,
+ 159, 159, 160, 161, 162, 163, 163, 164, 165, 166, 167,
+ 167, 168, 169, 170, 171, 171, 172, 173, 174, 175, 176,
+ 176, 177, 178, 179, 180, 181, 181, 182, 183, 184, 185,
+ 186, 186, 187, 188, 189, 190, 191, 192, 192, 193, 194,
+ 195, 196, 197, 198, 198, 199, 200, 201, 202, 203, 204,
+ 204, 205, 206, 207, 208, 209, 210, 211, 212, 212, 213,
+ 214, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223,
+ 224, 225, 226, 227, 228, 229, 230, 230, 231, 232, 233,
+ 234, 235, 236, 237, 238, 239, 240, 241, 242, 242, 243,
+ 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
+ 255, 256, 257, 258, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275,
+ 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286,
+ 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297,
+ 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308,
+ 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319,
+ 320, 321, 322, 323, 324, 325, 326, 327, 329, 330, 331,
+ 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342,
+ 343, 344, 345, 346, 348, 349, 350, 351, 352, 353, 354,
+ 355, 356, 357, 358, 359, 360, 362, 363, 364, 365, 366,
+ 367, 368, 369, 370, 371, 372, 374, 375, 376, 377, 378,
+ 379, 380, 381, 382, 383, 385, 386, 387, 388, 389, 390,
+ 391, 392, 393, 395, 396, 397, 398, 399, 400, 401, 402,
+ 404, 405, 406, 407, 408, 409, 410, 411, 413, 414, 415,
+ 416, 417, 418, 419, 421, 422, 423, 424, 425, 426, 428,
+ 429, 430, 431, 432, 433, 434, 436, 437, 438, 439, 440,
+ 441, 443, 444, 445, 446, 447, 448, 450, 451, 452, 453,
+ 454, 456, 457, 458, 459, 460, 461, 463, 464, 465, 466,
+ 467, 469, 470, 471, 472, 473, 475, 476, 477, 478, 479,
+ 481, 482, 483, 484, 485, 487, 488, 489, 490, 491, 493,
+ 494, 495, 496, 498, 499, 500, 501, 502, 504, 505, 506,
+ 507, 509, 510, 511, 512, 514, 515, 516, 517, 519, 520,
+ 521, 522, 523, 525, 526, 527, 528, 530, 531, 532, 533,
+ 535, 536, 537, 538, 540, 541, 542, 544, 545, 546, 547,
+ 549, 550, 551, 552, 554, 555, 556, 557, 559, 560, 561,
+ 563, 564, 565, 566, 568, 569, 570, 572, 573, 574, 575,
+ 577, 578, 579, 581, 582, 583, 584, 586, 587, 588, 590,
+ 591, 592, 594, 595, 596, 598, 599, 600, 601, 603, 604,
+ 605, 607, 608, 609, 611, 612, 613, 615, 616, 617, 619,
+ 620, 621, 623, 624, 625, 627, 628, 629, 631, 632, 633,
+ 635, 636, 637, 639, 640, 641, 643, 644, 645, 647, 648,
+ 649, 651, 652, 653, 655, 656, 657, 659, 660, 662, 663,
+ 664, 666, 667, 668, 670, 671, 672, 674, 675, 677, 678,
+ 679, 681, 682, 683, 685, 686, 688, 689, 690, 692, 693,
+ 694, 696, 697, 699, 700, 701, 703, 704, 706, 707, 708,
+ 710, 711, 712, 714, 715, 717, 718, 719, 721, 722, 724,
+ 725, 727, 728, 729, 731, 732, 734, 735, 736, 738, 739,
+ 741, 742, 743, 745, 746, 748, 749, 751, 752, 753, 755,
+ 756, 758, 759, 761, 762, 763, 765, 766, 768, 769, 771,
+ 772, 774, 775, 776, 778, 779, 781, 782, 784, 785, 787,
+ 788, 789, 791, 792, 794, 795, 797, 798, 800, 801, 803,
+ 804, 805, 807, 808, 810, 811, 813, 814, 816, 817, 819,
+ 820, 822, 823, 825, 826, 827, 829, 830, 832, 833, 835,
+ 836, 838, 839, 841, 842, 844, 845, 847, 848, 850, 851,
+ 853, 854, 856, 857, 859, 860, 862, 863, 865, 866, 868,
+ 869, 871, 872, 874, 875, 877, 878, 880, 881, 883, 884,
+ 886, 887, 889, 890, 892, 893, 895, 897, 898, 900, 901,
+ 903, 904, 906, 907, 909, 910, 912, 913, 915, 916, 918,
+ 919, 921, 923, 924, 926, 927, 929, 930, 932, 933, 935,
+ 936, 938, 940, 941, 943, 944, 946, 947, 949, 950, 952,
+ 954, 955, 957, 958, 960, 961, 963, 964, 966, 968, 969,
+ 971, 972, 974, 975, 977, 979, 980, 982, 983, 985, 986,
+ 988, 990, 991, 993, 994, 996, 998, 999, 1001, 1002, 1004,
+ 1005, 1007, 1009, 1010, 1012, 1013, 1015, 1017, 1018, 1020, 1021,
+ 1023,
+};
+
+static const u16 xgamma10_17[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3,
+ 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5,
+ 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7,
+ 7, 7, 8, 8, 8, 8, 8, 9, 9, 9, 9,
+ 10, 10, 10, 10, 11, 11, 11, 12, 12, 12, 12,
+ 13, 13, 13, 13, 14, 14, 14, 15, 15, 15, 15,
+ 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19,
+ 19, 20, 20, 20, 21, 21, 21, 22, 22, 22, 23,
+ 23, 23, 24, 24, 25, 25, 25, 26, 26, 26, 27,
+ 27, 28, 28, 28, 29, 29, 29, 30, 30, 31, 31,
+ 31, 32, 32, 33, 33, 34, 34, 34, 35, 35, 36,
+ 36, 37, 37, 37, 38, 38, 39, 39, 40, 40, 40,
+ 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, 46,
+ 46, 46, 47, 47, 48, 48, 49, 49, 50, 50, 51,
+ 51, 52, 52, 53, 53, 54, 54, 55, 55, 56, 56,
+ 57, 57, 58, 58, 59, 60, 60, 61, 61, 62, 62,
+ 63, 63, 64, 64, 65, 65, 66, 67, 67, 68, 68,
+ 69, 69, 70, 70, 71, 72, 72, 73, 73, 74, 74,
+ 75, 76, 76, 77, 77, 78, 79, 79, 80, 80, 81,
+ 82, 82, 83, 83, 84, 85, 85, 86, 86, 87, 88,
+ 88, 89, 89, 90, 91, 91, 92, 93, 93, 94, 95,
+ 95, 96, 96, 97, 98, 98, 99, 100, 100, 101, 102,
+ 102, 103, 104, 104, 105, 106, 106, 107, 108, 108, 109,
+ 110, 110, 111, 112, 112, 113, 114, 114, 115, 116, 116,
+ 117, 118, 119, 119, 120, 121, 121, 122, 123, 124, 124,
+ 125, 126, 126, 127, 128, 129, 129, 130, 131, 131, 132,
+ 133, 134, 134, 135, 136, 137, 137, 138, 139, 140, 140,
+ 141, 142, 143, 143, 144, 145, 146, 146, 147, 148, 149,
+ 149, 150, 151, 152, 153, 153, 154, 155, 156, 156, 157,
+ 158, 159, 160, 160, 161, 162, 163, 164, 164, 165, 166,
+ 167, 168, 168, 169, 170, 171, 172, 172, 173, 174, 175,
+ 176, 177, 177, 178, 179, 180, 181, 182, 182, 183, 184,
+ 185, 186, 187, 187, 188, 189, 190, 191, 192, 193, 193,
+ 194, 195, 196, 197, 198, 199, 199, 200, 201, 202, 203,
+ 204, 205, 206, 206, 207, 208, 209, 210, 211, 212, 213,
+ 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 222,
+ 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233,
+ 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243,
+ 244, 245, 246, 247, 248, 248, 249, 250, 251, 252, 253,
+ 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275,
+ 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286,
+ 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297,
+ 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308,
+ 309, 310, 311, 312, 313, 314, 315, 316, 317, 319, 320,
+ 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331,
+ 332, 333, 334, 336, 337, 338, 339, 340, 341, 342, 343,
+ 344, 345, 346, 347, 349, 350, 351, 352, 353, 354, 355,
+ 356, 357, 358, 360, 361, 362, 363, 364, 365, 366, 367,
+ 368, 370, 371, 372, 373, 374, 375, 376, 377, 379, 380,
+ 381, 382, 383, 384, 385, 386, 388, 389, 390, 391, 392,
+ 393, 394, 396, 397, 398, 399, 400, 401, 403, 404, 405,
+ 406, 407, 408, 409, 411, 412, 413, 414, 415, 417, 418,
+ 419, 420, 421, 422, 424, 425, 426, 427, 428, 430, 431,
+ 432, 433, 434, 435, 437, 438, 439, 440, 441, 443, 444,
+ 445, 446, 448, 449, 450, 451, 452, 454, 455, 456, 457,
+ 458, 460, 461, 462, 463, 465, 466, 467, 468, 469, 471,
+ 472, 473, 474, 476, 477, 478, 479, 481, 482, 483, 484,
+ 486, 487, 488, 489, 491, 492, 493, 494, 496, 497, 498,
+ 499, 501, 502, 503, 505, 506, 507, 508, 510, 511, 512,
+ 513, 515, 516, 517, 519, 520, 521, 522, 524, 525, 526,
+ 528, 529, 530, 532, 533, 534, 535, 537, 538, 539, 541,
+ 542, 543, 545, 546, 547, 549, 550, 551, 552, 554, 555,
+ 556, 558, 559, 560, 562, 563, 564, 566, 567, 568, 570,
+ 571, 572, 574, 575, 576, 578, 579, 580, 582, 583, 584,
+ 586, 587, 589, 590, 591, 593, 594, 595, 597, 598, 599,
+ 601, 602, 604, 605, 606, 608, 609, 610, 612, 613, 615,
+ 616, 617, 619, 620, 621, 623, 624, 626, 627, 628, 630,
+ 631, 633, 634, 635, 637, 638, 640, 641, 642, 644, 645,
+ 647, 648, 649, 651, 652, 654, 655, 656, 658, 659, 661,
+ 662, 664, 665, 666, 668, 669, 671, 672, 674, 675, 676,
+ 678, 679, 681, 682, 684, 685, 686, 688, 689, 691, 692,
+ 694, 695, 697, 698, 699, 701, 702, 704, 705, 707, 708,
+ 710, 711, 713, 714, 716, 717, 718, 720, 721, 723, 724,
+ 726, 727, 729, 730, 732, 733, 735, 736, 738, 739, 741,
+ 742, 744, 745, 747, 748, 750, 751, 753, 754, 756, 757,
+ 759, 760, 762, 763, 765, 766, 768, 769, 771, 772, 774,
+ 775, 777, 778, 780, 781, 783, 784, 786, 787, 789, 790,
+ 792, 793, 795, 797, 798, 800, 801, 803, 804, 806, 807,
+ 809, 810, 812, 814, 815, 817, 818, 820, 821, 823, 824,
+ 826, 827, 829, 831, 832, 834, 835, 837, 838, 840, 842,
+ 843, 845, 846, 848, 849, 851, 853, 854, 856, 857, 859,
+ 860, 862, 864, 865, 867, 868, 870, 872, 873, 875, 876,
+ 878, 880, 881, 883, 884, 886, 888, 889, 891, 892, 894,
+ 896, 897, 899, 900, 902, 904, 905, 907, 908, 910, 912,
+ 913, 915, 917, 918, 920, 921, 923, 925, 926, 928, 930,
+ 931, 933, 935, 936, 938, 939, 941, 943, 944, 946, 948,
+ 949, 951, 953, 954, 956, 958, 959, 961, 963, 964, 966,
+ 968, 969, 971, 973, 974, 976, 978, 979, 981, 983, 984,
+ 986, 988, 989, 991, 993, 994, 996, 998, 999, 1001, 1003,
+ 1004, 1006, 1008, 1009, 1011, 1013, 1015, 1016, 1018, 1020, 1021,
+ 1023,
+};
+
+static const u16 xgamma10_18[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
+ 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7,
+ 7, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9,
+ 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12,
+ 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15,
+ 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18,
+ 18, 19, 19, 19, 20, 20, 20, 21, 21, 21, 22,
+ 22, 22, 23, 23, 23, 24, 24, 24, 25, 25, 25,
+ 26, 26, 26, 27, 27, 27, 28, 28, 29, 29, 29,
+ 30, 30, 30, 31, 31, 32, 32, 32, 33, 33, 33,
+ 34, 34, 35, 35, 35, 36, 36, 37, 37, 38, 38,
+ 38, 39, 39, 40, 40, 40, 41, 41, 42, 42, 43,
+ 43, 43, 44, 44, 45, 45, 46, 46, 47, 47, 48,
+ 48, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53,
+ 53, 54, 54, 55, 55, 56, 56, 57, 57, 58, 58,
+ 59, 59, 60, 60, 61, 61, 62, 62, 63, 63, 64,
+ 64, 65, 65, 66, 66, 67, 68, 68, 69, 69, 70,
+ 70, 71, 71, 72, 72, 73, 74, 74, 75, 75, 76,
+ 76, 77, 78, 78, 79, 79, 80, 80, 81, 82, 82,
+ 83, 83, 84, 85, 85, 86, 86, 87, 88, 88, 89,
+ 89, 90, 91, 91, 92, 92, 93, 94, 94, 95, 96,
+ 96, 97, 97, 98, 99, 99, 100, 101, 101, 102, 103,
+ 103, 104, 104, 105, 106, 106, 107, 108, 108, 109, 110,
+ 110, 111, 112, 112, 113, 114, 114, 115, 116, 117, 117,
+ 118, 119, 119, 120, 121, 121, 122, 123, 123, 124, 125,
+ 126, 126, 127, 128, 128, 129, 130, 131, 131, 132, 133,
+ 133, 134, 135, 136, 136, 137, 138, 139, 139, 140, 141,
+ 142, 142, 143, 144, 145, 145, 146, 147, 148, 148, 149,
+ 150, 151, 151, 152, 153, 154, 155, 155, 156, 157, 158,
+ 158, 159, 160, 161, 162, 162, 163, 164, 165, 166, 166,
+ 167, 168, 169, 170, 170, 171, 172, 173, 174, 175, 175,
+ 176, 177, 178, 179, 179, 180, 181, 182, 183, 184, 184,
+ 185, 186, 187, 188, 189, 190, 190, 191, 192, 193, 194,
+ 195, 196, 196, 197, 198, 199, 200, 201, 202, 203, 203,
+ 204, 205, 206, 207, 208, 209, 210, 210, 211, 212, 213,
+ 214, 215, 216, 217, 218, 219, 219, 220, 221, 222, 223,
+ 224, 225, 226, 227, 228, 229, 230, 230, 231, 232, 233,
+ 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244,
+ 245, 246, 247, 247, 248, 249, 250, 251, 252, 253, 254,
+ 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265,
+ 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276,
+ 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287,
+ 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298,
+ 299, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310,
+ 311, 312, 313, 314, 315, 316, 317, 319, 320, 321, 322,
+ 323, 324, 325, 326, 327, 328, 329, 330, 331, 333, 334,
+ 335, 336, 337, 338, 339, 340, 341, 342, 344, 345, 346,
+ 347, 348, 349, 350, 351, 353, 354, 355, 356, 357, 358,
+ 359, 360, 362, 363, 364, 365, 366, 367, 368, 370, 371,
+ 372, 373, 374, 375, 376, 378, 379, 380, 381, 382, 383,
+ 385, 386, 387, 388, 389, 390, 392, 393, 394, 395, 396,
+ 397, 399, 400, 401, 402, 403, 405, 406, 407, 408, 409,
+ 411, 412, 413, 414, 415, 417, 418, 419, 420, 421, 423,
+ 424, 425, 426, 427, 429, 430, 431, 432, 434, 435, 436,
+ 437, 439, 440, 441, 442, 443, 445, 446, 447, 448, 450,
+ 451, 452, 453, 455, 456, 457, 458, 460, 461, 462, 464,
+ 465, 466, 467, 469, 470, 471, 472, 474, 475, 476, 478,
+ 479, 480, 481, 483, 484, 485, 487, 488, 489, 490, 492,
+ 493, 494, 496, 497, 498, 500, 501, 502, 504, 505, 506,
+ 507, 509, 510, 511, 513, 514, 515, 517, 518, 519, 521,
+ 522, 523, 525, 526, 527, 529, 530, 531, 533, 534, 535,
+ 537, 538, 540, 541, 542, 544, 545, 546, 548, 549, 550,
+ 552, 553, 555, 556, 557, 559, 560, 561, 563, 564, 566,
+ 567, 568, 570, 571, 572, 574, 575, 577, 578, 579, 581,
+ 582, 584, 585, 586, 588, 589, 591, 592, 594, 595, 596,
+ 598, 599, 601, 602, 603, 605, 606, 608, 609, 611, 612,
+ 613, 615, 616, 618, 619, 621, 622, 624, 625, 626, 628,
+ 629, 631, 632, 634, 635, 637, 638, 640, 641, 642, 644,
+ 645, 647, 648, 650, 651, 653, 654, 656, 657, 659, 660,
+ 662, 663, 665, 666, 668, 669, 671, 672, 673, 675, 676,
+ 678, 679, 681, 682, 684, 686, 687, 689, 690, 692, 693,
+ 695, 696, 698, 699, 701, 702, 704, 705, 707, 708, 710,
+ 711, 713, 714, 716, 717, 719, 721, 722, 724, 725, 727,
+ 728, 730, 731, 733, 734, 736, 738, 739, 741, 742, 744,
+ 745, 747, 749, 750, 752, 753, 755, 756, 758, 760, 761,
+ 763, 764, 766, 767, 769, 771, 772, 774, 775, 777, 779,
+ 780, 782, 783, 785, 787, 788, 790, 791, 793, 795, 796,
+ 798, 799, 801, 803, 804, 806, 807, 809, 811, 812, 814,
+ 816, 817, 819, 820, 822, 824, 825, 827, 829, 830, 832,
+ 834, 835, 837, 839, 840, 842, 843, 845, 847, 848, 850,
+ 852, 853, 855, 857, 858, 860, 862, 863, 865, 867, 868,
+ 870, 872, 873, 875, 877, 878, 880, 882, 884, 885, 887,
+ 889, 890, 892, 894, 895, 897, 899, 900, 902, 904, 906,
+ 907, 909, 911, 912, 914, 916, 918, 919, 921, 923, 924,
+ 926, 928, 930, 931, 933, 935, 936, 938, 940, 942, 943,
+ 945, 947, 949, 950, 952, 954, 956, 957, 959, 961, 963,
+ 964, 966, 968, 970, 971, 973, 975, 977, 978, 980, 982,
+ 984, 986, 987, 989, 991, 993, 994, 996, 998, 1000, 1002,
+ 1003, 1005, 1007, 1009, 1010, 1012, 1014, 1016, 1018, 1019, 1021,
+ 1023,
+};
+
+static const u16 xgamma10_19[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4,
+ 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9,
+ 10, 10, 10, 10, 11, 11, 11, 11, 11, 12, 12,
+ 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15,
+ 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17,
+ 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 21,
+ 21, 21, 22, 22, 22, 22, 23, 23, 23, 24, 24,
+ 24, 25, 25, 25, 26, 26, 26, 27, 27, 27, 28,
+ 28, 28, 29, 29, 29, 30, 30, 30, 31, 31, 32,
+ 32, 32, 33, 33, 33, 34, 34, 35, 35, 35, 36,
+ 36, 36, 37, 37, 38, 38, 38, 39, 39, 40, 40,
+ 41, 41, 41, 42, 42, 43, 43, 43, 44, 44, 45,
+ 45, 46, 46, 46, 47, 47, 48, 48, 49, 49, 50,
+ 50, 51, 51, 51, 52, 52, 53, 53, 54, 54, 55,
+ 55, 56, 56, 57, 57, 58, 58, 59, 59, 60, 60,
+ 61, 61, 62, 62, 63, 63, 64, 64, 65, 65, 66,
+ 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71,
+ 72, 72, 73, 74, 74, 75, 75, 76, 76, 77, 77,
+ 78, 79, 79, 80, 80, 81, 81, 82, 83, 83, 84,
+ 84, 85, 85, 86, 87, 87, 88, 88, 89, 90, 90,
+ 91, 91, 92, 93, 93, 94, 94, 95, 96, 96, 97,
+ 98, 98, 99, 99, 100, 101, 101, 102, 103, 103, 104,
+ 105, 105, 106, 107, 107, 108, 108, 109, 110, 110, 111,
+ 112, 112, 113, 114, 114, 115, 116, 116, 117, 118, 119,
+ 119, 120, 121, 121, 122, 123, 123, 124, 125, 125, 126,
+ 127, 128, 128, 129, 130, 130, 131, 132, 133, 133, 134,
+ 135, 135, 136, 137, 138, 138, 139, 140, 141, 141, 142,
+ 143, 144, 144, 145, 146, 147, 147, 148, 149, 150, 150,
+ 151, 152, 153, 154, 154, 155, 156, 157, 157, 158, 159,
+ 160, 161, 161, 162, 163, 164, 165, 165, 166, 167, 168,
+ 169, 169, 170, 171, 172, 173, 173, 174, 175, 176, 177,
+ 178, 178, 179, 180, 181, 182, 183, 183, 184, 185, 186,
+ 187, 188, 188, 189, 190, 191, 192, 193, 194, 195, 195,
+ 196, 197, 198, 199, 200, 201, 201, 202, 203, 204, 205,
+ 206, 207, 208, 209, 209, 210, 211, 212, 213, 214, 215,
+ 216, 217, 218, 219, 219, 220, 221, 222, 223, 224, 225,
+ 226, 227, 228, 229, 230, 231, 232, 232, 233, 234, 235,
+ 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246,
+ 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257,
+ 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268,
+ 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279,
+ 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290,
+ 291, 292, 293, 294, 295, 296, 297, 299, 300, 301, 302,
+ 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 314,
+ 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 326,
+ 327, 328, 329, 330, 331, 332, 333, 334, 336, 337, 338,
+ 339, 340, 341, 342, 343, 345, 346, 347, 348, 349, 350,
+ 351, 353, 354, 355, 356, 357, 358, 360, 361, 362, 363,
+ 364, 365, 367, 368, 369, 370, 371, 372, 374, 375, 376,
+ 377, 378, 379, 381, 382, 383, 384, 385, 387, 388, 389,
+ 390, 391, 393, 394, 395, 396, 397, 399, 400, 401, 402,
+ 404, 405, 406, 407, 408, 410, 411, 412, 413, 415, 416,
+ 417, 418, 420, 421, 422, 423, 425, 426, 427, 428, 430,
+ 431, 432, 433, 435, 436, 437, 439, 440, 441, 442, 444,
+ 445, 446, 447, 449, 450, 451, 453, 454, 455, 456, 458,
+ 459, 460, 462, 463, 464, 466, 467, 468, 470, 471, 472,
+ 473, 475, 476, 477, 479, 480, 481, 483, 484, 485, 487,
+ 488, 489, 491, 492, 493, 495, 496, 498, 499, 500, 502,
+ 503, 504, 506, 507, 508, 510, 511, 512, 514, 515, 517,
+ 518, 519, 521, 522, 523, 525, 526, 528, 529, 530, 532,
+ 533, 535, 536, 537, 539, 540, 542, 543, 544, 546, 547,
+ 549, 550, 551, 553, 554, 556, 557, 559, 560, 561, 563,
+ 564, 566, 567, 569, 570, 572, 573, 574, 576, 577, 579,
+ 580, 582, 583, 585, 586, 587, 589, 590, 592, 593, 595,
+ 596, 598, 599, 601, 602, 604, 605, 607, 608, 610, 611,
+ 613, 614, 616, 617, 619, 620, 622, 623, 625, 626, 628,
+ 629, 631, 632, 634, 635, 637, 638, 640, 641, 643, 644,
+ 646, 647, 649, 650, 652, 653, 655, 656, 658, 660, 661,
+ 663, 664, 666, 667, 669, 670, 672, 674, 675, 677, 678,
+ 680, 681, 683, 684, 686, 688, 689, 691, 692, 694, 696,
+ 697, 699, 700, 702, 703, 705, 707, 708, 710, 711, 713,
+ 715, 716, 718, 719, 721, 723, 724, 726, 728, 729, 731,
+ 732, 734, 736, 737, 739, 741, 742, 744, 745, 747, 749,
+ 750, 752, 754, 755, 757, 759, 760, 762, 764, 765, 767,
+ 768, 770, 772, 773, 775, 777, 778, 780, 782, 783, 785,
+ 787, 789, 790, 792, 794, 795, 797, 799, 800, 802, 804,
+ 805, 807, 809, 810, 812, 814, 816, 817, 819, 821, 822,
+ 824, 826, 828, 829, 831, 833, 834, 836, 838, 840, 841,
+ 843, 845, 847, 848, 850, 852, 854, 855, 857, 859, 861,
+ 862, 864, 866, 868, 869, 871, 873, 875, 876, 878, 880,
+ 882, 883, 885, 887, 889, 891, 892, 894, 896, 898, 899,
+ 901, 903, 905, 907, 908, 910, 912, 914, 916, 917, 919,
+ 921, 923, 925, 926, 928, 930, 932, 934, 936, 937, 939,
+ 941, 943, 945, 947, 948, 950, 952, 954, 956, 958, 959,
+ 961, 963, 965, 967, 969, 970, 972, 974, 976, 978, 980,
+ 982, 983, 985, 987, 989, 991, 993, 995, 997, 998, 1000,
+ 1002, 1004, 1006, 1008, 1010, 1012, 1014, 1015, 1017, 1019, 1021,
+ 1023,
+};
+
+static const u16 xgamma10_20[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4,
+ 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6,
+ 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9,
+ 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 12,
+ 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14,
+ 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17,
+ 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20,
+ 20, 20, 21, 21, 21, 21, 22, 22, 22, 23, 23,
+ 23, 23, 24, 24, 24, 25, 25, 25, 26, 26, 26,
+ 27, 27, 27, 28, 28, 28, 29, 29, 29, 30, 30,
+ 30, 31, 31, 31, 32, 32, 32, 33, 33, 33, 34,
+ 34, 35, 35, 35, 36, 36, 36, 37, 37, 38, 38,
+ 38, 39, 39, 39, 40, 40, 41, 41, 41, 42, 42,
+ 43, 43, 44, 44, 44, 45, 45, 46, 46, 46, 47,
+ 47, 48, 48, 49, 49, 49, 50, 50, 51, 51, 52,
+ 52, 53, 53, 54, 54, 54, 55, 55, 56, 56, 57,
+ 57, 58, 58, 59, 59, 60, 60, 61, 61, 62, 62,
+ 63, 63, 64, 64, 65, 65, 66, 66, 67, 67, 68,
+ 68, 69, 69, 70, 70, 71, 71, 72, 72, 73, 73,
+ 74, 74, 75, 76, 76, 77, 77, 78, 78, 79, 79,
+ 80, 81, 81, 82, 82, 83, 83, 84, 84, 85, 86,
+ 86, 87, 87, 88, 89, 89, 90, 90, 91, 92, 92,
+ 93, 93, 94, 95, 95, 96, 96, 97, 98, 98, 99,
+ 99, 100, 101, 101, 102, 103, 103, 104, 105, 105, 106,
+ 106, 107, 108, 108, 109, 110, 110, 111, 112, 112, 113,
+ 114, 114, 115, 116, 116, 117, 118, 118, 119, 120, 120,
+ 121, 122, 122, 123, 124, 125, 125, 126, 127, 127, 128,
+ 129, 130, 130, 131, 132, 132, 133, 134, 135, 135, 136,
+ 137, 137, 138, 139, 140, 140, 141, 142, 143, 143, 144,
+ 145, 146, 146, 147, 148, 149, 149, 150, 151, 152, 153,
+ 153, 154, 155, 156, 156, 157, 158, 159, 160, 160, 161,
+ 162, 163, 164, 164, 165, 166, 167, 168, 168, 169, 170,
+ 171, 172, 172, 173, 174, 175, 176, 177, 177, 178, 179,
+ 180, 181, 182, 182, 183, 184, 185, 186, 187, 188, 188,
+ 189, 190, 191, 192, 193, 194, 194, 195, 196, 197, 198,
+ 199, 200, 201, 201, 202, 203, 204, 205, 206, 207, 208,
+ 209, 210, 210, 211, 212, 213, 214, 215, 216, 217, 218,
+ 219, 220, 221, 221, 222, 223, 224, 225, 226, 227, 228,
+ 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+ 240, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249,
+ 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260,
+ 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271,
+ 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283,
+ 284, 285, 286, 287, 288, 289, 290, 291, 292, 294, 295,
+ 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 307,
+ 308, 309, 310, 311, 312, 313, 314, 315, 316, 318, 319,
+ 320, 321, 322, 323, 324, 325, 327, 328, 329, 330, 331,
+ 332, 333, 335, 336, 337, 338, 339, 340, 341, 343, 344,
+ 345, 346, 347, 348, 350, 351, 352, 353, 354, 355, 357,
+ 358, 359, 360, 361, 363, 364, 365, 366, 367, 369, 370,
+ 371, 372, 373, 375, 376, 377, 378, 379, 381, 382, 383,
+ 384, 386, 387, 388, 389, 390, 392, 393, 394, 395, 397,
+ 398, 399, 400, 402, 403, 404, 405, 407, 408, 409, 410,
+ 412, 413, 414, 416, 417, 418, 419, 421, 422, 423, 425,
+ 426, 427, 428, 430, 431, 432, 434, 435, 436, 437, 439,
+ 440, 441, 443, 444, 445, 447, 448, 449, 451, 452, 453,
+ 455, 456, 457, 459, 460, 461, 463, 464, 465, 467, 468,
+ 469, 471, 472, 474, 475, 476, 478, 479, 480, 482, 483,
+ 484, 486, 487, 489, 490, 491, 493, 494, 496, 497, 498,
+ 500, 501, 503, 504, 505, 507, 508, 510, 511, 512, 514,
+ 515, 517, 518, 519, 521, 522, 524, 525, 527, 528, 530,
+ 531, 532, 534, 535, 537, 538, 540, 541, 543, 544, 545,
+ 547, 548, 550, 551, 553, 554, 556, 557, 559, 560, 562,
+ 563, 565, 566, 568, 569, 571, 572, 574, 575, 577, 578,
+ 580, 581, 583, 584, 586, 587, 589, 590, 592, 593, 595,
+ 596, 598, 599, 601, 602, 604, 605, 607, 609, 610, 612,
+ 613, 615, 616, 618, 619, 621, 622, 624, 626, 627, 629,
+ 630, 632, 633, 635, 637, 638, 640, 641, 643, 645, 646,
+ 648, 649, 651, 652, 654, 656, 657, 659, 660, 662, 664,
+ 665, 667, 669, 670, 672, 673, 675, 677, 678, 680, 682,
+ 683, 685, 686, 688, 690, 691, 693, 695, 696, 698, 700,
+ 701, 703, 705, 706, 708, 710, 711, 713, 715, 716, 718,
+ 720, 721, 723, 725, 726, 728, 730, 731, 733, 735, 736,
+ 738, 740, 742, 743, 745, 747, 748, 750, 752, 754, 755,
+ 757, 759, 760, 762, 764, 766, 767, 769, 771, 773, 774,
+ 776, 778, 780, 781, 783, 785, 787, 788, 790, 792, 794,
+ 795, 797, 799, 801, 802, 804, 806, 808, 809, 811, 813,
+ 815, 817, 818, 820, 822, 824, 826, 827, 829, 831, 833,
+ 835, 836, 838, 840, 842, 844, 845, 847, 849, 851, 853,
+ 855, 856, 858, 860, 862, 864, 866, 867, 869, 871, 873,
+ 875, 877, 878, 880, 882, 884, 886, 888, 890, 892, 893,
+ 895, 897, 899, 901, 903, 905, 907, 908, 910, 912, 914,
+ 916, 918, 920, 922, 924, 925, 927, 929, 931, 933, 935,
+ 937, 939, 941, 943, 945, 946, 948, 950, 952, 954, 956,
+ 958, 960, 962, 964, 966, 968, 970, 972, 974, 976, 978,
+ 979, 981, 983, 985, 987, 989, 991, 993, 995, 997, 999,
+ 1001, 1003, 1005, 1007, 1009, 1011, 1013, 1015, 1017, 1019, 1021,
+ 1023,
+};
+
+static const u16 xgamma10_21[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6,
+ 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9,
+ 9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11,
+ 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 14,
+ 14, 14, 14, 15, 15, 15, 15, 15, 16, 16, 16,
+ 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19,
+ 19, 19, 20, 20, 20, 21, 21, 21, 21, 22, 22,
+ 22, 22, 23, 23, 23, 24, 24, 24, 24, 25, 25,
+ 25, 26, 26, 26, 27, 27, 27, 28, 28, 28, 29,
+ 29, 29, 29, 30, 30, 30, 31, 31, 31, 32, 32,
+ 33, 33, 33, 34, 34, 34, 35, 35, 35, 36, 36,
+ 36, 37, 37, 38, 38, 38, 39, 39, 39, 40, 40,
+ 41, 41, 41, 42, 42, 43, 43, 43, 44, 44, 45,
+ 45, 45, 46, 46, 47, 47, 47, 48, 48, 49, 49,
+ 50, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54,
+ 54, 55, 55, 56, 56, 57, 57, 58, 58, 59, 59,
+ 59, 60, 60, 61, 61, 62, 62, 63, 63, 64, 64,
+ 65, 65, 66, 66, 67, 67, 68, 68, 69, 69, 70,
+ 70, 71, 71, 72, 72, 73, 74, 74, 75, 75, 76,
+ 76, 77, 77, 78, 78, 79, 79, 80, 81, 81, 82,
+ 82, 83, 83, 84, 85, 85, 86, 86, 87, 87, 88,
+ 89, 89, 90, 90, 91, 91, 92, 93, 93, 94, 94,
+ 95, 96, 96, 97, 97, 98, 99, 99, 100, 101, 101,
+ 102, 102, 103, 104, 104, 105, 106, 106, 107, 108, 108,
+ 109, 110, 110, 111, 111, 112, 113, 113, 114, 115, 115,
+ 116, 117, 117, 118, 119, 120, 120, 121, 122, 122, 123,
+ 124, 124, 125, 126, 126, 127, 128, 129, 129, 130, 131,
+ 131, 132, 133, 134, 134, 135, 136, 136, 137, 138, 139,
+ 139, 140, 141, 142, 142, 143, 144, 145, 145, 146, 147,
+ 148, 148, 149, 150, 151, 152, 152, 153, 154, 155, 155,
+ 156, 157, 158, 159, 159, 160, 161, 162, 163, 163, 164,
+ 165, 166, 167, 167, 168, 169, 170, 171, 171, 172, 173,
+ 174, 175, 176, 176, 177, 178, 179, 180, 181, 181, 182,
+ 183, 184, 185, 186, 187, 187, 188, 189, 190, 191, 192,
+ 193, 194, 194, 195, 196, 197, 198, 199, 200, 201, 202,
+ 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212,
+ 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222,
+ 223, 224, 225, 226, 227, 227, 228, 229, 230, 231, 232,
+ 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243,
+ 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
+ 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265,
+ 266, 267, 268, 269, 271, 272, 273, 274, 275, 276, 277,
+ 278, 279, 280, 281, 282, 283, 284, 285, 286, 288, 289,
+ 290, 291, 292, 293, 294, 295, 296, 297, 298, 300, 301,
+ 302, 303, 304, 305, 306, 307, 308, 310, 311, 312, 313,
+ 314, 315, 316, 317, 319, 320, 321, 322, 323, 324, 326,
+ 327, 328, 329, 330, 331, 332, 334, 335, 336, 337, 338,
+ 339, 341, 342, 343, 344, 345, 347, 348, 349, 350, 351,
+ 353, 354, 355, 356, 357, 359, 360, 361, 362, 363, 365,
+ 366, 367, 368, 370, 371, 372, 373, 375, 376, 377, 378,
+ 380, 381, 382, 383, 385, 386, 387, 388, 390, 391, 392,
+ 393, 395, 396, 397, 399, 400, 401, 402, 404, 405, 406,
+ 408, 409, 410, 411, 413, 414, 415, 417, 418, 419, 421,
+ 422, 423, 425, 426, 427, 429, 430, 431, 433, 434, 435,
+ 437, 438, 439, 441, 442, 443, 445, 446, 447, 449, 450,
+ 452, 453, 454, 456, 457, 458, 460, 461, 463, 464, 465,
+ 467, 468, 469, 471, 472, 474, 475, 477, 478, 479, 481,
+ 482, 484, 485, 486, 488, 489, 491, 492, 494, 495, 496,
+ 498, 499, 501, 502, 504, 505, 507, 508, 509, 511, 512,
+ 514, 515, 517, 518, 520, 521, 523, 524, 526, 527, 529,
+ 530, 532, 533, 535, 536, 538, 539, 541, 542, 544, 545,
+ 547, 548, 550, 551, 553, 554, 556, 557, 559, 560, 562,
+ 563, 565, 566, 568, 569, 571, 573, 574, 576, 577, 579,
+ 580, 582, 583, 585, 587, 588, 590, 591, 593, 595, 596,
+ 598, 599, 601, 602, 604, 606, 607, 609, 610, 612, 614,
+ 615, 617, 618, 620, 622, 623, 625, 627, 628, 630, 631,
+ 633, 635, 636, 638, 640, 641, 643, 645, 646, 648, 650,
+ 651, 653, 654, 656, 658, 659, 661, 663, 664, 666, 668,
+ 670, 671, 673, 675, 676, 678, 680, 681, 683, 685, 686,
+ 688, 690, 692, 693, 695, 697, 698, 700, 702, 704, 705,
+ 707, 709, 711, 712, 714, 716, 717, 719, 721, 723, 724,
+ 726, 728, 730, 732, 733, 735, 737, 739, 740, 742, 744,
+ 746, 747, 749, 751, 753, 755, 756, 758, 760, 762, 764,
+ 765, 767, 769, 771, 773, 774, 776, 778, 780, 782, 784,
+ 785, 787, 789, 791, 793, 795, 796, 798, 800, 802, 804,
+ 806, 807, 809, 811, 813, 815, 817, 819, 821, 822, 824,
+ 826, 828, 830, 832, 834, 836, 837, 839, 841, 843, 845,
+ 847, 849, 851, 853, 855, 856, 858, 860, 862, 864, 866,
+ 868, 870, 872, 874, 876, 878, 880, 882, 883, 885, 887,
+ 889, 891, 893, 895, 897, 899, 901, 903, 905, 907, 909,
+ 911, 913, 915, 917, 919, 921, 923, 925, 927, 929, 931,
+ 933, 935, 937, 939, 941, 943, 945, 947, 949, 951, 953,
+ 955, 957, 959, 961, 963, 965, 967, 969, 971, 973, 975,
+ 977, 979, 981, 984, 986, 988, 990, 992, 994, 996, 998,
+ 1000, 1002, 1004, 1006, 1008, 1010, 1013, 1015, 1017, 1019, 1021,
+ 1023,
+};
+
+static const u16 xgamma10_22[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6,
+ 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9,
+ 9, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11,
+ 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+ 13, 14, 14, 14, 14, 15, 15, 15, 15, 15, 16,
+ 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
+ 18, 19, 19, 19, 19, 20, 20, 20, 21, 21, 21,
+ 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24,
+ 24, 25, 25, 25, 25, 26, 26, 26, 27, 27, 27,
+ 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 31,
+ 31, 31, 32, 32, 32, 33, 33, 33, 34, 34, 34,
+ 35, 35, 35, 36, 36, 37, 37, 37, 38, 38, 38,
+ 39, 39, 39, 40, 40, 41, 41, 41, 42, 42, 43,
+ 43, 43, 44, 44, 44, 45, 45, 46, 46, 46, 47,
+ 47, 48, 48, 49, 49, 49, 50, 50, 51, 51, 52,
+ 52, 52, 53, 53, 54, 54, 55, 55, 55, 56, 56,
+ 57, 57, 58, 58, 59, 59, 60, 60, 61, 61, 61,
+ 62, 62, 63, 63, 64, 64, 65, 65, 66, 66, 67,
+ 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 72,
+ 73, 73, 74, 75, 75, 76, 76, 77, 77, 78, 78,
+ 79, 79, 80, 80, 81, 82, 82, 83, 83, 84, 84,
+ 85, 85, 86, 87, 87, 88, 88, 89, 89, 90, 91,
+ 91, 92, 92, 93, 94, 94, 95, 95, 96, 97, 97,
+ 98, 98, 99, 100, 100, 101, 102, 102, 103, 103, 104,
+ 105, 105, 106, 107, 107, 108, 109, 109, 110, 110, 111,
+ 112, 112, 113, 114, 114, 115, 116, 116, 117, 118, 118,
+ 119, 120, 121, 121, 122, 123, 123, 124, 125, 125, 126,
+ 127, 127, 128, 129, 130, 130, 131, 132, 132, 133, 134,
+ 135, 135, 136, 137, 138, 138, 139, 140, 141, 141, 142,
+ 143, 144, 144, 145, 146, 147, 147, 148, 149, 150, 150,
+ 151, 152, 153, 154, 154, 155, 156, 157, 157, 158, 159,
+ 160, 161, 161, 162, 163, 164, 165, 166, 166, 167, 168,
+ 169, 170, 170, 171, 172, 173, 174, 175, 175, 176, 177,
+ 178, 179, 180, 181, 181, 182, 183, 184, 185, 186, 187,
+ 187, 188, 189, 190, 191, 192, 193, 194, 194, 195, 196,
+ 197, 198, 199, 200, 201, 202, 203, 203, 204, 205, 206,
+ 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 216,
+ 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227,
+ 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238,
+ 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249,
+ 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260,
+ 261, 262, 263, 264, 265, 266, 267, 269, 270, 271, 272,
+ 273, 274, 275, 276, 277, 278, 279, 280, 281, 283, 284,
+ 285, 286, 287, 288, 289, 290, 291, 292, 294, 295, 296,
+ 297, 298, 299, 300, 301, 303, 304, 305, 306, 307, 308,
+ 309, 311, 312, 313, 314, 315, 316, 317, 319, 320, 321,
+ 322, 323, 324, 326, 327, 328, 329, 330, 332, 333, 334,
+ 335, 336, 338, 339, 340, 341, 342, 344, 345, 346, 347,
+ 348, 350, 351, 352, 353, 355, 356, 357, 358, 360, 361,
+ 362, 363, 365, 366, 367, 368, 370, 371, 372, 373, 375,
+ 376, 377, 378, 380, 381, 382, 384, 385, 386, 387, 389,
+ 390, 391, 393, 394, 395, 397, 398, 399, 401, 402, 403,
+ 405, 406, 407, 409, 410, 411, 413, 414, 415, 417, 418,
+ 419, 421, 422, 423, 425, 426, 427, 429, 430, 432, 433,
+ 434, 436, 437, 438, 440, 441, 443, 444, 445, 447, 448,
+ 450, 451, 452, 454, 455, 457, 458, 459, 461, 462, 464,
+ 465, 467, 468, 469, 471, 472, 474, 475, 477, 478, 480,
+ 481, 483, 484, 485, 487, 488, 490, 491, 493, 494, 496,
+ 497, 499, 500, 502, 503, 505, 506, 508, 509, 511, 512,
+ 514, 515, 517, 518, 520, 521, 523, 524, 526, 527, 529,
+ 530, 532, 534, 535, 537, 538, 540, 541, 543, 544, 546,
+ 548, 549, 551, 552, 554, 555, 557, 559, 560, 562, 563,
+ 565, 567, 568, 570, 571, 573, 575, 576, 578, 579, 581,
+ 583, 584, 586, 587, 589, 591, 592, 594, 596, 597, 599,
+ 601, 602, 604, 605, 607, 609, 610, 612, 614, 615, 617,
+ 619, 620, 622, 624, 625, 627, 629, 631, 632, 634, 636,
+ 637, 639, 641, 642, 644, 646, 648, 649, 651, 653, 654,
+ 656, 658, 660, 661, 663, 665, 667, 668, 670, 672, 674,
+ 675, 677, 679, 681, 682, 684, 686, 688, 689, 691, 693,
+ 695, 697, 698, 700, 702, 704, 705, 707, 709, 711, 713,
+ 714, 716, 718, 720, 722, 724, 725, 727, 729, 731, 733,
+ 735, 736, 738, 740, 742, 744, 746, 747, 749, 751, 753,
+ 755, 757, 759, 760, 762, 764, 766, 768, 770, 772, 774,
+ 776, 777, 779, 781, 783, 785, 787, 789, 791, 793, 795,
+ 796, 798, 800, 802, 804, 806, 808, 810, 812, 814, 816,
+ 818, 820, 822, 824, 826, 828, 829, 831, 833, 835, 837,
+ 839, 841, 843, 845, 847, 849, 851, 853, 855, 857, 859,
+ 861, 863, 865, 867, 869, 871, 873, 875, 877, 879, 881,
+ 883, 885, 887, 889, 892, 894, 896, 898, 900, 902, 904,
+ 906, 908, 910, 912, 914, 916, 918, 920, 922, 925, 927,
+ 929, 931, 933, 935, 937, 939, 941, 943, 945, 948, 950,
+ 952, 954, 956, 958, 960, 962, 965, 967, 969, 971, 973,
+ 975, 977, 980, 982, 984, 986, 988, 990, 992, 995, 997,
+ 999, 1001, 1003, 1005, 1008, 1010, 1012, 1014, 1016, 1019, 1021,
+ 1023,
+};
+
+static const u16 xgamma10_23[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6,
+ 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9,
+ 9, 9, 10, 10, 10, 10, 10, 10, 11, 11, 11,
+ 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13,
+ 13, 13, 14, 14, 14, 14, 14, 15, 15, 15, 15,
+ 15, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18,
+ 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20,
+ 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23,
+ 23, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26,
+ 27, 27, 27, 27, 28, 28, 28, 29, 29, 29, 30,
+ 30, 30, 30, 31, 31, 31, 32, 32, 32, 33, 33,
+ 33, 34, 34, 34, 35, 35, 35, 36, 36, 36, 37,
+ 37, 38, 38, 38, 39, 39, 39, 40, 40, 40, 41,
+ 41, 42, 42, 42, 43, 43, 43, 44, 44, 45, 45,
+ 45, 46, 46, 47, 47, 47, 48, 48, 49, 49, 49,
+ 50, 50, 51, 51, 52, 52, 52, 53, 53, 54, 54,
+ 55, 55, 55, 56, 56, 57, 57, 58, 58, 59, 59,
+ 59, 60, 60, 61, 61, 62, 62, 63, 63, 64, 64,
+ 65, 65, 66, 66, 67, 67, 68, 68, 69, 69, 70,
+ 70, 71, 71, 72, 72, 73, 73, 74, 74, 75, 75,
+ 76, 76, 77, 77, 78, 78, 79, 80, 80, 81, 81,
+ 82, 82, 83, 83, 84, 85, 85, 86, 86, 87, 87,
+ 88, 89, 89, 90, 90, 91, 91, 92, 93, 93, 94,
+ 94, 95, 96, 96, 97, 97, 98, 99, 99, 100, 100,
+ 101, 102, 102, 103, 104, 104, 105, 106, 106, 107, 107,
+ 108, 109, 109, 110, 111, 111, 112, 113, 113, 114, 115,
+ 115, 116, 117, 117, 118, 119, 119, 120, 121, 121, 122,
+ 123, 124, 124, 125, 126, 126, 127, 128, 128, 129, 130,
+ 131, 131, 132, 133, 133, 134, 135, 136, 136, 137, 138,
+ 139, 139, 140, 141, 142, 142, 143, 144, 145, 145, 146,
+ 147, 148, 148, 149, 150, 151, 152, 152, 153, 154, 155,
+ 156, 156, 157, 158, 159, 160, 160, 161, 162, 163, 164,
+ 164, 165, 166, 167, 168, 168, 169, 170, 171, 172, 173,
+ 174, 174, 175, 176, 177, 178, 179, 179, 180, 181, 182,
+ 183, 184, 185, 186, 186, 187, 188, 189, 190, 191, 192,
+ 193, 194, 194, 195, 196, 197, 198, 199, 200, 201, 202,
+ 203, 204, 204, 205, 206, 207, 208, 209, 210, 211, 212,
+ 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 222,
+ 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233,
+ 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244,
+ 245, 246, 248, 249, 250, 251, 252, 253, 254, 255, 256,
+ 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 268,
+ 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 280,
+ 281, 282, 283, 284, 285, 286, 287, 288, 290, 291, 292,
+ 293, 294, 295, 296, 298, 299, 300, 301, 302, 303, 304,
+ 306, 307, 308, 309, 310, 311, 313, 314, 315, 316, 317,
+ 319, 320, 321, 322, 323, 325, 326, 327, 328, 329, 331,
+ 332, 333, 334, 335, 337, 338, 339, 340, 342, 343, 344,
+ 345, 347, 348, 349, 350, 352, 353, 354, 355, 357, 358,
+ 359, 360, 362, 363, 364, 366, 367, 368, 369, 371, 372,
+ 373, 375, 376, 377, 379, 380, 381, 383, 384, 385, 386,
+ 388, 389, 390, 392, 393, 394, 396, 397, 399, 400, 401,
+ 403, 404, 405, 407, 408, 409, 411, 412, 414, 415, 416,
+ 418, 419, 420, 422, 423, 425, 426, 427, 429, 430, 432,
+ 433, 435, 436, 437, 439, 440, 442, 443, 444, 446, 447,
+ 449, 450, 452, 453, 455, 456, 458, 459, 460, 462, 463,
+ 465, 466, 468, 469, 471, 472, 474, 475, 477, 478, 480,
+ 481, 483, 484, 486, 487, 489, 490, 492, 493, 495, 496,
+ 498, 499, 501, 502, 504, 506, 507, 509, 510, 512, 513,
+ 515, 516, 518, 520, 521, 523, 524, 526, 527, 529, 531,
+ 532, 534, 535, 537, 539, 540, 542, 543, 545, 547, 548,
+ 550, 551, 553, 555, 556, 558, 560, 561, 563, 565, 566,
+ 568, 569, 571, 573, 574, 576, 578, 579, 581, 583, 584,
+ 586, 588, 590, 591, 593, 595, 596, 598, 600, 601, 603,
+ 605, 606, 608, 610, 612, 613, 615, 617, 619, 620, 622,
+ 624, 625, 627, 629, 631, 632, 634, 636, 638, 640, 641,
+ 643, 645, 647, 648, 650, 652, 654, 655, 657, 659, 661,
+ 663, 664, 666, 668, 670, 672, 674, 675, 677, 679, 681,
+ 683, 684, 686, 688, 690, 692, 694, 696, 697, 699, 701,
+ 703, 705, 707, 709, 710, 712, 714, 716, 718, 720, 722,
+ 724, 725, 727, 729, 731, 733, 735, 737, 739, 741, 743,
+ 745, 746, 748, 750, 752, 754, 756, 758, 760, 762, 764,
+ 766, 768, 770, 772, 774, 776, 778, 780, 782, 784, 786,
+ 787, 789, 791, 793, 795, 797, 799, 801, 803, 805, 807,
+ 809, 811, 814, 816, 818, 820, 822, 824, 826, 828, 830,
+ 832, 834, 836, 838, 840, 842, 844, 846, 848, 850, 852,
+ 854, 857, 859, 861, 863, 865, 867, 869, 871, 873, 875,
+ 878, 880, 882, 884, 886, 888, 890, 892, 894, 897, 899,
+ 901, 903, 905, 907, 909, 912, 914, 916, 918, 920, 922,
+ 925, 927, 929, 931, 933, 936, 938, 940, 942, 944, 946,
+ 949, 951, 953, 955, 958, 960, 962, 964, 966, 969, 971,
+ 973, 975, 978, 980, 982, 984, 987, 989, 991, 993, 996,
+ 998, 1000, 1002, 1005, 1007, 1009, 1012, 1014, 1016, 1018, 1021,
+ 1023,
+};
+
+static const u16 xgamma10_24[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9,
+ 9, 9, 9, 10, 10, 10, 10, 10, 10, 11, 11,
+ 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 13,
+ 13, 13, 13, 13, 14, 14, 14, 14, 14, 15, 15,
+ 15, 15, 15, 16, 16, 16, 16, 16, 17, 17, 17,
+ 17, 18, 18, 18, 18, 18, 19, 19, 19, 19, 20,
+ 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22,
+ 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25,
+ 26, 26, 26, 26, 27, 27, 27, 28, 28, 28, 28,
+ 29, 29, 29, 30, 30, 30, 31, 31, 31, 32, 32,
+ 32, 32, 33, 33, 33, 34, 34, 34, 35, 35, 35,
+ 36, 36, 36, 37, 37, 38, 38, 38, 39, 39, 39,
+ 40, 40, 40, 41, 41, 41, 42, 42, 43, 43, 43,
+ 44, 44, 44, 45, 45, 46, 46, 46, 47, 47, 48,
+ 48, 48, 49, 49, 50, 50, 50, 51, 51, 52, 52,
+ 53, 53, 53, 54, 54, 55, 55, 56, 56, 56, 57,
+ 57, 58, 58, 59, 59, 60, 60, 61, 61, 61, 62,
+ 62, 63, 63, 64, 64, 65, 65, 66, 66, 67, 67,
+ 68, 68, 69, 69, 70, 70, 71, 71, 72, 72, 73,
+ 73, 74, 74, 75, 75, 76, 76, 77, 77, 78, 79,
+ 79, 80, 80, 81, 81, 82, 82, 83, 83, 84, 85,
+ 85, 86, 86, 87, 87, 88, 89, 89, 90, 90, 91,
+ 91, 92, 93, 93, 94, 94, 95, 96, 96, 97, 97,
+ 98, 99, 99, 100, 100, 101, 102, 102, 103, 104, 104,
+ 105, 106, 106, 107, 107, 108, 109, 109, 110, 111, 111,
+ 112, 113, 113, 114, 115, 115, 116, 117, 117, 118, 119,
+ 119, 120, 121, 121, 122, 123, 124, 124, 125, 126, 126,
+ 127, 128, 129, 129, 130, 131, 131, 132, 133, 134, 134,
+ 135, 136, 137, 137, 138, 139, 140, 140, 141, 142, 143,
+ 143, 144, 145, 146, 146, 147, 148, 149, 149, 150, 151,
+ 152, 153, 153, 154, 155, 156, 157, 157, 158, 159, 160,
+ 161, 161, 162, 163, 164, 165, 166, 166, 167, 168, 169,
+ 170, 171, 171, 172, 173, 174, 175, 176, 177, 177, 178,
+ 179, 180, 181, 182, 183, 184, 184, 185, 186, 187, 188,
+ 189, 190, 191, 192, 192, 193, 194, 195, 196, 197, 198,
+ 199, 200, 201, 202, 203, 204, 204, 205, 206, 207, 208,
+ 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
+ 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230,
+ 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241,
+ 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252,
+ 253, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 268, 269, 270, 271, 272, 273, 274, 275, 276,
+ 277, 279, 280, 281, 282, 283, 284, 285, 287, 288, 289,
+ 290, 291, 292, 293, 295, 296, 297, 298, 299, 300, 302,
+ 303, 304, 305, 306, 308, 309, 310, 311, 312, 314, 315,
+ 316, 317, 318, 320, 321, 322, 323, 324, 326, 327, 328,
+ 329, 331, 332, 333, 334, 336, 337, 338, 339, 341, 342,
+ 343, 344, 346, 347, 348, 350, 351, 352, 353, 355, 356,
+ 357, 359, 360, 361, 363, 364, 365, 367, 368, 369, 370,
+ 372, 373, 374, 376, 377, 378, 380, 381, 383, 384, 385,
+ 387, 388, 389, 391, 392, 393, 395, 396, 398, 399, 400,
+ 402, 403, 405, 406, 407, 409, 410, 412, 413, 414, 416,
+ 417, 419, 420, 421, 423, 424, 426, 427, 429, 430, 432,
+ 433, 434, 436, 437, 439, 440, 442, 443, 445, 446, 448,
+ 449, 451, 452, 454, 455, 457, 458, 460, 461, 463, 464,
+ 466, 467, 469, 470, 472, 473, 475, 476, 478, 479, 481,
+ 483, 484, 486, 487, 489, 490, 492, 493, 495, 497, 498,
+ 500, 501, 503, 505, 506, 508, 509, 511, 512, 514, 516,
+ 517, 519, 521, 522, 524, 525, 527, 529, 530, 532, 534,
+ 535, 537, 539, 540, 542, 543, 545, 547, 548, 550, 552,
+ 553, 555, 557, 559, 560, 562, 564, 565, 567, 569, 570,
+ 572, 574, 576, 577, 579, 581, 582, 584, 586, 588, 589,
+ 591, 593, 595, 596, 598, 600, 602, 603, 605, 607, 609,
+ 610, 612, 614, 616, 618, 619, 621, 623, 625, 627, 628,
+ 630, 632, 634, 636, 637, 639, 641, 643, 645, 647, 648,
+ 650, 652, 654, 656, 658, 660, 661, 663, 665, 667, 669,
+ 671, 673, 674, 676, 678, 680, 682, 684, 686, 688, 690,
+ 692, 693, 695, 697, 699, 701, 703, 705, 707, 709, 711,
+ 713, 715, 717, 719, 721, 723, 724, 726, 728, 730, 732,
+ 734, 736, 738, 740, 742, 744, 746, 748, 750, 752, 754,
+ 756, 758, 760, 762, 764, 766, 768, 770, 772, 774, 777,
+ 779, 781, 783, 785, 787, 789, 791, 793, 795, 797, 799,
+ 801, 803, 805, 808, 810, 812, 814, 816, 818, 820, 822,
+ 824, 826, 829, 831, 833, 835, 837, 839, 841, 844, 846,
+ 848, 850, 852, 854, 856, 859, 861, 863, 865, 867, 870,
+ 872, 874, 876, 878, 880, 883, 885, 887, 889, 891, 894,
+ 896, 898, 900, 903, 905, 907, 909, 912, 914, 916, 918,
+ 921, 923, 925, 927, 930, 932, 934, 936, 939, 941, 943,
+ 946, 948, 950, 952, 955, 957, 959, 962, 964, 966, 969,
+ 971, 973, 976, 978, 980, 983, 985, 987, 990, 992, 994,
+ 997, 999, 1002, 1004, 1006, 1009, 1011, 1013, 1016, 1018, 1021,
+ 1023,
+};
+
+static const u16 xgamma10_25[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7,
+ 7, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9,
+ 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 11,
+ 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12,
+ 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14,
+ 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 17,
+ 17, 17, 17, 18, 18, 18, 18, 18, 19, 19, 19,
+ 19, 20, 20, 20, 20, 20, 21, 21, 21, 21, 22,
+ 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 25,
+ 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 28,
+ 28, 28, 28, 29, 29, 29, 30, 30, 30, 31, 31,
+ 31, 31, 32, 32, 32, 33, 33, 33, 34, 34, 34,
+ 35, 35, 35, 36, 36, 36, 37, 37, 37, 38, 38,
+ 38, 39, 39, 39, 40, 40, 40, 41, 41, 42, 42,
+ 42, 43, 43, 43, 44, 44, 45, 45, 45, 46, 46,
+ 46, 47, 47, 48, 48, 48, 49, 49, 50, 50, 50,
+ 51, 51, 52, 52, 53, 53, 53, 54, 54, 55, 55,
+ 56, 56, 56, 57, 57, 58, 58, 59, 59, 60, 60,
+ 60, 61, 61, 62, 62, 63, 63, 64, 64, 65, 65,
+ 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71,
+ 71, 72, 72, 73, 73, 74, 74, 75, 75, 76, 76,
+ 77, 77, 78, 78, 79, 79, 80, 80, 81, 82, 82,
+ 83, 83, 84, 84, 85, 85, 86, 87, 87, 88, 88,
+ 89, 89, 90, 91, 91, 92, 92, 93, 94, 94, 95,
+ 95, 96, 97, 97, 98, 98, 99, 100, 100, 101, 102,
+ 102, 103, 103, 104, 105, 105, 106, 107, 107, 108, 109,
+ 109, 110, 110, 111, 112, 112, 113, 114, 114, 115, 116,
+ 117, 117, 118, 119, 119, 120, 121, 121, 122, 123, 123,
+ 124, 125, 126, 126, 127, 128, 128, 129, 130, 131, 131,
+ 132, 133, 133, 134, 135, 136, 136, 137, 138, 139, 139,
+ 140, 141, 142, 143, 143, 144, 145, 146, 146, 147, 148,
+ 149, 149, 150, 151, 152, 153, 153, 154, 155, 156, 157,
+ 158, 158, 159, 160, 161, 162, 162, 163, 164, 165, 166,
+ 167, 167, 168, 169, 170, 171, 172, 173, 173, 174, 175,
+ 176, 177, 178, 179, 180, 180, 181, 182, 183, 184, 185,
+ 186, 187, 188, 188, 189, 190, 191, 192, 193, 194, 195,
+ 196, 197, 198, 199, 200, 200, 201, 202, 203, 204, 205,
+ 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216,
+ 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227,
+ 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238,
+ 239, 240, 241, 242, 243, 244, 245, 247, 248, 249, 250,
+ 251, 252, 253, 254, 255, 256, 257, 258, 260, 261, 262,
+ 263, 264, 265, 266, 267, 268, 270, 271, 272, 273, 274,
+ 275, 276, 277, 279, 280, 281, 282, 283, 284, 286, 287,
+ 288, 289, 290, 291, 293, 294, 295, 296, 297, 298, 300,
+ 301, 302, 303, 304, 306, 307, 308, 309, 311, 312, 313,
+ 314, 315, 317, 318, 319, 320, 322, 323, 324, 325, 327,
+ 328, 329, 330, 332, 333, 334, 336, 337, 338, 339, 341,
+ 342, 343, 345, 346, 347, 349, 350, 351, 352, 354, 355,
+ 356, 358, 359, 360, 362, 363, 364, 366, 367, 369, 370,
+ 371, 373, 374, 375, 377, 378, 379, 381, 382, 384, 385,
+ 386, 388, 389, 391, 392, 393, 395, 396, 398, 399, 400,
+ 402, 403, 405, 406, 408, 409, 411, 412, 413, 415, 416,
+ 418, 419, 421, 422, 424, 425, 427, 428, 430, 431, 433,
+ 434, 436, 437, 439, 440, 442, 443, 445, 446, 448, 449,
+ 451, 452, 454, 455, 457, 458, 460, 461, 463, 465, 466,
+ 468, 469, 471, 472, 474, 476, 477, 479, 480, 482, 483,
+ 485, 487, 488, 490, 491, 493, 495, 496, 498, 500, 501,
+ 503, 504, 506, 508, 509, 511, 513, 514, 516, 518, 519,
+ 521, 523, 524, 526, 528, 529, 531, 533, 534, 536, 538,
+ 540, 541, 543, 545, 546, 548, 550, 552, 553, 555, 557,
+ 558, 560, 562, 564, 565, 567, 569, 571, 572, 574, 576,
+ 578, 580, 581, 583, 585, 587, 588, 590, 592, 594, 596,
+ 597, 599, 601, 603, 605, 607, 608, 610, 612, 614, 616,
+ 618, 619, 621, 623, 625, 627, 629, 631, 632, 634, 636,
+ 638, 640, 642, 644, 646, 648, 649, 651, 653, 655, 657,
+ 659, 661, 663, 665, 667, 669, 671, 673, 674, 676, 678,
+ 680, 682, 684, 686, 688, 690, 692, 694, 696, 698, 700,
+ 702, 704, 706, 708, 710, 712, 714, 716, 718, 720, 722,
+ 724, 726, 728, 730, 732, 734, 736, 739, 741, 743, 745,
+ 747, 749, 751, 753, 755, 757, 759, 761, 763, 766, 768,
+ 770, 772, 774, 776, 778, 780, 782, 785, 787, 789, 791,
+ 793, 795, 797, 800, 802, 804, 806, 808, 810, 813, 815,
+ 817, 819, 821, 824, 826, 828, 830, 832, 835, 837, 839,
+ 841, 843, 846, 848, 850, 852, 855, 857, 859, 861, 864,
+ 866, 868, 870, 873, 875, 877, 880, 882, 884, 886, 889,
+ 891, 893, 896, 898, 900, 903, 905, 907, 910, 912, 914,
+ 917, 919, 921, 924, 926, 928, 931, 933, 935, 938, 940,
+ 942, 945, 947, 950, 952, 954, 957, 959, 962, 964, 966,
+ 969, 971, 974, 976, 979, 981, 983, 986, 988, 991, 993,
+ 996, 998, 1001, 1003, 1006, 1008, 1011, 1013, 1016, 1018, 1021,
+ 1023,
+};
+
+static const u16 xgamma10_26[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7,
+ 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9,
+ 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10,
+ 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12,
+ 12, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14,
+ 14, 14, 15, 15, 15, 15, 15, 16, 16, 16, 16,
+ 16, 17, 17, 17, 17, 18, 18, 18, 18, 18, 19,
+ 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21,
+ 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24,
+ 24, 24, 25, 25, 25, 25, 26, 26, 26, 27, 27,
+ 27, 27, 28, 28, 28, 28, 29, 29, 29, 30, 30,
+ 30, 31, 31, 31, 31, 32, 32, 32, 33, 33, 33,
+ 34, 34, 34, 35, 35, 35, 36, 36, 36, 37, 37,
+ 37, 38, 38, 38, 39, 39, 39, 40, 40, 40, 41,
+ 41, 41, 42, 42, 43, 43, 43, 44, 44, 44, 45,
+ 45, 46, 46, 46, 47, 47, 47, 48, 48, 49, 49,
+ 49, 50, 50, 51, 51, 51, 52, 52, 53, 53, 54,
+ 54, 54, 55, 55, 56, 56, 57, 57, 57, 58, 58,
+ 59, 59, 60, 60, 61, 61, 62, 62, 62, 63, 63,
+ 64, 64, 65, 65, 66, 66, 67, 67, 68, 68, 69,
+ 69, 70, 70, 71, 71, 72, 72, 73, 73, 74, 74,
+ 75, 75, 76, 76, 77, 77, 78, 78, 79, 80, 80,
+ 81, 81, 82, 82, 83, 83, 84, 84, 85, 86, 86,
+ 87, 87, 88, 88, 89, 90, 90, 91, 91, 92, 93,
+ 93, 94, 94, 95, 96, 96, 97, 97, 98, 99, 99,
+ 100, 100, 101, 102, 102, 103, 104, 104, 105, 106, 106,
+ 107, 107, 108, 109, 109, 110, 111, 111, 112, 113, 113,
+ 114, 115, 115, 116, 117, 117, 118, 119, 120, 120, 121,
+ 122, 122, 123, 124, 124, 125, 126, 127, 127, 128, 129,
+ 129, 130, 131, 132, 132, 133, 134, 135, 135, 136, 137,
+ 138, 138, 139, 140, 141, 141, 142, 143, 144, 145, 145,
+ 146, 147, 148, 149, 149, 150, 151, 152, 153, 153, 154,
+ 155, 156, 157, 157, 158, 159, 160, 161, 162, 162, 163,
+ 164, 165, 166, 167, 167, 168, 169, 170, 171, 172, 173,
+ 173, 174, 175, 176, 177, 178, 179, 180, 181, 181, 182,
+ 183, 184, 185, 186, 187, 188, 189, 190, 191, 191, 192,
+ 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203,
+ 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214,
+ 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225,
+ 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236,
+ 237, 238, 239, 240, 241, 242, 243, 245, 246, 247, 248,
+ 249, 250, 251, 252, 253, 254, 256, 257, 258, 259, 260,
+ 261, 262, 263, 264, 266, 267, 268, 269, 270, 271, 272,
+ 274, 275, 276, 277, 278, 279, 281, 282, 283, 284, 285,
+ 286, 288, 289, 290, 291, 292, 294, 295, 296, 297, 299,
+ 300, 301, 302, 303, 305, 306, 307, 308, 310, 311, 312,
+ 313, 315, 316, 317, 318, 320, 321, 322, 323, 325, 326,
+ 327, 329, 330, 331, 333, 334, 335, 336, 338, 339, 340,
+ 342, 343, 344, 346, 347, 348, 350, 351, 352, 354, 355,
+ 356, 358, 359, 361, 362, 363, 365, 366, 367, 369, 370,
+ 372, 373, 374, 376, 377, 379, 380, 381, 383, 384, 386,
+ 387, 389, 390, 391, 393, 394, 396, 397, 399, 400, 402,
+ 403, 405, 406, 407, 409, 410, 412, 413, 415, 416, 418,
+ 419, 421, 422, 424, 425, 427, 428, 430, 432, 433, 435,
+ 436, 438, 439, 441, 442, 444, 445, 447, 449, 450, 452,
+ 453, 455, 456, 458, 460, 461, 463, 464, 466, 468, 469,
+ 471, 472, 474, 476, 477, 479, 481, 482, 484, 485, 487,
+ 489, 490, 492, 494, 495, 497, 499, 500, 502, 504, 505,
+ 507, 509, 510, 512, 514, 516, 517, 519, 521, 522, 524,
+ 526, 528, 529, 531, 533, 535, 536, 538, 540, 542, 543,
+ 545, 547, 549, 550, 552, 554, 556, 558, 559, 561, 563,
+ 565, 567, 568, 570, 572, 574, 576, 577, 579, 581, 583,
+ 585, 587, 588, 590, 592, 594, 596, 598, 600, 601, 603,
+ 605, 607, 609, 611, 613, 615, 617, 619, 620, 622, 624,
+ 626, 628, 630, 632, 634, 636, 638, 640, 642, 644, 646,
+ 648, 650, 651, 653, 655, 657, 659, 661, 663, 665, 667,
+ 669, 671, 673, 675, 677, 679, 681, 683, 685, 688, 690,
+ 692, 694, 696, 698, 700, 702, 704, 706, 708, 710, 712,
+ 714, 716, 718, 721, 723, 725, 727, 729, 731, 733, 735,
+ 737, 740, 742, 744, 746, 748, 750, 752, 755, 757, 759,
+ 761, 763, 765, 768, 770, 772, 774, 776, 779, 781, 783,
+ 785, 787, 790, 792, 794, 796, 798, 801, 803, 805, 807,
+ 810, 812, 814, 816, 819, 821, 823, 826, 828, 830, 832,
+ 835, 837, 839, 842, 844, 846, 849, 851, 853, 855, 858,
+ 860, 862, 865, 867, 870, 872, 874, 877, 879, 881, 884,
+ 886, 888, 891, 893, 896, 898, 900, 903, 905, 908, 910,
+ 913, 915, 917, 920, 922, 925, 927, 930, 932, 934, 937,
+ 939, 942, 944, 947, 949, 952, 954, 957, 959, 962, 964,
+ 967, 969, 972, 974, 977, 979, 982, 984, 987, 990, 992,
+ 995, 997, 1000, 1002, 1005, 1007, 1010, 1013, 1015, 1018, 1020,
+ 1023,
+};
+
+static const u16 xgamma10_27[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7,
+ 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9,
+ 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10,
+ 10, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12,
+ 12, 12, 12, 13, 13, 13, 13, 13, 14, 14, 14,
+ 14, 14, 14, 15, 15, 15, 15, 15, 16, 16, 16,
+ 16, 16, 17, 17, 17, 17, 17, 18, 18, 18, 18,
+ 18, 19, 19, 19, 19, 20, 20, 20, 20, 20, 21,
+ 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,
+ 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26,
+ 26, 27, 27, 27, 27, 28, 28, 28, 29, 29, 29,
+ 29, 30, 30, 30, 31, 31, 31, 32, 32, 32, 32,
+ 33, 33, 33, 34, 34, 34, 35, 35, 35, 36, 36,
+ 36, 37, 37, 37, 38, 38, 38, 39, 39, 39, 40,
+ 40, 40, 41, 41, 41, 42, 42, 43, 43, 43, 44,
+ 44, 44, 45, 45, 46, 46, 46, 47, 47, 47, 48,
+ 48, 49, 49, 49, 50, 50, 51, 51, 51, 52, 52,
+ 53, 53, 54, 54, 54, 55, 55, 56, 56, 57, 57,
+ 57, 58, 58, 59, 59, 60, 60, 61, 61, 61, 62,
+ 62, 63, 63, 64, 64, 65, 65, 66, 66, 67, 67,
+ 68, 68, 69, 69, 70, 70, 71, 71, 72, 72, 73,
+ 73, 74, 74, 75, 75, 76, 76, 77, 77, 78, 78,
+ 79, 79, 80, 81, 81, 82, 82, 83, 83, 84, 84,
+ 85, 86, 86, 87, 87, 88, 88, 89, 90, 90, 91,
+ 91, 92, 92, 93, 94, 94, 95, 95, 96, 97, 97,
+ 98, 99, 99, 100, 100, 101, 102, 102, 103, 104, 104,
+ 105, 105, 106, 107, 107, 108, 109, 109, 110, 111, 111,
+ 112, 113, 113, 114, 115, 115, 116, 117, 118, 118, 119,
+ 120, 120, 121, 122, 122, 123, 124, 125, 125, 126, 127,
+ 127, 128, 129, 130, 130, 131, 132, 133, 133, 134, 135,
+ 136, 136, 137, 138, 139, 139, 140, 141, 142, 143, 143,
+ 144, 145, 146, 146, 147, 148, 149, 150, 150, 151, 152,
+ 153, 154, 155, 155, 156, 157, 158, 159, 160, 160, 161,
+ 162, 163, 164, 165, 165, 166, 167, 168, 169, 170, 171,
+ 172, 172, 173, 174, 175, 176, 177, 178, 179, 180, 180,
+ 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
+ 192, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201,
+ 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212,
+ 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
+ 224, 225, 226, 227, 228, 229, 230, 231, 233, 234, 235,
+ 236, 237, 238, 239, 240, 241, 242, 243, 244, 246, 247,
+ 248, 249, 250, 251, 252, 253, 254, 256, 257, 258, 259,
+ 260, 261, 262, 263, 265, 266, 267, 268, 269, 270, 272,
+ 273, 274, 275, 276, 278, 279, 280, 281, 282, 283, 285,
+ 286, 287, 288, 290, 291, 292, 293, 294, 296, 297, 298,
+ 299, 301, 302, 303, 304, 306, 307, 308, 309, 311, 312,
+ 313, 315, 316, 317, 318, 320, 321, 322, 324, 325, 326,
+ 328, 329, 330, 332, 333, 334, 336, 337, 338, 340, 341,
+ 342, 344, 345, 346, 348, 349, 351, 352, 353, 355, 356,
+ 357, 359, 360, 362, 363, 364, 366, 367, 369, 370, 372,
+ 373, 374, 376, 377, 379, 380, 382, 383, 385, 386, 387,
+ 389, 390, 392, 393, 395, 396, 398, 399, 401, 402, 404,
+ 405, 407, 408, 410, 411, 413, 414, 416, 417, 419, 421,
+ 422, 424, 425, 427, 428, 430, 431, 433, 435, 436, 438,
+ 439, 441, 442, 444, 446, 447, 449, 450, 452, 454, 455,
+ 457, 459, 460, 462, 463, 465, 467, 468, 470, 472, 473,
+ 475, 477, 478, 480, 482, 483, 485, 487, 488, 490, 492,
+ 494, 495, 497, 499, 500, 502, 504, 506, 507, 509, 511,
+ 513, 514, 516, 518, 520, 521, 523, 525, 527, 528, 530,
+ 532, 534, 536, 537, 539, 541, 543, 545, 546, 548, 550,
+ 552, 554, 556, 557, 559, 561, 563, 565, 567, 569, 570,
+ 572, 574, 576, 578, 580, 582, 584, 586, 587, 589, 591,
+ 593, 595, 597, 599, 601, 603, 605, 607, 609, 611, 613,
+ 614, 616, 618, 620, 622, 624, 626, 628, 630, 632, 634,
+ 636, 638, 640, 642, 644, 646, 648, 650, 652, 654, 656,
+ 659, 661, 663, 665, 667, 669, 671, 673, 675, 677, 679,
+ 681, 683, 685, 688, 690, 692, 694, 696, 698, 700, 702,
+ 705, 707, 709, 711, 713, 715, 717, 720, 722, 724, 726,
+ 728, 730, 733, 735, 737, 739, 741, 744, 746, 748, 750,
+ 752, 755, 757, 759, 761, 764, 766, 768, 770, 773, 775,
+ 777, 779, 782, 784, 786, 789, 791, 793, 795, 798, 800,
+ 802, 805, 807, 809, 812, 814, 816, 819, 821, 823, 826,
+ 828, 831, 833, 835, 838, 840, 842, 845, 847, 850, 852,
+ 854, 857, 859, 862, 864, 867, 869, 871, 874, 876, 879,
+ 881, 884, 886, 889, 891, 894, 896, 899, 901, 903, 906,
+ 908, 911, 914, 916, 919, 921, 924, 926, 929, 931, 934,
+ 936, 939, 941, 944, 947, 949, 952, 954, 957, 959, 962,
+ 965, 967, 970, 973, 975, 978, 980, 983, 986, 988, 991,
+ 994, 996, 999, 1002, 1004, 1007, 1010, 1012, 1015, 1018, 1020,
+ 1023,
+};
+
+static const u16 xgamma10_28[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9,
+ 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10,
+ 10, 10, 11, 11, 11, 11, 11, 11, 12, 12, 12,
+ 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 14,
+ 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 16,
+ 16, 16, 16, 16, 17, 17, 17, 17, 17, 18, 18,
+ 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20,
+ 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23,
+ 23, 23, 24, 24, 24, 24, 25, 25, 25, 25, 26,
+ 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 29,
+ 29, 29, 29, 30, 30, 30, 31, 31, 31, 31, 32,
+ 32, 32, 33, 33, 33, 34, 34, 34, 35, 35, 35,
+ 35, 36, 36, 36, 37, 37, 37, 38, 38, 38, 39,
+ 39, 40, 40, 40, 41, 41, 41, 42, 42, 42, 43,
+ 43, 43, 44, 44, 45, 45, 45, 46, 46, 46, 47,
+ 47, 48, 48, 48, 49, 49, 50, 50, 50, 51, 51,
+ 52, 52, 52, 53, 53, 54, 54, 55, 55, 55, 56,
+ 56, 57, 57, 58, 58, 58, 59, 59, 60, 60, 61,
+ 61, 62, 62, 63, 63, 63, 64, 64, 65, 65, 66,
+ 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71,
+ 72, 72, 73, 73, 74, 74, 75, 75, 76, 76, 77,
+ 77, 78, 79, 79, 80, 80, 81, 81, 82, 82, 83,
+ 83, 84, 85, 85, 86, 86, 87, 87, 88, 89, 89,
+ 90, 90, 91, 92, 92, 93, 93, 94, 95, 95, 96,
+ 96, 97, 98, 98, 99, 99, 100, 101, 101, 102, 103,
+ 103, 104, 105, 105, 106, 106, 107, 108, 108, 109, 110,
+ 110, 111, 112, 112, 113, 114, 115, 115, 116, 117, 117,
+ 118, 119, 119, 120, 121, 122, 122, 123, 124, 124, 125,
+ 126, 127, 127, 128, 129, 130, 130, 131, 132, 132, 133,
+ 134, 135, 136, 136, 137, 138, 139, 139, 140, 141, 142,
+ 143, 143, 144, 145, 146, 146, 147, 148, 149, 150, 151,
+ 151, 152, 153, 154, 155, 155, 156, 157, 158, 159, 160,
+ 161, 161, 162, 163, 164, 165, 166, 167, 167, 168, 169,
+ 170, 171, 172, 173, 174, 175, 175, 176, 177, 178, 179,
+ 180, 181, 182, 183, 184, 185, 186, 186, 187, 188, 189,
+ 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200,
+ 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211,
+ 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222,
+ 223, 224, 225, 226, 228, 229, 230, 231, 232, 233, 234,
+ 235, 236, 237, 238, 239, 241, 242, 243, 244, 245, 246,
+ 247, 248, 249, 251, 252, 253, 254, 255, 256, 257, 259,
+ 260, 261, 262, 263, 264, 266, 267, 268, 269, 270, 272,
+ 273, 274, 275, 276, 278, 279, 280, 281, 282, 284, 285,
+ 286, 287, 289, 290, 291, 292, 294, 295, 296, 297, 299,
+ 300, 301, 302, 304, 305, 306, 308, 309, 310, 311, 313,
+ 314, 315, 317, 318, 319, 321, 322, 323, 325, 326, 327,
+ 329, 330, 331, 333, 334, 336, 337, 338, 340, 341, 342,
+ 344, 345, 347, 348, 349, 351, 352, 354, 355, 356, 358,
+ 359, 361, 362, 364, 365, 366, 368, 369, 371, 372, 374,
+ 375, 377, 378, 380, 381, 383, 384, 386, 387, 389, 390,
+ 392, 393, 395, 396, 398, 399, 401, 402, 404, 405, 407,
+ 408, 410, 412, 413, 415, 416, 418, 419, 421, 423, 424,
+ 426, 427, 429, 431, 432, 434, 435, 437, 439, 440, 442,
+ 444, 445, 447, 448, 450, 452, 453, 455, 457, 458, 460,
+ 462, 463, 465, 467, 468, 470, 472, 474, 475, 477, 479,
+ 480, 482, 484, 486, 487, 489, 491, 493, 494, 496, 498,
+ 500, 501, 503, 505, 507, 509, 510, 512, 514, 516, 518,
+ 519, 521, 523, 525, 527, 528, 530, 532, 534, 536, 538,
+ 539, 541, 543, 545, 547, 549, 551, 553, 554, 556, 558,
+ 560, 562, 564, 566, 568, 570, 572, 574, 575, 577, 579,
+ 581, 583, 585, 587, 589, 591, 593, 595, 597, 599, 601,
+ 603, 605, 607, 609, 611, 613, 615, 617, 619, 621, 623,
+ 625, 627, 629, 631, 633, 635, 637, 640, 642, 644, 646,
+ 648, 650, 652, 654, 656, 658, 660, 663, 665, 667, 669,
+ 671, 673, 675, 678, 680, 682, 684, 686, 688, 690, 693,
+ 695, 697, 699, 701, 704, 706, 708, 710, 712, 715, 717,
+ 719, 721, 724, 726, 728, 730, 733, 735, 737, 739, 742,
+ 744, 746, 749, 751, 753, 755, 758, 760, 762, 765, 767,
+ 769, 772, 774, 776, 779, 781, 783, 786, 788, 790, 793,
+ 795, 798, 800, 802, 805, 807, 810, 812, 814, 817, 819,
+ 822, 824, 827, 829, 831, 834, 836, 839, 841, 844, 846,
+ 849, 851, 854, 856, 859, 861, 864, 866, 869, 871, 874,
+ 876, 879, 881, 884, 887, 889, 892, 894, 897, 899, 902,
+ 905, 907, 910, 912, 915, 918, 920, 923, 925, 928, 931,
+ 933, 936, 939, 941, 944, 947, 949, 952, 955, 957, 960,
+ 963, 965, 968, 971, 973, 976, 979, 982, 984, 987, 990,
+ 992, 995, 998, 1001, 1004, 1006, 1009, 1012, 1015, 1017, 1020,
+ 1023,
+};
+
+static const u16 xgamma10_29[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9,
+ 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10,
+ 10, 10, 11, 11, 11, 11, 11, 11, 11, 12, 12,
+ 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13,
+ 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15,
+ 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 18,
+ 18, 18, 18, 18, 19, 19, 19, 19, 19, 20, 20,
+ 20, 20, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+ 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25,
+ 25, 26, 26, 26, 26, 27, 27, 27, 28, 28, 28,
+ 28, 29, 29, 29, 29, 30, 30, 30, 31, 31, 31,
+ 31, 32, 32, 32, 33, 33, 33, 34, 34, 34, 35,
+ 35, 35, 35, 36, 36, 36, 37, 37, 37, 38, 38,
+ 38, 39, 39, 39, 40, 40, 41, 41, 41, 42, 42,
+ 42, 43, 43, 43, 44, 44, 44, 45, 45, 46, 46,
+ 46, 47, 47, 48, 48, 48, 49, 49, 49, 50, 50,
+ 51, 51, 52, 52, 52, 53, 53, 54, 54, 54, 55,
+ 55, 56, 56, 57, 57, 57, 58, 58, 59, 59, 60,
+ 60, 61, 61, 61, 62, 62, 63, 63, 64, 64, 65,
+ 65, 66, 66, 67, 67, 68, 68, 69, 69, 70, 70,
+ 71, 71, 72, 72, 73, 73, 74, 74, 75, 75, 76,
+ 76, 77, 77, 78, 78, 79, 80, 80, 81, 81, 82,
+ 82, 83, 83, 84, 85, 85, 86, 86, 87, 87, 88,
+ 89, 89, 90, 90, 91, 92, 92, 93, 93, 94, 95,
+ 95, 96, 96, 97, 98, 98, 99, 99, 100, 101, 101,
+ 102, 103, 103, 104, 105, 105, 106, 107, 107, 108, 109,
+ 109, 110, 111, 111, 112, 113, 113, 114, 115, 115, 116,
+ 117, 117, 118, 119, 120, 120, 121, 122, 122, 123, 124,
+ 125, 125, 126, 127, 128, 128, 129, 130, 131, 131, 132,
+ 133, 134, 134, 135, 136, 137, 137, 138, 139, 140, 141,
+ 141, 142, 143, 144, 145, 145, 146, 147, 148, 149, 149,
+ 150, 151, 152, 153, 154, 154, 155, 156, 157, 158, 159,
+ 160, 160, 161, 162, 163, 164, 165, 166, 166, 167, 168,
+ 169, 170, 171, 172, 173, 174, 175, 175, 176, 177, 178,
+ 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189,
+ 190, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
+ 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210,
+ 211, 212, 214, 215, 216, 217, 218, 219, 220, 221, 222,
+ 223, 224, 225, 226, 227, 228, 229, 231, 232, 233, 234,
+ 235, 236, 237, 238, 239, 241, 242, 243, 244, 245, 246,
+ 247, 248, 250, 251, 252, 253, 254, 255, 257, 258, 259,
+ 260, 261, 263, 264, 265, 266, 267, 269, 270, 271, 272,
+ 273, 275, 276, 277, 278, 280, 281, 282, 283, 285, 286,
+ 287, 288, 290, 291, 292, 293, 295, 296, 297, 299, 300,
+ 301, 302, 304, 305, 306, 308, 309, 310, 312, 313, 314,
+ 316, 317, 318, 320, 321, 322, 324, 325, 327, 328, 329,
+ 331, 332, 333, 335, 336, 338, 339, 340, 342, 343, 345,
+ 346, 348, 349, 350, 352, 353, 355, 356, 358, 359, 361,
+ 362, 363, 365, 366, 368, 369, 371, 372, 374, 375, 377,
+ 378, 380, 381, 383, 384, 386, 388, 389, 391, 392, 394,
+ 395, 397, 398, 400, 402, 403, 405, 406, 408, 409, 411,
+ 413, 414, 416, 417, 419, 421, 422, 424, 426, 427, 429,
+ 430, 432, 434, 435, 437, 439, 440, 442, 444, 445, 447,
+ 449, 450, 452, 454, 456, 457, 459, 461, 462, 464, 466,
+ 468, 469, 471, 473, 475, 476, 478, 480, 482, 483, 485,
+ 487, 489, 491, 492, 494, 496, 498, 500, 501, 503, 505,
+ 507, 509, 511, 512, 514, 516, 518, 520, 522, 524, 525,
+ 527, 529, 531, 533, 535, 537, 539, 541, 542, 544, 546,
+ 548, 550, 552, 554, 556, 558, 560, 562, 564, 566, 568,
+ 570, 572, 574, 576, 578, 580, 582, 584, 586, 588, 590,
+ 592, 594, 596, 598, 600, 602, 604, 606, 608, 610, 612,
+ 614, 616, 618, 621, 623, 625, 627, 629, 631, 633, 635,
+ 637, 640, 642, 644, 646, 648, 650, 652, 655, 657, 659,
+ 661, 663, 665, 668, 670, 672, 674, 676, 679, 681, 683,
+ 685, 688, 690, 692, 694, 697, 699, 701, 703, 706, 708,
+ 710, 712, 715, 717, 719, 722, 724, 726, 729, 731, 733,
+ 736, 738, 740, 743, 745, 747, 750, 752, 754, 757, 759,
+ 762, 764, 766, 769, 771, 774, 776, 778, 781, 783, 786,
+ 788, 791, 793, 795, 798, 800, 803, 805, 808, 810, 813,
+ 815, 818, 820, 823, 825, 828, 830, 833, 835, 838, 841,
+ 843, 846, 848, 851, 853, 856, 859, 861, 864, 866, 869,
+ 872, 874, 877, 879, 882, 885, 887, 890, 893, 895, 898,
+ 901, 903, 906, 909, 911, 914, 917, 919, 922, 925, 927,
+ 930, 933, 936, 938, 941, 944, 947, 949, 952, 955, 958,
+ 960, 963, 966, 969, 972, 974, 977, 980, 983, 986, 989,
+ 991, 994, 997, 1000, 1003, 1006, 1009, 1011, 1014, 1017, 1020,
+ 1023,
+};
+
+static const u16 xgamma10_30[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9,
+ 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10,
+ 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 12,
+ 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13,
+ 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15,
+ 15, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17,
+ 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 20,
+ 20, 20, 20, 21, 21, 21, 21, 21, 22, 22, 22,
+ 22, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25,
+ 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 28,
+ 28, 28, 28, 29, 29, 29, 30, 30, 30, 30, 31,
+ 31, 31, 32, 32, 32, 33, 33, 33, 33, 34, 34,
+ 34, 35, 35, 35, 36, 36, 36, 37, 37, 37, 38,
+ 38, 38, 39, 39, 39, 40, 40, 40, 41, 41, 41,
+ 42, 42, 42, 43, 43, 43, 44, 44, 45, 45, 45,
+ 46, 46, 46, 47, 47, 48, 48, 48, 49, 49, 50,
+ 50, 50, 51, 51, 52, 52, 52, 53, 53, 54, 54,
+ 55, 55, 55, 56, 56, 57, 57, 58, 58, 58, 59,
+ 59, 60, 60, 61, 61, 62, 62, 63, 63, 63, 64,
+ 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 69,
+ 70, 70, 71, 71, 72, 72, 73, 73, 74, 74, 75,
+ 75, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81,
+ 81, 82, 83, 83, 84, 84, 85, 85, 86, 86, 87,
+ 88, 88, 89, 89, 90, 91, 91, 92, 92, 93, 94,
+ 94, 95, 95, 96, 97, 97, 98, 99, 99, 100, 100,
+ 101, 102, 102, 103, 104, 104, 105, 106, 106, 107, 108,
+ 108, 109, 110, 110, 111, 112, 112, 113, 114, 114, 115,
+ 116, 117, 117, 118, 119, 119, 120, 121, 122, 122, 123,
+ 124, 125, 125, 126, 127, 128, 128, 129, 130, 131, 131,
+ 132, 133, 134, 134, 135, 136, 137, 137, 138, 139, 140,
+ 141, 141, 142, 143, 144, 145, 146, 146, 147, 148, 149,
+ 150, 150, 151, 152, 153, 154, 155, 156, 156, 157, 158,
+ 159, 160, 161, 162, 162, 163, 164, 165, 166, 167, 168,
+ 169, 170, 171, 171, 172, 173, 174, 175, 176, 177, 178,
+ 179, 180, 181, 182, 183, 184, 185, 185, 186, 187, 188,
+ 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
+ 200, 201, 202, 203, 204, 205, 206, 207, 208, 210, 211,
+ 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222,
+ 223, 224, 226, 227, 228, 229, 230, 231, 232, 233, 234,
+ 236, 237, 238, 239, 240, 241, 242, 244, 245, 246, 247,
+ 248, 249, 250, 252, 253, 254, 255, 256, 258, 259, 260,
+ 261, 262, 264, 265, 266, 267, 269, 270, 271, 272, 273,
+ 275, 276, 277, 278, 280, 281, 282, 284, 285, 286, 287,
+ 289, 290, 291, 293, 294, 295, 296, 298, 299, 300, 302,
+ 303, 304, 306, 307, 308, 310, 311, 313, 314, 315, 317,
+ 318, 319, 321, 322, 324, 325, 326, 328, 329, 331, 332,
+ 333, 335, 336, 338, 339, 341, 342, 343, 345, 346, 348,
+ 349, 351, 352, 354, 355, 357, 358, 360, 361, 363, 364,
+ 366, 367, 369, 370, 372, 373, 375, 376, 378, 379, 381,
+ 383, 384, 386, 387, 389, 390, 392, 394, 395, 397, 398,
+ 400, 402, 403, 405, 406, 408, 410, 411, 413, 415, 416,
+ 418, 419, 421, 423, 424, 426, 428, 429, 431, 433, 435,
+ 436, 438, 440, 441, 443, 445, 447, 448, 450, 452, 453,
+ 455, 457, 459, 460, 462, 464, 466, 468, 469, 471, 473,
+ 475, 477, 478, 480, 482, 484, 486, 487, 489, 491, 493,
+ 495, 497, 498, 500, 502, 504, 506, 508, 510, 512, 513,
+ 515, 517, 519, 521, 523, 525, 527, 529, 531, 533, 535,
+ 537, 539, 540, 542, 544, 546, 548, 550, 552, 554, 556,
+ 558, 560, 562, 564, 566, 568, 570, 572, 574, 577, 579,
+ 581, 583, 585, 587, 589, 591, 593, 595, 597, 599, 601,
+ 604, 606, 608, 610, 612, 614, 616, 618, 621, 623, 625,
+ 627, 629, 631, 634, 636, 638, 640, 642, 645, 647, 649,
+ 651, 653, 656, 658, 660, 662, 665, 667, 669, 671, 674,
+ 676, 678, 680, 683, 685, 687, 690, 692, 694, 697, 699,
+ 701, 704, 706, 708, 711, 713, 715, 718, 720, 722, 725,
+ 727, 730, 732, 734, 737, 739, 742, 744, 746, 749, 751,
+ 754, 756, 759, 761, 764, 766, 769, 771, 774, 776, 779,
+ 781, 784, 786, 789, 791, 794, 796, 799, 801, 804, 806,
+ 809, 812, 814, 817, 819, 822, 824, 827, 830, 832, 835,
+ 837, 840, 843, 845, 848, 851, 853, 856, 859, 861, 864,
+ 867, 869, 872, 875, 878, 880, 883, 886, 888, 891, 894,
+ 897, 899, 902, 905, 908, 910, 913, 916, 919, 922, 924,
+ 927, 930, 933, 936, 938, 941, 944, 947, 950, 953, 956,
+ 958, 961, 964, 967, 970, 973, 976, 979, 982, 984, 987,
+ 990, 993, 996, 999, 1002, 1005, 1008, 1011, 1014, 1017, 1020,
+ 1023,
+};
+
+static const u16 xgamma10_31[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9,
+ 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10,
+ 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 12,
+ 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13,
+ 13, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15,
+ 15, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17,
+ 17, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19,
+ 20, 20, 20, 20, 21, 21, 21, 21, 21, 22, 22,
+ 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 25,
+ 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27,
+ 28, 28, 28, 28, 29, 29, 29, 30, 30, 30, 30,
+ 31, 31, 31, 32, 32, 32, 32, 33, 33, 33, 34,
+ 34, 34, 35, 35, 35, 36, 36, 36, 36, 37, 37,
+ 37, 38, 38, 38, 39, 39, 39, 40, 40, 41, 41,
+ 41, 42, 42, 42, 43, 43, 43, 44, 44, 44, 45,
+ 45, 46, 46, 46, 47, 47, 47, 48, 48, 49, 49,
+ 49, 50, 50, 51, 51, 51, 52, 52, 53, 53, 54,
+ 54, 54, 55, 55, 56, 56, 57, 57, 57, 58, 58,
+ 59, 59, 60, 60, 61, 61, 61, 62, 62, 63, 63,
+ 64, 64, 65, 65, 66, 66, 67, 67, 68, 68, 69,
+ 69, 70, 70, 71, 71, 72, 72, 73, 73, 74, 74,
+ 75, 75, 76, 76, 77, 77, 78, 79, 79, 80, 80,
+ 81, 81, 82, 82, 83, 84, 84, 85, 85, 86, 86,
+ 87, 88, 88, 89, 89, 90, 91, 91, 92, 92, 93,
+ 94, 94, 95, 95, 96, 97, 97, 98, 99, 99, 100,
+ 101, 101, 102, 102, 103, 104, 104, 105, 106, 106, 107,
+ 108, 108, 109, 110, 111, 111, 112, 113, 113, 114, 115,
+ 115, 116, 117, 118, 118, 119, 120, 120, 121, 122, 123,
+ 123, 124, 125, 126, 126, 127, 128, 129, 129, 130, 131,
+ 132, 132, 133, 134, 135, 136, 136, 137, 138, 139, 140,
+ 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149,
+ 149, 150, 151, 152, 153, 154, 155, 155, 156, 157, 158,
+ 159, 160, 161, 162, 162, 163, 164, 165, 166, 167, 168,
+ 169, 170, 171, 171, 172, 173, 174, 175, 176, 177, 178,
+ 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189,
+ 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200,
+ 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211,
+ 212, 213, 214, 216, 217, 218, 219, 220, 221, 222, 223,
+ 224, 225, 227, 228, 229, 230, 231, 232, 233, 234, 236,
+ 237, 238, 239, 240, 241, 243, 244, 245, 246, 247, 248,
+ 250, 251, 252, 253, 254, 256, 257, 258, 259, 260, 262,
+ 263, 264, 265, 267, 268, 269, 270, 272, 273, 274, 275,
+ 277, 278, 279, 281, 282, 283, 285, 286, 287, 288, 290,
+ 291, 292, 294, 295, 296, 298, 299, 300, 302, 303, 305,
+ 306, 307, 309, 310, 311, 313, 314, 316, 317, 318, 320,
+ 321, 323, 324, 325, 327, 328, 330, 331, 333, 334, 336,
+ 337, 338, 340, 341, 343, 344, 346, 347, 349, 350, 352,
+ 353, 355, 356, 358, 359, 361, 362, 364, 366, 367, 369,
+ 370, 372, 373, 375, 376, 378, 380, 381, 383, 384, 386,
+ 388, 389, 391, 392, 394, 396, 397, 399, 401, 402, 404,
+ 406, 407, 409, 411, 412, 414, 416, 417, 419, 421, 422,
+ 424, 426, 427, 429, 431, 433, 434, 436, 438, 440, 441,
+ 443, 445, 447, 448, 450, 452, 454, 456, 457, 459, 461,
+ 463, 465, 466, 468, 470, 472, 474, 476, 477, 479, 481,
+ 483, 485, 487, 489, 490, 492, 494, 496, 498, 500, 502,
+ 504, 506, 508, 510, 511, 513, 515, 517, 519, 521, 523,
+ 525, 527, 529, 531, 533, 535, 537, 539, 541, 543, 545,
+ 547, 549, 551, 553, 555, 557, 559, 561, 564, 566, 568,
+ 570, 572, 574, 576, 578, 580, 582, 584, 587, 589, 591,
+ 593, 595, 597, 599, 602, 604, 606, 608, 610, 613, 615,
+ 617, 619, 621, 624, 626, 628, 630, 632, 635, 637, 639,
+ 641, 644, 646, 648, 651, 653, 655, 657, 660, 662, 664,
+ 667, 669, 671, 674, 676, 678, 681, 683, 685, 688, 690,
+ 692, 695, 697, 700, 702, 704, 707, 709, 712, 714, 717,
+ 719, 721, 724, 726, 729, 731, 734, 736, 739, 741, 744,
+ 746, 749, 751, 754, 756, 759, 761, 764, 766, 769, 772,
+ 774, 777, 779, 782, 784, 787, 790, 792, 795, 797, 800,
+ 803, 805, 808, 811, 813, 816, 819, 821, 824, 827, 829,
+ 832, 835, 837, 840, 843, 845, 848, 851, 854, 856, 859,
+ 862, 865, 867, 870, 873, 876, 879, 881, 884, 887, 890,
+ 893, 895, 898, 901, 904, 907, 910, 913, 915, 918, 921,
+ 924, 927, 930, 933, 936, 939, 942, 945, 947, 950, 953,
+ 956, 959, 962, 965, 968, 971, 974, 977, 980, 983, 986,
+ 989, 992, 995, 998, 1001, 1005, 1008, 1011, 1014, 1017, 1020,
+ 1023,
+};
+
+static const u16 xgamma10_32[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10,
+ 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 12,
+ 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13,
+ 13, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15,
+ 15, 15, 16, 16, 16, 16, 16, 17, 17, 17, 17,
+ 17, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19,
+ 20, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22,
+ 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24,
+ 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27,
+ 27, 28, 28, 28, 28, 29, 29, 29, 30, 30, 30,
+ 30, 31, 31, 31, 32, 32, 32, 32, 33, 33, 33,
+ 34, 34, 34, 35, 35, 35, 36, 36, 36, 37, 37,
+ 37, 37, 38, 38, 38, 39, 39, 39, 40, 40, 41,
+ 41, 41, 42, 42, 42, 43, 43, 43, 44, 44, 44,
+ 45, 45, 46, 46, 46, 47, 47, 48, 48, 48, 49,
+ 49, 49, 50, 50, 51, 51, 51, 52, 52, 53, 53,
+ 54, 54, 54, 55, 55, 56, 56, 57, 57, 57, 58,
+ 58, 59, 59, 60, 60, 61, 61, 62, 62, 62, 63,
+ 63, 64, 64, 65, 65, 66, 66, 67, 67, 68, 68,
+ 69, 69, 70, 70, 71, 71, 72, 72, 73, 73, 74,
+ 74, 75, 75, 76, 77, 77, 78, 78, 79, 79, 80,
+ 80, 81, 81, 82, 83, 83, 84, 84, 85, 85, 86,
+ 87, 87, 88, 88, 89, 90, 90, 91, 91, 92, 93,
+ 93, 94, 95, 95, 96, 96, 97, 98, 98, 99, 100,
+ 100, 101, 102, 102, 103, 104, 104, 105, 106, 106, 107,
+ 108, 108, 109, 110, 110, 111, 112, 112, 113, 114, 114,
+ 115, 116, 117, 117, 118, 119, 120, 120, 121, 122, 122,
+ 123, 124, 125, 125, 126, 127, 128, 129, 129, 130, 131,
+ 132, 132, 133, 134, 135, 136, 136, 137, 138, 139, 140,
+ 140, 141, 142, 143, 144, 145, 145, 146, 147, 148, 149,
+ 150, 150, 151, 152, 153, 154, 155, 156, 157, 157, 158,
+ 159, 160, 161, 162, 163, 164, 165, 166, 166, 167, 168,
+ 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
+ 180, 181, 182, 183, 184, 185, 186, 186, 187, 188, 189,
+ 190, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201,
+ 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212,
+ 214, 215, 216, 217, 218, 219, 220, 221, 222, 224, 225,
+ 226, 227, 228, 229, 230, 231, 233, 234, 235, 236, 237,
+ 238, 240, 241, 242, 243, 244, 246, 247, 248, 249, 250,
+ 252, 253, 254, 255, 257, 258, 259, 260, 262, 263, 264,
+ 265, 267, 268, 269, 270, 272, 273, 274, 276, 277, 278,
+ 280, 281, 282, 283, 285, 286, 287, 289, 290, 291, 293,
+ 294, 296, 297, 298, 300, 301, 302, 304, 305, 307, 308,
+ 309, 311, 312, 314, 315, 316, 318, 319, 321, 322, 324,
+ 325, 327, 328, 330, 331, 332, 334, 335, 337, 338, 340,
+ 341, 343, 344, 346, 347, 349, 351, 352, 354, 355, 357,
+ 358, 360, 361, 363, 364, 366, 368, 369, 371, 372, 374,
+ 376, 377, 379, 380, 382, 384, 385, 387, 389, 390, 392,
+ 394, 395, 397, 399, 400, 402, 404, 405, 407, 409, 410,
+ 412, 414, 416, 417, 419, 421, 423, 424, 426, 428, 430,
+ 431, 433, 435, 437, 438, 440, 442, 444, 446, 447, 449,
+ 451, 453, 455, 457, 458, 460, 462, 464, 466, 468, 469,
+ 471, 473, 475, 477, 479, 481, 483, 485, 487, 488, 490,
+ 492, 494, 496, 498, 500, 502, 504, 506, 508, 510, 512,
+ 514, 516, 518, 520, 522, 524, 526, 528, 530, 532, 534,
+ 536, 538, 540, 542, 544, 547, 549, 551, 553, 555, 557,
+ 559, 561, 563, 565, 568, 570, 572, 574, 576, 578, 581,
+ 583, 585, 587, 589, 591, 594, 596, 598, 600, 602, 605,
+ 607, 609, 611, 614, 616, 618, 620, 623, 625, 627, 630,
+ 632, 634, 636, 639, 641, 643, 646, 648, 650, 653, 655,
+ 657, 660, 662, 665, 667, 669, 672, 674, 677, 679, 681,
+ 684, 686, 689, 691, 694, 696, 698, 701, 703, 706, 708,
+ 711, 713, 716, 718, 721, 723, 726, 728, 731, 734, 736,
+ 739, 741, 744, 746, 749, 751, 754, 757, 759, 762, 765,
+ 767, 770, 772, 775, 778, 780, 783, 786, 788, 791, 794,
+ 796, 799, 802, 804, 807, 810, 813, 815, 818, 821, 824,
+ 826, 829, 832, 835, 838, 840, 843, 846, 849, 852, 854,
+ 857, 860, 863, 866, 869, 871, 874, 877, 880, 883, 886,
+ 889, 892, 895, 897, 900, 903, 906, 909, 912, 915, 918,
+ 921, 924, 927, 930, 933, 936, 939, 942, 945, 948, 951,
+ 954, 957, 960, 963, 967, 970, 973, 976, 979, 982, 985,
+ 988, 991, 994, 998, 1001, 1004, 1007, 1010, 1013, 1017, 1020,
+ 1023,
+};
+
+static const u16 xgamma10_33[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9,
+ 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10,
+ 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 12,
+ 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13,
+ 13, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15,
+ 15, 15, 16, 16, 16, 16, 16, 17, 17, 17, 17,
+ 17, 17, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+ 19, 20, 20, 20, 20, 21, 21, 21, 21, 21, 22,
+ 22, 22, 22, 23, 23, 23, 23, 23, 24, 24, 24,
+ 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27,
+ 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30,
+ 30, 31, 31, 31, 31, 32, 32, 32, 33, 33, 33,
+ 33, 34, 34, 34, 35, 35, 35, 36, 36, 36, 37,
+ 37, 37, 38, 38, 38, 39, 39, 39, 40, 40, 40,
+ 41, 41, 41, 42, 42, 42, 43, 43, 44, 44, 44,
+ 45, 45, 45, 46, 46, 47, 47, 47, 48, 48, 48,
+ 49, 49, 50, 50, 50, 51, 51, 52, 52, 53, 53,
+ 53, 54, 54, 55, 55, 55, 56, 56, 57, 57, 58,
+ 58, 59, 59, 59, 60, 60, 61, 61, 62, 62, 63,
+ 63, 64, 64, 65, 65, 66, 66, 67, 67, 68, 68,
+ 69, 69, 70, 70, 71, 71, 72, 72, 73, 73, 74,
+ 74, 75, 75, 76, 76, 77, 77, 78, 79, 79, 80,
+ 80, 81, 81, 82, 82, 83, 84, 84, 85, 85, 86,
+ 87, 87, 88, 88, 89, 90, 90, 91, 91, 92, 93,
+ 93, 94, 94, 95, 96, 96, 97, 98, 98, 99, 100,
+ 100, 101, 102, 102, 103, 104, 104, 105, 106, 106, 107,
+ 108, 108, 109, 110, 110, 111, 112, 112, 113, 114, 115,
+ 115, 116, 117, 118, 118, 119, 120, 120, 121, 122, 123,
+ 123, 124, 125, 126, 127, 127, 128, 129, 130, 130, 131,
+ 132, 133, 134, 134, 135, 136, 137, 138, 138, 139, 140,
+ 141, 142, 143, 143, 144, 145, 146, 147, 148, 148, 149,
+ 150, 151, 152, 153, 154, 155, 155, 156, 157, 158, 159,
+ 160, 161, 162, 163, 164, 165, 165, 166, 167, 168, 169,
+ 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
+ 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
+ 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202,
+ 203, 204, 206, 207, 208, 209, 210, 211, 212, 213, 214,
+ 215, 216, 218, 219, 220, 221, 222, 223, 224, 226, 227,
+ 228, 229, 230, 231, 233, 234, 235, 236, 237, 238, 240,
+ 241, 242, 243, 245, 246, 247, 248, 249, 251, 252, 253,
+ 254, 256, 257, 258, 259, 261, 262, 263, 265, 266, 267,
+ 268, 270, 271, 272, 274, 275, 276, 278, 279, 280, 282,
+ 283, 284, 286, 287, 288, 290, 291, 292, 294, 295, 297,
+ 298, 299, 301, 302, 304, 305, 307, 308, 309, 311, 312,
+ 314, 315, 317, 318, 320, 321, 322, 324, 325, 327, 328,
+ 330, 331, 333, 334, 336, 337, 339, 341, 342, 344, 345,
+ 347, 348, 350, 351, 353, 355, 356, 358, 359, 361, 362,
+ 364, 366, 367, 369, 371, 372, 374, 375, 377, 379, 380,
+ 382, 384, 385, 387, 389, 390, 392, 394, 395, 397, 399,
+ 401, 402, 404, 406, 408, 409, 411, 413, 414, 416, 418,
+ 420, 422, 423, 425, 427, 429, 431, 432, 434, 436, 438,
+ 440, 441, 443, 445, 447, 449, 451, 453, 454, 456, 458,
+ 460, 462, 464, 466, 468, 470, 472, 473, 475, 477, 479,
+ 481, 483, 485, 487, 489, 491, 493, 495, 497, 499, 501,
+ 503, 505, 507, 509, 511, 513, 515, 517, 519, 521, 523,
+ 525, 528, 530, 532, 534, 536, 538, 540, 542, 544, 547,
+ 549, 551, 553, 555, 557, 559, 562, 564, 566, 568, 570,
+ 573, 575, 577, 579, 581, 584, 586, 588, 590, 593, 595,
+ 597, 599, 602, 604, 606, 609, 611, 613, 615, 618, 620,
+ 622, 625, 627, 629, 632, 634, 637, 639, 641, 644, 646,
+ 648, 651, 653, 656, 658, 661, 663, 665, 668, 670, 673,
+ 675, 678, 680, 683, 685, 688, 690, 693, 695, 698, 700,
+ 703, 705, 708, 710, 713, 716, 718, 721, 723, 726, 729,
+ 731, 734, 736, 739, 742, 744, 747, 750, 752, 755, 758,
+ 760, 763, 766, 768, 771, 774, 776, 779, 782, 785, 787,
+ 790, 793, 796, 798, 801, 804, 807, 810, 812, 815, 818,
+ 821, 824, 827, 829, 832, 835, 838, 841, 844, 847, 850,
+ 852, 855, 858, 861, 864, 867, 870, 873, 876, 879, 882,
+ 885, 888, 891, 894, 897, 900, 903, 906, 909, 912, 915,
+ 918, 921, 924, 927, 930, 933, 937, 940, 943, 946, 949,
+ 952, 955, 958, 962, 965, 968, 971, 974, 978, 981, 984,
+ 987, 990, 994, 997, 1000, 1003, 1007, 1010, 1013, 1016, 1020,
+ 1023,
+};
+
+static const u16 xgamma10_34[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9,
+ 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10,
+ 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 12,
+ 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13,
+ 13, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15,
+ 15, 15, 16, 16, 16, 16, 16, 17, 17, 17, 17,
+ 17, 17, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+ 19, 20, 20, 20, 20, 21, 21, 21, 21, 21, 22,
+ 22, 22, 22, 23, 23, 23, 23, 23, 24, 24, 24,
+ 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27,
+ 27, 27, 28, 28, 28, 29, 29, 29, 29, 30, 30,
+ 30, 30, 31, 31, 31, 32, 32, 32, 33, 33, 33,
+ 33, 34, 34, 34, 35, 35, 35, 36, 36, 36, 37,
+ 37, 37, 38, 38, 38, 39, 39, 39, 40, 40, 40,
+ 41, 41, 41, 42, 42, 42, 43, 43, 43, 44, 44,
+ 45, 45, 45, 46, 46, 46, 47, 47, 48, 48, 48,
+ 49, 49, 50, 50, 50, 51, 51, 52, 52, 52, 53,
+ 53, 54, 54, 55, 55, 55, 56, 56, 57, 57, 58,
+ 58, 59, 59, 59, 60, 60, 61, 61, 62, 62, 63,
+ 63, 64, 64, 65, 65, 66, 66, 67, 67, 68, 68,
+ 69, 69, 70, 70, 71, 71, 72, 72, 73, 73, 74,
+ 74, 75, 75, 76, 76, 77, 78, 78, 79, 79, 80,
+ 80, 81, 81, 82, 83, 83, 84, 84, 85, 86, 86,
+ 87, 87, 88, 88, 89, 90, 90, 91, 92, 92, 93,
+ 93, 94, 95, 95, 96, 97, 97, 98, 99, 99, 100,
+ 101, 101, 102, 102, 103, 104, 105, 105, 106, 107, 107,
+ 108, 109, 109, 110, 111, 111, 112, 113, 114, 114, 115,
+ 116, 117, 117, 118, 119, 119, 120, 121, 122, 123, 123,
+ 124, 125, 126, 126, 127, 128, 129, 129, 130, 131, 132,
+ 133, 133, 134, 135, 136, 137, 138, 138, 139, 140, 141,
+ 142, 143, 143, 144, 145, 146, 147, 148, 149, 149, 150,
+ 151, 152, 153, 154, 155, 156, 157, 157, 158, 159, 160,
+ 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171,
+ 172, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181,
+ 182, 183, 184, 185, 186, 187, 188, 189, 191, 192, 193,
+ 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204,
+ 205, 207, 208, 209, 210, 211, 212, 213, 214, 215, 217,
+ 218, 219, 220, 221, 222, 223, 225, 226, 227, 228, 229,
+ 231, 232, 233, 234, 235, 237, 238, 239, 240, 241, 243,
+ 244, 245, 246, 248, 249, 250, 251, 253, 254, 255, 256,
+ 258, 259, 260, 262, 263, 264, 266, 267, 268, 269, 271,
+ 272, 273, 275, 276, 278, 279, 280, 282, 283, 284, 286,
+ 287, 288, 290, 291, 293, 294, 296, 297, 298, 300, 301,
+ 303, 304, 306, 307, 308, 310, 311, 313, 314, 316, 317,
+ 319, 320, 322, 323, 325, 326, 328, 329, 331, 332, 334,
+ 335, 337, 339, 340, 342, 343, 345, 346, 348, 350, 351,
+ 353, 354, 356, 358, 359, 361, 363, 364, 366, 367, 369,
+ 371, 372, 374, 376, 377, 379, 381, 383, 384, 386, 388,
+ 389, 391, 393, 395, 396, 398, 400, 402, 403, 405, 407,
+ 409, 410, 412, 414, 416, 418, 419, 421, 423, 425, 427,
+ 429, 430, 432, 434, 436, 438, 440, 442, 443, 445, 447,
+ 449, 451, 453, 455, 457, 459, 461, 463, 464, 466, 468,
+ 470, 472, 474, 476, 478, 480, 482, 484, 486, 488, 490,
+ 492, 494, 496, 498, 500, 503, 505, 507, 509, 511, 513,
+ 515, 517, 519, 521, 523, 526, 528, 530, 532, 534, 536,
+ 538, 541, 543, 545, 547, 549, 551, 554, 556, 558, 560,
+ 563, 565, 567, 569, 572, 574, 576, 578, 581, 583, 585,
+ 587, 590, 592, 594, 597, 599, 601, 604, 606, 608, 611,
+ 613, 615, 618, 620, 623, 625, 627, 630, 632, 635, 637,
+ 640, 642, 644, 647, 649, 652, 654, 657, 659, 662, 664,
+ 667, 669, 672, 674, 677, 679, 682, 685, 687, 690, 692,
+ 695, 697, 700, 703, 705, 708, 711, 713, 716, 718, 721,
+ 724, 726, 729, 732, 734, 737, 740, 743, 745, 748, 751,
+ 753, 756, 759, 762, 764, 767, 770, 773, 776, 778, 781,
+ 784, 787, 790, 793, 795, 798, 801, 804, 807, 810, 813,
+ 815, 818, 821, 824, 827, 830, 833, 836, 839, 842, 845,
+ 848, 851, 854, 857, 860, 863, 866, 869, 872, 875, 878,
+ 881, 884, 887, 890, 893, 896, 899, 903, 906, 909, 912,
+ 915, 918, 921, 925, 928, 931, 934, 937, 940, 944, 947,
+ 950, 953, 957, 960, 963, 966, 970, 973, 976, 979, 983,
+ 986, 989, 993, 996, 999, 1003, 1006, 1009, 1013, 1016, 1020,
+ 1023,
+};
+
+static const u16 xgamma10_35[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9,
+ 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10,
+ 10, 10, 11, 11, 11, 11, 11, 11, 11, 12, 12,
+ 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13,
+ 13, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15,
+ 15, 15, 16, 16, 16, 16, 16, 17, 17, 17, 17,
+ 17, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+ 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 22,
+ 22, 22, 22, 23, 23, 23, 23, 23, 24, 24, 24,
+ 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27,
+ 27, 27, 28, 28, 28, 29, 29, 29, 29, 30, 30,
+ 30, 31, 31, 31, 31, 32, 32, 32, 33, 33, 33,
+ 33, 34, 34, 34, 35, 35, 35, 36, 36, 36, 37,
+ 37, 37, 38, 38, 38, 39, 39, 39, 40, 40, 40,
+ 41, 41, 41, 42, 42, 42, 43, 43, 43, 44, 44,
+ 45, 45, 45, 46, 46, 47, 47, 47, 48, 48, 48,
+ 49, 49, 50, 50, 50, 51, 51, 52, 52, 53, 53,
+ 53, 54, 54, 55, 55, 56, 56, 56, 57, 57, 58,
+ 58, 59, 59, 60, 60, 60, 61, 61, 62, 62, 63,
+ 63, 64, 64, 65, 65, 66, 66, 67, 67, 68, 68,
+ 69, 69, 70, 70, 71, 71, 72, 72, 73, 73, 74,
+ 75, 75, 76, 76, 77, 77, 78, 78, 79, 79, 80,
+ 81, 81, 82, 82, 83, 84, 84, 85, 85, 86, 86,
+ 87, 88, 88, 89, 89, 90, 91, 91, 92, 93, 93,
+ 94, 95, 95, 96, 96, 97, 98, 98, 99, 100, 100,
+ 101, 102, 102, 103, 104, 104, 105, 106, 107, 107, 108,
+ 109, 109, 110, 111, 111, 112, 113, 114, 114, 115, 116,
+ 117, 117, 118, 119, 120, 120, 121, 122, 123, 123, 124,
+ 125, 126, 126, 127, 128, 129, 130, 130, 131, 132, 133,
+ 134, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142,
+ 143, 144, 145, 146, 146, 147, 148, 149, 150, 151, 152,
+ 153, 154, 154, 155, 156, 157, 158, 159, 160, 161, 162,
+ 163, 164, 165, 166, 167, 167, 168, 169, 170, 171, 172,
+ 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183,
+ 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195,
+ 196, 197, 198, 199, 200, 201, 202, 204, 205, 206, 207,
+ 208, 209, 210, 211, 213, 214, 215, 216, 217, 218, 219,
+ 221, 222, 223, 224, 225, 227, 228, 229, 230, 231, 233,
+ 234, 235, 236, 237, 239, 240, 241, 242, 244, 245, 246,
+ 247, 249, 250, 251, 253, 254, 255, 256, 258, 259, 260,
+ 262, 263, 264, 266, 267, 268, 270, 271, 272, 274, 275,
+ 277, 278, 279, 281, 282, 284, 285, 286, 288, 289, 291,
+ 292, 293, 295, 296, 298, 299, 301, 302, 304, 305, 307,
+ 308, 310, 311, 313, 314, 316, 317, 319, 320, 322, 323,
+ 325, 326, 328, 329, 331, 332, 334, 336, 337, 339, 340,
+ 342, 344, 345, 347, 348, 350, 352, 353, 355, 357, 358,
+ 360, 362, 363, 365, 367, 368, 370, 372, 373, 375, 377,
+ 378, 380, 382, 384, 385, 387, 389, 391, 392, 394, 396,
+ 398, 400, 401, 403, 405, 407, 409, 410, 412, 414, 416,
+ 418, 420, 421, 423, 425, 427, 429, 431, 433, 435, 436,
+ 438, 440, 442, 444, 446, 448, 450, 452, 454, 456, 458,
+ 460, 462, 464, 466, 468, 470, 472, 474, 476, 478, 480,
+ 482, 484, 486, 488, 490, 492, 494, 496, 498, 500, 503,
+ 505, 507, 509, 511, 513, 515, 517, 520, 522, 524, 526,
+ 528, 531, 533, 535, 537, 539, 542, 544, 546, 548, 550,
+ 553, 555, 557, 560, 562, 564, 566, 569, 571, 573, 576,
+ 578, 580, 583, 585, 587, 590, 592, 594, 597, 599, 602,
+ 604, 606, 609, 611, 614, 616, 618, 621, 623, 626, 628,
+ 631, 633, 636, 638, 641, 643, 646, 648, 651, 653, 656,
+ 658, 661, 664, 666, 669, 671, 674, 677, 679, 682, 684,
+ 687, 690, 692, 695, 698, 700, 703, 706, 708, 711, 714,
+ 716, 719, 722, 725, 727, 730, 733, 736, 738, 741, 744,
+ 747, 750, 752, 755, 758, 761, 764, 766, 769, 772, 775,
+ 778, 781, 784, 787, 789, 792, 795, 798, 801, 804, 807,
+ 810, 813, 816, 819, 822, 825, 828, 831, 834, 837, 840,
+ 843, 846, 849, 852, 855, 858, 862, 865, 868, 871, 874,
+ 877, 880, 883, 887, 890, 893, 896, 899, 902, 906, 909,
+ 912, 915, 919, 922, 925, 928, 932, 935, 938, 941, 945,
+ 948, 951, 955, 958, 961, 965, 968, 971, 975, 978, 982,
+ 985, 988, 992, 995, 999, 1002, 1006, 1009, 1013, 1016, 1020,
+ 1023,
+};
+
+static const u16 xgamma10_36[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9,
+ 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10,
+ 10, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12,
+ 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13,
+ 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15,
+ 15, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17,
+ 17, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19,
+ 20, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22,
+ 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24,
+ 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27,
+ 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30,
+ 30, 31, 31, 31, 31, 32, 32, 32, 33, 33, 33,
+ 34, 34, 34, 35, 35, 35, 35, 36, 36, 36, 37,
+ 37, 37, 38, 38, 38, 39, 39, 39, 40, 40, 40,
+ 41, 41, 41, 42, 42, 43, 43, 43, 44, 44, 44,
+ 45, 45, 46, 46, 46, 47, 47, 47, 48, 48, 49,
+ 49, 49, 50, 50, 51, 51, 52, 52, 52, 53, 53,
+ 54, 54, 54, 55, 55, 56, 56, 57, 57, 58, 58,
+ 58, 59, 59, 60, 60, 61, 61, 62, 62, 63, 63,
+ 64, 64, 65, 65, 66, 66, 67, 67, 68, 68, 69,
+ 69, 70, 70, 71, 71, 72, 72, 73, 73, 74, 74,
+ 75, 76, 76, 77, 77, 78, 78, 79, 79, 80, 81,
+ 81, 82, 82, 83, 83, 84, 85, 85, 86, 86, 87,
+ 88, 88, 89, 90, 90, 91, 91, 92, 93, 93, 94,
+ 95, 95, 96, 97, 97, 98, 99, 99, 100, 101, 101,
+ 102, 103, 103, 104, 105, 105, 106, 107, 107, 108, 109,
+ 110, 110, 111, 112, 112, 113, 114, 115, 115, 116, 117,
+ 118, 118, 119, 120, 121, 121, 122, 123, 124, 125, 125,
+ 126, 127, 128, 129, 129, 130, 131, 132, 133, 133, 134,
+ 135, 136, 137, 138, 138, 139, 140, 141, 142, 143, 144,
+ 145, 145, 146, 147, 148, 149, 150, 151, 152, 153, 153,
+ 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
+ 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
+ 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186,
+ 187, 188, 189, 190, 191, 192, 193, 194, 196, 197, 198,
+ 199, 200, 201, 202, 203, 204, 205, 207, 208, 209, 210,
+ 211, 212, 214, 215, 216, 217, 218, 219, 221, 222, 223,
+ 224, 225, 227, 228, 229, 230, 231, 233, 234, 235, 236,
+ 238, 239, 240, 241, 243, 244, 245, 247, 248, 249, 250,
+ 252, 253, 254, 256, 257, 258, 260, 261, 262, 264, 265,
+ 266, 268, 269, 271, 272, 273, 275, 276, 277, 279, 280,
+ 282, 283, 285, 286, 287, 289, 290, 292, 293, 295, 296,
+ 298, 299, 301, 302, 304, 305, 307, 308, 310, 311, 313,
+ 314, 316, 317, 319, 320, 322, 324, 325, 327, 328, 330,
+ 331, 333, 335, 336, 338, 339, 341, 343, 344, 346, 348,
+ 349, 351, 353, 354, 356, 358, 359, 361, 363, 364, 366,
+ 368, 370, 371, 373, 375, 377, 378, 380, 382, 384, 385,
+ 387, 389, 391, 393, 394, 396, 398, 400, 402, 403, 405,
+ 407, 409, 411, 413, 415, 416, 418, 420, 422, 424, 426,
+ 428, 430, 432, 434, 436, 438, 439, 441, 443, 445, 447,
+ 449, 451, 453, 455, 457, 459, 461, 463, 465, 467, 470,
+ 472, 474, 476, 478, 480, 482, 484, 486, 488, 490, 492,
+ 495, 497, 499, 501, 503, 505, 508, 510, 512, 514, 516,
+ 518, 521, 523, 525, 527, 530, 532, 534, 536, 539, 541,
+ 543, 545, 548, 550, 552, 555, 557, 559, 562, 564, 566,
+ 569, 571, 573, 576, 578, 580, 583, 585, 588, 590, 592,
+ 595, 597, 600, 602, 605, 607, 610, 612, 615, 617, 620,
+ 622, 625, 627, 630, 632, 635, 637, 640, 642, 645, 648,
+ 650, 653, 655, 658, 661, 663, 666, 669, 671, 674, 677,
+ 679, 682, 685, 687, 690, 693, 695, 698, 701, 704, 706,
+ 709, 712, 715, 717, 720, 723, 726, 729, 732, 734, 737,
+ 740, 743, 746, 749, 751, 754, 757, 760, 763, 766, 769,
+ 772, 775, 778, 781, 784, 787, 790, 793, 796, 799, 802,
+ 805, 808, 811, 814, 817, 820, 823, 826, 829, 832, 835,
+ 838, 842, 845, 848, 851, 854, 857, 860, 864, 867, 870,
+ 873, 876, 880, 883, 886, 889, 893, 896, 899, 903, 906,
+ 909, 912, 916, 919, 922, 926, 929, 932, 936, 939, 943,
+ 946, 949, 953, 956, 960, 963, 967, 970, 973, 977, 980,
+ 984, 987, 991, 994, 998, 1002, 1005, 1009, 1012, 1016, 1019,
+ 1023,
+};
+
+static const u16 xgamma10_37[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9,
+ 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
+ 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12,
+ 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 14,
+ 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15,
+ 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17,
+ 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 20,
+ 20, 20, 20, 20, 21, 21, 21, 21, 21, 22, 22,
+ 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 24,
+ 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27,
+ 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30,
+ 31, 31, 31, 31, 32, 32, 32, 33, 33, 33, 33,
+ 34, 34, 34, 35, 35, 35, 36, 36, 36, 37, 37,
+ 37, 38, 38, 38, 39, 39, 39, 40, 40, 40, 41,
+ 41, 41, 42, 42, 42, 43, 43, 44, 44, 44, 45,
+ 45, 45, 46, 46, 47, 47, 47, 48, 48, 49, 49,
+ 49, 50, 50, 51, 51, 51, 52, 52, 53, 53, 54,
+ 54, 54, 55, 55, 56, 56, 57, 57, 58, 58, 58,
+ 59, 59, 60, 60, 61, 61, 62, 62, 63, 63, 64,
+ 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 69,
+ 70, 70, 71, 71, 72, 72, 73, 73, 74, 75, 75,
+ 76, 76, 77, 77, 78, 78, 79, 80, 80, 81, 81,
+ 82, 82, 83, 84, 84, 85, 85, 86, 87, 87, 88,
+ 89, 89, 90, 90, 91, 92, 92, 93, 94, 94, 95,
+ 96, 96, 97, 98, 98, 99, 100, 100, 101, 102, 102,
+ 103, 104, 104, 105, 106, 106, 107, 108, 109, 109, 110,
+ 111, 112, 112, 113, 114, 114, 115, 116, 117, 118, 118,
+ 119, 120, 121, 121, 122, 123, 124, 125, 125, 126, 127,
+ 128, 129, 129, 130, 131, 132, 133, 134, 134, 135, 136,
+ 137, 138, 139, 139, 140, 141, 142, 143, 144, 145, 146,
+ 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156,
+ 157, 158, 158, 159, 160, 161, 162, 163, 164, 165, 166,
+ 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177,
+ 178, 179, 180, 181, 182, 184, 185, 186, 187, 188, 189,
+ 190, 191, 192, 193, 194, 195, 197, 198, 199, 200, 201,
+ 202, 203, 204, 206, 207, 208, 209, 210, 211, 213, 214,
+ 215, 216, 217, 218, 220, 221, 222, 223, 225, 226, 227,
+ 228, 229, 231, 232, 233, 234, 236, 237, 238, 240, 241,
+ 242, 243, 245, 246, 247, 249, 250, 251, 253, 254, 255,
+ 257, 258, 259, 261, 262, 263, 265, 266, 268, 269, 270,
+ 272, 273, 275, 276, 277, 279, 280, 282, 283, 285, 286,
+ 288, 289, 291, 292, 294, 295, 297, 298, 300, 301, 303,
+ 304, 306, 307, 309, 310, 312, 313, 315, 316, 318, 320,
+ 321, 323, 324, 326, 328, 329, 331, 332, 334, 336, 337,
+ 339, 341, 342, 344, 346, 347, 349, 351, 352, 354, 356,
+ 358, 359, 361, 363, 364, 366, 368, 370, 372, 373, 375,
+ 377, 379, 380, 382, 384, 386, 388, 389, 391, 393, 395,
+ 397, 399, 401, 402, 404, 406, 408, 410, 412, 414, 416,
+ 418, 420, 421, 423, 425, 427, 429, 431, 433, 435, 437,
+ 439, 441, 443, 445, 447, 449, 451, 453, 455, 457, 459,
+ 462, 464, 466, 468, 470, 472, 474, 476, 478, 480, 483,
+ 485, 487, 489, 491, 493, 496, 498, 500, 502, 504, 507,
+ 509, 511, 513, 515, 518, 520, 522, 524, 527, 529, 531,
+ 534, 536, 538, 541, 543, 545, 548, 550, 552, 555, 557,
+ 559, 562, 564, 567, 569, 571, 574, 576, 579, 581, 584,
+ 586, 589, 591, 593, 596, 598, 601, 603, 606, 609, 611,
+ 614, 616, 619, 621, 624, 626, 629, 632, 634, 637, 639,
+ 642, 645, 647, 650, 653, 655, 658, 661, 663, 666, 669,
+ 672, 674, 677, 680, 682, 685, 688, 691, 694, 696, 699,
+ 702, 705, 708, 710, 713, 716, 719, 722, 725, 728, 730,
+ 733, 736, 739, 742, 745, 748, 751, 754, 757, 760, 763,
+ 766, 769, 772, 775, 778, 781, 784, 787, 790, 793, 796,
+ 799, 802, 805, 809, 812, 815, 818, 821, 824, 827, 831,
+ 834, 837, 840, 843, 847, 850, 853, 856, 860, 863, 866,
+ 869, 873, 876, 879, 883, 886, 889, 893, 896, 899, 903,
+ 906, 910, 913, 916, 920, 923, 927, 930, 934, 937, 940,
+ 944, 947, 951, 954, 958, 961, 965, 969, 972, 976, 979,
+ 983, 986, 990, 994, 997, 1001, 1005, 1008, 1012, 1016, 1019,
+ 1023,
+};
+
+static const u16 xgamma10_38[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11,
+ 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12,
+ 12, 12, 13, 13, 13, 13, 13, 13, 13, 14, 14,
+ 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 16,
+ 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 18,
+ 18, 18, 18, 18, 19, 19, 19, 19, 19, 20, 20,
+ 20, 20, 20, 21, 21, 21, 21, 21, 22, 22, 22,
+ 22, 23, 23, 23, 23, 24, 24, 24, 24, 24, 25,
+ 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 28,
+ 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 31,
+ 31, 31, 31, 32, 32, 32, 33, 33, 33, 33, 34,
+ 34, 34, 35, 35, 35, 36, 36, 36, 37, 37, 37,
+ 38, 38, 38, 39, 39, 39, 40, 40, 40, 41, 41,
+ 41, 42, 42, 43, 43, 43, 44, 44, 44, 45, 45,
+ 46, 46, 46, 47, 47, 47, 48, 48, 49, 49, 49,
+ 50, 50, 51, 51, 52, 52, 52, 53, 53, 54, 54,
+ 55, 55, 55, 56, 56, 57, 57, 58, 58, 59, 59,
+ 60, 60, 60, 61, 61, 62, 62, 63, 63, 64, 64,
+ 65, 65, 66, 66, 67, 67, 68, 68, 69, 69, 70,
+ 70, 71, 72, 72, 73, 73, 74, 74, 75, 75, 76,
+ 76, 77, 78, 78, 79, 79, 80, 81, 81, 82, 82,
+ 83, 83, 84, 85, 85, 86, 86, 87, 88, 88, 89,
+ 90, 90, 91, 92, 92, 93, 93, 94, 95, 95, 96,
+ 97, 97, 98, 99, 99, 100, 101, 102, 102, 103, 104,
+ 104, 105, 106, 106, 107, 108, 109, 109, 110, 111, 112,
+ 112, 113, 114, 115, 115, 116, 117, 118, 118, 119, 120,
+ 121, 122, 122, 123, 124, 125, 126, 126, 127, 128, 129,
+ 130, 130, 131, 132, 133, 134, 135, 136, 136, 137, 138,
+ 139, 140, 141, 142, 143, 143, 144, 145, 146, 147, 148,
+ 149, 150, 151, 152, 153, 153, 154, 155, 156, 157, 158,
+ 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169,
+ 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
+ 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192,
+ 193, 195, 196, 197, 198, 199, 200, 201, 203, 204, 205,
+ 206, 207, 208, 210, 211, 212, 213, 214, 216, 217, 218,
+ 219, 220, 222, 223, 224, 225, 227, 228, 229, 230, 232,
+ 233, 234, 235, 237, 238, 239, 241, 242, 243, 245, 246,
+ 247, 249, 250, 251, 253, 254, 255, 257, 258, 259, 261,
+ 262, 264, 265, 266, 268, 269, 271, 272, 274, 275, 276,
+ 278, 279, 281, 282, 284, 285, 287, 288, 290, 291, 293,
+ 294, 296, 297, 299, 300, 302, 303, 305, 307, 308, 310,
+ 311, 313, 314, 316, 318, 319, 321, 323, 324, 326, 327,
+ 329, 331, 332, 334, 336, 337, 339, 341, 342, 344, 346,
+ 348, 349, 351, 353, 354, 356, 358, 360, 361, 363, 365,
+ 367, 369, 370, 372, 374, 376, 378, 379, 381, 383, 385,
+ 387, 389, 391, 392, 394, 396, 398, 400, 402, 404, 406,
+ 408, 410, 412, 413, 415, 417, 419, 421, 423, 425, 427,
+ 429, 431, 433, 435, 437, 439, 441, 443, 446, 448, 450,
+ 452, 454, 456, 458, 460, 462, 464, 466, 469, 471, 473,
+ 475, 477, 479, 482, 484, 486, 488, 490, 493, 495, 497,
+ 499, 501, 504, 506, 508, 511, 513, 515, 517, 520, 522,
+ 524, 527, 529, 531, 534, 536, 538, 541, 543, 546, 548,
+ 550, 553, 555, 558, 560, 562, 565, 567, 570, 572, 575,
+ 577, 580, 582, 585, 587, 590, 592, 595, 597, 600, 603,
+ 605, 608, 610, 613, 616, 618, 621, 623, 626, 629, 631,
+ 634, 637, 639, 642, 645, 648, 650, 653, 656, 658, 661,
+ 664, 667, 669, 672, 675, 678, 681, 684, 686, 689, 692,
+ 695, 698, 701, 703, 706, 709, 712, 715, 718, 721, 724,
+ 727, 730, 733, 736, 739, 742, 745, 748, 751, 754, 757,
+ 760, 763, 766, 769, 772, 775, 778, 781, 785, 788, 791,
+ 794, 797, 800, 803, 807, 810, 813, 816, 820, 823, 826,
+ 829, 832, 836, 839, 842, 846, 849, 852, 856, 859, 862,
+ 866, 869, 872, 876, 879, 883, 886, 889, 893, 896, 900,
+ 903, 907, 910, 914, 917, 921, 924, 928, 931, 935, 938,
+ 942, 945, 949, 953, 956, 960, 964, 967, 971, 974, 978,
+ 982, 986, 989, 993, 997, 1000, 1004, 1008, 1012, 1015, 1019,
+ 1023,
+};
+
+static const u16 xgamma10_39[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11,
+ 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12,
+ 12, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14,
+ 14, 14, 14, 15, 15, 15, 15, 15, 15, 16, 16,
+ 16, 16, 16, 16, 17, 17, 17, 17, 17, 18, 18,
+ 18, 18, 18, 19, 19, 19, 19, 19, 20, 20, 20,
+ 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22,
+ 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25,
+ 25, 26, 26, 26, 26, 27, 27, 27, 27, 28, 28,
+ 28, 28, 29, 29, 29, 29, 30, 30, 30, 31, 31,
+ 31, 31, 32, 32, 32, 33, 33, 33, 34, 34, 34,
+ 35, 35, 35, 35, 36, 36, 36, 37, 37, 37, 38,
+ 38, 38, 39, 39, 39, 40, 40, 41, 41, 41, 42,
+ 42, 42, 43, 43, 43, 44, 44, 45, 45, 45, 46,
+ 46, 46, 47, 47, 48, 48, 48, 49, 49, 50, 50,
+ 51, 51, 51, 52, 52, 53, 53, 53, 54, 54, 55,
+ 55, 56, 56, 57, 57, 57, 58, 58, 59, 59, 60,
+ 60, 61, 61, 62, 62, 63, 63, 64, 64, 65, 65,
+ 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71,
+ 71, 72, 73, 73, 74, 74, 75, 75, 76, 76, 77,
+ 78, 78, 79, 79, 80, 80, 81, 82, 82, 83, 83,
+ 84, 85, 85, 86, 87, 87, 88, 88, 89, 90, 90,
+ 91, 92, 92, 93, 94, 94, 95, 96, 96, 97, 98,
+ 98, 99, 100, 100, 101, 102, 102, 103, 104, 105, 105,
+ 106, 107, 107, 108, 109, 110, 110, 111, 112, 113, 113,
+ 114, 115, 116, 116, 117, 118, 119, 120, 120, 121, 122,
+ 123, 124, 124, 125, 126, 127, 128, 129, 129, 130, 131,
+ 132, 133, 134, 134, 135, 136, 137, 138, 139, 140, 141,
+ 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151,
+ 152, 153, 153, 154, 155, 156, 157, 158, 159, 160, 161,
+ 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172,
+ 173, 174, 176, 177, 178, 179, 180, 181, 182, 183, 184,
+ 185, 186, 187, 188, 190, 191, 192, 193, 194, 195, 196,
+ 198, 199, 200, 201, 202, 203, 204, 206, 207, 208, 209,
+ 210, 212, 213, 214, 215, 217, 218, 219, 220, 221, 223,
+ 224, 225, 227, 228, 229, 230, 232, 233, 234, 236, 237,
+ 238, 239, 241, 242, 243, 245, 246, 248, 249, 250, 252,
+ 253, 254, 256, 257, 259, 260, 261, 263, 264, 266, 267,
+ 269, 270, 271, 273, 274, 276, 277, 279, 280, 282, 283,
+ 285, 286, 288, 289, 291, 292, 294, 295, 297, 299, 300,
+ 302, 303, 305, 306, 308, 310, 311, 313, 314, 316, 318,
+ 319, 321, 323, 324, 326, 328, 329, 331, 333, 334, 336,
+ 338, 340, 341, 343, 345, 346, 348, 350, 352, 353, 355,
+ 357, 359, 361, 362, 364, 366, 368, 370, 372, 373, 375,
+ 377, 379, 381, 383, 385, 386, 388, 390, 392, 394, 396,
+ 398, 400, 402, 404, 406, 408, 410, 412, 414, 416, 418,
+ 420, 422, 424, 426, 428, 430, 432, 434, 436, 438, 440,
+ 442, 444, 446, 448, 451, 453, 455, 457, 459, 461, 463,
+ 466, 468, 470, 472, 474, 477, 479, 481, 483, 485, 488,
+ 490, 492, 494, 497, 499, 501, 504, 506, 508, 511, 513,
+ 515, 518, 520, 522, 525, 527, 529, 532, 534, 537, 539,
+ 541, 544, 546, 549, 551, 554, 556, 559, 561, 564, 566,
+ 569, 571, 574, 576, 579, 581, 584, 586, 589, 592, 594,
+ 597, 599, 602, 605, 607, 610, 613, 615, 618, 621, 623,
+ 626, 629, 632, 634, 637, 640, 643, 645, 648, 651, 654,
+ 656, 659, 662, 665, 668, 671, 673, 676, 679, 682, 685,
+ 688, 691, 694, 697, 700, 702, 705, 708, 711, 714, 717,
+ 720, 723, 726, 729, 732, 735, 739, 742, 745, 748, 751,
+ 754, 757, 760, 763, 766, 770, 773, 776, 779, 782, 786,
+ 789, 792, 795, 798, 802, 805, 808, 811, 815, 818, 821,
+ 825, 828, 831, 835, 838, 841, 845, 848, 852, 855, 858,
+ 862, 865, 869, 872, 876, 879, 883, 886, 890, 893, 897,
+ 900, 904, 907, 911, 914, 918, 922, 925, 929, 933, 936,
+ 940, 944, 947, 951, 955, 958, 962, 966, 969, 973, 977,
+ 981, 985, 988, 992, 996, 1000, 1004, 1007, 1011, 1015, 1019,
+ 1023,
+};
+
+static const u16 xgamma10_40[GAMMA10_TABLE_LENGTH] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10,
+ 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11,
+ 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12,
+ 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14,
+ 14, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16,
+ 16, 16, 17, 17, 17, 17, 17, 18, 18, 18, 18,
+ 18, 18, 19, 19, 19, 19, 19, 20, 20, 20, 20,
+ 21, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23,
+ 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, 25,
+ 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28,
+ 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31,
+ 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 35,
+ 35, 35, 36, 36, 36, 37, 37, 37, 38, 38, 38,
+ 39, 39, 39, 40, 40, 40, 41, 41, 41, 42, 42,
+ 43, 43, 43, 44, 44, 44, 45, 45, 46, 46, 46,
+ 47, 47, 48, 48, 48, 49, 49, 50, 50, 50, 51,
+ 51, 52, 52, 53, 53, 53, 54, 54, 55, 55, 56,
+ 56, 57, 57, 57, 58, 58, 59, 59, 60, 60, 61,
+ 61, 62, 62, 63, 63, 64, 64, 65, 65, 66, 66,
+ 67, 67, 68, 68, 69, 69, 70, 70, 71, 72, 72,
+ 73, 73, 74, 74, 75, 75, 76, 77, 77, 78, 78,
+ 79, 79, 80, 81, 81, 82, 82, 83, 84, 84, 85,
+ 85, 86, 87, 87, 88, 89, 89, 90, 91, 91, 92,
+ 93, 93, 94, 95, 95, 96, 97, 97, 98, 99, 99,
+ 100, 101, 101, 102, 103, 104, 104, 105, 106, 106, 107,
+ 108, 109, 109, 110, 111, 112, 112, 113, 114, 115, 116,
+ 116, 117, 118, 119, 119, 120, 121, 122, 123, 123, 124,
+ 125, 126, 127, 128, 128, 129, 130, 131, 132, 133, 134,
+ 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 143,
+ 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
+ 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165,
+ 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176,
+ 177, 178, 179, 180, 182, 183, 184, 185, 186, 187, 188,
+ 189, 190, 192, 193, 194, 195, 196, 197, 199, 200, 201,
+ 202, 203, 204, 206, 207, 208, 209, 210, 212, 213, 214,
+ 215, 217, 218, 219, 220, 222, 223, 224, 226, 227, 228,
+ 229, 231, 232, 233, 235, 236, 237, 239, 240, 241, 243,
+ 244, 245, 247, 248, 250, 251, 252, 254, 255, 257, 258,
+ 259, 261, 262, 264, 265, 267, 268, 270, 271, 273, 274,
+ 276, 277, 279, 280, 282, 283, 285, 286, 288, 289, 291,
+ 292, 294, 296, 297, 299, 300, 302, 304, 305, 307, 308,
+ 310, 312, 313, 315, 317, 318, 320, 322, 323, 325, 327,
+ 328, 330, 332, 333, 335, 337, 339, 340, 342, 344, 346,
+ 348, 349, 351, 353, 355, 357, 358, 360, 362, 364, 366,
+ 368, 369, 371, 373, 375, 377, 379, 381, 383, 385, 386,
+ 388, 390, 392, 394, 396, 398, 400, 402, 404, 406, 408,
+ 410, 412, 414, 416, 418, 420, 422, 424, 426, 429, 431,
+ 433, 435, 437, 439, 441, 443, 445, 448, 450, 452, 454,
+ 456, 458, 461, 463, 465, 467, 469, 472, 474, 476, 478,
+ 481, 483, 485, 488, 490, 492, 495, 497, 499, 501, 504,
+ 506, 509, 511, 513, 516, 518, 521, 523, 525, 528, 530,
+ 533, 535, 538, 540, 543, 545, 548, 550, 553, 555, 558,
+ 560, 563, 565, 568, 570, 573, 576, 578, 581, 583, 586,
+ 589, 591, 594, 597, 599, 602, 605, 607, 610, 613, 616,
+ 618, 621, 624, 627, 629, 632, 635, 638, 641, 643, 646,
+ 649, 652, 655, 658, 660, 663, 666, 669, 672, 675, 678,
+ 681, 684, 687, 690, 693, 696, 699, 702, 705, 708, 711,
+ 714, 717, 720, 723, 726, 729, 732, 735, 739, 742, 745,
+ 748, 751, 754, 758, 761, 764, 767, 770, 774, 777, 780,
+ 783, 787, 790, 793, 797, 800, 803, 807, 810, 813, 817,
+ 820, 824, 827, 830, 834, 837, 841, 844, 848, 851, 855,
+ 858, 862, 865, 869, 872, 876, 879, 883, 886, 890, 894,
+ 897, 901, 905, 908, 912, 916, 919, 923, 927, 930, 934,
+ 938, 942, 945, 949, 953, 957, 960, 964, 968, 972, 976,
+ 980, 984, 987, 991, 995, 999, 1003, 1007, 1011, 1015, 1019,
+ 1023,
+};
+
+static const u16 *xgamma10_curves[GAMMA_CURVE_LENGTH] = {
+ &xgamma10_01[0],
+ &xgamma10_02[0],
+ &xgamma10_03[0],
+ &xgamma10_04[0],
+ &xgamma10_05[0],
+ &xgamma10_06[0],
+ &xgamma10_07[0],
+ &xgamma10_08[0],
+ &xgamma10_09[0],
+ &xgamma10_10[0],
+ &xgamma10_11[0],
+ &xgamma10_12[0],
+ &xgamma10_13[0],
+ &xgamma10_14[0],
+ &xgamma10_15[0],
+ &xgamma10_16[0],
+ &xgamma10_17[0],
+ &xgamma10_18[0],
+ &xgamma10_19[0],
+ &xgamma10_20[0],
+ &xgamma10_21[0],
+ &xgamma10_22[0],
+ &xgamma10_23[0],
+ &xgamma10_24[0],
+ &xgamma10_25[0],
+ &xgamma10_26[0],
+ &xgamma10_27[0],
+ &xgamma10_28[0],
+ &xgamma10_29[0],
+ &xgamma10_30[0],
+ &xgamma10_31[0],
+ &xgamma10_32[0],
+ &xgamma10_33[0],
+ &xgamma10_34[0],
+ &xgamma10_35[0],
+ &xgamma10_36[0],
+ &xgamma10_37[0],
+ &xgamma10_38[0],
+ &xgamma10_39[0],
+ &xgamma10_40[0],
+};
+#endif /* __XILINX_GAMMA_COEFF_H__ */
diff --git a/drivers/media/platform/xilinx/xilinx-gamma.c b/drivers/media/platform/xilinx/xilinx-gamma.c
new file mode 100644
index 000000000000..d7996d0f34fa
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-gamma.c
@@ -0,0 +1,543 @@
+/*
+ * Xilinx Gamma Correction IP
+ *
+ * Copyright (C) 2017 Xilinx, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/xilinx-v4l2-controls.h>
+
+#include <media/v4l2-async.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
+
+#include "xilinx-gamma-coeff.h"
+#include "xilinx-vip.h"
+
+#define XGAMMA_MIN_HEIGHT (64)
+#define XGAMMA_MAX_HEIGHT (4320)
+#define XGAMMA_DEF_HEIGHT (720)
+#define XGAMMA_MIN_WIDTH (64)
+#define XGAMMA_MAX_WIDTH (8192)
+#define XGAMMA_DEF_WIDTH (1280)
+
+#define XGAMMA_AP_CTRL (0x0000)
+#define XGAMMA_GIE (0x0004)
+#define XGAMMA_IER (0x0008)
+#define XGAMMA_ISR (0x000c)
+#define XGAMMA_WIDTH (0x0010)
+#define XGAMMA_HEIGHT (0x0018)
+#define XGAMMA_VIDEO_FORMAT (0x0020)
+#define XGAMMA_GAMMA_LUT_0_BASE (0x0800)
+#define XGAMMA_GAMMA_LUT_1_BASE (0x1000)
+#define XGAMMA_GAMMA_LUT_2_BASE (0x1800)
+
+#define XGAMMA_RESET_DEASSERT (0)
+#define XGAMMA_RESET_ASSERT (1)
+#define XGAMMA_START BIT(0)
+#define XGAMMA_AUTO_RESTART BIT(7)
+#define XGAMMA_STREAM_ON (XGAMMA_START | XGAMMA_AUTO_RESTART)
+
+enum xgamma_video_format {
+ XGAMMA_RGB = 0,
+};
+
+/**
+ * struct xgamma_dev - Xilinx Video Gamma LUT device structure
+ * @xvip: Xilinx Video IP device
+ * @pads: Scaler sub-device media pads
+ * @formats: V4L2 media bus formats at the sink and source pads
+ * @default_formats: default V4L2 media bus formats
+ * @ctrl_handler: V4L2 Control Handler for R,G,B Gamma Controls
+ * @red_lut: Pointer to the gamma coefficient as per the Red Gamma control
+ * @green_lut: Pointer to the gamma coefficient as per the Green Gamma control
+ * @blue_lut: Pointer to the gamma coefficient as per the Blue Gamma control
+ * @color_depth: Color depth of the Video Gamma IP
+ * @gamma_table: Pointer to the table containing various gamma values
+ * @rst_gpio: GPIO reset line to bring VPSS Scaler out of reset
+ * @max_width: Maximum width supported by this instance.
+ * @max_height: Maximum height supported by this instance.
+ */
+struct xgamma_dev {
+ struct xvip_device xvip;
+ struct media_pad pads[2];
+ struct v4l2_mbus_framefmt formats[2];
+ struct v4l2_mbus_framefmt default_formats[2];
+ struct v4l2_ctrl_handler ctrl_handler;
+
+ const u16 *red_lut;
+ const u16 *green_lut;
+ const u16 *blue_lut;
+ u32 color_depth;
+ const u16 **gamma_table;
+ struct gpio_desc *rst_gpio;
+ u32 max_width;
+ u32 max_height;
+};
+
+static inline u32 xg_read(struct xgamma_dev *xg, u32 reg)
+{
+ u32 data;
+
+ data = xvip_read(&xg->xvip, reg);
+ dev_dbg(xg->xvip.dev,
+ "Reading 0x%x from reg offset 0x%x", data, reg);
+ return data;
+}
+
+static inline void xg_write(struct xgamma_dev *xg, u32 reg, u32 data)
+{
+ dev_dbg(xg->xvip.dev,
+ "Writing 0x%x to reg offset 0x%x", data, reg);
+ xvip_write(&xg->xvip, reg, data);
+#ifdef DEBUG
+ if (xg_read(xg, reg) != data)
+ dev_err(xg->xvip.dev,
+ "Write 0x%x does not match read back", data);
+#endif
+}
+
+static inline struct xgamma_dev *to_xg(struct v4l2_subdev *subdev)
+{
+ return container_of(subdev, struct xgamma_dev, xvip.subdev);
+}
+
+static struct v4l2_mbus_framefmt *
+__xg_get_pad_format(struct xgamma_dev *xg,
+ struct v4l2_subdev_pad_config *cfg,
+ unsigned int pad, u32 which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_format(
+ &xg->xvip.subdev, cfg, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &xg->formats[pad];
+ default:
+ return NULL;
+ }
+}
+
+static void xg_set_lut_entries(struct xgamma_dev *xg,
+ const u16 *lut, const u32 lut_base)
+{
+ int itr;
+ u32 lut_offset, lut_data;
+
+ lut_offset = lut_base;
+ /* Write LUT Entries */
+ for (itr = 0; itr < BIT(xg->color_depth - 1); itr++) {
+ lut_data = (lut[2 * itr + 1] << 16) | lut[2 * itr];
+ xg_write(xg, lut_offset, lut_data);
+ lut_offset += 4;
+ }
+}
+
+static int xg_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+ struct xgamma_dev *xg = to_xg(subdev);
+
+ if (!enable) {
+ dev_dbg(xg->xvip.dev, "%s : Off", __func__);
+ gpiod_set_value_cansleep(xg->rst_gpio, XGAMMA_RESET_ASSERT);
+ gpiod_set_value_cansleep(xg->rst_gpio, XGAMMA_RESET_DEASSERT);
+ return 0;
+ }
+ dev_dbg(xg->xvip.dev, "%s : Started", __func__);
+
+ dev_dbg(xg->xvip.dev, "%s : Setting width %d and height %d",
+ __func__, xg->formats[XVIP_PAD_SINK].width,
+ xg->formats[XVIP_PAD_SINK].height);
+ xg_write(xg, XGAMMA_WIDTH, xg->formats[XVIP_PAD_SINK].width);
+ xg_write(xg, XGAMMA_HEIGHT, xg->formats[XVIP_PAD_SINK].height);
+ xg_write(xg, XGAMMA_VIDEO_FORMAT, XGAMMA_RGB);
+ xg_set_lut_entries(xg, xg->red_lut, XGAMMA_GAMMA_LUT_0_BASE);
+ xg_set_lut_entries(xg, xg->green_lut, XGAMMA_GAMMA_LUT_1_BASE);
+ xg_set_lut_entries(xg, xg->blue_lut, XGAMMA_GAMMA_LUT_2_BASE);
+
+ /* Start GAMMA Correction LUT Video IP */
+ xg_write(xg, XGAMMA_AP_CTRL, XGAMMA_STREAM_ON);
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops xg_video_ops = {
+ .s_stream = xg_s_stream,
+};
+
+static int xg_get_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xgamma_dev *xg = to_xg(subdev);
+
+ fmt->format = *__xg_get_pad_format(xg, cfg, fmt->pad, fmt->which);
+ return 0;
+}
+
+static int xg_set_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xgamma_dev *xg = to_xg(subdev);
+ struct v4l2_mbus_framefmt *__format;
+
+ __format = __xg_get_pad_format(xg, cfg, fmt->pad, fmt->which);
+ *__format = fmt->format;
+
+ if (fmt->pad == XVIP_PAD_SINK) {
+ if (__format->code != MEDIA_BUS_FMT_RBG888_1X24) {
+ dev_dbg(xg->xvip.dev,
+ "Unsupported sink media bus code format");
+ __format->code = MEDIA_BUS_FMT_RBG888_1X24;
+ }
+ }
+ __format->width = clamp_t(unsigned int, fmt->format.width,
+ XGAMMA_MIN_WIDTH, xg->max_width);
+ __format->height = clamp_t(unsigned int, fmt->format.height,
+ XGAMMA_MIN_HEIGHT, xg->max_height);
+
+ fmt->format = *__format;
+ /* Propagate to Source Pad */
+ __format = __xg_get_pad_format(xg, cfg, XVIP_PAD_SOURCE, fmt->which);
+ *__format = fmt->format;
+ return 0;
+}
+
+static int xg_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ struct xgamma_dev *xg = to_xg(subdev);
+ struct v4l2_mbus_framefmt *format;
+
+ format = v4l2_subdev_get_try_format(subdev, fh->pad, XVIP_PAD_SINK);
+ *format = xg->default_formats[XVIP_PAD_SINK];
+
+ format = v4l2_subdev_get_try_format(subdev, fh->pad, XVIP_PAD_SOURCE);
+ *format = xg->default_formats[XVIP_PAD_SOURCE];
+ return 0;
+}
+
+static int xg_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ return 0;
+}
+
+static const struct v4l2_subdev_internal_ops xg_internal_ops = {
+ .open = xg_open,
+ .close = xg_close,
+};
+
+static const struct v4l2_subdev_pad_ops xg_pad_ops = {
+ .enum_mbus_code = xvip_enum_mbus_code,
+ .enum_frame_size = xvip_enum_frame_size,
+ .get_fmt = xg_get_format,
+ .set_fmt = xg_set_format,
+};
+
+static const struct v4l2_subdev_ops xg_ops = {
+ .video = &xg_video_ops,
+ .pad = &xg_pad_ops,
+};
+
+static int
+select_gamma(s32 value, const u16 **coeff, const u16 **xgamma_curves)
+{
+ if (!coeff)
+ return -EINVAL;
+ if (value <= 0 || value > GAMMA_CURVE_LENGTH)
+ return -EINVAL;
+
+ *coeff = *(xgamma_curves + value - 1);
+ return 0;
+}
+
+static int xg_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ int rval;
+ struct xgamma_dev *xg =
+ container_of(ctrl->handler,
+ struct xgamma_dev, ctrl_handler);
+ dev_dbg(xg->xvip.dev, "%s called", __func__);
+ switch (ctrl->id) {
+ case V4L2_CID_XILINX_GAMMA_CORR_RED_GAMMA:
+ rval = select_gamma(ctrl->val, &xg->red_lut, xg->gamma_table);
+ if (rval < 0) {
+ dev_err(xg->xvip.dev, "Invalid Red Gamma");
+ return rval;
+ }
+ dev_dbg(xg->xvip.dev, "%s: Setting Red Gamma to %d.%d",
+ __func__, ctrl->val / 10, ctrl->val % 10);
+ xg_set_lut_entries(xg, xg->red_lut, XGAMMA_GAMMA_LUT_0_BASE);
+ break;
+ case V4L2_CID_XILINX_GAMMA_CORR_BLUE_GAMMA:
+ rval = select_gamma(ctrl->val, &xg->blue_lut, xg->gamma_table);
+ if (rval < 0) {
+ dev_err(xg->xvip.dev, "Invalid Blue Gamma");
+ return rval;
+ }
+ dev_dbg(xg->xvip.dev, "%s: Setting Blue Gamma to %d.%d",
+ __func__, ctrl->val / 10, ctrl->val % 10);
+ xg_set_lut_entries(xg, xg->blue_lut, XGAMMA_GAMMA_LUT_1_BASE);
+ break;
+ case V4L2_CID_XILINX_GAMMA_CORR_GREEN_GAMMA:
+ rval = select_gamma(ctrl->val, &xg->green_lut, xg->gamma_table);
+ if (rval < 0) {
+ dev_err(xg->xvip.dev, "Invalid Green Gamma");
+ return -EINVAL;
+ }
+ dev_dbg(xg->xvip.dev, "%s: Setting Green Gamma to %d.%d",
+ __func__, ctrl->val / 10, ctrl->val % 10);
+ xg_set_lut_entries(xg, xg->green_lut, XGAMMA_GAMMA_LUT_2_BASE);
+ break;
+ }
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops xg_ctrl_ops = {
+ .s_ctrl = xg_s_ctrl,
+};
+
+static struct v4l2_ctrl_config xg_ctrls[] = {
+ /* Red Gamma */
+ {
+ .ops = &xg_ctrl_ops,
+ .id = V4L2_CID_XILINX_GAMMA_CORR_RED_GAMMA,
+ .name = "Red Gamma Correction|1->0.1|10->1.0",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 1,
+ .max = 40,
+ .step = 1,
+ .def = 10,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ },
+ /* Blue Gamma */
+ {
+ .ops = &xg_ctrl_ops,
+ .id = V4L2_CID_XILINX_GAMMA_CORR_BLUE_GAMMA,
+ .name = "Blue Gamma Correction|1->0.1|10->1.0",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 1,
+ .max = 40,
+ .step = 1,
+ .def = 10,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ },
+ /* Green Gamma */
+ {
+ .ops = &xg_ctrl_ops,
+ .id = V4L2_CID_XILINX_GAMMA_CORR_GREEN_GAMMA,
+ .name = "Green Gamma Correction|1->0.1|10->1.0)",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 1,
+ .max = 40,
+ .step = 1,
+ .def = 10,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ },
+};
+
+static const struct media_entity_operations xg_media_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+static int xg_parse_of(struct xgamma_dev *xg)
+{
+ struct device *dev = xg->xvip.dev;
+ struct device_node *node = dev->of_node;
+ struct device_node *ports;
+ struct device_node *port;
+ u32 port_id = 0;
+ int rval;
+
+ rval = of_property_read_u32(node, "xlnx,max-height", &xg->max_height);
+ if (rval < 0) {
+ dev_err(dev, "xlnx,max-height is missing!");
+ return -EINVAL;
+ } else if (xg->max_height > XGAMMA_MAX_HEIGHT ||
+ xg->max_height < XGAMMA_MIN_HEIGHT) {
+ dev_err(dev, "Invalid height in dt");
+ return -EINVAL;
+ }
+
+ rval = of_property_read_u32(node, "xlnx,max-width", &xg->max_width);
+ if (rval < 0) {
+ dev_err(dev, "xlnx,max-width is missing!");
+ return -EINVAL;
+ } else if (xg->max_width > XGAMMA_MAX_WIDTH ||
+ xg->max_width < XGAMMA_MIN_WIDTH) {
+ dev_err(dev, "Invalid width in dt");
+ return -EINVAL;
+ }
+
+ ports = of_get_child_by_name(node, "ports");
+ if (!ports)
+ ports = node;
+
+ /* Get the format description for each pad */
+ for_each_child_of_node(ports, port) {
+ if (port->name && (of_node_cmp(port->name, "port") == 0)) {
+ rval = of_property_read_u32(port, "reg", &port_id);
+ if (rval < 0) {
+ dev_err(dev, "No reg in DT");
+ return rval;
+ }
+ if (port_id != 0 && port_id != 1) {
+ dev_err(dev, "Invalid reg in DT");
+ return -EINVAL;
+ }
+
+ rval = of_property_read_u32(port, "xlnx,video-width",
+ &xg->color_depth);
+ if (rval < 0) {
+ dev_err(dev, "Missing xlnx-video-width in DT");
+ return rval;
+ }
+ switch (xg->color_depth) {
+ case GAMMA_BPC_8:
+ xg->gamma_table = xgamma8_curves;
+ break;
+ case GAMMA_BPC_10:
+ xg->gamma_table = xgamma10_curves;
+ break;
+ default:
+ dev_err(dev, "Unsupported color depth %d",
+ xg->color_depth);
+ return -EINVAL;
+ }
+ }
+ }
+
+ xg->rst_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(xg->rst_gpio)) {
+ if (PTR_ERR(xg->rst_gpio) != -EPROBE_DEFER)
+ dev_err(dev, "Reset GPIO not setup in DT");
+ return PTR_ERR(xg->rst_gpio);
+ }
+ return 0;
+}
+
+static int xg_probe(struct platform_device *pdev)
+{
+ struct xgamma_dev *xg;
+ struct v4l2_subdev *subdev;
+ struct v4l2_mbus_framefmt *def_fmt;
+ int rval, itr;
+
+ dev_dbg(&pdev->dev, "Gamma LUT Probe Started");
+ xg = devm_kzalloc(&pdev->dev, sizeof(*xg), GFP_KERNEL);
+ if (!xg)
+ return -ENOMEM;
+ xg->xvip.dev = &pdev->dev;
+ rval = xg_parse_of(xg);
+ if (rval < 0)
+ return rval;
+ rval = xvip_init_resources(&xg->xvip);
+
+ dev_dbg(xg->xvip.dev, "Reset Xilinx Video Gamma Corrrection");
+ gpiod_set_value_cansleep(xg->rst_gpio, XGAMMA_RESET_DEASSERT);
+
+ /* Init V4L2 subdev */
+ subdev = &xg->xvip.subdev;
+ v4l2_subdev_init(subdev, &xg_ops);
+ subdev->dev = &pdev->dev;
+ subdev->internal_ops = &xg_internal_ops;
+ strlcpy(subdev->name, dev_name(&pdev->dev), sizeof(subdev->name));
+ subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ /* Default Formats Initialization */
+ def_fmt = &xg->default_formats[XVIP_PAD_SINK];
+ /* GAMMA LUT IP only to be supported for RGB */
+ def_fmt->code = MEDIA_BUS_FMT_RBG888_1X24;
+ def_fmt->field = V4L2_FIELD_NONE;
+ def_fmt->colorspace = V4L2_COLORSPACE_SRGB;
+ def_fmt->width = XGAMMA_DEF_WIDTH;
+ def_fmt->height = XGAMMA_DEF_HEIGHT;
+ xg->formats[XVIP_PAD_SINK] = *def_fmt;
+
+ def_fmt = &xg->default_formats[XVIP_PAD_SOURCE];
+ *def_fmt = xg->default_formats[XVIP_PAD_SINK];
+ xg->formats[XVIP_PAD_SOURCE] = *def_fmt;
+
+ xg->pads[XVIP_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ xg->pads[XVIP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+ /* Init Media Entity */
+ subdev->entity.ops = &xg_media_ops;
+ rval = media_entity_pads_init(&subdev->entity, 2, xg->pads);
+ if (rval < 0)
+ goto media_error;
+
+ /* V4L2 Controls */
+ v4l2_ctrl_handler_init(&xg->ctrl_handler, ARRAY_SIZE(xg_ctrls));
+ for (itr = 0; itr < ARRAY_SIZE(xg_ctrls); itr++) {
+ v4l2_ctrl_new_custom(&xg->ctrl_handler,
+ &xg_ctrls[itr], NULL);
+ }
+ if (xg->ctrl_handler.error) {
+ dev_err(&pdev->dev, "Failed to add V4L2 controls");
+ rval = xg->ctrl_handler.error;
+ goto ctrl_error;
+ }
+ subdev->ctrl_handler = &xg->ctrl_handler;
+ rval = v4l2_ctrl_handler_setup(&xg->ctrl_handler);
+ if (rval < 0) {
+ dev_err(&pdev->dev, "Failed to setup control handler");
+ goto ctrl_error;
+ }
+
+ platform_set_drvdata(pdev, xg);
+ rval = v4l2_async_register_subdev(subdev);
+ if (rval < 0) {
+ dev_err(&pdev->dev, "failed to register subdev");
+ goto v4l2_subdev_error;
+ }
+ dev_info(&pdev->dev,
+ "Xilinx %d-bit Video Gamma Correction LUT registered",
+ xg->color_depth);
+ return 0;
+ctrl_error:
+ v4l2_ctrl_handler_free(&xg->ctrl_handler);
+v4l2_subdev_error:
+ media_entity_cleanup(&subdev->entity);
+media_error:
+ xvip_cleanup_resources(&xg->xvip);
+ return rval;
+}
+
+static int xg_remove(struct platform_device *pdev)
+{
+ struct xgamma_dev *xg = platform_get_drvdata(pdev);
+ struct v4l2_subdev *subdev = &xg->xvip.subdev;
+
+ v4l2_async_unregister_subdev(subdev);
+ /* Add entry to cleanup v4l2 control handle */
+ media_entity_cleanup(&subdev->entity);
+ xvip_cleanup_resources(&xg->xvip);
+ return 0;
+}
+
+static const struct of_device_id xg_of_id_table[] = {
+ {.compatible = "xlnx,v-gamma-lut"},
+ { }
+};
+MODULE_DEVICE_TABLE(of, xg_of_id_table);
+
+static struct platform_driver xg_driver = {
+ .driver = {
+ .name = "xilinx-gamma-lut",
+ .of_match_table = xg_of_id_table,
+ },
+ .probe = xg_probe,
+ .remove = xg_remove,
+};
+
+module_platform_driver(xg_driver);
+MODULE_DESCRIPTION("Xilinx Video Gamma Correction LUT Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/xilinx/xilinx-hls-common.h b/drivers/media/platform/xilinx/xilinx-hls-common.h
new file mode 100644
index 000000000000..8ecc3cfb8a83
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-hls-common.h
@@ -0,0 +1,36 @@
+/*
+ * Xilinx HLS common header
+ *
+ * Copyright (C) 2013-2015 Xilinx, Inc.
+ *
+ * Contacts: Radhey Shyam Pandey <radheys@xilinx.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __XILINX_HLS_COMMON_H__
+#define __XILINX_HLS_COMMON_H__
+
+#include <linux/bitops.h>
+
+#define XHLS_DEF_WIDTH 1920
+#define XHLS_DEF_HEIGHT 1080
+
+#define XHLS_REG_CTRL_DONE BIT(1)
+#define XHLS_REG_CTRL_IDLE BIT(2)
+#define XHLS_REG_CTRL_READY BIT(3)
+#define XHLS_REG_CTRL_AUTO_RESTART BIT(7)
+#define XHLS_REG_GIE 0x04
+#define XHLS_REG_GIE_GIE BIT(0)
+#define XHLS_REG_IER 0x08
+#define XHLS_REG_IER_DONE BIT(0)
+#define XHLS_REG_IER_READY BIT(1)
+#define XHLS_REG_ISR 0x0c
+#define XHLS_REG_ISR_DONE BIT(0)
+#define XHLS_REG_ISR_READY BIT(1)
+#define XHLS_REG_ROWS 0x10
+#define XHLS_REG_COLS 0x18
+
+#endif /* __XILINX_HLS_COMMON_H__ */
diff --git a/drivers/media/platform/xilinx/xilinx-hls.c b/drivers/media/platform/xilinx/xilinx-hls.c
new file mode 100644
index 000000000000..fc42977440a9
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-hls.c
@@ -0,0 +1,481 @@
+/*
+ * Xilinx HLS Core
+ *
+ * Copyright (C) 2013-2015 Ideas on Board
+ * Copyright (C) 2013-2015 Xilinx, Inc.
+ *
+ * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
+ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/xilinx-hls.h>
+#include <linux/xilinx-v4l2-controls.h>
+
+#include <media/v4l2-async.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
+
+#include "xilinx-hls-common.h"
+#include "xilinx-vip.h"
+
+/**
+ * struct xhls_device - Xilinx HLS Core device structure
+ * @xvip: Xilinx Video IP device
+ * @pads: media pads
+ * @compatible: first DT compatible string for the device
+ * @formats: active V4L2 media bus formats at the sink and source pads
+ * @default_formats: default V4L2 media bus formats
+ * @vip_formats: format information corresponding to the pads active formats
+ * @model: additional description of IP implementation if available
+ * @ctrl_handler: control handler
+ * @user_mem: user portion of the register space
+ * @user_mem_size: size of the user portion of the register space
+ */
+struct xhls_device {
+ struct xvip_device xvip;
+ struct media_pad pads[2];
+
+ const char *compatible;
+
+ struct v4l2_mbus_framefmt formats[2];
+ struct v4l2_mbus_framefmt default_formats[2];
+ const struct xvip_video_format *vip_formats[2];
+
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_ctrl *model;
+
+ void __iomem *user_mem;
+ size_t user_mem_size;
+};
+
+static inline struct xhls_device *to_hls(struct v4l2_subdev *subdev)
+{
+ return container_of(subdev, struct xhls_device, xvip.subdev);
+}
+
+/* -----------------------------------------------------------------------------
+ * Controls
+ */
+
+static const struct v4l2_ctrl_config xhls_model_ctrl = {
+ .id = V4L2_CID_XILINX_HLS_MODEL,
+ .name = "HLS Model",
+ .type = V4L2_CTRL_TYPE_STRING,
+ .step = 1,
+ .flags = V4L2_CTRL_FLAG_READ_ONLY,
+};
+
+static int xhls_create_controls(struct xhls_device *xhls)
+{
+ struct v4l2_ctrl_config model = xhls_model_ctrl;
+ struct v4l2_ctrl *ctrl;
+
+ model.max = strlen(xhls->compatible);
+ model.min = model.max;
+
+ v4l2_ctrl_handler_init(&xhls->ctrl_handler, 1);
+
+ ctrl = v4l2_ctrl_new_custom(&xhls->ctrl_handler, &model, NULL);
+
+ if (xhls->ctrl_handler.error) {
+ dev_err(xhls->xvip.dev, "failed to add controls\n");
+ return xhls->ctrl_handler.error;
+ }
+
+ v4l2_ctrl_s_ctrl_string(ctrl, xhls->compatible);
+
+ xhls->xvip.subdev.ctrl_handler = &xhls->ctrl_handler;
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Core Operations
+ */
+
+static int xhls_user_read(struct xhls_device *xhls,
+ struct xilinx_axi_hls_registers *regs)
+{
+ unsigned int i;
+ u32 offset;
+ u32 value;
+
+ if (regs->num_regs >= xhls->user_mem_size / 4)
+ return -EINVAL;
+
+ for (i = 0; i < regs->num_regs; ++i) {
+ if (copy_from_user(&offset, &regs->regs[i].offset,
+ sizeof(offset)))
+ return -EFAULT;
+
+ if (offset >= xhls->user_mem_size || offset & 3)
+ return -EINVAL;
+
+ value = ioread32(xhls->user_mem + offset);
+
+ if (copy_to_user(&regs->regs[i].value, &value, sizeof(value)))
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int xhls_user_write(struct xhls_device *xhls,
+ struct xilinx_axi_hls_registers *regs)
+{
+ struct xilinx_axi_hls_register reg;
+ unsigned int i;
+
+ if (regs->num_regs >= xhls->user_mem_size / 4)
+ return -EINVAL;
+
+ for (i = 0; i < regs->num_regs; ++i) {
+ if (copy_from_user(&reg, &regs->regs[i], sizeof(reg)))
+ return -EFAULT;
+
+ if (reg.offset >= xhls->user_mem_size || reg.offset & 3)
+ return -EINVAL;
+
+ iowrite32(reg.value, xhls->user_mem + reg.offset);
+ }
+
+ return 0;
+}
+
+static long xhls_ioctl(struct v4l2_subdev *subdev, unsigned int cmd, void *arg)
+{
+ struct xhls_device *xhls = to_hls(subdev);
+
+ switch (cmd) {
+ case XILINX_AXI_HLS_READ:
+ return xhls_user_read(xhls, arg);
+ case XILINX_AXI_HLS_WRITE:
+ return xhls_user_write(xhls, arg);
+ }
+
+ return -ENOTTY;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Video Operations
+ */
+
+static int xhls_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+ struct xhls_device *xhls = to_hls(subdev);
+ struct v4l2_mbus_framefmt *format = &xhls->formats[XVIP_PAD_SINK];
+
+ if (!enable) {
+ xvip_write(&xhls->xvip, XVIP_CTRL_CONTROL, 0);
+ return 0;
+ }
+
+ xvip_write(&xhls->xvip, XHLS_REG_COLS, format->width);
+ xvip_write(&xhls->xvip, XHLS_REG_ROWS, format->height);
+
+ xvip_write(&xhls->xvip, XVIP_CTRL_CONTROL,
+ XHLS_REG_CTRL_AUTO_RESTART | XVIP_CTRL_CONTROL_SW_ENABLE);
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Pad Operations
+ */
+
+static struct v4l2_mbus_framefmt *
+__xhls_get_pad_format(struct xhls_device *xhls,
+ struct v4l2_subdev_pad_config *cfg,
+ unsigned int pad, u32 which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_format(&xhls->xvip.subdev, cfg, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &xhls->formats[pad];
+ default:
+ return NULL;
+ }
+}
+
+static int xhls_get_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xhls_device *xhls = to_hls(subdev);
+
+ fmt->format = *__xhls_get_pad_format(xhls, cfg, fmt->pad, fmt->which);
+
+ return 0;
+}
+
+static int xhls_set_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xhls_device *xhls = to_hls(subdev);
+ struct v4l2_mbus_framefmt *format;
+
+ format = __xhls_get_pad_format(xhls, cfg, fmt->pad, fmt->which);
+
+ if (fmt->pad == XVIP_PAD_SOURCE) {
+ fmt->format = *format;
+ return 0;
+ }
+
+ xvip_set_format_size(format, fmt);
+
+ fmt->format = *format;
+
+ /* Propagate the format to the source pad. */
+ format = __xhls_get_pad_format(xhls, cfg, XVIP_PAD_SOURCE,
+ fmt->which);
+
+ xvip_set_format_size(format, fmt);
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Operations
+ */
+
+static int xhls_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ struct xhls_device *xhls = to_hls(subdev);
+ struct v4l2_mbus_framefmt *format;
+
+ /* Initialize with default formats */
+ format = v4l2_subdev_get_try_format(subdev, fh->pad, XVIP_PAD_SINK);
+ *format = xhls->default_formats[XVIP_PAD_SINK];
+
+ format = v4l2_subdev_get_try_format(subdev, fh->pad, XVIP_PAD_SOURCE);
+ *format = xhls->default_formats[XVIP_PAD_SOURCE];
+
+ return 0;
+}
+
+static int xhls_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ return 0;
+}
+
+static struct v4l2_subdev_core_ops xhls_core_ops = {
+ .ioctl = xhls_ioctl,
+};
+
+static struct v4l2_subdev_video_ops xhls_video_ops = {
+ .s_stream = xhls_s_stream,
+};
+
+static struct v4l2_subdev_pad_ops xhls_pad_ops = {
+ .enum_mbus_code = xvip_enum_mbus_code,
+ .enum_frame_size = xvip_enum_frame_size,
+ .get_fmt = xhls_get_format,
+ .set_fmt = xhls_set_format,
+};
+
+static struct v4l2_subdev_ops xhls_ops = {
+ .core = &xhls_core_ops,
+ .video = &xhls_video_ops,
+ .pad = &xhls_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops xhls_internal_ops = {
+ .open = xhls_open,
+ .close = xhls_close,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media Operations
+ */
+
+static const struct media_entity_operations xhls_media_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+/* -----------------------------------------------------------------------------
+ * Platform Device Driver
+ */
+
+static void xhls_init_formats(struct xhls_device *xhls)
+{
+ struct v4l2_mbus_framefmt *format;
+
+ /* Initialize default and active formats */
+ format = &xhls->default_formats[XVIP_PAD_SINK];
+ format->code = xhls->vip_formats[XVIP_PAD_SINK]->code;
+ format->field = V4L2_FIELD_NONE;
+ format->colorspace = V4L2_COLORSPACE_SRGB;
+
+ format->width = xvip_read(&xhls->xvip, XHLS_REG_COLS);
+ format->height = xvip_read(&xhls->xvip, XHLS_REG_ROWS);
+
+ xhls->formats[XVIP_PAD_SINK] = *format;
+
+ format = &xhls->default_formats[XVIP_PAD_SOURCE];
+ *format = xhls->default_formats[XVIP_PAD_SINK];
+ format->code = xhls->vip_formats[XVIP_PAD_SOURCE]->code;
+
+ xhls->formats[XVIP_PAD_SOURCE] = *format;
+}
+
+static int xhls_parse_of(struct xhls_device *xhls)
+{
+ struct device *dev = xhls->xvip.dev;
+ struct device_node *node = xhls->xvip.dev->of_node;
+ struct device_node *ports;
+ struct device_node *port;
+ u32 port_id;
+ int ret;
+
+ ret = of_property_read_string(node, "compatible", &xhls->compatible);
+ if (ret < 0)
+ return -EINVAL;
+
+ ports = of_get_child_by_name(node, "ports");
+ if (ports == NULL)
+ ports = node;
+
+ /* Get the format description for each pad */
+ for_each_child_of_node(ports, port) {
+ if (port->name && (of_node_cmp(port->name, "port") == 0)) {
+ const struct xvip_video_format *vip_format;
+
+ vip_format = xvip_of_get_format(port);
+ if (IS_ERR(vip_format)) {
+ dev_err(dev, "invalid format in DT");
+ return PTR_ERR(vip_format);
+ }
+
+ ret = of_property_read_u32(port, "reg", &port_id);
+ if (ret < 0) {
+ dev_err(dev, "no reg in DT");
+ return ret;
+ }
+
+ if (port_id != 0 && port_id != 1) {
+ dev_err(dev, "invalid reg in DT");
+ return -EINVAL;
+ }
+
+ xhls->vip_formats[port_id] = vip_format;
+ }
+ }
+
+ return 0;
+}
+
+static int xhls_probe(struct platform_device *pdev)
+{
+ struct v4l2_subdev *subdev;
+ struct xhls_device *xhls;
+ struct resource *mem;
+ int ret;
+
+ xhls = devm_kzalloc(&pdev->dev, sizeof(*xhls), GFP_KERNEL);
+ if (!xhls)
+ return -ENOMEM;
+
+ xhls->xvip.dev = &pdev->dev;
+
+ ret = xhls_parse_of(xhls);
+ if (ret < 0)
+ return ret;
+
+ ret = xvip_init_resources(&xhls->xvip);
+ if (ret < 0)
+ return ret;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ xhls->user_mem = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(xhls->user_mem))
+ return PTR_ERR(xhls->user_mem);
+ xhls->user_mem_size = resource_size(mem);
+
+ /* Reset and initialize the core */
+ xvip_reset(&xhls->xvip);
+
+ /* Initialize V4L2 subdevice and media entity */
+ subdev = &xhls->xvip.subdev;
+ v4l2_subdev_init(subdev, &xhls_ops);
+ subdev->dev = &pdev->dev;
+ subdev->internal_ops = &xhls_internal_ops;
+ strlcpy(subdev->name, dev_name(&pdev->dev), sizeof(subdev->name));
+ v4l2_set_subdevdata(subdev, xhls);
+ subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ xhls_init_formats(xhls);
+
+ xhls->pads[XVIP_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ xhls->pads[XVIP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ subdev->entity.ops = &xhls_media_ops;
+ ret = media_entity_pads_init(&subdev->entity, 2, xhls->pads);
+ if (ret < 0)
+ goto error;
+
+ ret = xhls_create_controls(xhls);
+ if (ret < 0)
+ goto error;
+
+ platform_set_drvdata(pdev, xhls);
+
+ ret = v4l2_async_register_subdev(subdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to register subdev\n");
+ goto error;
+ }
+
+ dev_info(xhls->xvip.dev, "device %s found\n", xhls->compatible);
+
+ return 0;
+
+error:
+ v4l2_ctrl_handler_free(&xhls->ctrl_handler);
+ media_entity_cleanup(&subdev->entity);
+ xvip_cleanup_resources(&xhls->xvip);
+ return ret;
+}
+
+static int xhls_remove(struct platform_device *pdev)
+{
+ struct xhls_device *xhls = platform_get_drvdata(pdev);
+ struct v4l2_subdev *subdev = &xhls->xvip.subdev;
+
+ v4l2_async_unregister_subdev(subdev);
+ v4l2_ctrl_handler_free(&xhls->ctrl_handler);
+ media_entity_cleanup(&subdev->entity);
+
+ xvip_cleanup_resources(&xhls->xvip);
+
+ return 0;
+}
+
+static const struct of_device_id xhls_of_id_table[] = {
+ { .compatible = "xlnx,v-hls" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, xhls_of_id_table);
+
+static struct platform_driver xhls_driver = {
+ .driver = {
+ .name = "xilinx-hls",
+ .of_match_table = xhls_of_id_table,
+ },
+ .probe = xhls_probe,
+ .remove = xhls_remove,
+};
+
+module_platform_driver(xhls_driver);
+
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_DESCRIPTION("Xilinx HLS Core Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/xilinx/xilinx-m2m.c b/drivers/media/platform/xilinx/xilinx-m2m.c
new file mode 100644
index 000000000000..5a932a45e571
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-m2m.c
@@ -0,0 +1,2106 @@
+//SPDX-License-Identifier: GPL-2.0
+/*
+ * Xilinx V4L2 mem2mem driver
+ *
+ * Copyright (C) 2017-2018 Xilinx, Inc.
+ *
+ * Author: Satish Kumar Nagireddy <satish.nagireddy.nagireddy@xilinx.com>
+ */
+
+#include <drm/drm_fourcc.h>
+#include <linux/delay.h>
+#include <linux/dma/xilinx_frmbuf.h>
+#include <linux/lcm.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <media/v4l2-async.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "xilinx-vip.h"
+
+#define XVIP_M2M_NAME "xilinx-mem2mem"
+#define XVIP_M2M_DEFAULT_FMT V4L2_PIX_FMT_RGB24
+
+/* Minimum and maximum widths are expressed in bytes */
+#define XVIP_M2M_MIN_WIDTH 1U
+#define XVIP_M2M_MAX_WIDTH 65535U
+#define XVIP_M2M_MIN_HEIGHT 1U
+#define XVIP_M2M_MAX_HEIGHT 8191U
+
+#define XVIP_M2M_DEF_WIDTH 1920
+#define XVIP_M2M_DEF_HEIGHT 1080
+
+#define XVIP_M2M_PAD_SINK 1
+#define XVIP_M2M_PAD_SOURCE 0
+
+/**
+ * struct xvip_graph_entity - Entity in the video graph
+ * @list: list entry in a graph entities list
+ * @node: the entity's DT node
+ * @entity: media entity, from the corresponding V4L2 subdev
+ * @asd: subdev asynchronous registration information
+ * @subdev: V4L2 subdev
+ * @streaming: status of the V4L2 subdev if streaming or not
+ */
+struct xvip_graph_entity {
+ struct list_head list;
+ struct device_node *node;
+ struct media_entity *entity;
+
+ struct v4l2_async_subdev asd;
+ struct v4l2_subdev *subdev;
+ bool streaming;
+};
+
+/**
+ * struct xvip_pipeline - Xilinx Video IP pipeline structure
+ * @pipe: media pipeline
+ * @lock: protects the pipeline @stream_count
+ * @use_count: number of DMA engines using the pipeline
+ * @stream_count: number of DMA engines currently streaming
+ * @num_dmas: number of DMA engines in the pipeline
+ * @xdev: Composite device the pipe belongs to
+ */
+struct xvip_pipeline {
+ struct media_pipeline pipe;
+
+ /* protects the pipeline @stream_count */
+ struct mutex lock;
+ unsigned int use_count;
+ unsigned int stream_count;
+
+ unsigned int num_dmas;
+ struct xvip_m2m_dev *xdev;
+};
+
+struct xventity_list {
+ struct list_head list;
+ struct media_entity *entity;
+};
+
+/**
+ * struct xvip_m2m_dev - Xilinx Video mem2mem device structure
+ * @v4l2_dev: V4L2 device
+ * @dev: (OF) device
+ * @media_dev: media device
+ * @notifier: V4L2 asynchronous subdevs notifier
+ * @entities: entities in the graph as a list of xvip_graph_entity
+ * @num_subdevs: number of subdevs in the pipeline
+ * @lock: This is to protect mem2mem context structure data
+ * @queued_lock: This is to protect video buffer information
+ * @dma: Video DMA channels
+ * @m2m_dev: V4L2 mem2mem device structure
+ * @v4l2_caps: V4L2 capabilities of the whole device
+ */
+struct xvip_m2m_dev {
+ struct v4l2_device v4l2_dev;
+ struct device *dev;
+
+ struct media_device media_dev;
+ struct v4l2_async_notifier notifier;
+ struct list_head entities;
+ unsigned int num_subdevs;
+
+ /* Protects to m2m context data */
+ struct mutex lock;
+
+ /* Protects vb2_v4l2_buffer data */
+ spinlock_t queued_lock;
+ struct xvip_m2m_dma *dma;
+ struct v4l2_m2m_dev *m2m_dev;
+ u32 v4l2_caps;
+};
+
+static inline struct xvip_pipeline *to_xvip_pipeline(struct media_entity *e)
+{
+ return container_of(e->pipe, struct xvip_pipeline, pipe);
+}
+
+/**
+ * struct xvip_m2m_dma - Video DMA channel
+ * @video: V4L2 video device associated with the DMA channel
+ * @xdev: composite mem2mem device the DMA channels belongs to
+ * @chan_tx: DMA engine channel for MEM2DEV transfer
+ * @chan_rx: DMA engine channel for DEV2MEM transfer
+ * @outfmt: active V4L2 OUTPUT port pixel format
+ * @capfmt: active V4L2 CAPTURE port pixel format
+ * @r: crop rectangle parameters
+ * @outinfo: format information corresponding to the active @outfmt
+ * @capinfo: format information corresponding to the active @capfmt
+ * @align: transfer alignment required by the DMA channel (in bytes)
+ * @crop: boolean flag to indicate if crop is requested
+ * @pads: media pads for the video M2M device entity
+ * @pipe: pipeline belonging to the DMA channel
+ */
+struct xvip_m2m_dma {
+ struct video_device video;
+ struct xvip_m2m_dev *xdev;
+ struct dma_chan *chan_tx;
+ struct dma_chan *chan_rx;
+ struct v4l2_format outfmt;
+ struct v4l2_format capfmt;
+ struct v4l2_rect r;
+ const struct xvip_video_format *outinfo;
+ const struct xvip_video_format *capinfo;
+ u32 align;
+ bool crop;
+
+ struct media_pad pads[2];
+ struct xvip_pipeline pipe;
+};
+
+/**
+ * struct xvip_m2m_ctx - VIPP mem2mem context
+ * @fh: V4L2 file handler
+ * @xdev: composite mem2mem device the DMA channels belongs to
+ * @xt: dma interleaved template for dma configuration
+ * @sgl: data chunk structure for dma_interleaved_template
+ */
+struct xvip_m2m_ctx {
+ struct v4l2_fh fh;
+ struct xvip_m2m_dev *xdev;
+ struct dma_interleaved_template xt;
+ struct data_chunk sgl[1];
+};
+
+static inline struct xvip_m2m_ctx *file2ctx(struct file *file)
+{
+ return container_of(file->private_data, struct xvip_m2m_ctx, fh);
+}
+
+static struct v4l2_subdev *
+xvip_dma_remote_subdev(struct media_pad *local, u32 *pad)
+{
+ struct media_pad *remote;
+
+ remote = media_entity_remote_pad(local);
+ if (!remote || !is_media_entity_v4l2_subdev(remote->entity))
+ return NULL;
+
+ if (pad)
+ *pad = remote->index;
+
+ return media_entity_to_v4l2_subdev(remote->entity);
+}
+
+static int xvip_dma_verify_format(struct xvip_m2m_dma *dma)
+{
+ struct v4l2_subdev_format fmt;
+ struct v4l2_subdev *subdev;
+ int ret;
+ int width, height;
+
+ subdev = xvip_dma_remote_subdev(&dma->pads[XVIP_PAD_SOURCE], &fmt.pad);
+ if (!subdev)
+ return -EPIPE;
+
+ fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
+ if (ret < 0)
+ return ret == -ENOIOCTLCMD ? -EINVAL : ret;
+
+ if (dma->outinfo->code != fmt.format.code)
+ return -EINVAL;
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(dma->outfmt.type)) {
+ width = dma->outfmt.fmt.pix_mp.width;
+ height = dma->outfmt.fmt.pix_mp.height;
+ } else {
+ width = dma->outfmt.fmt.pix.width;
+ height = dma->outfmt.fmt.pix.height;
+ }
+
+ if (width != fmt.format.width || height != fmt.format.height)
+ return -EINVAL;
+
+ return 0;
+}
+
+#define to_xvip_dma(vdev) container_of(vdev, struct xvip_m2m_dma, video)
+/* -----------------------------------------------------------------------------
+ * Pipeline Stream Management
+ */
+
+/**
+ * xvip_subdev_set_streaming - Find and update streaming status of subdev
+ * @xdev: Composite video device
+ * @subdev: V4L2 sub-device
+ * @enable: enable/disable streaming status
+ *
+ * Walk the xvip graph entities list and find if subdev is present. Returns
+ * streaming status of subdev and update the status as requested
+ *
+ * Return: streaming status (true or false) if successful or warn_on if subdev
+ * is not present and return false
+ */
+static bool xvip_subdev_set_streaming(struct xvip_m2m_dev *xdev,
+ struct v4l2_subdev *subdev, bool enable)
+{
+ struct xvip_graph_entity *entity;
+
+ list_for_each_entry(entity, &xdev->entities, list)
+ if (entity->node == subdev->dev->of_node) {
+ bool status = entity->streaming;
+
+ entity->streaming = enable;
+ return status;
+ }
+
+ WARN(1, "Should never get here\n");
+ return false;
+}
+
+static int xvip_entity_start_stop(struct xvip_m2m_dev *xdev,
+ struct media_entity *entity, bool start)
+{
+ struct v4l2_subdev *subdev;
+ bool is_streaming;
+ int ret = 0;
+
+ dev_dbg(xdev->dev, "%s entity %s\n",
+ start ? "Starting" : "Stopping", entity->name);
+ subdev = media_entity_to_v4l2_subdev(entity);
+
+ /* This is to maintain list of stream on/off devices */
+ is_streaming = xvip_subdev_set_streaming(xdev, subdev, start);
+
+ /*
+ * start or stop the subdev only once in case if they are
+ * shared between sub-graphs
+ */
+ if (start && !is_streaming) {
+ /* power-on subdevice */
+ ret = v4l2_subdev_call(subdev, core, s_power, 1);
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
+ dev_err(xdev->dev,
+ "s_power on failed on subdev\n");
+ xvip_subdev_set_streaming(xdev, subdev, 0);
+ return ret;
+ }
+
+ /* stream-on subdevice */
+ ret = v4l2_subdev_call(subdev, video, s_stream, 1);
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
+ dev_err(xdev->dev,
+ "s_stream on failed on subdev\n");
+ v4l2_subdev_call(subdev, core, s_power, 0);
+ xvip_subdev_set_streaming(xdev, subdev, 0);
+ }
+ } else if (!start && is_streaming) {
+ /* stream-off subdevice */
+ ret = v4l2_subdev_call(subdev, video, s_stream, 0);
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
+ dev_err(xdev->dev,
+ "s_stream off failed on subdev\n");
+ xvip_subdev_set_streaming(xdev, subdev, 1);
+ }
+
+ /* power-off subdevice */
+ ret = v4l2_subdev_call(subdev, core, s_power, 0);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ dev_err(xdev->dev,
+ "s_power off failed on subdev\n");
+ }
+
+ return ret;
+}
+
+/**
+ * xvip_pipeline_start_stop - Start ot stop streaming on a pipeline
+ * @xdev: Composite video device
+ * @dma: xvip dma
+ * @start: Start (when true) or stop (when false) the pipeline
+ *
+ * Walk the entities chain starting @dma and start or stop all of them
+ *
+ * Return: 0 if successful, or the return value of the failed video::s_stream
+ * operation otherwise.
+ */
+static int xvip_pipeline_start_stop(struct xvip_m2m_dev *xdev,
+ struct xvip_m2m_dma *dma, bool start)
+{
+ struct media_graph graph;
+ struct media_entity *entity = &dma->video.entity;
+ struct media_device *mdev = entity->graph_obj.mdev;
+ struct xventity_list *temp, *_temp;
+ LIST_HEAD(ent_list);
+ int ret = 0;
+
+ mutex_lock(&mdev->graph_mutex);
+
+ /* Walk the graph to locate the subdev nodes */
+ ret = media_graph_walk_init(&graph, mdev);
+ if (ret)
+ goto error;
+
+ media_graph_walk_start(&graph, entity);
+
+ /* get the list of entities */
+ while ((entity = media_graph_walk_next(&graph))) {
+ struct xventity_list *ele;
+
+ /* We want to stream on/off only subdevs */
+ if (!is_media_entity_v4l2_subdev(entity))
+ continue;
+
+ /* Maintain the pipeline sequence in a list */
+ ele = kzalloc(sizeof(*ele), GFP_KERNEL);
+ if (!ele) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ele->entity = entity;
+ list_add(&ele->list, &ent_list);
+ }
+
+ if (start) {
+ list_for_each_entry_safe(temp, _temp, &ent_list, list) {
+ /* Enable all subdevs from sink to source */
+ ret = xvip_entity_start_stop(xdev, temp->entity, start);
+ if (ret < 0) {
+ dev_err(xdev->dev, "ret = %d for entity %s\n",
+ ret, temp->entity->name);
+ break;
+ }
+ }
+ } else {
+ list_for_each_entry_safe_reverse(temp, _temp, &ent_list, list)
+ /* Enable all subdevs from source to sink */
+ xvip_entity_start_stop(xdev, temp->entity, start);
+ }
+
+ list_for_each_entry_safe(temp, _temp, &ent_list, list) {
+ list_del(&temp->list);
+ kfree(temp);
+ }
+
+error:
+ mutex_unlock(&mdev->graph_mutex);
+ media_graph_walk_cleanup(&graph);
+ return ret;
+}
+
+/**
+ * xvip_pipeline_set_stream - Enable/disable streaming on a pipeline
+ * @pipe: The pipeline
+ * @on: Turn the stream on when true or off when false
+ *
+ * The pipeline is shared between all DMA engines connect at its input and
+ * output. While the stream state of DMA engines can be controlled
+ * independently, pipelines have a shared stream state that enable or disable
+ * all entities in the pipeline. For this reason the pipeline uses a streaming
+ * counter that tracks the number of DMA engines that have requested the stream
+ * to be enabled. This will walk the graph starting from each DMA and enable or
+ * disable the entities in the path.
+ *
+ * When called with the @on argument set to true, this function will increment
+ * the pipeline streaming count. If the streaming count reaches the number of
+ * DMA engines in the pipeline it will enable all entities that belong to the
+ * pipeline.
+ *
+ * Similarly, when called with the @on argument set to false, this function will
+ * decrement the pipeline streaming count and disable all entities in the
+ * pipeline when the streaming count reaches zero.
+ *
+ * Return: 0 if successful, or the return value of the failed video::s_stream
+ * operation otherwise. Stopping the pipeline never fails. The pipeline state is
+ * not updated when the operation fails.
+ */
+static int xvip_pipeline_set_stream(struct xvip_pipeline *pipe, bool on)
+{
+ struct xvip_m2m_dev *xdev;
+ struct xvip_m2m_dma *dma;
+ int ret = 0;
+
+ mutex_lock(&pipe->lock);
+ xdev = pipe->xdev;
+ dma = xdev->dma;
+
+ if (on) {
+ ret = xvip_pipeline_start_stop(xdev, dma, true);
+ if (ret < 0)
+ goto done;
+ pipe->stream_count++;
+ } else {
+ if (--pipe->stream_count == 0)
+ xvip_pipeline_start_stop(xdev, dma, false);
+ }
+
+done:
+ mutex_unlock(&pipe->lock);
+ return ret;
+}
+
+static int xvip_pipeline_validate(struct xvip_pipeline *pipe,
+ struct xvip_m2m_dma *start)
+{
+ struct media_graph graph;
+ struct media_entity *entity = &start->video.entity;
+ struct media_device *mdev = entity->graph_obj.mdev;
+ unsigned int num_inputs = 0;
+ unsigned int num_outputs = 0;
+ int ret;
+
+ mutex_lock(&mdev->graph_mutex);
+
+ /* Walk the graph to locate the video nodes. */
+ ret = media_graph_walk_init(&graph, mdev);
+ if (ret) {
+ mutex_unlock(&mdev->graph_mutex);
+ return ret;
+ }
+
+ media_graph_walk_start(&graph, entity);
+
+ while ((entity = media_graph_walk_next(&graph))) {
+ struct xvip_m2m_dma *dma;
+
+ if (entity->function != MEDIA_ENT_F_IO_V4L)
+ continue;
+
+ dma = to_xvip_dma(media_entity_to_video_device(entity));
+
+ num_outputs++;
+ num_inputs++;
+ }
+
+ mutex_unlock(&mdev->graph_mutex);
+
+ media_graph_walk_cleanup(&graph);
+
+ /* We need at least one DMA to proceed */
+ if (num_outputs == 0 && num_inputs == 0)
+ return -EPIPE;
+
+ pipe->num_dmas = num_inputs + num_outputs;
+ pipe->xdev = start->xdev;
+
+ return 0;
+}
+
+static void __xvip_pipeline_cleanup(struct xvip_pipeline *pipe)
+{
+ pipe->num_dmas = 0;
+}
+
+/**
+ * xvip_pipeline_cleanup - Cleanup the pipeline after streaming
+ * @pipe: the pipeline
+ *
+ * Decrease the pipeline use count and clean it up if we were the last user.
+ */
+static void xvip_pipeline_cleanup(struct xvip_pipeline *pipe)
+{
+ mutex_lock(&pipe->lock);
+
+ /* If we're the last user clean up the pipeline. */
+ if (--pipe->use_count == 0)
+ __xvip_pipeline_cleanup(pipe);
+
+ mutex_unlock(&pipe->lock);
+}
+
+/**
+ * xvip_pipeline_prepare - Prepare the pipeline for streaming
+ * @pipe: the pipeline
+ * @dma: DMA engine at one end of the pipeline
+ *
+ * Validate the pipeline if no user exists yet, otherwise just increase the use
+ * count.
+ *
+ * Return: 0 if successful or -EPIPE if the pipeline is not valid.
+ */
+static int xvip_pipeline_prepare(struct xvip_pipeline *pipe,
+ struct xvip_m2m_dma *dma)
+{
+ int ret;
+
+ mutex_lock(&pipe->lock);
+
+ /* If we're the first user validate and initialize the pipeline. */
+ if (pipe->use_count == 0) {
+ ret = xvip_pipeline_validate(pipe, dma);
+ if (ret < 0) {
+ __xvip_pipeline_cleanup(pipe);
+ goto done;
+ }
+ }
+
+ pipe->use_count++;
+ ret = 0;
+
+done:
+ mutex_unlock(&pipe->lock);
+ return ret;
+}
+
+static void xvip_m2m_dma_callback_mem2dev(void *data)
+{
+}
+
+static void xvip_m2m_dma_callback(void *data)
+{
+ struct xvip_m2m_ctx *ctx = data;
+ struct xvip_m2m_dev *xdev = ctx->xdev;
+ struct vb2_v4l2_buffer *src_vb, *dst_vb;
+
+ spin_lock(&xdev->queued_lock);
+ src_vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+
+ dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp;
+ dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+ dst_vb->flags |=
+ src_vb->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+ dst_vb->timecode = src_vb->timecode;
+
+ v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
+ v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
+ v4l2_m2m_job_finish(xdev->m2m_dev, ctx->fh.m2m_ctx);
+ spin_unlock(&xdev->queued_lock);
+}
+
+/*
+ * Queue operations
+ */
+
+static int xvip_m2m_queue_setup(struct vb2_queue *vq,
+ u32 *nbuffers, u32 *nplanes,
+ u32 sizes[], struct device *alloc_devs[])
+{
+ struct xvip_m2m_ctx *ctx = vb2_get_drv_priv(vq);
+ struct xvip_m2m_dma *dma = ctx->xdev->dma;
+ struct v4l2_format *f;
+ const struct xvip_video_format *info;
+ u32 i;
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ f = &dma->outfmt;
+ info = dma->outinfo;
+ } else {
+ f = &dma->capfmt;
+ info = dma->capinfo;
+ }
+
+ if (*nplanes) {
+ if (*nplanes != f->fmt.pix_mp.num_planes)
+ return -EINVAL;
+
+ for (i = 0; i < *nplanes; i++) {
+ if (sizes[i] < f->fmt.pix_mp.plane_fmt[i].sizeimage)
+ return -EINVAL;
+ }
+ } else {
+ *nplanes = info->buffers;
+ for (i = 0; i < info->buffers; i++)
+ sizes[i] = f->fmt.pix_mp.plane_fmt[i].sizeimage;
+ }
+
+ return 0;
+}
+
+static int xvip_m2m_buf_prepare(struct vb2_buffer *vb)
+{
+ struct xvip_m2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct xvip_m2m_dma *dma = ctx->xdev->dma;
+ struct v4l2_format *f;
+ const struct xvip_video_format *info;
+ u32 i;
+
+ if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ f = &dma->outfmt;
+ info = dma->outinfo;
+ } else {
+ f = &dma->capfmt;
+ info = dma->capinfo;
+ }
+
+ for (i = 0; i < info->buffers; i++) {
+ if (vb2_plane_size(vb, i) <
+ f->fmt.pix_mp.plane_fmt[i].sizeimage) {
+ dev_err(ctx->xdev->dev,
+ "insufficient plane size (%u < %u)\n",
+ (u32)vb2_plane_size(vb, i),
+ f->fmt.pix_mp.plane_fmt[i].sizeimage);
+ return -EINVAL;
+ }
+
+ vb2_set_plane_payload(vb, i,
+ f->fmt.pix_mp.plane_fmt[i].sizeimage);
+ }
+
+ return 0;
+}
+
+static void xvip_m2m_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct xvip_m2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+ v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
+}
+
+static void xvip_m2m_stop_streaming(struct vb2_queue *q)
+{
+ struct xvip_m2m_ctx *ctx = vb2_get_drv_priv(q);
+ struct xvip_m2m_dma *dma = ctx->xdev->dma;
+ struct xvip_pipeline *pipe = to_xvip_pipeline(&dma->video.entity);
+ struct vb2_v4l2_buffer *vbuf;
+
+ dma->crop = false;
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ dmaengine_terminate_sync(dma->chan_tx);
+ else
+ dmaengine_terminate_sync(dma->chan_rx);
+
+ if (ctx->xdev->num_subdevs) {
+ /* Stop the pipeline. */
+ xvip_pipeline_set_stream(pipe, false);
+
+ /* Cleanup the pipeline and mark it as being stopped. */
+ xvip_pipeline_cleanup(pipe);
+ media_pipeline_stop(&dma->video.entity);
+ }
+
+ for (;;) {
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ else
+ vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+
+ if (!vbuf)
+ return;
+
+ spin_lock(&ctx->xdev->queued_lock);
+ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
+ spin_unlock(&ctx->xdev->queued_lock);
+ }
+}
+
+static int xvip_m2m_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct xvip_m2m_ctx *ctx = vb2_get_drv_priv(q);
+ struct xvip_m2m_dma *dma = ctx->xdev->dma;
+ struct xvip_m2m_dev *xdev = ctx->xdev;
+ struct xvip_pipeline *pipe;
+ int ret;
+
+ if (!xdev->num_subdevs)
+ return 0;
+
+ pipe = dma->video.entity.pipe
+ ? to_xvip_pipeline(&dma->video.entity) : &dma->pipe;
+
+ ret = media_pipeline_start(&dma->video.entity, &pipe->pipe);
+ if (ret < 0)
+ goto error;
+
+ /* Verify that the configured format matches the output of the
+ * connected subdev.
+ */
+ ret = xvip_dma_verify_format(dma);
+ if (ret < 0)
+ goto error_stop;
+
+ ret = xvip_pipeline_prepare(pipe, dma);
+ if (ret < 0)
+ goto error_stop;
+
+ /* Start the pipeline. */
+ ret = xvip_pipeline_set_stream(pipe, true);
+ if (ret < 0)
+ goto error_stop;
+
+ return 0;
+error_stop:
+ media_pipeline_stop(&dma->video.entity);
+
+error:
+ xvip_m2m_stop_streaming(q);
+
+ return ret;
+}
+
+static const struct vb2_ops m2m_vb2_ops = {
+ .queue_setup = xvip_m2m_queue_setup,
+ .buf_prepare = xvip_m2m_buf_prepare,
+ .buf_queue = xvip_m2m_buf_queue,
+ .start_streaming = xvip_m2m_start_streaming,
+ .stop_streaming = xvip_m2m_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+static int xvip_m2m_queue_init(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq)
+{
+ struct xvip_m2m_ctx *ctx = priv;
+ int ret;
+
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ src_vq->drv_priv = ctx;
+ src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ src_vq->ops = &m2m_vb2_ops;
+ src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->dev = ctx->xdev->v4l2_dev.dev;
+
+ ret = vb2_queue_init(src_vq);
+ if (ret)
+ return ret;
+
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ dst_vq->drv_priv = ctx;
+ dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ dst_vq->ops = &m2m_vb2_ops;
+ dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->dev = ctx->xdev->v4l2_dev.dev;
+
+ return vb2_queue_init(dst_vq);
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 ioctls
+ */
+
+static int
+xvip_dma_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
+{
+ cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+ strlcpy(cap->driver, XVIP_M2M_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, XVIP_M2M_NAME, sizeof(cap->card));
+ strlcpy(cap->bus_info, XVIP_M2M_NAME, sizeof(cap->card));
+
+ return 0;
+}
+
+static int
+xvip_m2m_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+{
+ struct xvip_m2m_ctx *ctx = file2ctx(file);
+ struct xvip_m2m_dma *dma = ctx->xdev->dma;
+ const struct xvip_video_format *fmtinfo;
+ const struct xvip_video_format *fmt;
+ struct v4l2_subdev *subdev;
+ struct v4l2_subdev_format v4l_fmt;
+ struct xvip_m2m_dev *xdev = ctx->xdev;
+ u32 i, fmt_cnt, *fmts;
+ int ret;
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ ret = xilinx_xdma_get_v4l2_vid_fmts(dma->chan_rx,
+ &fmt_cnt, &fmts);
+ else
+ ret = xilinx_xdma_get_v4l2_vid_fmts(dma->chan_tx,
+ &fmt_cnt, &fmts);
+ if (ret)
+ return ret;
+
+ if (f->index >= fmt_cnt)
+ return -EINVAL;
+
+ if (!xdev->num_subdevs) {
+ fmt = xvip_get_format_by_fourcc(fmts[f->index]);
+ if (IS_ERR(fmt))
+ return PTR_ERR(fmt);
+
+ f->pixelformat = fmt->fourcc;
+ strlcpy(f->description, fmt->description,
+ sizeof(f->description));
+ return 0;
+ }
+
+ if (f->index > 0)
+ return -EINVAL;
+
+ /* Establish media pad format */
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ subdev = xvip_dma_remote_subdev(&dma->pads[XVIP_PAD_SOURCE],
+ &v4l_fmt.pad);
+ else
+ subdev = xvip_dma_remote_subdev(&dma->pads[XVIP_PAD_SINK],
+ &v4l_fmt.pad);
+ if (!subdev)
+ return -EPIPE;
+
+ v4l_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &v4l_fmt);
+ if (ret < 0)
+ return ret == -ENOIOCTLCMD ? -EINVAL : ret;
+
+ for (i = 0; i < fmt_cnt; i++) {
+ fmt = xvip_get_format_by_fourcc(fmts[i]);
+ if (IS_ERR(fmt))
+ return PTR_ERR(fmt);
+
+ if (fmt->code == v4l_fmt.format.code)
+ break;
+ }
+
+ if (i >= fmt_cnt)
+ return -EINVAL;
+
+ fmtinfo = xvip_get_format_by_fourcc(fmts[i]);
+ f->pixelformat = fmtinfo->fourcc;
+ strlcpy(f->description, fmtinfo->description, sizeof(f->description));
+
+ return 0;
+}
+
+static int xvip_m2m_get_fmt(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct xvip_m2m_ctx *ctx = file2ctx(file);
+ struct xvip_m2m_dma *dma = ctx->xdev->dma;
+ struct vb2_queue *vq;
+
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+ if (!vq)
+ return -EINVAL;
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ f->fmt.pix_mp = dma->outfmt.fmt.pix_mp;
+ else
+ f->fmt.pix_mp = dma->capfmt.fmt.pix_mp;
+
+ return 0;
+}
+
+static int __xvip_m2m_try_fmt(struct xvip_m2m_ctx *ctx, struct v4l2_format *f)
+{
+ struct xvip_m2m_dma *dma = ctx->xdev->dma;
+ const struct xvip_video_format *info;
+ struct v4l2_pix_format_mplane *pix_mp;
+ struct v4l2_plane_pix_format *plane_fmt;
+ u32 align, min_width, max_width;
+ u32 bpl, min_bpl, max_bpl;
+ u32 padding_factor_nume, padding_factor_deno;
+ u32 bpl_nume, bpl_deno;
+ u32 i, plane_width, plane_height;
+ struct v4l2_subdev_format fmt;
+ struct v4l2_subdev *subdev;
+ struct xvip_m2m_dev *xdev = ctx->xdev;
+ int ret;
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
+ f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return -EINVAL;
+
+ if (xdev->num_subdevs) {
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ subdev = xvip_dma_remote_subdev
+ (&dma->pads[XVIP_PAD_SOURCE], &fmt.pad);
+ else
+ subdev = xvip_dma_remote_subdev
+ (&dma->pads[XVIP_PAD_SINK], &fmt.pad);
+
+ if (!subdev)
+ return -EPIPE;
+
+ fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
+ if (ret < 0)
+ return -EINVAL;
+ }
+
+ pix_mp = &f->fmt.pix_mp;
+ plane_fmt = pix_mp->plane_fmt;
+ info = xvip_get_format_by_fourcc(f->fmt.pix_mp.pixelformat);
+ if (info) {
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ dma->outinfo = info;
+ else
+ dma->capinfo = info;
+ } else {
+ info = xvip_get_format_by_fourcc(XVIP_M2M_DEFAULT_FMT);
+ }
+
+ if (xdev->num_subdevs) {
+ if (info->code != fmt.format.code ||
+ fmt.format.width != pix_mp->width ||
+ fmt.format.height != pix_mp->height) {
+ dev_err(xdev->dev, "Failed to set format\n");
+ dev_info(xdev->dev,
+ "Reqed Code = %d, Width = %d, Height = %d\n",
+ info->code, pix_mp->width, pix_mp->height);
+ dev_info(xdev->dev,
+ "Subdev Code = %d, Width = %d, Height = %d",
+ fmt.format.code, fmt.format.width,
+ fmt.format.height);
+ return -EINVAL;
+ }
+ }
+
+ xvip_width_padding_factor(info->fourcc, &padding_factor_nume,
+ &padding_factor_deno);
+ xvip_bpl_scaling_factor(info->fourcc, &bpl_nume, &bpl_deno);
+
+ /*
+ * V4L2 specification suggests the driver corrects the format struct
+ * if any of the dimensions is unsupported
+ */
+ align = lcm(dma->align, info->bpp >> 3);
+ min_width = roundup(XVIP_M2M_MIN_WIDTH, align);
+ max_width = rounddown(XVIP_M2M_MAX_WIDTH, align);
+ pix_mp->width = clamp(pix_mp->width, min_width, max_width);
+ pix_mp->height = clamp(pix_mp->height, XVIP_M2M_MIN_HEIGHT,
+ XVIP_M2M_MAX_HEIGHT);
+
+ /*
+ * Clamp the requested bytes per line value. If the maximum
+ * bytes per line value is zero, the module doesn't support
+ * user configurable line sizes. Override the requested value
+ * with the minimum in that case.
+ */
+ max_bpl = rounddown(XVIP_M2M_MAX_WIDTH, align);
+
+ if (info->buffers == 1) {
+ /* Handling contiguous data with mplanes */
+ min_bpl = (pix_mp->width * info->bpl_factor *
+ padding_factor_nume * bpl_nume) /
+ (padding_factor_deno * bpl_deno);
+ min_bpl = roundup(min_bpl, align);
+ bpl = roundup(plane_fmt[0].bytesperline, align);
+ plane_fmt[0].bytesperline = clamp(bpl, min_bpl, max_bpl);
+
+ if (info->num_planes == 1) {
+ /* Single plane formats */
+ plane_fmt[0].sizeimage = plane_fmt[0].bytesperline *
+ pix_mp->height;
+ } else {
+ /* Multi plane formats in contiguous buffer*/
+ plane_fmt[0].sizeimage =
+ DIV_ROUND_UP(plane_fmt[0].bytesperline *
+ pix_mp->height *
+ info->bpp, 8);
+ }
+ } else {
+ /* Handling non-contiguous data with mplanes */
+ for (i = 0; i < info->num_planes; i++) {
+ plane_width = pix_mp->width / (i ? info->hsub : 1);
+ plane_height = pix_mp->height / (i ? info->vsub : 1);
+ min_bpl = (plane_width * info->bpl_factor *
+ padding_factor_nume * bpl_nume) /
+ (padding_factor_deno * bpl_deno);
+ min_bpl = roundup(min_bpl, align);
+ bpl = rounddown(plane_fmt[i].bytesperline, align);
+ plane_fmt[i].bytesperline = clamp(bpl, min_bpl,
+ max_bpl);
+ plane_fmt[i].sizeimage = plane_fmt[i].bytesperline *
+ plane_height;
+ }
+ }
+
+ return 0;
+}
+
+static int xvip_m2m_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct xvip_m2m_ctx *ctx = file2ctx(file);
+ int ret;
+
+ ret = __xvip_m2m_try_fmt(ctx, f);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int xvip_m2m_set_fmt(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct xvip_m2m_ctx *ctx = file2ctx(file);
+ struct xvip_m2m_dma *dma = ctx->xdev->dma;
+ struct vb2_queue *vq;
+ int ret;
+
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+ if (!vq)
+ return -EINVAL;
+
+ if (vb2_is_busy(vq)) {
+ v4l2_err(&ctx->xdev->v4l2_dev, "%s queue busy\n", __func__);
+ return -EBUSY;
+ }
+
+ ret = __xvip_m2m_try_fmt(ctx, f);
+ if (ret < 0)
+ return ret;
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ dma->outfmt.fmt.pix_mp = f->fmt.pix_mp;
+ else
+ dma->capfmt.fmt.pix_mp = f->fmt.pix_mp;
+
+ return 0;
+}
+
+static int
+xvip_m2m_g_selection(struct file *file, void *fh, struct v4l2_selection *s)
+{
+ struct xvip_m2m_ctx *ctx = file2ctx(file);
+ struct xvip_m2m_dma *dma = ctx->xdev->dma;
+ int ret = 0;
+
+ if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+ s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ switch (s->target) {
+ case V4L2_SEL_TGT_COMPOSE:
+ ret = -ENOTTY;
+ break;
+ case V4L2_SEL_TGT_CROP:
+ s->r.left = 0;
+ s->r.top = 0;
+ s->r.width = dma->r.width;
+ s->r.height = dma->r.height;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int
+xvip_m2m_s_selection(struct file *file, void *fh, struct v4l2_selection *s)
+{
+ struct xvip_m2m_ctx *ctx = file2ctx(file);
+ struct xvip_m2m_dma *dma = ctx->xdev->dma;
+ u32 min_width, max_width;
+ int ret = 0;
+
+ if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+ s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ switch (s->target) {
+ case V4L2_SEL_TGT_COMPOSE:
+ ret = -ENOTTY;
+ break;
+ case V4L2_SEL_TGT_CROP:
+ if (s->r.width > dma->outfmt.fmt.pix_mp.width ||
+ s->r.height > dma->outfmt.fmt.pix_mp.height ||
+ s->r.top != 0 || s->r.left != 0)
+ return -EINVAL;
+
+ dma->crop = true;
+ min_width = roundup(XVIP_M2M_MIN_WIDTH, dma->align);
+ max_width = rounddown(XVIP_M2M_MAX_WIDTH, dma->align);
+ dma->r.width = clamp(s->r.width, min_width, max_width);
+ dma->r.height = s->r.height;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static const struct v4l2_ioctl_ops xvip_m2m_ioctl_ops = {
+ .vidioc_querycap = xvip_dma_querycap,
+
+ .vidioc_enum_fmt_vid_cap_mplane = xvip_m2m_enum_fmt,
+ .vidioc_g_fmt_vid_cap_mplane = xvip_m2m_get_fmt,
+ .vidioc_try_fmt_vid_cap_mplane = xvip_m2m_try_fmt,
+ .vidioc_s_fmt_vid_cap_mplane = xvip_m2m_set_fmt,
+
+ .vidioc_enum_fmt_vid_out_mplane = xvip_m2m_enum_fmt,
+ .vidioc_g_fmt_vid_out_mplane = xvip_m2m_get_fmt,
+ .vidioc_try_fmt_vid_out_mplane = xvip_m2m_try_fmt,
+ .vidioc_s_fmt_vid_out_mplane = xvip_m2m_set_fmt,
+ .vidioc_s_selection = xvip_m2m_s_selection,
+ .vidioc_g_selection = xvip_m2m_g_selection,
+
+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+
+ .vidioc_streamon = v4l2_m2m_ioctl_streamon,
+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+};
+
+/*
+ * File operations
+ */
+static int xvip_m2m_open(struct file *file)
+{
+ struct xvip_m2m_dev *xdev = video_drvdata(file);
+ struct xvip_m2m_ctx *ctx = NULL;
+ int ret;
+
+ ctx = devm_kzalloc(xdev->dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ v4l2_fh_init(&ctx->fh, video_devdata(file));
+ file->private_data = &ctx->fh;
+ ctx->xdev = xdev;
+
+ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(xdev->m2m_dev, ctx,
+ &xvip_m2m_queue_init);
+ if (IS_ERR(ctx->fh.m2m_ctx)) {
+ ret = PTR_ERR(ctx->fh.m2m_ctx);
+ v4l2_fh_exit(&ctx->fh);
+ return ret;
+ }
+
+ v4l2_fh_add(&ctx->fh);
+ dev_info(xdev->dev, "Created instance %p, m2m_ctx: %p\n", ctx,
+ ctx->fh.m2m_ctx);
+ return 0;
+}
+
+static int xvip_m2m_release(struct file *file)
+{
+ struct xvip_m2m_ctx *ctx = file->private_data;
+
+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+ return 0;
+}
+
+static u32 xvip_m2m_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct xvip_m2m_ctx *ctx = file->private_data;
+ int ret;
+
+ mutex_lock(&ctx->xdev->lock);
+ ret = v4l2_m2m_poll(file, ctx->fh.m2m_ctx, wait);
+ mutex_unlock(&ctx->xdev->lock);
+
+ return ret;
+}
+
+static int xvip_m2m_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct xvip_m2m_ctx *ctx = file->private_data;
+
+ return v4l2_m2m_mmap(file, ctx->fh.m2m_ctx, vma);
+}
+
+/*
+ * mem2mem callbacks
+ */
+
+static int xvip_m2m_job_ready(void *priv)
+{
+ struct xvip_m2m_ctx *ctx = priv;
+
+ if ((v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) &&
+ (v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) > 0))
+ return 1;
+
+ return 0;
+}
+
+static void xvip_m2m_job_abort(void *priv)
+{
+ struct xvip_m2m_ctx *ctx = priv;
+
+ /* Will cancel the transaction in the next interrupt handler */
+ v4l2_m2m_job_finish(ctx->xdev->m2m_dev, ctx->fh.m2m_ctx);
+}
+
+static void xvip_m2m_prep_submit_dev2mem_desc(struct xvip_m2m_ctx *ctx,
+ struct vb2_v4l2_buffer *dst_buf)
+{
+ struct xvip_m2m_dma *dma = ctx->xdev->dma;
+ struct xvip_m2m_dev *xdev = ctx->xdev;
+ struct dma_async_tx_descriptor *desc;
+ dma_addr_t p_out;
+ const struct xvip_video_format *info;
+ struct v4l2_pix_format_mplane *pix_mp;
+ u32 padding_factor_nume, padding_factor_deno;
+ u32 bpl_nume, bpl_deno;
+ u32 luma_size;
+ u32 flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
+ enum operation_mode mode = DEFAULT;
+
+ p_out = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
+
+ if (!p_out) {
+ dev_err(xdev->dev,
+ "Acquiring kernel pointer to buffer failed\n");
+ return;
+ }
+
+ ctx->xt.dir = DMA_DEV_TO_MEM;
+ ctx->xt.src_sgl = false;
+ ctx->xt.dst_sgl = true;
+ ctx->xt.dst_start = p_out;
+
+ pix_mp = &dma->capfmt.fmt.pix_mp;
+ info = dma->capinfo;
+ xilinx_xdma_set_mode(dma->chan_rx, mode);
+ xilinx_xdma_v4l2_config(dma->chan_rx, pix_mp->pixelformat);
+ xvip_width_padding_factor(pix_mp->pixelformat, &padding_factor_nume,
+ &padding_factor_deno);
+ xvip_bpl_scaling_factor(pix_mp->pixelformat, &bpl_nume, &bpl_deno);
+
+ ctx->xt.frame_size = info->num_planes;
+ ctx->sgl[0].size = (pix_mp->width * info->bpl_factor *
+ padding_factor_nume * bpl_nume) /
+ (padding_factor_deno * bpl_deno);
+ ctx->sgl[0].icg = pix_mp->plane_fmt[0].bytesperline - ctx->sgl[0].size;
+ ctx->xt.numf = pix_mp->height;
+
+ /*
+ * dst_icg is the number of bytes to jump after last luma addr
+ * and before first chroma addr
+ */
+ ctx->sgl[0].src_icg = 0;
+
+ if (info->buffers == 1) {
+ /* Handling contiguous data with mplanes */
+ ctx->sgl[0].dst_icg = 0;
+ } else {
+ /* Handling non-contiguous data with mplanes */
+ if (info->buffers == 2) {
+ dma_addr_t chroma_cap =
+ vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 1);
+ luma_size = pix_mp->plane_fmt[0].bytesperline *
+ ctx->xt.numf;
+ if (chroma_cap > p_out)
+ ctx->sgl[0].dst_icg = chroma_cap - p_out -
+ luma_size;
+ }
+ }
+
+ desc = dmaengine_prep_interleaved_dma(dma->chan_rx, &ctx->xt, flags);
+ if (!desc) {
+ dev_err(xdev->dev, "Failed to prepare DMA rx transfer\n");
+ return;
+ }
+
+ desc->callback = xvip_m2m_dma_callback;
+ desc->callback_param = ctx;
+ dmaengine_submit(desc);
+ dma_async_issue_pending(dma->chan_rx);
+}
+
+static void xvip_m2m_prep_submit_mem2dev_desc(struct xvip_m2m_ctx *ctx,
+ struct vb2_v4l2_buffer *src_buf)
+{
+ struct xvip_m2m_dma *dma = ctx->xdev->dma;
+ struct xvip_m2m_dev *xdev = ctx->xdev;
+ struct dma_async_tx_descriptor *desc;
+ dma_addr_t p_in;
+ const struct xvip_video_format *info;
+ struct v4l2_pix_format_mplane *pix_mp;
+ u32 padding_factor_nume, padding_factor_deno;
+ u32 bpl_nume, bpl_deno;
+ u32 luma_size;
+ u32 flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
+ enum operation_mode mode = DEFAULT;
+ u32 bpl, src_width, src_height;
+
+ p_in = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
+
+ if (!p_in) {
+ dev_err(xdev->dev,
+ "Acquiring kernel pointer to buffer failed\n");
+ return;
+ }
+
+ ctx->xt.dir = DMA_MEM_TO_DEV;
+ ctx->xt.src_sgl = true;
+ ctx->xt.dst_sgl = false;
+ ctx->xt.src_start = p_in;
+
+ pix_mp = &dma->outfmt.fmt.pix_mp;
+ bpl = pix_mp->plane_fmt[0].bytesperline;
+ if (dma->crop) {
+ src_width = dma->r.width;
+ src_height = dma->r.height;
+ } else {
+ src_width = pix_mp->width;
+ src_height = pix_mp->height;
+ }
+
+ info = dma->outinfo;
+ xilinx_xdma_set_mode(dma->chan_tx, mode);
+ xilinx_xdma_v4l2_config(dma->chan_tx, pix_mp->pixelformat);
+ xvip_width_padding_factor(pix_mp->pixelformat, &padding_factor_nume,
+ &padding_factor_deno);
+ xvip_bpl_scaling_factor(pix_mp->pixelformat, &bpl_nume, &bpl_deno);
+
+ ctx->xt.frame_size = info->num_planes;
+ ctx->sgl[0].size = (src_width * info->bpl_factor *
+ padding_factor_nume * bpl_nume) /
+ (padding_factor_deno * bpl_deno);
+ ctx->sgl[0].icg = bpl - ctx->sgl[0].size;
+ ctx->xt.numf = src_height;
+
+ /*
+ * src_icg is the number of bytes to jump after last luma addr
+ * and before first chroma addr
+ */
+ ctx->sgl[0].dst_icg = 0;
+
+ if (info->buffers == 1) {
+ /* Handling contiguous data with mplanes */
+ ctx->sgl[0].src_icg = 0;
+ if (dma->crop)
+ ctx->sgl[0].src_icg = bpl *
+ (pix_mp->height - src_height);
+ } else {
+ /* Handling non-contiguous data with mplanes */
+ if (info->buffers == 2) {
+ dma_addr_t chroma_out =
+ vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 1);
+ luma_size = bpl * ctx->xt.numf;
+ if (chroma_out > p_in)
+ ctx->sgl[0].src_icg = chroma_out - p_in -
+ luma_size;
+ }
+ }
+
+ desc = dmaengine_prep_interleaved_dma(dma->chan_tx, &ctx->xt, flags);
+ if (!desc) {
+ dev_err(xdev->dev, "Failed to prepare DMA tx transfer\n");
+ return;
+ }
+
+ desc->callback = xvip_m2m_dma_callback_mem2dev;
+ desc->callback_param = ctx;
+ dmaengine_submit(desc);
+ dma_async_issue_pending(dma->chan_tx);
+}
+
+/**
+ * xvip_m2m_device_run - prepares and starts the device
+ *
+ * @priv: Instance private data
+ *
+ * This simulates all the immediate preparations required before starting
+ * a device. This will be called by the framework when it decides to schedule
+ * a particular instance.
+ */
+static void xvip_m2m_device_run(void *priv)
+{
+ struct xvip_m2m_ctx *ctx = priv;
+ struct vb2_v4l2_buffer *src_buf, *dst_buf;
+
+ src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+
+ /* Prepare and submit mem2dev transaction */
+ xvip_m2m_prep_submit_mem2dev_desc(ctx, src_buf);
+
+ /* Prepare and submit dev2mem transaction */
+ xvip_m2m_prep_submit_dev2mem_desc(ctx, dst_buf);
+}
+
+static const struct v4l2_file_operations xvip_m2m_fops = {
+ .owner = THIS_MODULE,
+ .open = xvip_m2m_open,
+ .release = xvip_m2m_release,
+ .poll = xvip_m2m_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = xvip_m2m_mmap,
+};
+
+static struct video_device xvip_m2m_videodev = {
+ .name = XVIP_M2M_NAME,
+ .fops = &xvip_m2m_fops,
+ .ioctl_ops = &xvip_m2m_ioctl_ops,
+ .release = video_device_release_empty,
+ .vfl_dir = VFL_DIR_M2M,
+ .device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING,
+ .vfl_type = VFL_TYPE_GRABBER,
+};
+
+static const struct v4l2_m2m_ops xvip_m2m_ops = {
+ .device_run = xvip_m2m_device_run,
+ .job_ready = xvip_m2m_job_ready,
+ .job_abort = xvip_m2m_job_abort,
+};
+
+static int xvip_m2m_dma_init(struct xvip_m2m_dma *dma)
+{
+ struct xvip_m2m_dev *xdev;
+ struct v4l2_pix_format_mplane *pix_mp;
+ int ret;
+
+ xdev = dma->xdev;
+ mutex_init(&xdev->lock);
+ mutex_init(&dma->pipe.lock);
+ spin_lock_init(&xdev->queued_lock);
+
+ /* Format info on capture port - NV12 is the default format */
+ dma->capinfo = xvip_get_format_by_fourcc(XVIP_M2M_DEFAULT_FMT);
+ pix_mp = &dma->capfmt.fmt.pix_mp;
+ pix_mp->pixelformat = dma->capinfo->fourcc;
+
+ pix_mp->field = V4L2_FIELD_NONE;
+ pix_mp->width = XVIP_M2M_DEF_WIDTH;
+ pix_mp->height = XVIP_M2M_DEF_HEIGHT;
+ pix_mp->plane_fmt[0].bytesperline = pix_mp->width *
+ dma->capinfo->bpl_factor;
+ pix_mp->plane_fmt[0].sizeimage =
+ DIV_ROUND_UP(pix_mp->plane_fmt[0].bytesperline *
+ pix_mp->height * dma->capinfo->bpp, 8);
+
+ /* Format info on output port - NV12 is the default format */
+ dma->outinfo = xvip_get_format_by_fourcc(XVIP_M2M_DEFAULT_FMT);
+ pix_mp = &dma->capfmt.fmt.pix_mp;
+ pix_mp->pixelformat = dma->outinfo->fourcc;
+ pix_mp->field = V4L2_FIELD_NONE;
+ pix_mp->width = XVIP_M2M_DEF_WIDTH;
+ pix_mp->height = XVIP_M2M_DEF_HEIGHT;
+ pix_mp->plane_fmt[0].bytesperline = pix_mp->width *
+ dma->outinfo->bpl_factor;
+ pix_mp->plane_fmt[0].sizeimage =
+ DIV_ROUND_UP(pix_mp->plane_fmt[0].bytesperline *
+ pix_mp->height * dma->outinfo->bpp, 8);
+
+ /* DMA channels for mem2mem */
+ dma->chan_tx = dma_request_chan(xdev->dev, "tx");
+ if (IS_ERR(dma->chan_tx)) {
+ ret = PTR_ERR(dma->chan_tx);
+ if (ret != -EPROBE_DEFER)
+ dev_err(xdev->dev, "mem2mem DMA tx channel not found");
+
+ return ret;
+ }
+
+ dma->chan_rx = dma_request_chan(xdev->dev, "rx");
+ if (IS_ERR(dma->chan_rx)) {
+ ret = PTR_ERR(dma->chan_rx);
+ if (ret != -EPROBE_DEFER)
+ dev_err(xdev->dev, "mem2mem DMA rx channel not found");
+
+ goto tx;
+ }
+
+ dma->align = BIT(dma->chan_tx->device->copy_align);
+
+ /* Video node */
+ dma->video = xvip_m2m_videodev;
+ dma->video.v4l2_dev = &xdev->v4l2_dev;
+ dma->video.lock = &xdev->lock;
+
+ dma->pads[XVIP_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ dma->pads[XVIP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(&dma->video.entity, 2, dma->pads);
+ if (ret < 0)
+ goto error;
+
+ ret = video_register_device(&dma->video, VFL_TYPE_GRABBER, -1);
+ if (ret < 0) {
+ dev_err(xdev->dev, "Failed to register mem2mem video device\n");
+ goto tx_rx;
+ }
+
+ video_set_drvdata(&dma->video, dma->xdev);
+ return 0;
+
+tx_rx:
+ dma_release_channel(dma->chan_rx);
+tx:
+ dma_release_channel(dma->chan_tx);
+error:
+ return ret;
+}
+
+static void xvip_m2m_dma_deinit(struct xvip_m2m_dma *dma)
+{
+ if (video_is_registered(&dma->video))
+ video_unregister_device(&dma->video);
+
+ mutex_destroy(&dma->pipe.lock);
+ mutex_destroy(&dma->xdev->lock);
+ dma_release_channel(dma->chan_tx);
+ dma_release_channel(dma->chan_rx);
+}
+
+static int xvip_m2m_dma_alloc_init(struct xvip_m2m_dev *xdev)
+{
+ struct xvip_m2m_dma *dma = NULL;
+ int ret;
+
+ dma = devm_kzalloc(xdev->dev, sizeof(*dma), GFP_KERNEL);
+ if (!dma)
+ return -ENOMEM;
+
+ dma->xdev = xdev;
+ xdev->dma = dma;
+
+ ret = xvip_m2m_dma_init(xdev->dma);
+ if (ret) {
+ dev_err(xdev->dev, "DMA initialization failed\n");
+ return ret;
+ }
+
+ xdev->v4l2_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Platform Device Driver
+ */
+static void xvip_composite_v4l2_cleanup(struct xvip_m2m_dev *xdev)
+{
+ v4l2_device_unregister(&xdev->v4l2_dev);
+ media_device_unregister(&xdev->media_dev);
+ media_device_cleanup(&xdev->media_dev);
+}
+
+static int xvip_composite_v4l2_init(struct xvip_m2m_dev *xdev)
+{
+ int ret;
+
+ xdev->media_dev.dev = xdev->dev;
+ strlcpy(xdev->media_dev.model, "Xilinx Videoi M2M Composite Device",
+ sizeof(xdev->media_dev.model));
+ xdev->media_dev.hw_revision = 0;
+
+ media_device_init(&xdev->media_dev);
+
+ xdev->v4l2_dev.mdev = &xdev->media_dev;
+ ret = v4l2_device_register(xdev->dev, &xdev->v4l2_dev);
+ if (ret < 0) {
+ dev_err(xdev->dev, "V4L2 device registration failed (%d)\n",
+ ret);
+ media_device_cleanup(&xdev->media_dev);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct xvip_graph_entity *
+xvip_graph_find_entity(struct xvip_m2m_dev *xdev,
+ const struct device_node *node)
+{
+ struct xvip_graph_entity *entity;
+
+ list_for_each_entry(entity, &xdev->entities, list) {
+ if (entity->node == node)
+ return entity;
+ }
+
+ return NULL;
+}
+
+static int xvip_graph_build_one(struct xvip_m2m_dev *xdev,
+ struct xvip_graph_entity *entity)
+{
+ u32 link_flags = MEDIA_LNK_FL_ENABLED;
+ struct media_entity *local = entity->entity;
+ struct media_entity *remote;
+ struct media_pad *local_pad;
+ struct media_pad *remote_pad;
+ struct xvip_graph_entity *ent;
+ struct v4l2_fwnode_link link;
+ struct device_node *ep = NULL;
+ struct device_node *next;
+ int ret = 0;
+
+ dev_dbg(xdev->dev, "creating links for entity %s\n", local->name);
+
+ while (1) {
+ /* Get the next endpoint and parse its link. */
+ next = of_graph_get_next_endpoint(entity->node, ep);
+ if (!next)
+ break;
+
+ ep = next;
+
+ dev_dbg(xdev->dev, "processing endpoint %pOF\n", ep);
+
+ ret = v4l2_fwnode_parse_link(of_fwnode_handle(ep), &link);
+ if (ret < 0) {
+ dev_err(xdev->dev, "failed to parse link for %pOF\n",
+ ep);
+ continue;
+ }
+
+ /* Skip sink ports, they will be processed from the other end of
+ * the link.
+ */
+ if (link.local_port >= local->num_pads) {
+ dev_err(xdev->dev, "invalid port number %u for %pOF\n",
+ link.local_port,
+ to_of_node(link.local_node));
+ v4l2_fwnode_put_link(&link);
+ ret = -EINVAL;
+ break;
+ }
+
+ local_pad = &local->pads[link.local_port];
+
+ if (local_pad->flags & MEDIA_PAD_FL_SINK) {
+ dev_dbg(xdev->dev, "skipping sink port %pOF:%u\n",
+ to_of_node(link.local_node),
+ link.local_port);
+ v4l2_fwnode_put_link(&link);
+ continue;
+ }
+
+ /* Skip DMA engines, they will be processed separately. */
+ if (link.remote_node == of_fwnode_handle(xdev->dev->of_node)) {
+ dev_dbg(xdev->dev, "skipping DMA port %pOF:%u\n",
+ to_of_node(link.local_node),
+ link.local_port);
+ v4l2_fwnode_put_link(&link);
+ continue;
+ }
+
+ /* Find the remote entity. */
+ ent = xvip_graph_find_entity(xdev,
+ to_of_node(link.remote_node));
+ if (!ent) {
+ dev_err(xdev->dev, "no entity found for %pOF\n",
+ to_of_node(link.remote_node));
+ v4l2_fwnode_put_link(&link);
+ ret = -ENODEV;
+ break;
+ }
+
+ remote = ent->entity;
+
+ if (link.remote_port >= remote->num_pads) {
+ dev_err(xdev->dev, "invalid port number %u on %pOF\n",
+ link.remote_port, to_of_node(link.remote_node));
+ v4l2_fwnode_put_link(&link);
+ ret = -EINVAL;
+ break;
+ }
+
+ remote_pad = &remote->pads[link.remote_port];
+
+ v4l2_fwnode_put_link(&link);
+
+ /* Create the media link. */
+ dev_dbg(xdev->dev, "creating %s:%u -> %s:%u link\n",
+ local->name, local_pad->index,
+ remote->name, remote_pad->index);
+
+ ret = media_create_pad_link(local, local_pad->index,
+ remote, remote_pad->index,
+ link_flags);
+ if (ret < 0) {
+ dev_err(xdev->dev,
+ "failed to create %s:%u -> %s:%u link\n",
+ local->name, local_pad->index,
+ remote->name, remote_pad->index);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int xvip_graph_parse_one(struct xvip_m2m_dev *xdev,
+ struct device_node *node)
+{
+ struct xvip_graph_entity *entity;
+ struct device_node *remote;
+ struct device_node *ep = NULL;
+ int ret = 0;
+
+ dev_dbg(xdev->dev, "parsing node %pOF\n", node);
+
+ while (1) {
+ ep = of_graph_get_next_endpoint(node, ep);
+ if (!ep)
+ break;
+
+ dev_dbg(xdev->dev, "handling endpoint %pOF %s\n",
+ ep, ep->name);
+
+ remote = of_graph_get_remote_port_parent(ep);
+ if (!remote) {
+ ret = -EINVAL;
+ break;
+ }
+ dev_dbg(xdev->dev, "Remote endpoint %pOF %s\n",
+ remote, remote->name);
+
+ /* Skip entities that we have already processed. */
+ if (remote == xdev->dev->of_node ||
+ xvip_graph_find_entity(xdev, remote)) {
+ of_node_put(remote);
+ continue;
+ }
+
+ entity = devm_kzalloc(xdev->dev, sizeof(*entity), GFP_KERNEL);
+ if (!entity) {
+ of_node_put(remote);
+ ret = -ENOMEM;
+ break;
+ }
+
+ entity->node = remote;
+ entity->asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
+ entity->asd.match.fwnode = of_fwnode_handle(remote);
+ list_add_tail(&entity->list, &xdev->entities);
+ xdev->num_subdevs++;
+ }
+
+ of_node_put(ep);
+ return ret;
+}
+
+static int xvip_graph_parse(struct xvip_m2m_dev *xdev)
+{
+ struct xvip_graph_entity *entity;
+ int ret;
+
+ /*
+ * Walk the links to parse the full graph. Start by parsing the
+ * composite node and then parse entities in turn. The list_for_each
+ * loop will handle entities added at the end of the list while walking
+ * the links.
+ */
+ ret = xvip_graph_parse_one(xdev, xdev->dev->of_node);
+ if (ret < 0)
+ return 0;
+
+ list_for_each_entry(entity, &xdev->entities, list) {
+ ret = xvip_graph_parse_one(xdev, entity->node);
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
+}
+
+static int xvip_graph_build_dma(struct xvip_m2m_dev *xdev)
+{
+ u32 link_flags = MEDIA_LNK_FL_ENABLED;
+ struct device_node *node = xdev->dev->of_node;
+ struct media_entity *source;
+ struct media_entity *sink;
+ struct media_pad *source_pad;
+ struct media_pad *sink_pad;
+ struct xvip_graph_entity *ent;
+ struct v4l2_fwnode_link link;
+ struct device_node *ep = NULL;
+ struct device_node *next;
+ struct xvip_m2m_dma *dma = xdev->dma;
+ int ret = 0;
+
+ dev_dbg(xdev->dev, "creating links for DMA engines\n");
+
+ while (1) {
+ /* Get the next endpoint and parse its link. */
+ next = of_graph_get_next_endpoint(node, ep);
+ if (!next)
+ break;
+
+ ep = next;
+
+ dev_dbg(xdev->dev, "processing endpoint %pOF\n", ep);
+
+ ret = v4l2_fwnode_parse_link(of_fwnode_handle(ep), &link);
+ if (ret < 0) {
+ dev_err(xdev->dev, "failed to parse link for %pOF\n",
+ ep);
+ continue;
+ }
+
+ dev_dbg(xdev->dev, "creating link for DMA engine %s\n",
+ dma->video.name);
+
+ /* Find the remote entity. */
+ ent = xvip_graph_find_entity(xdev,
+ to_of_node(link.remote_node));
+ if (!ent) {
+ dev_err(xdev->dev, "no entity found for %pOF\n",
+ to_of_node(link.remote_node));
+ v4l2_fwnode_put_link(&link);
+ ret = -ENODEV;
+ break;
+ }
+ if (link.remote_port >= ent->entity->num_pads) {
+ dev_err(xdev->dev, "invalid port number %u on %pOF\n",
+ link.remote_port,
+ to_of_node(link.remote_node));
+ v4l2_fwnode_put_link(&link);
+ ret = -EINVAL;
+ break;
+ }
+
+ dev_dbg(xdev->dev, "Entity %s %s\n", ent->node->name,
+ ent->node->full_name);
+ dev_dbg(xdev->dev, "port number %u on %pOF\n",
+ link.remote_port, to_of_node(link.remote_node));
+ dev_dbg(xdev->dev, "local port number %u on %pOF\n",
+ link.local_port, to_of_node(link.local_node));
+
+ if (link.local_port == XVIP_PAD_SOURCE) {
+ source = &dma->video.entity;
+ source_pad = &dma->pads[XVIP_PAD_SOURCE];
+ sink = ent->entity;
+ sink_pad = &sink->pads[XVIP_PAD_SINK];
+
+ } else {
+ source = ent->entity;
+ source_pad = &source->pads[XVIP_PAD_SOURCE];
+ sink = &dma->video.entity;
+ sink_pad = &dma->pads[XVIP_PAD_SINK];
+ }
+
+ v4l2_fwnode_put_link(&link);
+
+ /* Create the media link. */
+ dev_dbg(xdev->dev, "creating %s:%u -> %s:%u link\n",
+ source->name, source_pad->index,
+ sink->name, sink_pad->index);
+
+ ret = media_create_pad_link(source, source_pad->index,
+ sink, sink_pad->index,
+ link_flags);
+ if (ret < 0) {
+ dev_err(xdev->dev,
+ "failed to create %s:%u -> %s:%u link\n",
+ source->name, source_pad->index,
+ sink->name, sink_pad->index);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int xvip_graph_notify_complete(struct v4l2_async_notifier *notifier)
+{
+ struct xvip_m2m_dev *xdev =
+ container_of(notifier, struct xvip_m2m_dev, notifier);
+ struct xvip_graph_entity *entity;
+ int ret;
+
+ dev_dbg(xdev->dev, "notify complete, all subdevs registered\n");
+
+ /* Create links for every entity. */
+ list_for_each_entry(entity, &xdev->entities, list) {
+ ret = xvip_graph_build_one(xdev, entity);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Create links for DMA channels. */
+ ret = xvip_graph_build_dma(xdev);
+ if (ret < 0)
+ return ret;
+
+ ret = v4l2_device_register_subdev_nodes(&xdev->v4l2_dev);
+ if (ret < 0)
+ dev_err(xdev->dev, "failed to register subdev nodes\n");
+
+ return media_device_register(&xdev->media_dev);
+}
+
+static int xvip_graph_notify_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_subdev *asd)
+{
+ struct xvip_m2m_dev *xdev =
+ container_of(notifier, struct xvip_m2m_dev, notifier);
+ struct xvip_graph_entity *entity;
+
+ /* Locate the entity corresponding to the bound subdev and store the
+ * subdev pointer.
+ */
+ list_for_each_entry(entity, &xdev->entities, list) {
+ if (entity->node != subdev->dev->of_node)
+ continue;
+
+ if (entity->subdev) {
+ dev_err(xdev->dev, "duplicate subdev for node %pOF\n",
+ entity->node);
+ return -EINVAL;
+ }
+
+ dev_dbg(xdev->dev, "subdev %s bound\n", subdev->name);
+ entity->entity = &subdev->entity;
+ entity->subdev = subdev;
+ return 0;
+ }
+
+ dev_err(xdev->dev, "no entity for subdev %s\n", subdev->name);
+ return -EINVAL;
+}
+
+static const struct v4l2_async_notifier_operations xvip_graph_notify_ops = {
+ .bound = xvip_graph_notify_bound,
+ .complete = xvip_graph_notify_complete,
+};
+
+static void xvip_graph_cleanup(struct xvip_m2m_dev *xdev)
+{
+ struct xvip_graph_entity *entityp;
+ struct xvip_graph_entity *entity;
+
+ v4l2_async_notifier_unregister(&xdev->notifier);
+
+ list_for_each_entry_safe(entity, entityp, &xdev->entities, list) {
+ of_node_put(entity->node);
+ list_del(&entity->list);
+ }
+}
+
+static int xvip_graph_init(struct xvip_m2m_dev *xdev)
+{
+ struct xvip_graph_entity *entity;
+ struct v4l2_async_subdev **subdevs = NULL;
+ unsigned int num_subdevs;
+ int ret;
+
+ /* Init the DMA channels. */
+ ret = xvip_m2m_dma_alloc_init(xdev);
+ if (ret < 0) {
+ dev_err(xdev->dev, "DMA initialization failed\n");
+ goto done;
+ }
+
+ /* Parse the graph to extract a list of subdevice DT nodes. */
+ ret = xvip_graph_parse(xdev);
+ if (ret < 0) {
+ dev_err(xdev->dev, "graph parsing failed\n");
+ goto done;
+ }
+ dev_dbg(xdev->dev, "Number of subdev = %d\n", xdev->num_subdevs);
+
+ if (!xdev->num_subdevs) {
+ dev_err(xdev->dev, "no subdev found in graph\n");
+ goto done;
+ }
+
+ /* Register the subdevices notifier. */
+ num_subdevs = xdev->num_subdevs;
+ subdevs = devm_kzalloc(xdev->dev, sizeof(*subdevs) * num_subdevs,
+ GFP_KERNEL);
+ if (!subdevs) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ v4l2_async_notifier_init(&xdev->notifier);
+ list_for_each_entry(entity, &xdev->entities, list) {
+ ret = v4l2_async_notifier_add_subdev(&xdev->notifier, &entity->asd);
+ if (ret)
+ goto done;
+ xdev->notifier.ops = &xvip_graph_notify_ops;
+ }
+
+ ret = v4l2_async_notifier_register(&xdev->v4l2_dev, &xdev->notifier);
+ if (ret < 0) {
+ dev_err(xdev->dev, "notifier registration failed\n");
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ if (ret < 0)
+ xvip_graph_cleanup(xdev);
+
+ return ret;
+}
+
+static int xvip_composite_remove(struct platform_device *pdev)
+{
+ struct xvip_m2m_dev *xdev = platform_get_drvdata(pdev);
+
+ xvip_graph_cleanup(xdev);
+ xvip_composite_v4l2_cleanup(xdev);
+
+ return 0;
+}
+
+static int xvip_m2m_probe(struct platform_device *pdev)
+{
+ struct xvip_m2m_dev *xdev = NULL;
+ int ret;
+
+ xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL);
+ if (!xdev)
+ return -ENOMEM;
+
+ xdev->dev = &pdev->dev;
+ INIT_LIST_HEAD(&xdev->entities);
+
+ ret = xvip_composite_v4l2_init(xdev);
+ if (ret)
+ return -EINVAL;
+
+ ret = xvip_graph_init(xdev);
+ if (ret < 0)
+ goto error;
+
+ ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
+ if (ret) {
+ dev_err(&pdev->dev, "dma_set_coherent_mask: %d\n", ret);
+ goto dma_cleanup;
+ }
+
+ platform_set_drvdata(pdev, xdev);
+
+ xdev->m2m_dev = v4l2_m2m_init(&xvip_m2m_ops);
+ if (IS_ERR(xdev->m2m_dev)) {
+ dev_err(xdev->dev, "Failed to init mem2mem device\n");
+ ret = PTR_ERR(xdev->m2m_dev);
+ goto dma_cleanup;
+ }
+
+ dev_info(xdev->dev, "mem2mem device registered\n");
+ return 0;
+
+dma_cleanup:
+ xvip_m2m_dma_deinit(xdev->dma);
+
+error:
+ v4l2_device_unregister(&xdev->v4l2_dev);
+ return ret;
+}
+
+static int xvip_m2m_remove(struct platform_device *pdev)
+{
+ xvip_composite_remove(pdev);
+ return 0;
+}
+
+static const struct of_device_id xvip_m2m_of_id_table[] = {
+ { .compatible = "xlnx,mem2mem" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, xvip_m2m_of_id_table);
+
+static struct platform_driver xvip_m2m_driver = {
+ .driver = {
+ .name = XVIP_M2M_NAME,
+ .of_match_table = xvip_m2m_of_id_table,
+ },
+ .probe = xvip_m2m_probe,
+ .remove = xvip_m2m_remove,
+};
+
+module_platform_driver(xvip_m2m_driver);
+
+MODULE_AUTHOR("Xilinx Inc.");
+MODULE_DESCRIPTION("Xilinx V4L2 mem2mem driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/xilinx/xilinx-multi-scaler-coeff.h b/drivers/media/platform/xilinx/xilinx-multi-scaler-coeff.h
new file mode 100644
index 000000000000..65a3482aa249
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-multi-scaler-coeff.h
@@ -0,0 +1,574 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Xilinx Memory-to-Memory Video Multi-Scaler IP
+ *
+ * Copyright (C) 2018 Xilinx, Inc.
+ *
+ * Author: Suresh Gupta <sureshg@xilinx.com>
+ *
+ * The file contains the coefficients used by the Xilinx
+ * Video Multi Scaler Controller driver (xm2msc)
+ *
+ */
+
+#define XSCALER_MAX_PHASES (64)
+#define XSCALER_MAX_TAPS (12)
+
+#define XSCALER_TAPS_6 (6)
+#define XSCALER_TAPS_8 (8)
+#define XSCALER_TAPS_10 (10)
+#define XSCALER_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,
+};
+
+/* H-scaler coefficients for 6, 8, 10 and 12 tap filters */
+static const short
+xhsc_coeff_taps6[XSCALER_MAX_PHASES][XSCALER_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 short
+xhsc_coeff_taps8[XSCALER_MAX_PHASES][XSCALER_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 short
+xhsc_coeff_taps10[XSCALER_MAX_PHASES][XSCALER_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 short
+xhsc_coeff_taps12[XSCALER_MAX_PHASES][XSCALER_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 short
+xvsc_coeff_taps6[XSCALER_MAX_PHASES][XSCALER_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 short
+xvsc_coeff_taps8[XSCALER_MAX_PHASES][XSCALER_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 short
+xvsc_coeff_taps10[XSCALER_MAX_PHASES][XSCALER_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 short
+xvsc_coeff_taps12[XSCALER_MAX_PHASES][XSCALER_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, },
+};
diff --git a/drivers/media/platform/xilinx/xilinx-multi-scaler.c b/drivers/media/platform/xilinx/xilinx-multi-scaler.c
new file mode 100644
index 000000000000..2892ed5c223a
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-multi-scaler.c
@@ -0,0 +1,2449 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Xilinx Memory-to-Memory Video Multi-Scaler IP
+ *
+ * Copyright (C) 2018 Xilinx, Inc.
+ *
+ * Author: Suresh Gupta <suresh.gupta@xilinx.com>
+ *
+ * Based on the virtual v4l2-mem2mem example device
+ *
+ * This driver adds support to control the Xilinx Video Multi
+ * Scaler Controller
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.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/sched.h>
+#include <linux/slab.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "xilinx-multi-scaler-coeff.h"
+
+/* 0x0000 : Control signals */
+#define XM2MSC_AP_CTRL 0x0000
+#define XM2MSC_AP_CTRL_START BIT(0)
+#define XM2MSC_AP_CTRL_DONE BIT(1)
+#define XM2MSC_AP_CTRL_IDEL BIT(2)
+#define XM2MSC_AP_CTRL_READY BIT(3)
+#define XM2MSC_AP_CTRL_AUTO_RESTART BIT(7)
+
+/* 0x0004 : Global Interrupt Enable Register */
+#define XM2MSC_GIE 0x0004
+#define XM2MSC_GIE_EN BIT(0)
+
+/* 0x0008 : IP Interrupt Enable Register (Read/Write) */
+#define XM2MSC_IER 0x0008
+#define XM2MSC_ISR 0x000c
+#define XM2MSC_ISR_DONE BIT(0)
+#define XM2MSC_ISR_READY BIT(1)
+
+#define XM2MSC_NUM_OUTS 0x0010
+
+#define XM2MSC_WIDTHIN 0x000
+#define XM2MSC_WIDTHOUT 0x008
+#define XM2MSC_HEIGHTIN 0x010
+#define XM2MSC_HEIGHTOUT 0x018
+#define XM2MSC_LINERATE 0x020
+#define XM2MSC_PIXELRATE 0x028
+#define XM2MSC_INPIXELFMT 0x030
+#define XM2MSC_OUTPIXELFMT 0x038
+#define XM2MSC_INSTRIDE 0x050
+#define XM2MSC_OUTSTRIDE 0x058
+#define XM2MSC_SRCIMGBUF0 0x060
+#define XM2MSC_SRCIMGBUF1 0x070
+#define XM2MSC_DSTIMGBUF0 0x090
+#define XM2MSC_DSTIMGBUF1 0x0100
+
+#define XM2MVSC_VFLTCOEFF_L 0x2000
+#define XM2MVSC_VFLTCOEFF(x) (XM2MVSC_VFLTCOEFF_L + 0x2000 * (x))
+#define XM2MVSC_HFLTCOEFF_L 0x2800
+#define XM2MVSC_HFLTCOEFF(x) (XM2MVSC_HFLTCOEFF_L + 0x2000 * (x))
+
+#define XM2MSC_CHAN_REGS_START(x) (0x100 + 0x200 * (x))
+
+/*
+ * IP has reserved area between XM2MSC_DSTIMGBUF0 and
+ * XM2MSC_DSTIMGBUF1 registers of channel 4
+ */
+#define XM2MSC_RESERVED_AREA 0x600
+
+/* GPIO RESET MACROS */
+#define XM2MSC_RESET_ASSERT (0x1)
+#define XM2MSC_RESET_DEASSERT (0x0)
+
+#define XM2MSC_MIN_CHAN 1
+#define XM2MSC_MAX_CHAN 8
+
+#define XM2MSC_MAX_WIDTH (8192)
+#define XM2MSC_MAX_HEIGHT (4320)
+#define XM2MSC_MIN_WIDTH (64)
+#define XM2MSC_MIN_HEIGHT (64)
+#define XM2MSC_STEP_PRECISION (65536)
+/* Mask definitions for Low 16 bits in a 32 bit number */
+#define XM2MSC_MASK_LOW_16BITS GENMASK(15, 0)
+#define XM2MSC_BITSHIFT_16 (16)
+
+#define XM2MSC_DRIVER_NAME "xm2msc"
+
+#define CHAN_ATTACHED BIT(0)
+#define CHAN_OPENED BIT(1)
+
+#define XM2MSC_CHAN_OUT 0
+#define XM2MSC_CHAN_CAP 1
+
+#define NUM_STREAM(_x) \
+ ({ typeof(_x) (x) = (_x); \
+ min(ffz(x->out_streamed_chan), \
+ ffz(x->cap_streamed_chan)); })
+
+#define XM2MSC_ALIGN_MUL 8
+
+/*
+ * These are temporary variables. Once the stride and height
+ * alignment support added to plugin, these variables will
+ * be remove.
+ */
+static unsigned int output_stride_align[XM2MSC_MAX_CHAN] = {
+ 1, 1, 1, 1, 1, 1, 1, 1 };
+module_param_array(output_stride_align, uint, NULL, 0644);
+MODULE_PARM_DESC(output_stride_align,
+ "Per Cahnnel stride alignment requied at output.");
+
+static unsigned int capture_stride_align[XM2MSC_MAX_CHAN] = {
+ 1, 1, 1, 1, 1, 1, 1, 1 };
+module_param_array(capture_stride_align, uint, NULL, 0644);
+MODULE_PARM_DESC(capture_stride_align,
+ "Per channel stride alignment requied at capture.");
+
+static unsigned int output_height_align[XM2MSC_MAX_CHAN] = {
+ 1, 1, 1, 1, 1, 1, 1, 1 };
+module_param_array(output_height_align, uint, NULL, 0644);
+MODULE_PARM_DESC(output_height_align,
+ "Per Channel height alignment requied at output.");
+
+static unsigned int capture_height_align[XM2MSC_MAX_CHAN] = {
+ 1, 1, 1, 1, 1, 1, 1, 1 };
+module_param_array(capture_height_align, uint, NULL, 0644);
+MODULE_PARM_DESC(capture_height_align,
+ "Per channel height alignment requied at capture.");
+
+/* Xilinx Video Specific Color/Pixel Formats */
+enum xm2msc_pix_fmt {
+ XILINX_M2MSC_FMT_RGBX8 = 10,
+ XILINX_M2MSC_FMT_YUVX8 = 11,
+ XILINX_M2MSC_FMT_YUYV8 = 12,
+ XILINX_M2MSC_FMT_RGBX10 = 15,
+ XILINX_M2MSC_FMT_YUVX10 = 16,
+ XILINX_M2MSC_FMT_Y_UV8 = 18,
+ XILINX_M2MSC_FMT_Y_UV8_420 = 19,
+ XILINX_M2MSC_FMT_RGB8 = 20,
+ XILINX_M2MSC_FMT_YUV8 = 21,
+ XILINX_M2MSC_FMT_Y_UV10 = 22,
+ XILINX_M2MSC_FMT_Y_UV10_420 = 23,
+ XILINX_M2MSC_FMT_Y8 = 24,
+ XILINX_M2MSC_FMT_Y10 = 25,
+ XILINX_M2MSC_FMT_BGRX8 = 27,
+ XILINX_M2MSC_FMT_UYVY8 = 28,
+ XILINX_M2MSC_FMT_BGR8 = 29,
+};
+
+/**
+ * struct xm2msc_fmt - driver info for each of the supported video formats
+ * @name: human-readable device tree name for this entry
+ * @fourcc: standard format identifier
+ * @xm2msc_fmt: Xilinx Video Specific Color/Pixel Formats
+ * @num_buffs: number of physically non-contiguous data planes/buffs
+ */
+struct xm2msc_fmt {
+ char *name;
+ u32 fourcc;
+ enum xm2msc_pix_fmt xm2msc_fmt;
+ u32 num_buffs;
+};
+
+static const struct xm2msc_fmt formats[] = {
+ {
+ .name = "xbgr8888",
+ .fourcc = V4L2_PIX_FMT_BGRX32,
+ .xm2msc_fmt = XILINX_M2MSC_FMT_RGBX8,
+ .num_buffs = 1,
+ },
+ {
+ .name = "xvuy8888",
+ .fourcc = V4L2_PIX_FMT_XVUY32,
+ .xm2msc_fmt = XILINX_M2MSC_FMT_YUVX8,
+ .num_buffs = 1,
+ },
+ {
+ .name = "yuyv",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .xm2msc_fmt = XILINX_M2MSC_FMT_YUYV8,
+ .num_buffs = 1,
+ },
+ {
+ .name = "xbgr2101010",
+ .fourcc = V4L2_PIX_FMT_XBGR30,
+ .xm2msc_fmt = XILINX_M2MSC_FMT_RGBX10,
+ .num_buffs = 1,
+ },
+ {
+ .name = "yuvx2101010",
+ .fourcc = V4L2_PIX_FMT_XVUY10,
+ .xm2msc_fmt = XILINX_M2MSC_FMT_YUVX10,
+ .num_buffs = 1,
+ },
+ {
+ .name = "nv16",
+ .fourcc = V4L2_PIX_FMT_NV16M,
+ .xm2msc_fmt = XILINX_M2MSC_FMT_Y_UV8,
+ .num_buffs = 2,
+ },
+ {
+ .name = "nv16",
+ .fourcc = V4L2_PIX_FMT_NV16,
+ .xm2msc_fmt = XILINX_M2MSC_FMT_Y_UV8,
+ .num_buffs = 1,
+ },
+ {
+ .name = "nv12",
+ .fourcc = V4L2_PIX_FMT_NV12M,
+ .xm2msc_fmt = XILINX_M2MSC_FMT_Y_UV8_420,
+ .num_buffs = 2,
+ },
+ {
+ .name = "nv12",
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .xm2msc_fmt = XILINX_M2MSC_FMT_Y_UV8_420,
+ .num_buffs = 1,
+ },
+ {
+ .name = "bgr888",
+ .fourcc = V4L2_PIX_FMT_RGB24,
+ .xm2msc_fmt = XILINX_M2MSC_FMT_RGB8,
+ .num_buffs = 1,
+ },
+ {
+ .name = "vuy888",
+ .fourcc = V4L2_PIX_FMT_VUY24,
+ .xm2msc_fmt = XILINX_M2MSC_FMT_YUV8,
+ .num_buffs = 1,
+ },
+ {
+ .name = "xv20",
+ .fourcc = V4L2_PIX_FMT_XV20M,
+ .xm2msc_fmt = XILINX_M2MSC_FMT_Y_UV10,
+ .num_buffs = 2,
+ },
+ {
+ .name = "xv20",
+ .fourcc = V4L2_PIX_FMT_XV20,
+ .xm2msc_fmt = XILINX_M2MSC_FMT_Y_UV10,
+ .num_buffs = 1,
+ },
+ {
+ .name = "xv15",
+ .fourcc = V4L2_PIX_FMT_XV15M,
+ .xm2msc_fmt = XILINX_M2MSC_FMT_Y_UV10_420,
+ .num_buffs = 2,
+ },
+ {
+ .name = "xv15",
+ .fourcc = V4L2_PIX_FMT_XV15,
+ .xm2msc_fmt = XILINX_M2MSC_FMT_Y_UV10_420,
+ .num_buffs = 1,
+ },
+ {
+ .name = "y8",
+ .fourcc = V4L2_PIX_FMT_GREY,
+ .xm2msc_fmt = XILINX_M2MSC_FMT_Y8,
+ .num_buffs = 1,
+ },
+ {
+ .name = "y10",
+ .fourcc = V4L2_PIX_FMT_Y10,
+ .xm2msc_fmt = XILINX_M2MSC_FMT_Y10,
+ .num_buffs = 1,
+ },
+ {
+ .name = "xrgb8888",
+ .fourcc = V4L2_PIX_FMT_XBGR32,
+ .xm2msc_fmt = XILINX_M2MSC_FMT_BGRX8,
+ .num_buffs = 1,
+ },
+ {
+ .name = "uyvy",
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .xm2msc_fmt = XILINX_M2MSC_FMT_UYVY8,
+ .num_buffs = 1,
+ },
+ {
+ .name = "rgb888",
+ .fourcc = V4L2_PIX_FMT_BGR24,
+ .xm2msc_fmt = XILINX_M2MSC_FMT_BGR8,
+ .num_buffs = 1,
+ },
+};
+
+/**
+ * struct xm2msc_q_data - Per-queue, driver-specific private data
+ * There is one source queue and one destination queue for each m2m context.
+ * @width: frame width
+ * @height: frame height
+ * @stride: bytes per lines
+ * @nbuffs: Current number of buffs
+ * @bytesperline: bytes per line per plane
+ * @sizeimage: image size per plane
+ * @colorspace: supported colorspace
+ * @field: supported field value
+ * @fmt: format info
+ */
+struct xm2msc_q_data {
+ unsigned int width;
+ unsigned int height;
+ unsigned int stride;
+ unsigned int nbuffs;
+ unsigned int bytesperline[2];
+ unsigned int sizeimage[2];
+ enum v4l2_colorspace colorspace;
+ enum v4l2_field field;
+ const struct xm2msc_fmt *fmt;
+};
+
+/**
+ * struct xm2msc_chan_ctx - Scaler Channel Info, Per-Channel context
+ * @regs: IO mapped base address of the Channel
+ * @xm2msc_dev: Pointer to struct xm2m_msc_dev
+ * @num: HW Scaling Channel number
+ * @minor: Minor number of the video device
+ * @output_stride_align: required align stride value at output pad
+ * @capture_stride_align: required align stride valure at capture pad
+ * @output_height_align: required align height value at output pad
+ * @capture_height_align: required align heigh value at capture pad
+ * @status: channel status, CHAN_ATTACHED or CHAN_OPENED
+ * @frames: number of frames processed
+ * @vfd: V4L2 device
+ * @fh: v4l2 file handle
+ * @m2m_dev: m2m device
+ * @m2m_ctx: memory to memory context structure
+ * @q_data: src & dst queue data
+ */
+struct xm2msc_chan_ctx {
+ void __iomem *regs;
+ struct xm2m_msc_dev *xm2msc_dev;
+ u32 num;
+ u32 minor;
+ u32 output_stride_align;
+ u32 capture_stride_align;
+ u32 output_height_align;
+ u32 capture_height_align;
+ u8 status;
+ unsigned long frames;
+
+ struct video_device vfd;
+ struct v4l2_fh fh;
+ struct v4l2_m2m_dev *m2m_dev;
+ struct v4l2_m2m_ctx *m2m_ctx;
+
+ struct xm2msc_q_data q_data[2];
+};
+
+/**
+ * struct xm2m_msc_dev - Xilinx M2M Multi-scaler Device
+ * @dev: pointer to struct device instance used by the driver
+ * @regs: IO mapped base address of the HW/IP
+ * @irq: interrupt number
+ * @clk: video core clock
+ * @max_chan: maximum number of Scaling Channels
+ * @max_ht: maximum number of rows in a plane
+ * @max_wd: maximum number of column in a plane
+ * @taps: number of taps set in HW
+ * @supported_fmt: bitmap for all supported fmts by HW
+ * @dma_addr_size: Size of dma address pointer in IP (either 32 or 64)
+ * @ppc: Pixels per clock set in IP (1, 2 or 4)
+ * @rst_gpio: reset gpio handler
+ * @opened_chan: bitmap for all open channel
+ * @out_streamed_chan: bitmap for all out streamed channel
+ * @cap_streamed_chan: bitmap for all capture streamed channel
+ * @running_chan: currently running channels
+ * @device_busy: HW device is busy or not
+ * @isr_wait: flag to follow the ISR complete or not
+ * @isr_finished: Wait queue used to wait for IP to complete processing
+ * @v4l2_dev: main struct to for V4L2 device drivers
+ * @dev_mutex: lock for V4L2 device
+ * @mutex: lock for channel ctx
+ * @lock: lock used in IRQ
+ * @xm2msc_chan: arrey of channel context
+ * @hscaler_coeff: Array of filter coefficients for the Horizontal Scaler
+ * @vscaler_coeff: Array of filter coefficients for the Vertical Scaler
+ */
+struct xm2m_msc_dev {
+ struct device *dev;
+ void __iomem *regs;
+ int irq;
+ struct clk *clk;
+ u32 max_chan;
+ u32 max_ht;
+ u32 max_wd;
+ u32 taps;
+ u32 supported_fmt;
+ u32 dma_addr_size;
+ u8 ppc;
+ struct gpio_desc *rst_gpio;
+
+ u32 opened_chan;
+ u32 out_streamed_chan;
+ u32 cap_streamed_chan;
+ u32 running_chan;
+ bool device_busy;
+ bool isr_wait;
+ wait_queue_head_t isr_finished;
+
+ struct v4l2_device v4l2_dev;
+
+ struct mutex dev_mutex; /*the mutex for v4l2*/
+ struct mutex mutex; /*lock for bitmap reg*/
+ spinlock_t lock; /*IRQ lock*/
+
+ struct xm2msc_chan_ctx xm2msc_chan[XM2MSC_MAX_CHAN];
+ short hscaler_coeff[XSCALER_MAX_PHASES][XSCALER_MAX_TAPS];
+ short vscaler_coeff[XSCALER_MAX_PHASES][XSCALER_MAX_TAPS];
+};
+
+#define fh_to_chanctx(__fh) container_of(__fh, struct xm2msc_chan_ctx, fh)
+
+static inline u32 xm2msc_readreg(const void __iomem *addr)
+{
+ return ioread32(addr);
+}
+
+static inline void xm2msc_write64reg(void __iomem *addr, u64 value)
+{
+ iowrite32(lower_32_bits(value), addr);
+ iowrite32(upper_32_bits(value), (void __iomem *)(addr + 4));
+}
+
+static inline void xm2msc_writereg(void __iomem *addr, u32 value)
+{
+ iowrite32(value, addr);
+}
+
+static bool xm2msc_is_yuv_singlebuff(u32 fourcc)
+{
+ if (fourcc == V4L2_PIX_FMT_NV12 || fourcc == V4L2_PIX_FMT_XV15 ||
+ fourcc == V4L2_PIX_FMT_NV16 || fourcc == V4L2_PIX_FMT_XV20)
+ return true;
+
+ return false;
+}
+
+static inline u32 xm2msc_yuv_1stplane_size(struct xm2msc_q_data *q_data,
+ u32 row_align)
+{
+ return q_data->bytesperline[0] * ALIGN(q_data->height, row_align);
+}
+
+static struct xm2msc_q_data *get_q_data(struct xm2msc_chan_ctx *chan_ctx,
+ enum v4l2_buf_type type)
+{
+ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ return &chan_ctx->q_data[XM2MSC_CHAN_OUT];
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ return &chan_ctx->q_data[XM2MSC_CHAN_CAP];
+ default:
+ v4l2_err(&chan_ctx->xm2msc_dev->v4l2_dev,
+ "Not supported Q type %d\n", type);
+ }
+ return NULL;
+}
+
+static u32 find_format_index(struct v4l2_format *f)
+{
+ const struct xm2msc_fmt *fmt;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(formats); i++) {
+ fmt = &formats[i];
+ if (fmt->fourcc == f->fmt.pix_mp.pixelformat)
+ break;
+ }
+
+ return i;
+}
+
+static const struct xm2msc_fmt *find_format(struct v4l2_format *f)
+{
+ const struct xm2msc_fmt *fmt;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(formats); i++) {
+ fmt = &formats[i];
+ if (fmt->fourcc == f->fmt.pix_mp.pixelformat)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(formats))
+ return NULL;
+
+ return &formats[i];
+}
+
+static void
+xm2msc_hscaler_load_ext_coeff(struct xm2m_msc_dev *xm2msc,
+ 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 = XSCALER_MAX_TAPS - ntaps;
+ offset = pad >> 1;
+
+ memset(xm2msc->hscaler_coeff, 0, sizeof(xm2msc->hscaler_coeff));
+
+ /* Load coefficients into scaler coefficient table */
+ for (i = 0; i < nphases; i++) {
+ for (j = 0; j < ntaps; ++j)
+ xm2msc->hscaler_coeff[i][j + offset] =
+ coeff[i * ntaps + j];
+ }
+}
+
+static void xm2msc_hscaler_set_coeff(struct xm2msc_chan_ctx *chan_ctx,
+ const u32 base_addr)
+{
+ struct xm2m_msc_dev *xm2msc = chan_ctx->xm2msc_dev;
+ int val, offset, rd_indx;
+ unsigned int i, j;
+ u32 ntaps = chan_ctx->xm2msc_dev->taps;
+ const u32 nphases = XSCALER_MAX_PHASES;
+
+ offset = (XSCALER_MAX_TAPS - ntaps) / 2;
+ for (i = 0; i < nphases; i++) {
+ for (j = 0; j < ntaps / 2; j++) {
+ rd_indx = j * 2 + offset;
+ val = (xm2msc->hscaler_coeff[i][rd_indx + 1] <<
+ XM2MSC_BITSHIFT_16) |
+ (xm2msc->hscaler_coeff[i][rd_indx] &
+ XM2MSC_MASK_LOW_16BITS);
+ xm2msc_writereg((xm2msc->regs + base_addr) +
+ ((i * ntaps / 2 + j) * 4), val);
+ }
+ }
+}
+
+static void
+xm2msc_vscaler_load_ext_coeff(struct xm2m_msc_dev *xm2msc,
+ const short *coeff, const u32 ntaps)
+{
+ unsigned int i, j;
+ int pad, offset;
+ const u32 nphases = XSCALER_MAX_PHASES;
+
+ /* Determine if coefficient needs padding (effective vs. max taps) */
+ pad = XSCALER_MAX_TAPS - ntaps;
+ offset = pad ? (pad >> 1) : 0;
+
+ /* Zero Entire Array */
+ memset(xm2msc->vscaler_coeff, 0, sizeof(xm2msc->vscaler_coeff));
+
+ /* Load User defined coefficients into scaler coefficient table */
+ for (i = 0; i < nphases; i++) {
+ for (j = 0; j < ntaps; ++j)
+ xm2msc->vscaler_coeff[i][j + offset] =
+ coeff[i * ntaps + j];
+ }
+}
+
+static void
+xm2msc_vscaler_set_coeff(struct xm2msc_chan_ctx *chan_ctx,
+ const u32 base_addr)
+{
+ struct xm2m_msc_dev *xm2msc = chan_ctx->xm2msc_dev;
+ u32 val, i, j, offset, rd_indx;
+ u32 ntaps = chan_ctx->xm2msc_dev->taps;
+ const u32 nphases = XSCALER_MAX_PHASES;
+
+ offset = (XSCALER_MAX_TAPS - ntaps) / 2;
+
+ for (i = 0; i < nphases; i++) {
+ for (j = 0; j < ntaps / 2; j++) {
+ rd_indx = j * 2 + offset;
+ val = (xm2msc->vscaler_coeff[i][rd_indx + 1] <<
+ XM2MSC_BITSHIFT_16) |
+ (xm2msc->vscaler_coeff[i][rd_indx] &
+ XM2MSC_MASK_LOW_16BITS);
+ xm2msc_writereg((xm2msc->regs +
+ base_addr) + ((i * ntaps / 2 + j) * 4), val);
+ }
+ }
+}
+
+static u32
+xm2msc_select_hcoeff(struct xm2msc_chan_ctx *chan_ctx, const short **coeff)
+{
+ u16 hscale_ratio;
+ u32 width_in = chan_ctx->q_data[XM2MSC_CHAN_OUT].width;
+ u32 width_out = chan_ctx->q_data[XM2MSC_CHAN_CAP].width;
+ u32 ntaps = chan_ctx->xm2msc_dev->taps;
+
+ if (width_out < width_in) {
+ hscale_ratio = (width_in * 10) / width_out;
+
+ switch (chan_ctx->xm2msc_dev->taps) {
+ case XSCALER_TAPS_12:
+ if (hscale_ratio > 35) {
+ *coeff = &xhsc_coeff_taps12[0][0];
+ ntaps = XSCALER_TAPS_12;
+ } else if (hscale_ratio > 25) {
+ *coeff = &xhsc_coeff_taps10[0][0];
+ ntaps = XSCALER_TAPS_10;
+ } else if (hscale_ratio > 15) {
+ *coeff = &xhsc_coeff_taps8[0][0];
+ ntaps = XSCALER_TAPS_8;
+ } else {
+ *coeff = &xhsc_coeff_taps6[0][0];
+ ntaps = XSCALER_TAPS_6;
+ }
+ break;
+ case XSCALER_TAPS_10:
+ if (hscale_ratio > 25) {
+ *coeff = &xhsc_coeff_taps10[0][0];
+ ntaps = XSCALER_TAPS_10;
+ } else if (hscale_ratio > 15) {
+ *coeff = &xhsc_coeff_taps8[0][0];
+ ntaps = XSCALER_TAPS_8;
+ } else {
+ *coeff = &xhsc_coeff_taps6[0][0];
+ ntaps = XSCALER_TAPS_6;
+ }
+ break;
+ case XSCALER_TAPS_8:
+ if (hscale_ratio > 15) {
+ *coeff = &xhsc_coeff_taps8[0][0];
+ ntaps = XSCALER_TAPS_8;
+ } else {
+ *coeff = &xhsc_coeff_taps6[0][0];
+ ntaps = XSCALER_TAPS_6;
+ }
+ break;
+ default: /* or XSCALER_TAPS_6 */
+ *coeff = &xhsc_coeff_taps6[0][0];
+ ntaps = XSCALER_TAPS_6;
+ }
+ } else {
+ /*
+ * Scale Up Mode will always use 6 tap filter
+ * This also includes 1:1
+ */
+ *coeff = &xhsc_coeff_taps6[0][0];
+ ntaps = XSCALER_TAPS_6;
+ }
+
+ return ntaps;
+}
+
+static u32
+xm2msc_select_vcoeff(struct xm2msc_chan_ctx *chan_ctx, const short **coeff)
+{
+ u16 vscale_ratio;
+ u32 height_in = chan_ctx->q_data[XM2MSC_CHAN_OUT].height;
+ u32 height_out = chan_ctx->q_data[XM2MSC_CHAN_CAP].height;
+ u32 ntaps = chan_ctx->xm2msc_dev->taps;
+
+ if (height_out < height_in) {
+ vscale_ratio = (height_in * 10) / height_out;
+
+ switch (chan_ctx->xm2msc_dev->taps) {
+ case XSCALER_TAPS_12:
+ if (vscale_ratio > 35) {
+ *coeff = &xvsc_coeff_taps12[0][0];
+ ntaps = XSCALER_TAPS_12;
+ } else if (vscale_ratio > 25) {
+ *coeff = &xvsc_coeff_taps10[0][0];
+ ntaps = XSCALER_TAPS_10;
+ } else if (vscale_ratio > 15) {
+ *coeff = &xvsc_coeff_taps8[0][0];
+ ntaps = XSCALER_TAPS_8;
+ } else {
+ *coeff = &xvsc_coeff_taps6[0][0];
+ ntaps = XSCALER_TAPS_6;
+ }
+ break;
+ case XSCALER_TAPS_10:
+ if (vscale_ratio > 25) {
+ *coeff = &xvsc_coeff_taps10[0][0];
+ ntaps = XSCALER_TAPS_10;
+ } else if (vscale_ratio > 15) {
+ *coeff = &xvsc_coeff_taps8[0][0];
+ ntaps = XSCALER_TAPS_8;
+ } else {
+ *coeff = &xvsc_coeff_taps6[0][0];
+ ntaps = XSCALER_TAPS_6;
+ }
+ break;
+ case XSCALER_TAPS_8:
+ if (vscale_ratio > 15) {
+ *coeff = &xvsc_coeff_taps8[0][0];
+ ntaps = XSCALER_TAPS_8;
+ } else {
+ *coeff = &xvsc_coeff_taps6[0][0];
+ ntaps = XSCALER_TAPS_6;
+ }
+ break;
+ default: /* or XSCALER_TAPS_6 */
+ *coeff = &xvsc_coeff_taps6[0][0];
+ ntaps = XSCALER_TAPS_6;
+ }
+ } else {
+ /*
+ * Scale Up Mode will always use 6 tap filter
+ * This also includes 1:1
+ */
+ *coeff = &xvsc_coeff_taps6[0][0];
+ ntaps = XSCALER_TAPS_6;
+ }
+
+ return ntaps;
+}
+
+static void xm2mvsc_initialize_coeff_banks(struct xm2msc_chan_ctx *chan_ctx)
+{
+ const short *coeff = NULL;
+ u32 ntaps;
+ struct xm2m_msc_dev *xm2msc = chan_ctx->xm2msc_dev;
+
+ ntaps = xm2msc_select_hcoeff(chan_ctx, &coeff);
+ xm2msc_hscaler_load_ext_coeff(xm2msc, coeff, ntaps);
+ xm2msc_hscaler_set_coeff(chan_ctx, XM2MVSC_HFLTCOEFF(chan_ctx->num));
+
+ dev_dbg(xm2msc->dev, "htaps %d selected for chan %d\n",
+ ntaps, chan_ctx->num);
+
+ ntaps = xm2msc_select_vcoeff(chan_ctx, &coeff);
+ xm2msc_vscaler_load_ext_coeff(xm2msc, coeff, ntaps);
+ xm2msc_vscaler_set_coeff(chan_ctx, XM2MVSC_VFLTCOEFF(chan_ctx->num));
+
+ dev_dbg(xm2msc->dev, "vtaps %d selected for chan %d\n",
+ ntaps, chan_ctx->num);
+}
+
+static void xm2msc_set_chan_params(struct xm2msc_chan_ctx *chan_ctx,
+ enum v4l2_buf_type type)
+{
+ struct xm2msc_q_data *q_data = get_q_data(chan_ctx, type);
+ const struct xm2msc_fmt *fmt = q_data->fmt;
+ void __iomem *base = chan_ctx->regs;
+
+ if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ xm2msc_writereg(base + XM2MSC_WIDTHIN, q_data->width);
+ xm2msc_writereg(base + XM2MSC_HEIGHTIN, q_data->height);
+ xm2msc_writereg(base + XM2MSC_INPIXELFMT, fmt->xm2msc_fmt);
+ xm2msc_writereg(base + XM2MSC_INSTRIDE, q_data->stride);
+ } else {
+ xm2msc_writereg(base + XM2MSC_WIDTHOUT, q_data->width);
+ xm2msc_writereg(base + XM2MSC_HEIGHTOUT, q_data->height);
+ xm2msc_writereg(base + XM2MSC_OUTPIXELFMT, fmt->xm2msc_fmt);
+ xm2msc_writereg(base + XM2MSC_OUTSTRIDE, q_data->stride);
+ }
+}
+
+static void xm2msc_set_chan_com_params(struct xm2msc_chan_ctx *chan_ctx)
+{
+ void __iomem *base = chan_ctx->regs;
+ struct xm2msc_q_data *out_q_data = &chan_ctx->q_data[XM2MSC_CHAN_OUT];
+ struct xm2msc_q_data *cap_q_data = &chan_ctx->q_data[XM2MSC_CHAN_CAP];
+ u32 pixel_rate;
+ u32 line_rate;
+
+ xm2mvsc_initialize_coeff_banks(chan_ctx);
+
+ pixel_rate = (out_q_data->width * XM2MSC_STEP_PRECISION) /
+ cap_q_data->width;
+ line_rate = (out_q_data->height * XM2MSC_STEP_PRECISION) /
+ cap_q_data->height;
+
+ xm2msc_writereg(base + XM2MSC_PIXELRATE, pixel_rate);
+ xm2msc_writereg(base + XM2MSC_LINERATE, line_rate);
+}
+
+static void xm2msc_program_allchan(struct xm2m_msc_dev *xm2msc)
+{
+ u32 chan;
+
+ for (chan = 0; chan < xm2msc->running_chan; chan++) {
+ struct xm2msc_chan_ctx *chan_ctx;
+
+ chan_ctx = &xm2msc->xm2msc_chan[chan];
+
+ xm2msc_set_chan_params(chan_ctx,
+ V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+ xm2msc_set_chan_params(chan_ctx,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+ xm2msc_set_chan_com_params(chan_ctx);
+ }
+}
+
+static void
+xm2msc_pr_q(struct device *dev, struct xm2msc_q_data *q, int chan,
+ int type, const char *fun_name)
+{
+ unsigned int i;
+ const struct xm2msc_fmt *fmt = q->fmt;
+
+ if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ dev_dbg(dev, "\n\nOUTPUT Q (%d) Context from [[ %s ]]",
+ chan, fun_name);
+ else
+ dev_dbg(dev, "\n\nCAPTURE Q (%d) Context from [[ %s ]]",
+ chan, fun_name);
+
+ dev_dbg(dev, "width height stride clrspace field planes\n");
+ dev_dbg(dev, " %d %d %d %d %d %d\n",
+ q->width, q->height, q->stride,
+ q->colorspace, q->field, q->nbuffs);
+
+ for (i = 0; i < q->nbuffs; i++) {
+ dev_dbg(dev, "[plane %d ] bytesperline sizeimage\n", i);
+ dev_dbg(dev, " %d %d\n",
+ q->bytesperline[i], q->sizeimage[i]);
+ }
+
+ dev_dbg(dev, "fmt_name 4cc xlnx-fmt\n");
+ dev_dbg(dev, "%s %d %d\n",
+ fmt->name, fmt->fourcc, fmt->xm2msc_fmt);
+ dev_dbg(dev, "\n\n");
+}
+
+static void
+xm2msc_pr_status(struct xm2m_msc_dev *xm2msc,
+ const char *fun_name)
+{
+ struct device *dev = xm2msc->dev;
+
+ dev_dbg(dev, "Status in %s\n", fun_name);
+ dev_dbg(dev, "opened_chan out_streamed_chan cap_streamed_chan\n");
+ dev_dbg(dev, "0x%x 0x%x 0x%x\n",
+ xm2msc->opened_chan, xm2msc->out_streamed_chan,
+ xm2msc->cap_streamed_chan);
+ dev_dbg(dev, "\n\n");
+}
+
+static void
+xm2msc_pr_chanctx(struct xm2msc_chan_ctx *ctx, const char *fun_name)
+{
+ struct device *dev = ctx->xm2msc_dev->dev;
+
+ dev_dbg(dev, "\n\n----- [[ %s ]]: Channel %d (0x%p) context -----\n",
+ fun_name, ctx->num, ctx);
+ dev_dbg(dev, "minor = %d\n", ctx->minor);
+ dev_dbg(dev, "reg mapped at %p\n", ctx->regs);
+ dev_dbg(dev, "xm2msc \tm2m_dev \tm2m_ctx\n");
+ dev_dbg(dev, "%p \t%p \t%p\n", ctx->xm2msc_dev,
+ ctx->m2m_dev, ctx->m2m_ctx);
+
+ if (ctx->status & CHAN_OPENED)
+ dev_dbg(dev, "Opened ");
+ if (ctx->status & CHAN_ATTACHED)
+ dev_dbg(dev, "and attached");
+ dev_dbg(dev, "\n");
+ dev_dbg(dev, "-----------------------------------\n");
+ dev_dbg(dev, "\n\n");
+}
+
+static void
+xm2msc_pr_screg(struct device *dev, const void __iomem *base)
+{
+ dev_dbg(dev, "Ctr, GIE, IE, IS OUT\n");
+ dev_dbg(dev, "0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ xm2msc_readreg(base + XM2MSC_AP_CTRL),
+ xm2msc_readreg(base + XM2MSC_GIE),
+ xm2msc_readreg(base + XM2MSC_IER),
+ xm2msc_readreg(base + XM2MSC_ISR),
+ xm2msc_readreg(base + XM2MSC_NUM_OUTS));
+}
+
+static void
+xm2msc_pr_chanreg(struct device *dev, struct xm2msc_chan_ctx *chan)
+{
+ const void __iomem *base = chan->regs;
+
+ dev_dbg(dev, "WIN HIN INPIXELFMT INSTRIDE SRCB0L/H SRCB1L/H\n");
+ dev_dbg(dev, "%d %d %d %d 0x%x/0x%x 0x%x/0x%x\n",
+ xm2msc_readreg(base + XM2MSC_WIDTHIN),
+ xm2msc_readreg(base + XM2MSC_HEIGHTIN),
+ xm2msc_readreg(base + XM2MSC_INPIXELFMT),
+ xm2msc_readreg(base + XM2MSC_INSTRIDE),
+ xm2msc_readreg(base + XM2MSC_SRCIMGBUF0),
+ xm2msc_readreg(base + XM2MSC_SRCIMGBUF0 + 4),
+ xm2msc_readreg(base + XM2MSC_SRCIMGBUF1),
+ xm2msc_readreg(base + XM2MSC_SRCIMGBUF1 + 4));
+ dev_dbg(dev, "WOUT HOUT OUTPIXELFMT OUTSTRIDE DBUF0L/H DBUF1L/H\n");
+ dev_dbg(dev, "%d %d %d %d 0x%x/0x%x 0x%x/0x%x\n",
+ xm2msc_readreg(base + XM2MSC_WIDTHOUT),
+ xm2msc_readreg(base + XM2MSC_HEIGHTOUT),
+ xm2msc_readreg(base + XM2MSC_OUTPIXELFMT),
+ xm2msc_readreg(base + XM2MSC_OUTSTRIDE),
+ xm2msc_readreg(base + XM2MSC_DSTIMGBUF0),
+ xm2msc_readreg(base + XM2MSC_DSTIMGBUF0 + 4),
+ chan->num == 4 ?
+ xm2msc_readreg(base +
+ XM2MSC_DSTIMGBUF1 + XM2MSC_RESERVED_AREA) :
+ xm2msc_readreg(base + XM2MSC_DSTIMGBUF1),
+ chan->num == 4 ?
+ xm2msc_readreg(base +
+ XM2MSC_DSTIMGBUF1 + XM2MSC_RESERVED_AREA + 4) :
+ xm2msc_readreg(base + XM2MSC_DSTIMGBUF1 + 4));
+
+ dev_dbg(dev, "LINERATE PIXELRATE\n");
+ dev_dbg(dev, "0x%x 0x%x\n",
+ xm2msc_readreg(base + XM2MSC_LINERATE),
+ xm2msc_readreg(base + XM2MSC_PIXELRATE));
+}
+
+static void
+xm2msc_pr_allchanreg(struct xm2m_msc_dev *xm2msc)
+{
+ unsigned int i;
+ struct xm2msc_chan_ctx *chan_ctx;
+ struct device *dev = xm2msc->dev;
+
+ xm2msc_pr_screg(xm2msc->dev, xm2msc->regs);
+
+ for (i = 0; i < xm2msc->running_chan; i++) {
+ chan_ctx = &xm2msc->xm2msc_chan[i];
+ dev_dbg(dev, "Regs val for channel %d\n", i);
+ dev_dbg(dev, "______________________________________________\n");
+ xm2msc_pr_chanreg(dev, chan_ctx);
+ dev_dbg(dev, "processed frames = %lu\n", chan_ctx->frames);
+ dev_dbg(dev, "______________________________________________\n");
+ }
+}
+
+static inline bool xm2msc_testbit(int num, u32 *addr)
+{
+ return (*addr & BIT(num));
+}
+
+static inline void xm2msc_setbit(int num, u32 *addr)
+{
+ *addr |= BIT(num);
+}
+
+static inline void xm2msc_clrbit(int num, u32 *addr)
+{
+ *addr &= ~BIT(num);
+}
+
+static void xm2msc_stop(struct xm2m_msc_dev *xm2msc)
+{
+ void __iomem *base = xm2msc->regs;
+ u32 data = xm2msc_readreg(base + XM2MSC_AP_CTRL);
+
+ data &= ~XM2MSC_AP_CTRL_START;
+ xm2msc_writereg(base + XM2MSC_AP_CTRL, data);
+}
+
+static void xm2msc_start(struct xm2m_msc_dev *xm2msc)
+{
+ void __iomem *base = xm2msc->regs;
+ u32 data = xm2msc_readreg(base + XM2MSC_AP_CTRL);
+
+ data |= XM2MSC_AP_CTRL_START;
+ xm2msc_writereg(base + XM2MSC_AP_CTRL, data);
+}
+
+static void xm2msc_set_chan(struct xm2msc_chan_ctx *ctx, bool state)
+{
+ mutex_lock(&ctx->xm2msc_dev->mutex);
+ if (state)
+ xm2msc_setbit(ctx->num, &ctx->xm2msc_dev->opened_chan);
+ else
+ xm2msc_clrbit(ctx->num, &ctx->xm2msc_dev->opened_chan);
+ mutex_unlock(&ctx->xm2msc_dev->mutex);
+}
+
+static void
+xm2msc_set_chan_stream(struct xm2msc_chan_ctx *ctx, bool state, int type)
+{
+ u32 *ptr;
+
+ if (type == XM2MSC_CHAN_OUT)
+ ptr = &ctx->xm2msc_dev->out_streamed_chan;
+ else
+ ptr = &ctx->xm2msc_dev->cap_streamed_chan;
+
+ spin_lock(&ctx->xm2msc_dev->lock);
+ if (state)
+ xm2msc_setbit(ctx->num, ptr);
+ else
+ xm2msc_clrbit(ctx->num, ptr);
+
+ spin_unlock(&ctx->xm2msc_dev->lock);
+}
+
+static int
+xm2msc_chk_chan_stream(struct xm2msc_chan_ctx *ctx, int type)
+{
+ u32 *ptr;
+ int ret;
+
+ if (type == XM2MSC_CHAN_OUT)
+ ptr = &ctx->xm2msc_dev->out_streamed_chan;
+ else
+ ptr = &ctx->xm2msc_dev->cap_streamed_chan;
+
+ mutex_lock(&ctx->xm2msc_dev->mutex);
+ ret = xm2msc_testbit(ctx->num, ptr);
+ mutex_unlock(&ctx->xm2msc_dev->mutex);
+
+ return ret;
+}
+
+static void xm2msc_set_fmt(struct xm2m_msc_dev *xm2msc, u32 index)
+{
+ xm2msc_setbit(index, &xm2msc->supported_fmt);
+}
+
+static int xm2msc_chk_fmt(struct xm2m_msc_dev *xm2msc, u32 index)
+{
+ return xm2msc_testbit(index, &xm2msc->supported_fmt);
+}
+
+static void xm2msc_reset(struct xm2m_msc_dev *xm2msc)
+{
+ gpiod_set_value_cansleep(xm2msc->rst_gpio, XM2MSC_RESET_ASSERT);
+ gpiod_set_value_cansleep(xm2msc->rst_gpio, XM2MSC_RESET_DEASSERT);
+}
+
+/*
+ * mem2mem callbacks
+ */
+static int xm2msc_job_ready(void *priv)
+{
+ struct xm2msc_chan_ctx *chan_ctx = priv;
+
+ if ((v4l2_m2m_num_src_bufs_ready(chan_ctx->m2m_ctx) > 0) &&
+ (v4l2_m2m_num_dst_bufs_ready(chan_ctx->m2m_ctx) > 0))
+ return 1;
+ return 0;
+}
+
+static bool xm2msc_alljob_ready(struct xm2m_msc_dev *xm2msc)
+{
+ struct xm2msc_chan_ctx *chan_ctx;
+ unsigned int chan;
+
+ for (chan = 0; chan < xm2msc->running_chan; chan++) {
+ chan_ctx = &xm2msc->xm2msc_chan[chan];
+
+ if (!xm2msc_job_ready((void *)chan_ctx)) {
+ dev_dbg(xm2msc->dev, "chan %d not ready\n",
+ chan_ctx->num);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void xm2msc_chan_abort_bufs(struct xm2msc_chan_ctx *chan_ctx)
+{
+ struct xm2m_msc_dev *xm2msc = chan_ctx->xm2msc_dev;
+ struct vb2_v4l2_buffer *dst_vb, *src_vb;
+
+ spin_lock(&xm2msc->lock);
+ dev_dbg(xm2msc->dev, "aborting all buffers\n");
+
+ while (v4l2_m2m_num_src_bufs_ready(chan_ctx->m2m_ctx) > 0) {
+ src_vb = v4l2_m2m_src_buf_remove(chan_ctx->m2m_ctx);
+ v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR);
+ }
+
+ while (v4l2_m2m_num_dst_bufs_ready(chan_ctx->m2m_ctx) > 0) {
+ dst_vb = v4l2_m2m_dst_buf_remove(chan_ctx->m2m_ctx);
+ v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR);
+ }
+
+ v4l2_m2m_job_finish(chan_ctx->m2m_dev, chan_ctx->m2m_ctx);
+ spin_unlock(&xm2msc->lock);
+}
+
+static void xm2msc_job_abort(void *priv)
+{
+ struct xm2msc_chan_ctx *chan_ctx = priv;
+
+ xm2msc_chan_abort_bufs(chan_ctx);
+
+ /*
+ * Stream off the channel as job_abort may not always
+ * be called after streamoff
+ */
+ xm2msc_set_chan_stream(chan_ctx, false, XM2MSC_CHAN_OUT);
+ xm2msc_set_chan_stream(chan_ctx, false, XM2MSC_CHAN_CAP);
+}
+
+static int xm2msc_set_bufaddr(struct xm2m_msc_dev *xm2msc)
+{
+ unsigned int chan;
+ u32 row_align;
+ struct xm2msc_chan_ctx *chan_ctx;
+ struct vb2_v4l2_buffer *src_vb, *dst_vb;
+ void __iomem *base;
+ struct xm2msc_q_data *q_data;
+ dma_addr_t src_luma, dst_luma;
+ dma_addr_t src_croma, dst_croma;
+
+ if (!xm2msc_alljob_ready(xm2msc))
+ return -EINVAL;
+
+ for (chan = 0; chan < xm2msc->running_chan; chan++) {
+ chan_ctx = &xm2msc->xm2msc_chan[chan];
+ base = chan_ctx->regs;
+
+ src_vb = v4l2_m2m_next_src_buf(chan_ctx->m2m_ctx);
+ dst_vb = v4l2_m2m_next_dst_buf(chan_ctx->m2m_ctx);
+
+ if (!src_vb || !dst_vb) {
+ v4l2_err(&xm2msc->v4l2_dev, "buffer not found chan = %d\n",
+ chan_ctx->num);
+ return -EINVAL;
+ }
+
+ src_luma = vb2_dma_contig_plane_dma_addr(&src_vb->vb2_buf, 0);
+ dst_luma = vb2_dma_contig_plane_dma_addr(&dst_vb->vb2_buf, 0);
+
+ q_data = &chan_ctx->q_data[XM2MSC_CHAN_OUT];
+ row_align = chan_ctx->output_height_align;
+ if (chan_ctx->q_data[XM2MSC_CHAN_OUT].nbuffs == 2)
+ /* fmts having 2 planes 2 buffers */
+ src_croma =
+ vb2_dma_contig_plane_dma_addr(&src_vb->vb2_buf,
+ 1);
+ else if (xm2msc_is_yuv_singlebuff(q_data->fmt->fourcc))
+ /* fmts having 2 planes 1 contiguous buffer */
+ src_croma = src_luma +
+ xm2msc_yuv_1stplane_size(q_data, row_align);
+ else /* fmts having 1 planes 1 contiguous buffer */
+ src_croma = 0;
+
+ q_data = &chan_ctx->q_data[XM2MSC_CHAN_CAP];
+ row_align = chan_ctx->capture_height_align;
+ if (chan_ctx->q_data[XM2MSC_CHAN_CAP].nbuffs == 2)
+ dst_croma =
+ vb2_dma_contig_plane_dma_addr(&dst_vb->vb2_buf,
+ 1);
+ else if (xm2msc_is_yuv_singlebuff(q_data->fmt->fourcc))
+ dst_croma = dst_luma +
+ xm2msc_yuv_1stplane_size(q_data, row_align);
+ else
+ dst_croma = 0;
+
+ if (xm2msc->dma_addr_size == 64 &&
+ sizeof(dma_addr_t) == sizeof(u64)) {
+ xm2msc_write64reg(base + XM2MSC_SRCIMGBUF0, src_luma);
+ xm2msc_write64reg(base + XM2MSC_SRCIMGBUF1, src_croma);
+ xm2msc_write64reg(base + XM2MSC_DSTIMGBUF0, dst_luma);
+ if (chan_ctx->num == 4) /* TODO: To be fixed in HW */
+ xm2msc_write64reg(base + XM2MSC_DSTIMGBUF1 +
+ XM2MSC_RESERVED_AREA,
+ dst_croma);
+ else
+ xm2msc_write64reg(base + XM2MSC_DSTIMGBUF1,
+ dst_croma);
+ } else {
+ xm2msc_writereg(base + XM2MSC_SRCIMGBUF0, src_luma);
+ xm2msc_writereg(base + XM2MSC_SRCIMGBUF1, src_croma);
+ xm2msc_writereg(base + XM2MSC_DSTIMGBUF0, dst_luma);
+ if (chan_ctx->num == 4) /* TODO: To be fixed in HW */
+ xm2msc_writereg(base + XM2MSC_DSTIMGBUF1 +
+ XM2MSC_RESERVED_AREA,
+ dst_croma);
+ else
+ xm2msc_writereg(base + XM2MSC_DSTIMGBUF1,
+ dst_croma);
+ }
+ }
+ return 0;
+}
+
+static void xm2msc_job_finish(struct xm2m_msc_dev *xm2msc)
+{
+ unsigned int chan;
+
+ for (chan = 0; chan < xm2msc->running_chan; chan++) {
+ struct xm2msc_chan_ctx *chan_ctx;
+
+ chan_ctx = &xm2msc->xm2msc_chan[chan];
+ v4l2_m2m_job_finish(chan_ctx->m2m_dev, chan_ctx->m2m_ctx);
+ }
+}
+
+static void xm2msc_job_done(struct xm2m_msc_dev *xm2msc)
+{
+ u32 chan;
+
+ for (chan = 0; chan < xm2msc->running_chan; chan++) {
+ struct xm2msc_chan_ctx *chan_ctx;
+ struct vb2_v4l2_buffer *src_vb, *dst_vb;
+ unsigned long flags;
+
+ chan_ctx = &xm2msc->xm2msc_chan[chan];
+
+ src_vb = v4l2_m2m_src_buf_remove(chan_ctx->m2m_ctx);
+ dst_vb = v4l2_m2m_dst_buf_remove(chan_ctx->m2m_ctx);
+
+ if (src_vb && dst_vb) {
+ dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp;
+ dst_vb->timecode = src_vb->timecode;
+ dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+ dst_vb->flags |=
+ src_vb->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
+
+ spin_lock_irqsave(&xm2msc->lock, flags);
+ v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
+ v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
+ spin_unlock_irqrestore(&xm2msc->lock, flags);
+ }
+ chan_ctx->frames++;
+ }
+}
+
+static void xm2msc_device_run(void *priv)
+{
+ struct xm2msc_chan_ctx *chan_ctx = priv;
+ struct xm2m_msc_dev *xm2msc = chan_ctx->xm2msc_dev;
+ void __iomem *base = xm2msc->regs;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&xm2msc->lock, flags);
+ if (xm2msc->device_busy) {
+ spin_unlock_irqrestore(&xm2msc->lock, flags);
+ return;
+ }
+ xm2msc->device_busy = true;
+
+ if (xm2msc->running_chan != NUM_STREAM(xm2msc)) {
+ dev_dbg(xm2msc->dev, "Running chan was %d\n",
+ xm2msc->running_chan);
+ xm2msc->running_chan = NUM_STREAM(xm2msc);
+
+ /* IP need reset for updating of XM2MSC_NUM_OUT */
+ xm2msc_reset(xm2msc);
+ xm2msc_writereg(base + XM2MSC_NUM_OUTS, xm2msc->running_chan);
+ xm2msc_program_allchan(xm2msc);
+ }
+ spin_unlock_irqrestore(&xm2msc->lock, flags);
+
+ dev_dbg(xm2msc->dev, "Running chan = %d\n", xm2msc->running_chan);
+ if (!xm2msc->running_chan) {
+ xm2msc->device_busy = false;
+ return;
+ }
+
+ ret = xm2msc_set_bufaddr(xm2msc);
+ if (ret) {
+ /*
+ * All channel does not have buffer
+ * Currently we do not handle the removal of any Intermediate
+ * channel while streaming is going on
+ */
+ if (xm2msc->out_streamed_chan || xm2msc->cap_streamed_chan)
+ dev_err(xm2msc->dev,
+ "Buffer not available, streaming chan 0x%x\n",
+ xm2msc->cap_streamed_chan);
+
+ xm2msc->device_busy = false;
+ return;
+ }
+
+ xm2msc_writereg(base + XM2MSC_GIE, XM2MSC_GIE_EN);
+ xm2msc_writereg(base + XM2MSC_IER, XM2MSC_ISR_DONE);
+
+ xm2msc_pr_status(xm2msc, __func__);
+ xm2msc_pr_screg(xm2msc->dev, base);
+ xm2msc_pr_allchanreg(xm2msc);
+
+ xm2msc_start(xm2msc);
+
+ xm2msc->isr_wait = true;
+ wait_event(xm2msc->isr_finished, !xm2msc->isr_wait);
+
+ xm2msc_job_done(xm2msc);
+
+ xm2msc->device_busy = false;
+
+ if (xm2msc_alljob_ready(xm2msc))
+ xm2msc_device_run(xm2msc->xm2msc_chan);
+
+ xm2msc_job_finish(xm2msc);
+}
+
+static irqreturn_t xm2msc_isr(int irq, void *data)
+{
+ struct xm2m_msc_dev *xm2msc = (struct xm2m_msc_dev *)data;
+ void __iomem *base = xm2msc->regs;
+ u32 status;
+
+ status = xm2msc_readreg(base + XM2MSC_ISR);
+ if (!(status & XM2MSC_ISR_DONE))
+ return IRQ_NONE;
+
+ xm2msc_writereg(base + XM2MSC_ISR, status & XM2MSC_ISR_DONE);
+
+ xm2msc_stop(xm2msc);
+
+ xm2msc->isr_wait = false;
+ wake_up(&xm2msc->isr_finished);
+
+ return IRQ_HANDLED;
+}
+
+static int xm2msc_streamon(struct file *file, void *fh,
+ enum v4l2_buf_type type)
+{
+ struct xm2msc_chan_ctx *chan_ctx = fh_to_chanctx(fh);
+
+ return v4l2_m2m_streamon(file, chan_ctx->m2m_ctx, type);
+}
+
+static int xm2msc_streamoff(struct file *file, void *fh,
+ enum v4l2_buf_type type)
+{
+ struct xm2msc_chan_ctx *chan_ctx = fh_to_chanctx(fh);
+ int ret;
+
+ ret = v4l2_m2m_streamoff(file, chan_ctx->m2m_ctx, type);
+
+ /* Check if any channel is still running */
+ xm2msc_device_run(chan_ctx);
+ return ret;
+}
+
+static int xm2msc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+ struct xm2msc_chan_ctx *chan_ctx = fh_to_chanctx(fh);
+
+ return v4l2_m2m_qbuf(file, chan_ctx->m2m_ctx, buf);
+}
+
+static int xm2msc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+ struct xm2msc_chan_ctx *chan_ctx = fh_to_chanctx(fh);
+
+ return v4l2_m2m_dqbuf(file, chan_ctx->m2m_ctx, buf);
+}
+
+static int xm2msc_expbuf(struct file *file, void *fh,
+ struct v4l2_exportbuffer *eb)
+{
+ struct xm2msc_chan_ctx *chan_ctx = fh_to_chanctx(fh);
+
+ return v4l2_m2m_expbuf(file, chan_ctx->m2m_ctx, eb);
+}
+
+static int xm2msc_createbufs(struct file *file, void *fh,
+ struct v4l2_create_buffers *cb)
+{
+ struct xm2msc_chan_ctx *chan_ctx = fh_to_chanctx(fh);
+
+ return v4l2_m2m_create_bufs(file, chan_ctx->m2m_ctx, cb);
+}
+
+static int xm2msc_reqbufs(struct file *file, void *fh,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct xm2msc_chan_ctx *chan_ctx = fh_to_chanctx(fh);
+
+ return v4l2_m2m_reqbufs(file, chan_ctx->m2m_ctx, reqbufs);
+}
+
+static int xm2msc_querybuf(struct file *file, void *fh,
+ struct v4l2_buffer *buf)
+{
+ struct xm2msc_chan_ctx *chan_ctx = fh_to_chanctx(fh);
+
+ return v4l2_m2m_querybuf(file, chan_ctx->m2m_ctx, buf);
+}
+
+static void
+xm2msc_cal_imagesize(struct xm2msc_chan_ctx *chan_ctx,
+ struct xm2msc_q_data *q_data, u32 type)
+{
+ unsigned int i;
+ u32 fourcc = q_data->fmt->fourcc;
+ u32 height = q_data->height;
+
+ if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ height = ALIGN(height, chan_ctx->output_height_align);
+ else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ height = ALIGN(height, chan_ctx->capture_height_align);
+
+ for (i = 0; i < q_data->nbuffs; i++) {
+ q_data->bytesperline[i] = q_data->stride;
+ q_data->sizeimage[i] = q_data->stride * height;
+ }
+
+ switch (fourcc) {
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_XV15:
+ /*
+ * Adding chroma plane size as NV12/XV15
+ * have a contiguous buffer for luma and chroma
+ */
+ q_data->sizeimage[0] +=
+ q_data->stride * (height / 2);
+ break;
+ case V4L2_PIX_FMT_NV12M:
+ case V4L2_PIX_FMT_XV15M:
+ q_data->sizeimage[1] =
+ q_data->stride * (height / 2);
+ break;
+ default:
+ break;
+ }
+}
+
+static unsigned int
+xm2msc_cal_stride(unsigned int width, enum xm2msc_pix_fmt xfmt, u8 ppc)
+{
+ unsigned int stride;
+ u32 align;
+
+ /* Stride in Bytes = (Width × Bytes per Pixel); */
+ switch (xfmt) {
+ case XILINX_M2MSC_FMT_RGBX8:
+ case XILINX_M2MSC_FMT_YUVX8:
+ case XILINX_M2MSC_FMT_RGBX10:
+ case XILINX_M2MSC_FMT_YUVX10:
+ case XILINX_M2MSC_FMT_BGRX8:
+ stride = width * 4;
+ break;
+ case XILINX_M2MSC_FMT_YUYV8:
+ case XILINX_M2MSC_FMT_UYVY8:
+ stride = width * 2;
+ break;
+ case XILINX_M2MSC_FMT_Y_UV8:
+ case XILINX_M2MSC_FMT_Y_UV8_420:
+ case XILINX_M2MSC_FMT_Y8:
+ stride = width * 1;
+ break;
+ case XILINX_M2MSC_FMT_RGB8:
+ case XILINX_M2MSC_FMT_YUV8:
+ case XILINX_M2MSC_FMT_BGR8:
+ stride = width * 3;
+ break;
+ case XILINX_M2MSC_FMT_Y_UV10:
+ case XILINX_M2MSC_FMT_Y_UV10_420:
+ case XILINX_M2MSC_FMT_Y10:
+ /* 4 bytes per 3 pixels */
+ stride = DIV_ROUND_UP(width * 4, 3);
+ break;
+ default:
+ stride = 0;
+ }
+
+ /* The data size is 64*pixels per clock bits */
+ align = ppc * XM2MSC_ALIGN_MUL;
+ stride = ALIGN(stride, align);
+
+ return stride;
+}
+
+static int
+vidioc_try_fmt(struct xm2msc_chan_ctx *chan_ctx, struct v4l2_format *f)
+{
+ struct xm2m_msc_dev *xm2msc = chan_ctx->xm2msc_dev;
+ struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+ struct xm2msc_q_data *q_data;
+ struct vb2_queue *vq;
+ int index;
+
+ if (pix->width < XM2MSC_MIN_WIDTH || pix->width > xm2msc->max_wd ||
+ pix->height < XM2MSC_MIN_HEIGHT || pix->height > xm2msc->max_ht)
+ dev_dbg(xm2msc->dev,
+ "Wrong input parameters %d, wxh: %dx%d.\n",
+ f->type, f->fmt.pix.width, f->fmt.pix.height);
+
+ /* The width value must be a multiple of pixels per clock */
+ if (pix->width % chan_ctx->xm2msc_dev->ppc) {
+ dev_info(xm2msc->dev,
+ "Wrong align parameters %d, wxh: %dx%d.\n",
+ f->type, f->fmt.pix.width, f->fmt.pix.height);
+ pix->width = ALIGN(pix->width, chan_ctx->xm2msc_dev->ppc);
+ }
+
+ /*
+ * V4L2 specification suggests the driver corrects the
+ * format struct if any of the dimensions is unsupported
+ */
+ if (pix->height < XM2MSC_MIN_HEIGHT)
+ pix->height = XM2MSC_MIN_HEIGHT;
+ else if (pix->height > xm2msc->max_ht)
+ pix->height = xm2msc->max_ht;
+
+ if (pix->width < XM2MSC_MIN_WIDTH)
+ pix->width = XM2MSC_MIN_WIDTH;
+ else if (pix->width > xm2msc->max_wd)
+ pix->width = xm2msc->max_wd;
+
+ vq = v4l2_m2m_get_vq(chan_ctx->m2m_ctx, f->type);
+ if (!vq)
+ return -EINVAL;
+
+ q_data = get_q_data(chan_ctx, f->type);
+ if (!q_data)
+ return -EINVAL;
+
+ if (vb2_is_busy(vq)) {
+ v4l2_err(&xm2msc->v4l2_dev,
+ "%s queue busy\n", __func__);
+ return -EBUSY;
+ }
+
+ q_data->fmt = find_format(f);
+ index = find_format_index(f);
+ if (!q_data->fmt || index == ARRAY_SIZE(formats) ||
+ !xm2msc_chk_fmt(xm2msc, index)) {
+ v4l2_err(&xm2msc->v4l2_dev,
+ "Couldn't set format type %d, wxh: %dx%d. ",
+ f->type, f->fmt.pix.width, f->fmt.pix.height);
+ v4l2_err(&xm2msc->v4l2_dev,
+ "fmt: %d, field: %d\n",
+ f->fmt.pix.pixelformat, f->fmt.pix.field);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void xm2msc_get_align(struct xm2msc_chan_ctx *chan_ctx)
+{
+ /*
+ * TODO: This is a temporary solution, will be reverted once stride and
+ * height align value come from application.
+ */
+ chan_ctx->output_stride_align = output_stride_align[chan_ctx->num];
+ chan_ctx->capture_stride_align = capture_stride_align[chan_ctx->num];
+ chan_ctx->output_height_align = output_height_align[chan_ctx->num];
+ chan_ctx->capture_height_align = capture_height_align[chan_ctx->num];
+ if (output_stride_align[chan_ctx->num] != 1 ||
+ capture_stride_align[chan_ctx->num] != 1 ||
+ output_height_align[chan_ctx->num] != 1 ||
+ capture_height_align[chan_ctx->num] != 1) {
+ dev_info(chan_ctx->xm2msc_dev->dev,
+ "You entered values other than default values.\n");
+ dev_info(chan_ctx->xm2msc_dev->dev,
+ "Please note this may not be available for longer");
+ dev_info(chan_ctx->xm2msc_dev->dev,
+ "and align values will come from application\n");
+ dev_info(chan_ctx->xm2msc_dev->dev,
+ "value entered are -\n"
+ "output_stride_align = %d\n"
+ "output_height_align = %d\n"
+ "capture_stride_align = %d\n"
+ "capture_height_align = %d\n",
+ chan_ctx->output_stride_align,
+ chan_ctx->output_height_align,
+ chan_ctx->capture_stride_align,
+ chan_ctx->capture_height_align);
+ }
+}
+
+static int
+vidioc_s_fmt(struct xm2msc_chan_ctx *chan_ctx, struct v4l2_format *f)
+{
+ struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+ struct xm2msc_q_data *q_data = get_q_data(chan_ctx, f->type);
+ unsigned int i;
+ unsigned int align = 1;
+
+ q_data = get_q_data(chan_ctx, f->type);
+
+ q_data->width = pix->width;
+ q_data->height = pix->height;
+ q_data->stride = xm2msc_cal_stride(pix->width,
+ q_data->fmt->xm2msc_fmt,
+ chan_ctx->xm2msc_dev->ppc);
+
+ xm2msc_get_align(chan_ctx);
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ align = chan_ctx->output_stride_align;
+ else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ align = chan_ctx->capture_stride_align;
+
+ q_data->stride = ALIGN(q_data->stride, align);
+
+ q_data->colorspace = pix->colorspace;
+ q_data->field = pix->field;
+ q_data->nbuffs = q_data->fmt->num_buffs;
+
+ xm2msc_cal_imagesize(chan_ctx, q_data, f->type);
+
+ for (i = 0; i < q_data->nbuffs; i++) {
+ pix->plane_fmt[i].bytesperline = q_data->bytesperline[i];
+ pix->plane_fmt[i].sizeimage = q_data->sizeimage[i];
+ }
+
+ xm2msc_pr_q(chan_ctx->xm2msc_dev->dev, q_data,
+ chan_ctx->num, f->type, __func__);
+
+ return 0;
+}
+
+static int xm2msc_try_fmt_vid_out(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct xm2msc_chan_ctx *chan_ctx = fh_to_chanctx(fh);
+
+ return vidioc_try_fmt(chan_ctx, f);
+}
+
+static int xm2msc_try_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct xm2msc_chan_ctx *chan_ctx = fh_to_chanctx(fh);
+
+ return vidioc_try_fmt(chan_ctx, f);
+}
+
+static int xm2msc_s_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ int ret;
+ struct xm2msc_chan_ctx *chan_ctx = fh_to_chanctx(fh);
+
+ ret = xm2msc_try_fmt_vid_cap(file, fh, f);
+ if (ret)
+ return ret;
+ return vidioc_s_fmt(chan_ctx, f);
+}
+
+static int xm2msc_s_fmt_vid_out(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ int ret;
+ struct xm2msc_chan_ctx *chan_ctx = fh_to_chanctx(fh);
+
+ ret = xm2msc_try_fmt_vid_out(file, fh, f);
+ if (ret)
+ return ret;
+
+ return vidioc_s_fmt(chan_ctx, f);
+}
+
+static int vidioc_g_fmt(struct xm2msc_chan_ctx *chan_ctx, struct v4l2_format *f)
+{
+ struct vb2_queue *vq;
+ struct xm2msc_q_data *q_data;
+ struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+ unsigned int i;
+
+ vq = v4l2_m2m_get_vq(chan_ctx->m2m_ctx, f->type);
+ if (!vq)
+ return -EINVAL;
+
+ q_data = get_q_data(chan_ctx, f->type);
+ if (!q_data)
+ return -EINVAL;
+
+ pix->width = q_data->width;
+ pix->height = q_data->height;
+ pix->field = V4L2_FIELD_NONE;
+ pix->pixelformat = q_data->fmt->fourcc;
+ pix->colorspace = q_data->colorspace;
+ pix->num_planes = q_data->nbuffs;
+
+ for (i = 0; i < pix->num_planes; i++) {
+ pix->plane_fmt[i].bytesperline = q_data->bytesperline[i];
+ pix->plane_fmt[i].sizeimage = q_data->sizeimage[i];
+ }
+
+ return 0;
+}
+
+static int xm2msc_g_fmt_vid_out(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct xm2msc_chan_ctx *chan_ctx = fh_to_chanctx(fh);
+
+ return vidioc_g_fmt(chan_ctx, f);
+}
+
+static int xm2msc_g_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct xm2msc_chan_ctx *chan_ctx = fh_to_chanctx(fh);
+
+ return vidioc_g_fmt(chan_ctx, f);
+}
+
+static int enum_fmt(struct xm2m_msc_dev *xm2msc, struct v4l2_fmtdesc *f)
+{
+ const struct xm2msc_fmt *fmt;
+ unsigned int i, enabled = 0;
+
+ for (i = 0; i < ARRAY_SIZE(formats); i++) {
+ if (xm2msc_chk_fmt(xm2msc, i) && enabled++ == f->index)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(formats))
+ /* Format not found */
+ return -EINVAL;
+
+ /* Format found */
+ fmt = &formats[i];
+ strlcpy(f->description, fmt->name,
+ sizeof(f->description));
+ f->pixelformat = fmt->fourcc;
+
+ return 0;
+}
+
+static int xm2msc_enum_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f)
+{
+ struct xm2msc_chan_ctx *chan_ctx = fh_to_chanctx(fh);
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return -EINVAL;
+
+ return enum_fmt(chan_ctx->xm2msc_dev, f);
+}
+
+static int xm2msc_enum_fmt_vid_out(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f)
+{
+ struct xm2msc_chan_ctx *chan_ctx = fh_to_chanctx(fh);
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return -EINVAL;
+
+ return enum_fmt(chan_ctx->xm2msc_dev, f);
+}
+
+static int xm2msc_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ strncpy(cap->driver, XM2MSC_DRIVER_NAME, sizeof(cap->driver) - 1);
+ strncpy(cap->card, XM2MSC_DRIVER_NAME, sizeof(cap->card) - 1);
+ snprintf(cap->bus_info, sizeof(cap->bus_info),
+ "platform:%s", XM2MSC_DRIVER_NAME);
+ /*
+ * This is only a mem-to-mem video device. The STREAMING
+ * device capability flags are left only for compatibility
+ * and are scheduled for removal.
+ */
+ cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+ return 0;
+}
+
+static int xm2msc_queue_setup(struct vb2_queue *vq,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], struct device *alloc_devs[])
+{
+ unsigned int i;
+ struct xm2msc_chan_ctx *chan_ctx = vb2_get_drv_priv(vq);
+ struct xm2msc_q_data *q_data;
+
+ q_data = get_q_data(chan_ctx, vq->type);
+ if (!q_data)
+ return -EINVAL;
+
+ *nplanes = q_data->nbuffs;
+
+ for (i = 0; i < *nplanes; i++)
+ sizes[i] = q_data->sizeimage[i];
+
+ dev_dbg(chan_ctx->xm2msc_dev->dev, "get %d buffer(s) of size %d",
+ *nbuffers, sizes[0]);
+ if (q_data->nbuffs == 2)
+ dev_dbg(chan_ctx->xm2msc_dev->dev, " and %d\n", sizes[1]);
+
+ return 0;
+}
+
+static int xm2msc_buf_prepare(struct vb2_buffer *vb)
+{
+ struct xm2msc_chan_ctx *chan_ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct xm2m_msc_dev *xm2msc = chan_ctx->xm2msc_dev;
+ struct xm2msc_q_data *q_data;
+ unsigned int i, num_buffs;
+
+ q_data = get_q_data(chan_ctx, vb->vb2_queue->type);
+ if (!q_data)
+ return -EINVAL;
+ num_buffs = q_data->nbuffs;
+
+ for (i = 0; i < num_buffs; i++) {
+ if (vb2_plane_size(vb, i) < q_data->sizeimage[i]) {
+ v4l2_err(&xm2msc->v4l2_dev, "data will not fit into plane ");
+ v4l2_err(&xm2msc->v4l2_dev, "(%lu < %lu)\n",
+ vb2_plane_size(vb, i),
+ (long)q_data->sizeimage[i]);
+ return -EINVAL;
+ }
+ }
+
+ for (i = 0; i < num_buffs; i++)
+ vb2_set_plane_payload(vb, i, q_data->sizeimage[i]);
+
+ return 0;
+}
+
+static void xm2msc_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct xm2msc_chan_ctx *chan_ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+ v4l2_m2m_buf_queue(chan_ctx->m2m_ctx, vbuf);
+}
+
+static void xm2msc_return_all_buffers(struct xm2msc_chan_ctx *chan_ctx,
+ struct vb2_queue *q,
+ enum vb2_buffer_state state)
+{
+ struct vb2_v4l2_buffer *vb;
+ unsigned long flags;
+
+ for (;;) {
+ if (V4L2_TYPE_IS_OUTPUT(q->type))
+ vb = v4l2_m2m_src_buf_remove(chan_ctx->m2m_ctx);
+ else
+ vb = v4l2_m2m_dst_buf_remove(chan_ctx->m2m_ctx);
+ if (!vb)
+ break;
+ spin_lock_irqsave(&chan_ctx->xm2msc_dev->lock, flags);
+ v4l2_m2m_buf_done(vb, state);
+ spin_unlock_irqrestore(&chan_ctx->xm2msc_dev->lock, flags);
+ }
+}
+
+static int xm2msc_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct xm2msc_chan_ctx *chan_ctx = vb2_get_drv_priv(q);
+ static struct xm2msc_q_data *q_data;
+ int type;
+
+ if (V4L2_TYPE_IS_OUTPUT(q->type))
+ xm2msc_set_chan_stream(chan_ctx, true, XM2MSC_CHAN_OUT);
+ else
+ xm2msc_set_chan_stream(chan_ctx, true, XM2MSC_CHAN_CAP);
+
+ xm2msc_set_chan_params(chan_ctx, q->type);
+
+ if (xm2msc_chk_chan_stream(chan_ctx, XM2MSC_CHAN_CAP) &&
+ xm2msc_chk_chan_stream(chan_ctx, XM2MSC_CHAN_OUT))
+ xm2msc_set_chan_com_params(chan_ctx);
+
+ type = V4L2_TYPE_IS_OUTPUT(q->type) ?
+ V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ q_data = get_q_data(chan_ctx, type);
+ xm2msc_pr_q(chan_ctx->xm2msc_dev->dev, q_data, chan_ctx->num,
+ type, __func__);
+ xm2msc_pr_status(chan_ctx->xm2msc_dev, __func__);
+
+ return 0;
+}
+
+static void xm2msc_stop_streaming(struct vb2_queue *q)
+{
+ struct xm2msc_chan_ctx *chan_ctx = vb2_get_drv_priv(q);
+
+ xm2msc_return_all_buffers(chan_ctx, q, VB2_BUF_STATE_ERROR);
+
+ if (V4L2_TYPE_IS_OUTPUT(q->type))
+ xm2msc_set_chan_stream(chan_ctx, false, XM2MSC_CHAN_OUT);
+ else
+ xm2msc_set_chan_stream(chan_ctx, false, XM2MSC_CHAN_CAP);
+}
+
+static const struct vb2_ops xm2msc_qops = {
+ .queue_setup = xm2msc_queue_setup,
+ .buf_prepare = xm2msc_buf_prepare,
+ .buf_queue = xm2msc_buf_queue,
+ .start_streaming = xm2msc_start_streaming,
+ .stop_streaming = xm2msc_stop_streaming,
+};
+
+static int queue_init(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq)
+{
+ struct xm2msc_chan_ctx *chan_ctx = priv;
+ struct xm2m_msc_dev *xm2msc = chan_ctx->xm2msc_dev;
+ int ret;
+
+ memset(src_vq, 0, sizeof(*src_vq));
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ src_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR;
+ src_vq->drv_priv = chan_ctx;
+ src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ src_vq->ops = &xm2msc_qops;
+ src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->lock = &xm2msc->dev_mutex;
+ src_vq->dev = xm2msc->v4l2_dev.dev;
+
+ ret = vb2_queue_init(src_vq);
+ if (ret)
+ return ret;
+
+ memset(dst_vq, 0, sizeof(*dst_vq));
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ dst_vq->io_modes = VB2_MMAP | VB2_DMABUF | VB2_USERPTR;
+ dst_vq->drv_priv = chan_ctx;
+ dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ dst_vq->ops = &xm2msc_qops;
+ dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->lock = &xm2msc->dev_mutex;
+ dst_vq->dev = xm2msc->v4l2_dev.dev;
+
+ return vb2_queue_init(dst_vq);
+}
+
+static const struct v4l2_ioctl_ops xm2msc_ioctl_ops = {
+ .vidioc_querycap = xm2msc_querycap,
+
+ .vidioc_enum_fmt_vid_cap_mplane = xm2msc_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap_mplane = xm2msc_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap_mplane = xm2msc_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap_mplane = xm2msc_s_fmt_vid_cap,
+
+ .vidioc_enum_fmt_vid_out_mplane = xm2msc_enum_fmt_vid_out,
+ .vidioc_g_fmt_vid_out_mplane = xm2msc_g_fmt_vid_out,
+ .vidioc_try_fmt_vid_out_mplane = xm2msc_try_fmt_vid_out,
+ .vidioc_s_fmt_vid_out_mplane = xm2msc_s_fmt_vid_out,
+
+ .vidioc_reqbufs = xm2msc_reqbufs,
+ .vidioc_querybuf = xm2msc_querybuf,
+ .vidioc_expbuf = xm2msc_expbuf,
+ .vidioc_create_bufs = xm2msc_createbufs,
+
+ .vidioc_qbuf = xm2msc_qbuf,
+ .vidioc_dqbuf = xm2msc_dqbuf,
+
+ .vidioc_streamon = xm2msc_streamon,
+ .vidioc_streamoff = xm2msc_streamoff,
+};
+
+static void xm2msc_set_q_data(struct xm2msc_chan_ctx *chan_ctx,
+ const struct xm2msc_fmt *fmt,
+ enum v4l2_buf_type type)
+{
+ struct xm2msc_q_data *q_data;
+ struct xm2m_msc_dev *xm2msc = chan_ctx->xm2msc_dev;
+
+ q_data = get_q_data(chan_ctx, type);
+
+ q_data->fmt = fmt;
+ q_data->width = xm2msc->max_wd;
+ q_data->height = xm2msc->max_ht;
+ q_data->field = V4L2_FIELD_NONE;
+ q_data->nbuffs = q_data->fmt->num_buffs;
+
+ q_data->stride = xm2msc_cal_stride(q_data->width,
+ q_data->fmt->xm2msc_fmt,
+ xm2msc->ppc);
+
+ xm2msc_cal_imagesize(chan_ctx, q_data, type);
+}
+
+static int xm2msc_set_chan_parm(struct xm2msc_chan_ctx *chan_ctx)
+{
+ int ret = 0;
+ unsigned int i;
+ struct xm2m_msc_dev *xm2msc = chan_ctx->xm2msc_dev;
+
+ chan_ctx->output_stride_align = 1;
+ chan_ctx->output_height_align = 1;
+ chan_ctx->capture_stride_align = 1;
+ chan_ctx->capture_height_align = 1;
+
+ for (i = 0; i < ARRAY_SIZE(formats); i++) {
+ if (xm2msc_chk_fmt(xm2msc, i))
+ break;
+ }
+
+ /* No supported format */
+ if (i == ARRAY_SIZE(formats)) {
+ dev_err(xm2msc->dev, "no supported format found\n");
+ return -EINVAL;
+ }
+
+ xm2msc_set_q_data(chan_ctx, &formats[i],
+ V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+ xm2msc_set_q_data(chan_ctx, &formats[i],
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+
+ return ret;
+}
+
+static int xm2msc_open(struct file *file)
+{
+ struct xm2m_msc_dev *xm2msc = video_drvdata(file);
+ struct xm2msc_chan_ctx *chan_ctx = NULL;
+ u32 minor, chan;
+ int ret;
+
+ if (mutex_lock_interruptible(&xm2msc->dev_mutex))
+ return -ERESTARTSYS;
+
+ minor = iminor(file_inode(file));
+
+ for (chan = 0; chan < xm2msc->max_chan; chan++) {
+ chan_ctx = &xm2msc->xm2msc_chan[chan];
+
+ if ((chan_ctx->status & CHAN_ATTACHED) &&
+ chan_ctx->minor == minor)
+ break;
+ }
+
+ if (chan == xm2msc->max_chan) {
+ v4l2_err(&xm2msc->v4l2_dev,
+ "%s Chan not found with minor = %d\n",
+ __func__, minor);
+ ret = -EBADF;
+ goto unlock;
+ }
+
+ /* Already opened, do not allow same channel
+ * to be open more then once
+ */
+ if (chan_ctx->status & CHAN_OPENED) {
+ v4l2_warn(&xm2msc->v4l2_dev,
+ "%s Chan already opened for minor = %d\n",
+ __func__, minor);
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ v4l2_fh_init(&chan_ctx->fh, &chan_ctx->vfd);
+ file->private_data = &chan_ctx->fh;
+ v4l2_fh_add(&chan_ctx->fh);
+
+ chan_ctx->m2m_ctx = v4l2_m2m_ctx_init(chan_ctx->m2m_dev,
+ chan_ctx, &queue_init);
+ if (IS_ERR(chan_ctx->m2m_ctx)) {
+ ret = PTR_ERR(chan_ctx->m2m_ctx);
+ v4l2_err(&xm2msc->v4l2_dev,
+ "%s Chan M2M CTX not creted for minor %d\n",
+ __func__, minor);
+ goto error_m2m;
+ }
+
+ chan_ctx->fh.m2m_ctx = chan_ctx->m2m_ctx;
+ chan_ctx->status |= CHAN_OPENED;
+ chan_ctx->xm2msc_dev = xm2msc;
+ chan_ctx->frames = 0;
+
+ xm2msc_set_chan(chan_ctx, true);
+
+ v4l2_info(&xm2msc->v4l2_dev, "Channel %d instance created\n", chan);
+
+ mutex_unlock(&xm2msc->dev_mutex);
+ xm2msc_pr_chanctx(chan_ctx, __func__);
+ xm2msc_pr_status(xm2msc, __func__);
+ return 0;
+
+error_m2m:
+ v4l2_fh_del(&chan_ctx->fh);
+ v4l2_fh_exit(&chan_ctx->fh);
+unlock:
+ mutex_unlock(&xm2msc->dev_mutex);
+ xm2msc_pr_chanctx(chan_ctx, __func__);
+ xm2msc_pr_status(xm2msc, __func__);
+ return ret;
+}
+
+static int xm2msc_release(struct file *file)
+{
+ struct xm2m_msc_dev *xm2msc = video_drvdata(file);
+ struct xm2msc_chan_ctx *chan_ctx = fh_to_chanctx(file->private_data);
+
+ if (mutex_lock_interruptible(&xm2msc->dev_mutex))
+ return -ERESTARTSYS;
+
+ v4l2_m2m_ctx_release(chan_ctx->m2m_ctx);
+ v4l2_fh_del(&chan_ctx->fh);
+ v4l2_fh_exit(&chan_ctx->fh);
+ chan_ctx->status &= ~CHAN_OPENED;
+ xm2msc_set_chan(chan_ctx, false);
+
+ v4l2_info(&xm2msc->v4l2_dev, "Channel %d instance released\n",
+ chan_ctx->num);
+
+ mutex_unlock(&xm2msc->dev_mutex);
+ return 0;
+}
+
+static unsigned int xm2msc_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct xm2msc_chan_ctx *chan_ctx = fh_to_chanctx(file->private_data);
+ struct xm2m_msc_dev *xm2msc = chan_ctx->xm2msc_dev;
+ int ret;
+
+ mutex_lock(&xm2msc->dev_mutex);
+ ret = v4l2_m2m_poll(file, chan_ctx->m2m_ctx, wait);
+ mutex_unlock(&xm2msc->dev_mutex);
+
+ return ret;
+}
+
+static int xm2msc_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct xm2msc_chan_ctx *chan_ctx = file->private_data;
+ struct xm2m_msc_dev *xm2msc = chan_ctx->xm2msc_dev;
+ int ret;
+
+ mutex_lock(&xm2msc->dev_mutex);
+ ret = v4l2_m2m_mmap(file, chan_ctx->m2m_ctx, vma);
+
+ mutex_unlock(&xm2msc->dev_mutex);
+ return ret;
+}
+
+static const struct v4l2_file_operations xm2msc_fops = {
+ .owner = THIS_MODULE,
+ .open = xm2msc_open,
+ .release = xm2msc_release,
+ .poll = xm2msc_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = xm2msc_mmap,
+};
+
+static const struct video_device xm2msc_videodev = {
+ .name = XM2MSC_DRIVER_NAME,
+ .fops = &xm2msc_fops,
+ .ioctl_ops = &xm2msc_ioctl_ops,
+ .minor = -1,
+ .release = video_device_release_empty,
+ .vfl_dir = VFL_DIR_M2M,
+};
+
+static const struct v4l2_m2m_ops xm2msc_m2m_ops = {
+ .device_run = xm2msc_device_run,
+ .job_ready = xm2msc_job_ready,
+ .job_abort = xm2msc_job_abort,
+};
+
+static int xm2msc_parse_of(struct platform_device *pdev,
+ struct xm2m_msc_dev *xm2msc)
+{
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
+ int hw_vid_fmt_cnt;
+ const char *vid_fmts[ARRAY_SIZE(formats)];
+ int ret;
+ u32 i, j;
+
+ xm2msc->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(xm2msc->clk)) {
+ ret = PTR_ERR(xm2msc->clk);
+ dev_err(dev, "failed to get clk (%d)\n", ret);
+ return ret;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ xm2msc->regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR((__force void *)xm2msc->regs))
+ return PTR_ERR((__force const void *)xm2msc->regs);
+
+ dev_dbg(dev, "IO Mem 0x%llx mapped at %p\n", res->start, xm2msc->regs);
+
+ ret = of_property_read_u32(node, "xlnx,max-chan",
+ &xm2msc->max_chan);
+ if (ret < 0)
+ return ret;
+
+ if (xm2msc->max_chan < XM2MSC_MIN_CHAN ||
+ xm2msc->max_chan > XM2MSC_MAX_CHAN) {
+ dev_err(dev,
+ "Invalid maximum scaler channels : %d",
+ xm2msc->max_chan);
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32(node, "xlnx,max-width",
+ &xm2msc->max_wd);
+ if (ret < 0) {
+ dev_err(dev,
+ "missing xlnx,max-width prop\n");
+ return ret;
+ }
+
+ if (xm2msc->max_wd < XM2MSC_MIN_WIDTH ||
+ xm2msc->max_wd > XM2MSC_MAX_WIDTH) {
+ dev_err(dev, "Invalid width : %d",
+ xm2msc->max_wd);
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32(node, "xlnx,max-height",
+ &xm2msc->max_ht);
+ if (ret < 0) {
+ dev_err(dev, "missing xlnx,max-height prop\n");
+ return ret;
+ }
+
+ if (xm2msc->max_ht < XM2MSC_MIN_HEIGHT ||
+ xm2msc->max_ht > XM2MSC_MAX_HEIGHT) {
+ dev_err(dev, "Invalid height : %d",
+ xm2msc->max_ht);
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32(node, "xlnx,dma-addr-width",
+ &xm2msc->dma_addr_size);
+ if (ret || (xm2msc->dma_addr_size != 32 &&
+ xm2msc->dma_addr_size != 64)) {
+ dev_err(dev, "missing/invalid addr width dts prop\n");
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u8(node, "xlnx,pixels-per-clock",
+ &xm2msc->ppc);
+ if (ret || (xm2msc->ppc != 1 && xm2msc->ppc != 2 && xm2msc->ppc != 4)) {
+ dev_err(dev, "missing or invalid pixels per clock dts prop\n");
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32(node, "xlnx,num-taps",
+ &xm2msc->taps);
+ if (ret || (xm2msc->taps != XSCALER_TAPS_6 &&
+ xm2msc->taps != XSCALER_TAPS_8 &&
+ xm2msc->taps != XSCALER_TAPS_10 &&
+ xm2msc->taps != XSCALER_TAPS_12)) {
+ dev_err(dev, "missing/invalid taps in dts prop\n");
+ return -EINVAL;
+ }
+
+ xm2msc->irq = irq_of_parse_and_map(node, 0);
+ if (xm2msc->irq < 0) {
+ dev_err(dev, "Unable to get IRQ");
+ return xm2msc->irq;
+ }
+
+ dev_dbg(dev, "Max Channel Supported = %d\n", xm2msc->max_chan);
+ dev_dbg(dev, "DMA Addr width Supported = %d\n", xm2msc->dma_addr_size);
+ dev_dbg(dev, "Max col/row Supported = (%d) / (%d)\n",
+ xm2msc->max_wd, xm2msc->max_ht);
+ dev_dbg(dev, "taps Supported = %d\n", xm2msc->taps);
+ /* read supported video formats and update internal table */
+ hw_vid_fmt_cnt = of_property_count_strings(node, "xlnx,vid-formats");
+
+ ret = of_property_read_string_array(node, "xlnx,vid-formats",
+ vid_fmts, hw_vid_fmt_cnt);
+ if (ret < 0) {
+ dev_err(dev,
+ "Missing or invalid xlnx,vid-formats dts prop\n");
+ return ret;
+ }
+
+ dev_dbg(dev, "Supported format = ");
+ for (i = 0; i < hw_vid_fmt_cnt; i++) {
+ const char *vid_fmt_name = vid_fmts[i];
+
+ for (j = 0; j < ARRAY_SIZE(formats); j++) {
+ const char *dts_name = formats[j].name;
+
+ if (strcmp(vid_fmt_name, dts_name))
+ continue;
+ dev_dbg(dev, "%s ", dts_name);
+
+ xm2msc_set_fmt(xm2msc, j);
+ }
+ }
+ dev_dbg(dev, "\n");
+ xm2msc->rst_gpio = devm_gpiod_get(dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(xm2msc->rst_gpio)) {
+ ret = PTR_ERR(xm2msc->rst_gpio);
+ if (ret == -EPROBE_DEFER)
+ dev_info(dev,
+ "Probe deferred due to GPIO reset defer\n");
+ else
+ dev_err(dev,
+ "Unable to locate reset property in dt\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void xm2msc_unreg_video_n_m2m(struct xm2m_msc_dev *xm2msc)
+{
+ struct xm2msc_chan_ctx *chan_ctx;
+ unsigned int chan;
+
+ for (chan = 0; chan < xm2msc->max_chan; chan++) {
+ chan_ctx = &xm2msc->xm2msc_chan[chan];
+ if (!(chan_ctx->status & CHAN_ATTACHED))
+ break; /*We register video sequentially */
+ video_unregister_device(&chan_ctx->vfd);
+ chan_ctx->status &= ~CHAN_ATTACHED;
+
+ if (!IS_ERR(chan_ctx->m2m_dev))
+ v4l2_m2m_release(chan_ctx->m2m_dev);
+ }
+}
+
+static int xm2m_msc_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct xm2m_msc_dev *xm2msc;
+ struct xm2msc_chan_ctx *chan_ctx;
+ struct video_device *vfd;
+ unsigned int chan;
+
+ xm2msc = devm_kzalloc(&pdev->dev, sizeof(*xm2msc), GFP_KERNEL);
+ if (!xm2msc)
+ return -ENOMEM;
+
+ ret = xm2msc_parse_of(pdev, xm2msc);
+ if (ret < 0)
+ return ret;
+
+ xm2msc->dev = &pdev->dev;
+
+ ret = clk_prepare_enable(xm2msc->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable clk (%d)\n", ret);
+ return ret;
+ }
+
+ xm2msc_reset(xm2msc);
+
+ spin_lock_init(&xm2msc->lock);
+
+ ret = v4l2_device_register(&pdev->dev, &xm2msc->v4l2_dev);
+ if (ret)
+ goto reg_dev_err;
+
+ for (chan = 0; chan < xm2msc->max_chan; chan++) {
+ chan_ctx = &xm2msc->xm2msc_chan[chan];
+
+ vfd = &chan_ctx->vfd;
+ *vfd = xm2msc_videodev;
+ vfd->lock = &xm2msc->dev_mutex;
+ vfd->v4l2_dev = &xm2msc->v4l2_dev;
+
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, chan);
+ if (ret) {
+ v4l2_err(&xm2msc->v4l2_dev,
+ "Failed to register video dev for chan %d\n",
+ chan);
+ goto unreg_dev;
+ }
+
+ chan_ctx->status = CHAN_ATTACHED;
+
+ video_set_drvdata(vfd, xm2msc);
+ snprintf(vfd->name, sizeof(vfd->name),
+ "%s", xm2msc_videodev.name);
+ v4l2_info(&xm2msc->v4l2_dev,
+ " Device registered as /dev/video%d\n", vfd->num);
+
+ dev_dbg(xm2msc->dev, "%s Device registered as /dev/video%d\n",
+ __func__, vfd->num);
+
+ chan_ctx->m2m_dev = v4l2_m2m_init(&xm2msc_m2m_ops);
+ if (IS_ERR(chan_ctx->m2m_dev)) {
+ v4l2_err(&xm2msc->v4l2_dev,
+ "Failed to init mem2mem device for chan %d\n",
+ chan);
+ ret = PTR_ERR(chan_ctx->m2m_dev);
+ goto unreg_dev;
+ }
+ chan_ctx->xm2msc_dev = xm2msc;
+ chan_ctx->regs = xm2msc->regs + XM2MSC_CHAN_REGS_START(chan);
+ if (chan > 4) /* TODO: To be fixed in HW */
+ chan_ctx->regs += XM2MSC_RESERVED_AREA;
+ chan_ctx->num = chan;
+ chan_ctx->minor = vfd->minor;
+
+ /* Set channel parameters to default values */
+ ret = xm2msc_set_chan_parm(chan_ctx);
+ if (ret)
+ goto unreg_dev;
+
+ xm2msc_pr_chanctx(chan_ctx, __func__);
+ }
+
+ mutex_init(&xm2msc->dev_mutex);
+ mutex_init(&xm2msc->mutex);
+ init_waitqueue_head(&xm2msc->isr_finished);
+
+ ret = devm_request_irq(&pdev->dev, xm2msc->irq,
+ xm2msc_isr, IRQF_SHARED,
+ XM2MSC_DRIVER_NAME, xm2msc);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Unable to register IRQ\n");
+ goto unreg_dev;
+ }
+
+ platform_set_drvdata(pdev, xm2msc);
+
+ return 0;
+
+unreg_dev:
+ xm2msc_unreg_video_n_m2m(xm2msc);
+ v4l2_device_unregister(&xm2msc->v4l2_dev);
+reg_dev_err:
+ clk_disable_unprepare(xm2msc->clk);
+ return ret;
+}
+
+static int xm2m_msc_remove(struct platform_device *pdev)
+{
+ struct xm2m_msc_dev *xm2msc = platform_get_drvdata(pdev);
+
+ xm2msc_unreg_video_n_m2m(xm2msc);
+ v4l2_device_unregister(&xm2msc->v4l2_dev);
+ clk_disable_unprepare(xm2msc->clk);
+ return 0;
+}
+
+static const struct of_device_id xm2m_msc_of_id_table[] = {
+ {.compatible = "xlnx,v-multi-scaler-v1.0"},
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, xm2m_msc_of_id_table);
+
+static struct platform_driver xm2m_msc_driver = {
+ .driver = {
+ .name = "xilinx-multiscaler",
+ .of_match_table = xm2m_msc_of_id_table,
+ },
+ .probe = xm2m_msc_probe,
+ .remove = xm2m_msc_remove,
+};
+
+module_platform_driver(xm2m_msc_driver);
+
+MODULE_DESCRIPTION("Xilinx M2M Multi-Scaler Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("xlnx_m2m_multiscaler_dev");
diff --git a/drivers/media/platform/xilinx/xilinx-remapper.c b/drivers/media/platform/xilinx/xilinx-remapper.c
new file mode 100644
index 000000000000..d2e84ec1f2d6
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-remapper.c
@@ -0,0 +1,546 @@
+/*
+ * Xilinx Video Remapper
+ *
+ * Copyright (C) 2013-2015 Ideas on Board
+ * Copyright (C) 2013-2015 Xilinx, Inc.
+ *
+ * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
+ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <media/v4l2-async.h>
+#include <media/v4l2-subdev.h>
+
+#include "xilinx-vip.h"
+
+#define XREMAP_MIN_WIDTH 1
+#define XREMAP_DEF_WIDTH 1920
+#define XREMAP_MAX_WIDTH 65535
+#define XREMAP_MIN_HEIGHT 1
+#define XREMAP_DEF_HEIGHT 1080
+#define XREMAP_MAX_HEIGHT 65535
+
+#define XREMAP_PAD_SINK 0
+#define XREMAP_PAD_SOURCE 1
+
+/**
+ * struct xremap_mapping_output - Output format description
+ * @code: media bus pixel core after remapping
+ * @num_components: number of pixel components after remapping
+ * @component_maps: configuration array corresponding to this output
+ */
+struct xremap_mapping_output {
+ u32 code;
+ unsigned int num_components;
+ unsigned int component_maps[4];
+};
+
+/**
+ * struct xremap_mapping - Input-output remapping description
+ * @code: media bus pixel code before remapping
+ * @width: video bus width in bits
+ * @num_components: number of pixel components before remapping
+ * @outputs: array of possible output formats
+ */
+struct xremap_mapping {
+ u32 code;
+ unsigned int width;
+ unsigned int num_components;
+ const struct xremap_mapping_output *outputs;
+};
+
+/**
+ * struct xremap_device - Xilinx Test Pattern Generator device structure
+ * @xvip: Xilinx Video IP device
+ * @pads: media pads
+ * @formats: V4L2 media bus formats at the sink and source pads
+ * @config: device configuration parsed from its DT node
+ * @config.width: video bus width in bits
+ * @config.num_s_components: number of pixel components at the input
+ * @config.num_m_components: number of pixel components at the output
+ * @config.component_maps: component remapping configuration
+ * @default_mapping: Default mapping compatible with the configuration
+ * @default_output: Default output format for the default mapping
+ */
+struct xremap_device {
+ struct xvip_device xvip;
+ struct media_pad pads[2];
+ struct v4l2_mbus_framefmt formats[2];
+
+ struct {
+ unsigned int width;
+ unsigned int num_s_components;
+ unsigned int num_m_components;
+ unsigned int component_maps[4];
+ } config;
+
+ const struct xremap_mapping *default_mapping;
+ const struct xremap_mapping_output *default_output;
+};
+
+static inline struct xremap_device *to_remap(struct v4l2_subdev *subdev)
+{
+ return container_of(subdev, struct xremap_device, xvip.subdev);
+}
+
+/* -----------------------------------------------------------------------------
+ * Mappings
+ */
+
+static const struct xremap_mapping xremap_mappings[] = {
+ {
+ .code = MEDIA_BUS_FMT_RBG888_1X24,
+ .width = 8,
+ .num_components = 3,
+ .outputs = (const struct xremap_mapping_output[]) {
+ { MEDIA_BUS_FMT_RGB888_1X32_PADHI, 4, { 1, 0, 2, 4 } },
+ { },
+ },
+ },
+};
+
+static const struct xremap_mapping_output *
+xremap_match_mapping(struct xremap_device *xremap,
+ const struct xremap_mapping *mapping)
+{
+ const struct xremap_mapping_output *output;
+
+ if (mapping->width != xremap->config.width ||
+ mapping->num_components != xremap->config.num_s_components)
+ return NULL;
+
+ for (output = mapping->outputs; output->code; ++output) {
+ unsigned int i;
+
+ if (output->num_components != xremap->config.num_m_components)
+ continue;
+
+ for (i = 0; i < output->num_components; ++i) {
+ if (output->component_maps[i] !=
+ xremap->config.component_maps[i])
+ break;
+ }
+
+ if (i == output->num_components)
+ return output;
+ }
+
+ return NULL;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Pad Operations
+ */
+
+static int xremap_enum_mbus_code(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct xremap_device *xremap = to_remap(subdev);
+ struct v4l2_mbus_framefmt *format;
+
+ if (code->pad == XREMAP_PAD_SINK) {
+ const struct xremap_mapping *mapping = NULL;
+ unsigned int index = code->index + 1;
+ unsigned int i;
+
+ /* Iterate through the mappings and skip the ones that don't
+ * match the remapper configuration until we reach the requested
+ * index.
+ */
+ for (i = 0; i < ARRAY_SIZE(xremap_mappings) && index; ++i) {
+ mapping = &xremap_mappings[i];
+
+ if (xremap_match_mapping(xremap, mapping))
+ index--;
+ }
+
+ /* If the index was larger than the number of supported mappings
+ * return -EINVAL.
+ */
+ if (index > 0)
+ return -EINVAL;
+
+ code->code = mapping->code;
+ } else {
+ if (code->index)
+ return -EINVAL;
+
+ format = v4l2_subdev_get_try_format(subdev, cfg, code->pad);
+ code->code = format->code;
+ }
+
+ return 0;
+}
+
+static int xremap_enum_frame_size(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct v4l2_mbus_framefmt *format;
+
+ format = v4l2_subdev_get_try_format(subdev, cfg, fse->pad);
+
+ if (fse->index || fse->code != format->code)
+ return -EINVAL;
+
+ if (fse->pad == XREMAP_PAD_SINK) {
+ /* The remapper doesn't restrict the size on the sink pad. */
+ fse->min_width = XREMAP_MIN_WIDTH;
+ fse->max_width = XREMAP_MAX_WIDTH;
+ fse->min_height = XREMAP_MIN_HEIGHT;
+ fse->max_height = XREMAP_MAX_HEIGHT;
+ } else {
+ /* The size on the source pad are fixed and always identical to
+ * the size on the sink pad.
+ */
+ fse->min_width = format->width;
+ fse->max_width = format->width;
+ fse->min_height = format->height;
+ fse->max_height = format->height;
+ }
+
+ return 0;
+}
+
+static struct v4l2_mbus_framefmt *
+xremap_get_pad_format(struct xremap_device *xremap,
+ struct v4l2_subdev_pad_config *cfg,
+ unsigned int pad, u32 which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_format(&xremap->xvip.subdev, cfg,
+ pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &xremap->formats[pad];
+ default:
+ return NULL;
+ }
+}
+
+static int xremap_get_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xremap_device *xremap = to_remap(subdev);
+
+ fmt->format = *xremap_get_pad_format(xremap, cfg, fmt->pad, fmt->which);
+
+ return 0;
+}
+
+static int xremap_set_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xremap_device *xremap = to_remap(subdev);
+ const struct xremap_mapping_output *output;
+ const struct xremap_mapping *mapping;
+ struct v4l2_mbus_framefmt *format;
+ unsigned int i;
+
+ format = xremap_get_pad_format(xremap, cfg, fmt->pad, fmt->which);
+
+ if (fmt->pad == XREMAP_PAD_SOURCE) {
+ fmt->format = *format;
+ return 0;
+ }
+
+ /* Find the mapping. If the requested format has no mapping, use the
+ * default.
+ */
+ for (i = 0; i < ARRAY_SIZE(xremap_mappings); ++i) {
+ mapping = &xremap_mappings[i];
+ if (mapping->code != fmt->format.code)
+ continue;
+
+ output = xremap_match_mapping(xremap, mapping);
+ if (output)
+ break;
+ }
+
+ if (!output) {
+ mapping = xremap->default_mapping;
+ output = xremap->default_output;
+ }
+
+ format->code = mapping->code;
+ format->width = clamp_t(unsigned int, fmt->format.width,
+ XREMAP_MIN_WIDTH, XREMAP_MAX_WIDTH);
+ format->height = clamp_t(unsigned int, fmt->format.height,
+ XREMAP_MIN_HEIGHT, XREMAP_MAX_HEIGHT);
+ format->field = V4L2_FIELD_NONE;
+ format->colorspace = V4L2_COLORSPACE_SRGB;
+
+ fmt->format = *format;
+
+ /* Propagate the format to the source pad. */
+ format = xremap_get_pad_format(xremap, cfg, XREMAP_PAD_SOURCE,
+ fmt->which);
+ *format = fmt->format;
+ format->code = output->code;
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Operations
+ */
+
+/*
+ * xremap_init_formats - Initialize formats on all pads
+ * @subdev: remapper V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ *
+ * Initialize all pad formats with default values. If fh is not NULL, try
+ * formats are initialized on the file handle. Otherwise active formats are
+ * initialized on the device.
+ */
+static void xremap_init_formats(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh)
+{
+ struct xremap_device *xremap = to_remap(subdev);
+ struct v4l2_subdev_format format;
+
+ memset(&format, 0, sizeof(format));
+
+ format.pad = XREMAP_PAD_SINK;
+ format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+ format.format.code = xremap->default_mapping->code;
+ format.format.width = XREMAP_DEF_WIDTH;
+ format.format.height = XREMAP_DEF_HEIGHT;
+
+ xremap_set_format(subdev, fh ? fh->pad : NULL, &format);
+}
+
+static int xremap_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ xremap_init_formats(subdev, fh);
+
+ return 0;
+}
+
+static int xremap_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ return 0;
+}
+
+static struct v4l2_subdev_core_ops xremap_core_ops = {
+};
+
+static struct v4l2_subdev_video_ops xremap_video_ops = {
+};
+
+static struct v4l2_subdev_pad_ops xremap_pad_ops = {
+ .enum_mbus_code = xremap_enum_mbus_code,
+ .enum_frame_size = xremap_enum_frame_size,
+ .get_fmt = xremap_get_format,
+ .set_fmt = xremap_set_format,
+};
+
+static struct v4l2_subdev_ops xremap_ops = {
+ .core = &xremap_core_ops,
+ .video = &xremap_video_ops,
+ .pad = &xremap_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops xremap_internal_ops = {
+ .open = xremap_open,
+ .close = xremap_close,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media Operations
+ */
+
+static const struct media_entity_operations xremap_media_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+/* -----------------------------------------------------------------------------
+ * Platform Device Driver
+ */
+
+static int xremap_parse_of(struct xremap_device *xremap)
+{
+ struct device_node *node = xremap->xvip.dev->of_node;
+ unsigned int i;
+ int ret;
+
+ /* Parse the DT properties. */
+ ret = of_property_read_u32(node, "xlnx,video-width",
+ &xremap->config.width);
+ if (ret < 0) {
+ dev_dbg(xremap->xvip.dev, "unable to parse %s property\n",
+ "xlnx,video-width");
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32(node, "#xlnx,s-components",
+ &xremap->config.num_s_components);
+ if (ret < 0) {
+ dev_dbg(xremap->xvip.dev, "unable to parse %s property\n",
+ "#xlnx,s-components");
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32(node, "#xlnx,m-components",
+ &xremap->config.num_m_components);
+ if (ret < 0) {
+ dev_dbg(xremap->xvip.dev, "unable to parse %s property\n",
+ "#xlnx,m-components");
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32_array(node, "xlnx,component-maps",
+ xremap->config.component_maps,
+ xremap->config.num_m_components);
+ if (ret < 0) {
+ dev_dbg(xremap->xvip.dev, "unable to parse %s property\n",
+ "xlnx,component-maps");
+ return -EINVAL;
+ }
+
+ /* Validate the parsed values. */
+ if (xremap->config.num_s_components > 4 ||
+ xremap->config.num_m_components > 4) {
+ dev_dbg(xremap->xvip.dev,
+ "invalid number of components (s %u m %u)\n",
+ xremap->config.num_s_components,
+ xremap->config.num_m_components);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < xremap->config.num_m_components; ++i) {
+ if (xremap->config.component_maps[i] > 4) {
+ dev_dbg(xremap->xvip.dev, "invalid map %u @%u\n",
+ xremap->config.component_maps[i], i);
+ return -EINVAL;
+ }
+ }
+
+ /* Find the first mapping that matches the remapper configuration and
+ * store it as the default mapping.
+ */
+ for (i = 0; i < ARRAY_SIZE(xremap_mappings); ++i) {
+ const struct xremap_mapping_output *output;
+ const struct xremap_mapping *mapping;
+
+ mapping = &xremap_mappings[i];
+ output = xremap_match_mapping(xremap, mapping);
+
+ if (output) {
+ xremap->default_mapping = mapping;
+ xremap->default_output = output;
+ return 0;
+ }
+ }
+
+ dev_err(xremap->xvip.dev,
+ "No format compatible with device configuration\n");
+
+ return -EINVAL;
+}
+
+static int xremap_probe(struct platform_device *pdev)
+{
+ struct xremap_device *xremap;
+ struct v4l2_subdev *subdev;
+ int ret;
+
+ xremap = devm_kzalloc(&pdev->dev, sizeof(*xremap), GFP_KERNEL);
+ if (!xremap)
+ return -ENOMEM;
+
+ xremap->xvip.dev = &pdev->dev;
+
+ ret = xremap_parse_of(xremap);
+ if (ret < 0)
+ return ret;
+
+ xremap->xvip.clk = devm_clk_get(xremap->xvip.dev, NULL);
+ if (IS_ERR(xremap->xvip.clk))
+ return PTR_ERR(xremap->xvip.clk);
+
+ clk_prepare_enable(xremap->xvip.clk);
+
+ /* Initialize V4L2 subdevice and media entity */
+ subdev = &xremap->xvip.subdev;
+ v4l2_subdev_init(subdev, &xremap_ops);
+ subdev->dev = &pdev->dev;
+ subdev->internal_ops = &xremap_internal_ops;
+ strlcpy(subdev->name, dev_name(&pdev->dev), sizeof(subdev->name));
+ v4l2_set_subdevdata(subdev, xremap);
+ subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ xremap_init_formats(subdev, NULL);
+
+ xremap->pads[XREMAP_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ xremap->pads[XREMAP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ subdev->entity.ops = &xremap_media_ops;
+ ret = media_entity_pads_init(&subdev->entity, 2, xremap->pads);
+ if (ret < 0)
+ goto error;
+
+ platform_set_drvdata(pdev, xremap);
+
+ ret = v4l2_async_register_subdev(subdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to register subdev\n");
+ goto error;
+ }
+
+ dev_info(&pdev->dev, "device registered\n");
+
+ return 0;
+
+error:
+ media_entity_cleanup(&subdev->entity);
+ clk_disable_unprepare(xremap->xvip.clk);
+ return ret;
+}
+
+static int xremap_remove(struct platform_device *pdev)
+{
+ struct xremap_device *xremap = platform_get_drvdata(pdev);
+ struct v4l2_subdev *subdev = &xremap->xvip.subdev;
+
+ v4l2_async_unregister_subdev(subdev);
+ media_entity_cleanup(&subdev->entity);
+
+ clk_disable_unprepare(xremap->xvip.clk);
+
+ return 0;
+}
+
+static const struct of_device_id xremap_of_id_table[] = {
+ { .compatible = "xlnx,v-remapper" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, xremap_of_id_table);
+
+static struct platform_driver xremap_driver = {
+ .driver = {
+ .name = "xilinx-remapper",
+ .of_match_table = xremap_of_id_table,
+ },
+ .probe = xremap_probe,
+ .remove = xremap_remove,
+};
+
+module_platform_driver(xremap_driver);
+
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_DESCRIPTION("Xilinx Video Remapper Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/xilinx/xilinx-rgb2yuv.c b/drivers/media/platform/xilinx/xilinx-rgb2yuv.c
new file mode 100644
index 000000000000..20ae95946ca3
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-rgb2yuv.c
@@ -0,0 +1,566 @@
+/*
+ * Xilinx RGB to YUV Convertor
+ *
+ * Copyright (C) 2013-2015 Ideas on Board
+ * Copyright (C) 2013-2015 Xilinx, Inc.
+ *
+ * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
+ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/xilinx-v4l2-controls.h>
+
+#include <media/v4l2-async.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
+
+#include "xilinx-vip.h"
+
+#define XRGB2YUV_YMAX 0x100
+#define XRGB2YUV_YMIN 0x104
+#define XRGB2YUV_CBMAX 0x108
+#define XRGB2YUV_CBMIN 0x10c
+#define XRGB2YUV_CRMAX 0x110
+#define XRGB2YUV_CRMIN 0x114
+#define XRGB2YUV_YOFFSET 0x118
+#define XRGB2YUV_CBOFFSET 0x11c
+#define XRGB2YUV_CROFFSET 0x120
+#define XRGB2YUV_ACOEF 0x124
+#define XRGB2YUV_BCOEF 0x128
+#define XRGB2YUV_CCOEF 0x12c
+#define XRGB2YUV_DCOEF 0x130
+
+/**
+ * struct xrgb2yuv_device - Xilinx RGB2YUV device structure
+ * @xvip: Xilinx Video IP device
+ * @pads: media pads
+ * @formats: V4L2 media bus formats at the sink and source pads
+ * @default_formats: default V4L2 media bus formats
+ * @vip_formats: Xilinx Video IP formats
+ * @ctrl_handler: control handler
+ */
+struct xrgb2yuv_device {
+ struct xvip_device xvip;
+
+ struct media_pad pads[2];
+
+ struct v4l2_mbus_framefmt formats[2];
+ struct v4l2_mbus_framefmt default_formats[2];
+ const struct xvip_video_format *vip_formats[2];
+
+ struct v4l2_ctrl_handler ctrl_handler;
+};
+
+static inline struct xrgb2yuv_device *to_rgb2yuv(struct v4l2_subdev *subdev)
+{
+ return container_of(subdev, struct xrgb2yuv_device, xvip.subdev);
+}
+
+/*
+ * V4L2 Subdevice Video Operations
+ */
+
+static int xrgb2yuv_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+ struct xrgb2yuv_device *xrgb2yuv = to_rgb2yuv(subdev);
+
+ if (!enable) {
+ xvip_stop(&xrgb2yuv->xvip);
+ return 0;
+ }
+
+ xvip_set_frame_size(&xrgb2yuv->xvip, &xrgb2yuv->formats[XVIP_PAD_SINK]);
+
+ xvip_start(&xrgb2yuv->xvip);
+
+ return 0;
+}
+
+/*
+ * V4L2 Subdevice Pad Operations
+ */
+
+static struct v4l2_mbus_framefmt *
+__xrgb2yuv_get_pad_format(struct xrgb2yuv_device *xrgb2yuv,
+ struct v4l2_subdev_pad_config *cfg,
+ unsigned int pad, u32 which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_format(&xrgb2yuv->xvip.subdev, cfg,
+ pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &xrgb2yuv->formats[pad];
+ default:
+ return NULL;
+ }
+}
+
+static int xrgb2yuv_get_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xrgb2yuv_device *xrgb2yuv = to_rgb2yuv(subdev);
+
+ fmt->format = *__xrgb2yuv_get_pad_format(xrgb2yuv, cfg, fmt->pad,
+ fmt->which);
+
+ return 0;
+}
+
+static int xrgb2yuv_set_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xrgb2yuv_device *xrgb2yuv = to_rgb2yuv(subdev);
+ struct v4l2_mbus_framefmt *format;
+
+ format = __xrgb2yuv_get_pad_format(xrgb2yuv, cfg, fmt->pad, fmt->which);
+
+ if (fmt->pad == XVIP_PAD_SOURCE) {
+ fmt->format = *format;
+ return 0;
+ }
+
+ xvip_set_format_size(format, fmt);
+
+ fmt->format = *format;
+
+ /* Propagate the format to the source pad. */
+ format = __xrgb2yuv_get_pad_format(xrgb2yuv, cfg, XVIP_PAD_SOURCE,
+ fmt->which);
+
+ xvip_set_format_size(format, fmt);
+
+ return 0;
+}
+
+/*
+ * V4L2 Subdevice Operations
+ */
+
+static int xrgb2yuv_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ struct xrgb2yuv_device *xrgb2yuv = to_rgb2yuv(subdev);
+ struct v4l2_mbus_framefmt *format;
+
+ /* Initialize with default formats */
+ format = v4l2_subdev_get_try_format(subdev, fh->pad, XVIP_PAD_SINK);
+ *format = xrgb2yuv->default_formats[XVIP_PAD_SINK];
+
+ format = v4l2_subdev_get_try_format(subdev, fh->pad, XVIP_PAD_SOURCE);
+ *format = xrgb2yuv->default_formats[XVIP_PAD_SOURCE];
+
+ return 0;
+}
+
+static int xrgb2yuv_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ return 0;
+}
+
+static int xrgb2yuv_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct xrgb2yuv_device *xrgb2yuv =
+ container_of(ctrl->handler, struct xrgb2yuv_device,
+ ctrl_handler);
+
+ switch (ctrl->id) {
+ case V4L2_CID_XILINX_RGB2YUV_YMAX:
+ xvip_write(&xrgb2yuv->xvip, XRGB2YUV_YMAX, ctrl->val);
+ return 0;
+ case V4L2_CID_XILINX_RGB2YUV_YMIN:
+ xvip_write(&xrgb2yuv->xvip, XRGB2YUV_YMIN, ctrl->val);
+ return 0;
+ case V4L2_CID_XILINX_RGB2YUV_CBMAX:
+ xvip_write(&xrgb2yuv->xvip, XRGB2YUV_CBMAX, ctrl->val);
+ return 0;
+ case V4L2_CID_XILINX_RGB2YUV_CBMIN:
+ xvip_write(&xrgb2yuv->xvip, XRGB2YUV_CBMIN, ctrl->val);
+ return 0;
+ case V4L2_CID_XILINX_RGB2YUV_CRMAX:
+ xvip_write(&xrgb2yuv->xvip, XRGB2YUV_CRMAX, ctrl->val);
+ return 0;
+ case V4L2_CID_XILINX_RGB2YUV_CRMIN:
+ xvip_write(&xrgb2yuv->xvip, XRGB2YUV_CRMIN, ctrl->val);
+ return 0;
+ case V4L2_CID_XILINX_RGB2YUV_YOFFSET:
+ xvip_write(&xrgb2yuv->xvip, XRGB2YUV_YOFFSET, ctrl->val);
+ return 0;
+ case V4L2_CID_XILINX_RGB2YUV_CBOFFSET:
+ xvip_write(&xrgb2yuv->xvip, XRGB2YUV_CBOFFSET, ctrl->val);
+ return 0;
+ case V4L2_CID_XILINX_RGB2YUV_CROFFSET:
+ xvip_write(&xrgb2yuv->xvip, XRGB2YUV_CROFFSET, ctrl->val);
+ return 0;
+ case V4L2_CID_XILINX_RGB2YUV_ACOEF:
+ xvip_write(&xrgb2yuv->xvip, XRGB2YUV_ACOEF, ctrl->val);
+ return 0;
+ case V4L2_CID_XILINX_RGB2YUV_BCOEF:
+ xvip_write(&xrgb2yuv->xvip, XRGB2YUV_BCOEF, ctrl->val);
+ return 0;
+ case V4L2_CID_XILINX_RGB2YUV_CCOEF:
+ xvip_write(&xrgb2yuv->xvip, XRGB2YUV_CCOEF, ctrl->val);
+ return 0;
+ case V4L2_CID_XILINX_RGB2YUV_DCOEF:
+ xvip_write(&xrgb2yuv->xvip, XRGB2YUV_DCOEF, ctrl->val);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static const struct v4l2_ctrl_ops xrgb2yuv_ctrl_ops = {
+ .s_ctrl = xrgb2yuv_s_ctrl,
+};
+
+static struct v4l2_subdev_video_ops xrgb2yuv_video_ops = {
+ .s_stream = xrgb2yuv_s_stream,
+};
+
+static struct v4l2_subdev_pad_ops xrgb2yuv_pad_ops = {
+ .enum_mbus_code = xvip_enum_mbus_code,
+ .enum_frame_size = xvip_enum_frame_size,
+ .get_fmt = xrgb2yuv_get_format,
+ .set_fmt = xrgb2yuv_set_format,
+};
+
+static struct v4l2_subdev_ops xrgb2yuv_ops = {
+ .video = &xrgb2yuv_video_ops,
+ .pad = &xrgb2yuv_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops xrgb2yuv_internal_ops = {
+ .open = xrgb2yuv_open,
+ .close = xrgb2yuv_close,
+};
+
+/*
+ * Control Configs
+ */
+
+static struct v4l2_ctrl_config xrgb2yuv_ctrls[] = {
+ {
+ .ops = &xrgb2yuv_ctrl_ops,
+ .id = V4L2_CID_XILINX_RGB2YUV_YMAX,
+ .name = "RGB to YUV: Maximum Y value",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = (1 << 16) - 1,
+ .step = 1,
+ }, {
+ .ops = &xrgb2yuv_ctrl_ops,
+ .id = V4L2_CID_XILINX_RGB2YUV_YMIN,
+ .name = "RGB to YUV: Minimum Y value",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = (1 << 16) - 1,
+ .step = 1,
+ }, {
+ .ops = &xrgb2yuv_ctrl_ops,
+ .id = V4L2_CID_XILINX_RGB2YUV_CBMAX,
+ .name = "RGB to YUV: Maximum Cb value",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = (1 << 16) - 1,
+ .step = 1,
+ }, {
+ .ops = &xrgb2yuv_ctrl_ops,
+ .id = V4L2_CID_XILINX_RGB2YUV_CBMIN,
+ .name = "RGB to YUV: Minimum Cb value",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = (1 << 16) - 1,
+ .step = 1,
+ }, {
+ .ops = &xrgb2yuv_ctrl_ops,
+ .id = V4L2_CID_XILINX_RGB2YUV_CRMAX,
+ .name = "RGB to YUV: Maximum Cr value",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = (1 << 16) - 1,
+ .step = 1,
+ }, {
+ .ops = &xrgb2yuv_ctrl_ops,
+ .id = V4L2_CID_XILINX_RGB2YUV_CRMIN,
+ .name = "RGB to YUV: Minimum Cr value",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = (1 << 16) - 1,
+ .step = 1,
+ }, {
+ .ops = &xrgb2yuv_ctrl_ops,
+ .id = V4L2_CID_XILINX_RGB2YUV_YOFFSET,
+ .name = "RGB to YUV: Luma offset",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = (1 << 17) - 1,
+ .step = 1,
+ }, {
+ .ops = &xrgb2yuv_ctrl_ops,
+ .id = V4L2_CID_XILINX_RGB2YUV_CBOFFSET,
+ .name = "RGB to YUV: Chroma Cb offset",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = (1 << 17) - 1,
+ .step = 1,
+ }, {
+ .ops = &xrgb2yuv_ctrl_ops,
+ .id = V4L2_CID_XILINX_RGB2YUV_CROFFSET,
+ .name = "RGB to YUV: Chroma Cr offset",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = (1 << 17) - 1,
+ .step = 1,
+ }, {
+ .ops = &xrgb2yuv_ctrl_ops,
+ .id = V4L2_CID_XILINX_RGB2YUV_ACOEF,
+ .name = "RGB to YUV: CA coefficient",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = -((1 << 17) - 1),
+ .max = (1 << 17) - 1,
+ .step = 1,
+ }, {
+ .ops = &xrgb2yuv_ctrl_ops,
+ .id = V4L2_CID_XILINX_RGB2YUV_BCOEF,
+ .name = "RGB to YUV: CB coefficient",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = -((1 << 17) - 1),
+ .max = (1 << 17) - 1,
+ .step = 1,
+ }, {
+ .ops = &xrgb2yuv_ctrl_ops,
+ .id = V4L2_CID_XILINX_RGB2YUV_CCOEF,
+ .name = "RGB to YUV: CC coefficient",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = -((1 << 17) - 1),
+ .max = (1 << 17) - 1,
+ .step = 1,
+ }, {
+ .ops = &xrgb2yuv_ctrl_ops,
+ .id = V4L2_CID_XILINX_RGB2YUV_DCOEF,
+ .name = "RGB to YUV: CD coefficient",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = -((1 << 17) - 1),
+ .max = (1 << 17) - 1,
+ .step = 1,
+ },
+};
+
+/*
+ * Media Operations
+ */
+
+static const struct media_entity_operations xrgb2yuv_media_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+/*
+ * Power Management
+ */
+
+static int __maybe_unused xrgb2yuv_pm_suspend(struct device *dev)
+{
+ struct xrgb2yuv_device *xrgb2yuv = dev_get_drvdata(dev);
+
+ xvip_suspend(&xrgb2yuv->xvip);
+
+ return 0;
+}
+
+static int __maybe_unused xrgb2yuv_pm_resume(struct device *dev)
+{
+ struct xrgb2yuv_device *xrgb2yuv = dev_get_drvdata(dev);
+
+ xvip_resume(&xrgb2yuv->xvip);
+
+ return 0;
+}
+
+/*
+ * Platform Device Driver
+ */
+
+static int xrgb2yuv_parse_of(struct xrgb2yuv_device *xrgb2yuv)
+{
+ struct device *dev = xrgb2yuv->xvip.dev;
+ struct device_node *node = xrgb2yuv->xvip.dev->of_node;
+ struct device_node *ports;
+ struct device_node *port;
+ u32 port_id;
+ int ret;
+
+ ports = of_get_child_by_name(node, "ports");
+ if (ports == NULL)
+ ports = node;
+
+ /* Get the format description for each pad */
+ for_each_child_of_node(ports, port) {
+ if (port->name && (of_node_cmp(port->name, "port") == 0)) {
+ const struct xvip_video_format *vip_format;
+
+ vip_format = xvip_of_get_format(port);
+ if (IS_ERR(vip_format)) {
+ dev_err(dev, "invalid format in DT");
+ return PTR_ERR(vip_format);
+ }
+
+ ret = of_property_read_u32(port, "reg", &port_id);
+ if (ret < 0) {
+ dev_err(dev, "no reg in DT");
+ return ret;
+ }
+
+ if (port_id != 0 && port_id != 1) {
+ dev_err(dev, "invalid reg in DT");
+ return -EINVAL;
+ }
+
+ xrgb2yuv->vip_formats[port_id] = vip_format;
+ }
+ }
+
+ return 0;
+}
+
+static int xrgb2yuv_probe(struct platform_device *pdev)
+{
+ struct xrgb2yuv_device *xrgb2yuv;
+ struct v4l2_subdev *subdev;
+ struct v4l2_mbus_framefmt *default_format;
+ unsigned int i;
+ int ret;
+
+ xrgb2yuv = devm_kzalloc(&pdev->dev, sizeof(*xrgb2yuv), GFP_KERNEL);
+ if (!xrgb2yuv)
+ return -ENOMEM;
+
+ xrgb2yuv->xvip.dev = &pdev->dev;
+
+ ret = xrgb2yuv_parse_of(xrgb2yuv);
+ if (ret < 0)
+ return ret;
+
+ ret = xvip_init_resources(&xrgb2yuv->xvip);
+ if (ret < 0)
+ return ret;
+
+ /* Reset and initialize the core */
+ xvip_reset(&xrgb2yuv->xvip);
+
+ /* Initialize V4L2 subdevice and media entity */
+ subdev = &xrgb2yuv->xvip.subdev;
+ v4l2_subdev_init(subdev, &xrgb2yuv_ops);
+ subdev->dev = &pdev->dev;
+ subdev->internal_ops = &xrgb2yuv_internal_ops;
+ strlcpy(subdev->name, dev_name(&pdev->dev), sizeof(subdev->name));
+ v4l2_set_subdevdata(subdev, xrgb2yuv);
+ subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ /* Initialize default and active formats */
+ default_format = &xrgb2yuv->default_formats[XVIP_PAD_SINK];
+ default_format->code = xrgb2yuv->vip_formats[XVIP_PAD_SINK]->code;
+ default_format->field = V4L2_FIELD_NONE;
+ default_format->colorspace = V4L2_COLORSPACE_SRGB;
+ xvip_get_frame_size(&xrgb2yuv->xvip, default_format);
+
+ xrgb2yuv->formats[XVIP_PAD_SINK] = *default_format;
+
+ default_format = &xrgb2yuv->default_formats[XVIP_PAD_SOURCE];
+ *default_format = xrgb2yuv->default_formats[XVIP_PAD_SINK];
+ default_format->code = xrgb2yuv->vip_formats[XVIP_PAD_SOURCE]->code;
+
+ xrgb2yuv->formats[XVIP_PAD_SOURCE] = *default_format;
+
+ xrgb2yuv->pads[XVIP_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ xrgb2yuv->pads[XVIP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ subdev->entity.ops = &xrgb2yuv_media_ops;
+ ret = media_entity_pads_init(&subdev->entity, 2, xrgb2yuv->pads);
+ if (ret < 0)
+ goto error;
+
+ v4l2_ctrl_handler_init(&xrgb2yuv->ctrl_handler, 13);
+
+ for (i = 0; i < ARRAY_SIZE(xrgb2yuv_ctrls); i++) {
+ xrgb2yuv_ctrls[i].def = xvip_read(&xrgb2yuv->xvip,
+ XRGB2YUV_YMAX + i * 4);
+ v4l2_ctrl_new_custom(&xrgb2yuv->ctrl_handler,
+ &xrgb2yuv_ctrls[i], NULL);
+ }
+
+ if (xrgb2yuv->ctrl_handler.error) {
+ dev_err(&pdev->dev, "failed to add controls\n");
+ ret = xrgb2yuv->ctrl_handler.error;
+ goto error;
+ }
+ subdev->ctrl_handler = &xrgb2yuv->ctrl_handler;
+
+ platform_set_drvdata(pdev, xrgb2yuv);
+
+ xvip_print_version(&xrgb2yuv->xvip);
+
+ ret = v4l2_async_register_subdev(subdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to register subdev\n");
+ goto error;
+ }
+
+ return 0;
+
+error:
+ v4l2_ctrl_handler_free(&xrgb2yuv->ctrl_handler);
+ media_entity_cleanup(&subdev->entity);
+ xvip_cleanup_resources(&xrgb2yuv->xvip);
+ return ret;
+}
+
+static int xrgb2yuv_remove(struct platform_device *pdev)
+{
+ struct xrgb2yuv_device *xrgb2yuv = platform_get_drvdata(pdev);
+ struct v4l2_subdev *subdev = &xrgb2yuv->xvip.subdev;
+
+ v4l2_async_unregister_subdev(subdev);
+ v4l2_ctrl_handler_free(&xrgb2yuv->ctrl_handler);
+ media_entity_cleanup(&subdev->entity);
+
+ xvip_cleanup_resources(&xrgb2yuv->xvip);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(xrgb2yuv_pm_ops, xrgb2yuv_pm_suspend,
+ xrgb2yuv_pm_resume);
+
+static const struct of_device_id xrgb2yuv_of_id_table[] = {
+ { .compatible = "xlnx,v-rgb2yuv-7.1" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, xrgb2yuv_of_id_table);
+
+static struct platform_driver xrgb2yuv_driver = {
+ .driver = {
+ .name = "xilinx-rgb2yuv",
+ .pm = &xrgb2yuv_pm_ops,
+ .of_match_table = xrgb2yuv_of_id_table,
+ },
+ .probe = xrgb2yuv_probe,
+ .remove = xrgb2yuv_remove,
+};
+
+module_platform_driver(xrgb2yuv_driver);
+
+MODULE_DESCRIPTION("Xilinx RGB to YUV Converter Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/xilinx/xilinx-scaler.c b/drivers/media/platform/xilinx/xilinx-scaler.c
new file mode 100644
index 000000000000..bb0d52627a50
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-scaler.c
@@ -0,0 +1,708 @@
+/*
+ * Xilinx Scaler
+ *
+ * Copyright (C) 2013-2015 Ideas on Board
+ * Copyright (C) 2013-2015 Xilinx, Inc.
+ *
+ * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
+ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/fixp-arith.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <media/v4l2-async.h>
+#include <media/v4l2-subdev.h>
+
+#include "xilinx-vip.h"
+
+#define XSCALER_MIN_WIDTH 32
+#define XSCALER_MAX_WIDTH 4096
+#define XSCALER_MIN_HEIGHT 32
+#define XSCALER_MAX_HEIGHT 4096
+
+#define XSCALER_HSF 0x0100
+#define XSCALER_VSF 0x0104
+#define XSCALER_SF_SHIFT 20
+#define XSCALER_SF_MASK 0xffffff
+#define XSCALER_SOURCE_SIZE 0x0108
+#define XSCALER_SIZE_HORZ_SHIFT 0
+#define XSCALER_SIZE_VERT_SHIFT 16
+#define XSCALER_SIZE_MASK 0xfff
+#define XSCALER_HAPERTURE 0x010c
+#define XSCALER_VAPERTURE 0x0110
+#define XSCALER_APERTURE_START_SHIFT 0
+#define XSCALER_APERTURE_END_SHIFT 16
+#define XSCALER_OUTPUT_SIZE 0x0114
+#define XSCALER_COEF_DATA_IN 0x0134
+#define XSCALER_COEF_DATA_IN_SHIFT 16
+
+/* Fixed point operations */
+#define FRAC_N 8
+
+static inline s16 fixp_new(s16 a)
+{
+ return a << FRAC_N;
+}
+
+static inline s16 fixp_mult(s16 a, s16 b)
+{
+ return ((s32)(a * b)) >> FRAC_N;
+}
+
+/**
+ * struct xscaler_device - Xilinx Scaler device structure
+ * @xvip: Xilinx Video IP device
+ * @pads: media pads
+ * @formats: V4L2 media bus formats at the sink and source pads
+ * @default_formats: default V4L2 media bus formats
+ * @vip_format: Xilinx Video IP format
+ * @crop: Active crop rectangle for the sink pad
+ * @num_hori_taps: number of vertical taps
+ * @num_vert_taps: number of vertical taps
+ * @max_num_phases: maximum number of phases
+ * @separate_yc_coef: separate coefficients for Luma(y) and Chroma(c)
+ * @separate_hv_coef: separate coefficients for Horizontal(h) and Vertical(v)
+ */
+struct xscaler_device {
+ struct xvip_device xvip;
+
+ struct media_pad pads[2];
+
+ struct v4l2_mbus_framefmt formats[2];
+ struct v4l2_mbus_framefmt default_formats[2];
+ const struct xvip_video_format *vip_format;
+ struct v4l2_rect crop;
+
+ u32 num_hori_taps;
+ u32 num_vert_taps;
+ u32 max_num_phases;
+ bool separate_yc_coef;
+ bool separate_hv_coef;
+};
+
+static inline struct xscaler_device *to_scaler(struct v4l2_subdev *subdev)
+{
+ return container_of(subdev, struct xscaler_device, xvip.subdev);
+}
+
+/*
+ * V4L2 Subdevice Video Operations
+ */
+
+/**
+ * lanczos - Lanczos 2D FIR kernel convolution
+ * @x: phase
+ * @a: Lanczos kernel size
+ *
+ * Return: the coefficient value in fixed point format.
+ */
+static s16 lanczos(s16 x, s16 a)
+{
+ s16 pi;
+ s16 numerator;
+ s16 denominator;
+ s16 temp;
+
+ if (x < -a || x > a)
+ return 0;
+ else if (x == 0)
+ return fixp_new(1);
+
+ /* a * sin(pi * x) * sin(pi * x / a) / (pi * pi * x * x) */
+
+ pi = (fixp_new(157) << FRAC_N) / fixp_new(50);
+
+ if (x < 0)
+ x = -x;
+
+ /* sin(pi * x) */
+ temp = fixp_mult(fixp_new(180), x);
+ temp = fixp_sin16(temp >> FRAC_N);
+
+ /* a * sin(pi * x) */
+ numerator = fixp_mult(temp, a);
+
+ /* sin(pi * x / a) */
+ temp = (fixp_mult(fixp_new(180), x) << FRAC_N) / a;
+ temp = fixp_sin16(temp >> FRAC_N);
+
+ /* a * sin(pi * x) * sin(pi * x / a) */
+ numerator = fixp_mult(temp, numerator);
+
+ /* pi * pi * x * x */
+ denominator = fixp_mult(pi, pi);
+ temp = fixp_mult(x, x);
+ denominator = fixp_mult(temp, denominator);
+
+ return (numerator << FRAC_N) / denominator;
+}
+
+/**
+ * xscaler_set_coefs - generate and program the coefficient table
+ * @xscaler: scaler device
+ * @taps: maximum coefficient tap index
+ *
+ * Generate the coefficient table using Lanczos resampling, and program
+ * generated coefficients to the scaler. The generated coefficients are
+ * supposed to work regardless of resolutions.
+ *
+ * Return: 0 if the coefficient table is programmed, and -ENOMEM if memory
+ * allocation for the table fails.
+ */
+static int xscaler_set_coefs(struct xscaler_device *xscaler, s16 taps)
+{
+ s16 *coef;
+ s16 dy;
+ u32 coef_val;
+ u16 phases = xscaler->max_num_phases;
+ u16 i;
+ u16 j;
+
+ coef = kcalloc(phases, sizeof(*coef), GFP_KERNEL);
+ if (!coef)
+ return -ENOMEM;
+
+ for (i = 0; i < phases; i++) {
+ s16 sum = 0;
+
+ dy = ((fixp_new(i) << FRAC_N) / fixp_new(phases));
+
+ /* Generate Lanczos coefficients */
+ for (j = 0; j < taps; j++) {
+ coef[j] = lanczos(fixp_new(j - (taps >> 1)) + dy,
+ fixp_new(taps >> 1));
+ sum += coef[j];
+ }
+
+ /* Program coefficients */
+ for (j = 0; j < taps; j += 2) {
+ /* Normalize and multiply coefficients */
+ coef_val = (((coef[j] << FRAC_N) << (FRAC_N - 2)) /
+ sum) & 0xffff;
+ if (j + 1 < taps)
+ coef_val |= ((((coef[j + 1] << FRAC_N) <<
+ (FRAC_N - 2)) / sum) & 0xffff) <<
+ 16;
+
+ xvip_write(&xscaler->xvip, XSCALER_COEF_DATA_IN,
+ coef_val);
+ }
+ }
+
+ kfree(coef);
+
+ return 0;
+}
+
+static void xscaler_set_aperture(struct xscaler_device *xscaler)
+{
+ u16 start;
+ u16 end;
+ u32 scale_factor;
+
+ xvip_disable_reg_update(&xscaler->xvip);
+
+ /* set horizontal aperture */
+ start = xscaler->crop.left;
+ end = start + xscaler->crop.width - 1;
+ xvip_write(&xscaler->xvip, XSCALER_HAPERTURE,
+ (end << XSCALER_APERTURE_END_SHIFT) |
+ (start << XSCALER_APERTURE_START_SHIFT));
+
+ /* set vertical aperture */
+ start = xscaler->crop.top;
+ end = start + xscaler->crop.height - 1;
+ xvip_write(&xscaler->xvip, XSCALER_VAPERTURE,
+ (end << XSCALER_APERTURE_END_SHIFT) |
+ (start << XSCALER_APERTURE_START_SHIFT));
+
+ /* set scaling factors */
+ scale_factor = ((xscaler->crop.width << XSCALER_SF_SHIFT) /
+ xscaler->formats[XVIP_PAD_SOURCE].width) &
+ XSCALER_SF_MASK;
+ xvip_write(&xscaler->xvip, XSCALER_HSF, scale_factor);
+
+ scale_factor = ((xscaler->crop.height << XSCALER_SF_SHIFT) /
+ xscaler->formats[XVIP_PAD_SOURCE].height) &
+ XSCALER_SF_MASK;
+ xvip_write(&xscaler->xvip, XSCALER_VSF, scale_factor);
+
+ xvip_enable_reg_update(&xscaler->xvip);
+}
+
+static int xscaler_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+ struct xscaler_device *xscaler = to_scaler(subdev);
+ u32 width;
+ u32 height;
+
+ if (!enable) {
+ xvip_stop(&xscaler->xvip);
+ return 0;
+ }
+
+ /* set input width / height */
+ width = xscaler->formats[XVIP_PAD_SINK].width;
+ height = xscaler->formats[XVIP_PAD_SINK].height;
+ xvip_write(&xscaler->xvip, XSCALER_SOURCE_SIZE,
+ (height << XSCALER_SIZE_VERT_SHIFT) |
+ (width << XSCALER_SIZE_HORZ_SHIFT));
+
+ /* set output width / height */
+ width = xscaler->formats[XVIP_PAD_SOURCE].width;
+ height = xscaler->formats[XVIP_PAD_SOURCE].height;
+ xvip_write(&xscaler->xvip, XSCALER_OUTPUT_SIZE,
+ (height << XSCALER_SIZE_VERT_SHIFT) |
+ (width << XSCALER_SIZE_HORZ_SHIFT));
+
+ /* set aperture */
+ xscaler_set_aperture(xscaler);
+
+ xvip_start(&xscaler->xvip);
+
+ return 0;
+}
+
+/*
+ * V4L2 Subdevice Pad Operations
+ */
+
+static int xscaler_enum_frame_size(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct v4l2_mbus_framefmt *format;
+
+ format = v4l2_subdev_get_try_format(subdev, cfg, fse->pad);
+
+ if (fse->index || fse->code != format->code)
+ return -EINVAL;
+
+ fse->min_width = XSCALER_MIN_WIDTH;
+ fse->max_width = XSCALER_MAX_WIDTH;
+ fse->min_height = XSCALER_MIN_HEIGHT;
+ fse->max_height = XSCALER_MAX_HEIGHT;
+
+ return 0;
+}
+
+static struct v4l2_mbus_framefmt *
+__xscaler_get_pad_format(struct xscaler_device *xscaler,
+ struct v4l2_subdev_pad_config *cfg,
+ unsigned int pad, u32 which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_format(&xscaler->xvip.subdev, cfg,
+ pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &xscaler->formats[pad];
+ default:
+ return NULL;
+ }
+}
+
+static struct v4l2_rect *__xscaler_get_crop(struct xscaler_device *xscaler,
+ struct v4l2_subdev_pad_config *cfg,
+ u32 which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_crop(&xscaler->xvip.subdev, cfg,
+ XVIP_PAD_SINK);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &xscaler->crop;
+ default:
+ return NULL;
+ }
+}
+
+static int xscaler_get_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xscaler_device *xscaler = to_scaler(subdev);
+
+ fmt->format = *__xscaler_get_pad_format(xscaler, cfg, fmt->pad,
+ fmt->which);
+
+ return 0;
+}
+
+static void xscaler_try_crop(const struct v4l2_mbus_framefmt *sink,
+ struct v4l2_rect *crop)
+{
+
+ crop->left = min_t(u32, crop->left, sink->width - XSCALER_MIN_WIDTH);
+ crop->top = min_t(u32, crop->top, sink->height - XSCALER_MIN_HEIGHT);
+ crop->width = clamp_t(u32, crop->width, XSCALER_MIN_WIDTH,
+ sink->width - crop->left);
+ crop->height = clamp_t(u32, crop->height, XSCALER_MIN_HEIGHT,
+ sink->height - crop->top);
+}
+
+static int xscaler_set_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xscaler_device *xscaler = to_scaler(subdev);
+ struct v4l2_mbus_framefmt *format;
+ struct v4l2_rect *crop;
+
+ format = __xscaler_get_pad_format(xscaler, cfg, fmt->pad, fmt->which);
+
+ format->width = clamp_t(unsigned int, fmt->format.width,
+ XSCALER_MIN_WIDTH, XSCALER_MAX_WIDTH);
+ format->height = clamp_t(unsigned int, fmt->format.height,
+ XSCALER_MIN_HEIGHT, XSCALER_MAX_HEIGHT);
+
+ fmt->format = *format;
+
+ if (fmt->pad == XVIP_PAD_SINK) {
+ /* Set the crop rectangle to the full frame */
+ crop = __xscaler_get_crop(xscaler, cfg, fmt->which);
+ crop->left = 0;
+ crop->top = 0;
+ crop->width = fmt->format.width;
+ crop->height = fmt->format.height;
+ }
+
+ return 0;
+}
+
+static int xscaler_get_selection(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_selection *sel)
+{
+ struct xscaler_device *xscaler = to_scaler(subdev);
+ struct v4l2_mbus_framefmt *format;
+
+ if (sel->pad != XVIP_PAD_SINK)
+ return -EINVAL;
+
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ format = __xscaler_get_pad_format(xscaler, cfg, XVIP_PAD_SINK,
+ sel->which);
+ sel->r.left = 0;
+ sel->r.top = 0;
+ sel->r.width = format->width;
+ sel->r.height = format->height;
+ return 0;
+ case V4L2_SEL_TGT_CROP:
+ sel->r = *__xscaler_get_crop(xscaler, cfg, sel->which);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int xscaler_set_selection(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_selection *sel)
+{
+ struct xscaler_device *xscaler = to_scaler(subdev);
+ struct v4l2_mbus_framefmt *format;
+
+ if ((sel->target != V4L2_SEL_TGT_CROP) || (sel->pad != XVIP_PAD_SINK))
+ return -EINVAL;
+
+ format = __xscaler_get_pad_format(xscaler, cfg, XVIP_PAD_SINK,
+ sel->which);
+ xscaler_try_crop(format, &sel->r);
+ *__xscaler_get_crop(xscaler, cfg, sel->which) = sel->r;
+
+ return 0;
+}
+
+/*
+ * V4L2 Subdevice Operations
+ */
+
+static int xscaler_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ struct xscaler_device *xscaler = to_scaler(subdev);
+ struct v4l2_mbus_framefmt *format;
+
+ /* Initialize with default formats */
+ format = v4l2_subdev_get_try_format(subdev, fh->pad, XVIP_PAD_SINK);
+ *format = xscaler->default_formats[XVIP_PAD_SINK];
+
+ format = v4l2_subdev_get_try_format(subdev, fh->pad, XVIP_PAD_SOURCE);
+ *format = xscaler->default_formats[XVIP_PAD_SOURCE];
+
+ return 0;
+}
+
+static int xscaler_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ return 0;
+}
+
+static struct v4l2_subdev_video_ops xscaler_video_ops = {
+ .s_stream = xscaler_s_stream,
+};
+
+static struct v4l2_subdev_pad_ops xscaler_pad_ops = {
+ .enum_mbus_code = xvip_enum_mbus_code,
+ .enum_frame_size = xscaler_enum_frame_size,
+ .get_fmt = xscaler_get_format,
+ .set_fmt = xscaler_set_format,
+ .get_selection = xscaler_get_selection,
+ .set_selection = xscaler_set_selection,
+};
+
+static struct v4l2_subdev_ops xscaler_ops = {
+ .video = &xscaler_video_ops,
+ .pad = &xscaler_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops xscaler_internal_ops = {
+ .open = xscaler_open,
+ .close = xscaler_close,
+};
+
+/*
+ * Media Operations
+ */
+
+static const struct media_entity_operations xscaler_media_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+/*
+ * Power Management
+ */
+
+static int __maybe_unused xscaler_pm_suspend(struct device *dev)
+{
+ struct xscaler_device *xscaler = dev_get_drvdata(dev);
+
+ xvip_suspend(&xscaler->xvip);
+
+ return 0;
+}
+
+static int __maybe_unused xscaler_pm_resume(struct device *dev)
+{
+ struct xscaler_device *xscaler = dev_get_drvdata(dev);
+
+ xvip_resume(&xscaler->xvip);
+
+ return 0;
+}
+
+/*
+ * Platform Device Driver
+ */
+
+static int xscaler_parse_of(struct xscaler_device *xscaler)
+{
+ struct device *dev = xscaler->xvip.dev;
+ struct device_node *node = xscaler->xvip.dev->of_node;
+ struct device_node *ports;
+ struct device_node *port;
+ int ret;
+
+ ports = of_get_child_by_name(node, "ports");
+ if (ports == NULL)
+ ports = node;
+
+ /* Get the format description for each pad */
+ for_each_child_of_node(ports, port) {
+ if (port->name && (of_node_cmp(port->name, "port") == 0)) {
+ const struct xvip_video_format *vip_format;
+
+ vip_format = xvip_of_get_format(port);
+ if (IS_ERR(vip_format)) {
+ dev_err(dev, "invalid format in DT");
+ return PTR_ERR(vip_format);
+ }
+
+ if (!xscaler->vip_format) {
+ xscaler->vip_format = vip_format;
+ } else if (xscaler->vip_format != vip_format) {
+ dev_err(dev, "in/out format mismatch in DT");
+ return -EINVAL;
+ }
+ }
+ }
+
+ ret = of_property_read_u32(node, "xlnx,num-hori-taps",
+ &xscaler->num_hori_taps);
+ if (ret < 0)
+ return ret;
+
+ ret = of_property_read_u32(node, "xlnx,num-vert-taps",
+ &xscaler->num_vert_taps);
+ if (ret < 0)
+ return ret;
+
+ ret = of_property_read_u32(node, "xlnx,max-num-phases",
+ &xscaler->max_num_phases);
+ if (ret < 0)
+ return ret;
+
+ xscaler->separate_yc_coef =
+ of_property_read_bool(node, "xlnx,separate-yc-coef");
+
+ xscaler->separate_hv_coef =
+ of_property_read_bool(node, "xlnx,separate-hv-coef");
+
+ return 0;
+}
+
+static int xscaler_probe(struct platform_device *pdev)
+{
+ struct xscaler_device *xscaler;
+ struct v4l2_subdev *subdev;
+ struct v4l2_mbus_framefmt *default_format;
+ u32 size;
+ int ret;
+
+ xscaler = devm_kzalloc(&pdev->dev, sizeof(*xscaler), GFP_KERNEL);
+ if (!xscaler)
+ return -ENOMEM;
+
+ xscaler->xvip.dev = &pdev->dev;
+
+ ret = xscaler_parse_of(xscaler);
+ if (ret < 0)
+ return ret;
+
+ ret = xvip_init_resources(&xscaler->xvip);
+ if (ret < 0)
+ return ret;
+
+ /* Reset and initialize the core */
+ xvip_reset(&xscaler->xvip);
+
+ /* Initialize V4L2 subdevice and media entity */
+ subdev = &xscaler->xvip.subdev;
+ v4l2_subdev_init(subdev, &xscaler_ops);
+ subdev->dev = &pdev->dev;
+ subdev->internal_ops = &xscaler_internal_ops;
+ strlcpy(subdev->name, dev_name(&pdev->dev), sizeof(subdev->name));
+ v4l2_set_subdevdata(subdev, xscaler);
+ subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ /* Initialize default and active formats */
+ default_format = &xscaler->default_formats[XVIP_PAD_SINK];
+ default_format->code = xscaler->vip_format->code;
+ default_format->field = V4L2_FIELD_NONE;
+ default_format->colorspace = V4L2_COLORSPACE_SRGB;
+ size = xvip_read(&xscaler->xvip, XSCALER_SOURCE_SIZE);
+ default_format->width = (size >> XSCALER_SIZE_HORZ_SHIFT) &
+ XSCALER_SIZE_MASK;
+ default_format->height = (size >> XSCALER_SIZE_VERT_SHIFT) &
+ XSCALER_SIZE_MASK;
+
+ xscaler->formats[XVIP_PAD_SINK] = *default_format;
+
+ default_format = &xscaler->default_formats[XVIP_PAD_SOURCE];
+ *default_format = xscaler->default_formats[XVIP_PAD_SINK];
+ size = xvip_read(&xscaler->xvip, XSCALER_OUTPUT_SIZE);
+ default_format->width = (size >> XSCALER_SIZE_HORZ_SHIFT) &
+ XSCALER_SIZE_MASK;
+ default_format->height = (size >> XSCALER_SIZE_VERT_SHIFT) &
+ XSCALER_SIZE_MASK;
+
+ xscaler->formats[XVIP_PAD_SOURCE] = *default_format;
+
+ xscaler->pads[XVIP_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ xscaler->pads[XVIP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ subdev->entity.ops = &xscaler_media_ops;
+
+ ret = media_entity_pads_init(&subdev->entity, 2, xscaler->pads);
+ if (ret < 0)
+ goto error;
+
+ platform_set_drvdata(pdev, xscaler);
+
+ xvip_print_version(&xscaler->xvip);
+
+ ret = xscaler_set_coefs(xscaler, (s16)xscaler->num_hori_taps);
+ if (ret < 0)
+ goto error;
+
+ if (xscaler->separate_hv_coef) {
+ ret = xscaler_set_coefs(xscaler, (s16)xscaler->num_vert_taps);
+ if (ret < 0)
+ goto error;
+ }
+
+ if (xscaler->separate_yc_coef) {
+ ret = xscaler_set_coefs(xscaler, (s16)xscaler->num_hori_taps);
+ if (ret < 0)
+ goto error;
+
+ if (xscaler->separate_hv_coef) {
+ ret = xscaler_set_coefs(xscaler,
+ (s16)xscaler->num_vert_taps);
+ if (ret < 0)
+ goto error;
+ }
+ }
+
+ ret = v4l2_async_register_subdev(subdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to register subdev\n");
+ goto error;
+ }
+
+ return 0;
+
+error:
+ media_entity_cleanup(&subdev->entity);
+ xvip_cleanup_resources(&xscaler->xvip);
+ return ret;
+}
+
+static int xscaler_remove(struct platform_device *pdev)
+{
+ struct xscaler_device *xscaler = platform_get_drvdata(pdev);
+ struct v4l2_subdev *subdev = &xscaler->xvip.subdev;
+
+ v4l2_async_unregister_subdev(subdev);
+ media_entity_cleanup(&subdev->entity);
+
+ xvip_cleanup_resources(&xscaler->xvip);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(xscaler_pm_ops, xscaler_pm_suspend, xscaler_pm_resume);
+
+static const struct of_device_id xscaler_of_id_table[] = {
+ { .compatible = "xlnx,v-scaler-8.1" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, xscaler_of_id_table);
+
+static struct platform_driver xscaler_driver = {
+ .driver = {
+ .name = "xilinx-scaler",
+ .of_match_table = xscaler_of_id_table,
+ },
+ .probe = xscaler_probe,
+ .remove = xscaler_remove,
+};
+
+module_platform_driver(xscaler_driver);
+
+MODULE_DESCRIPTION("Xilinx Scaler Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/xilinx/xilinx-scenechange-channel.c b/drivers/media/platform/xilinx/xilinx-scenechange-channel.c
new file mode 100644
index 000000000000..852191ac6500
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-scenechange-channel.c
@@ -0,0 +1,352 @@
+//SPDX-License-Identifier: GPL-2.0
+/*
+ * Xilinx Scene Change Detection driver
+ *
+ * Copyright (C) 2018 Xilinx, Inc.
+ *
+ * Authors: Anand Ashok Dumbre <anand.ashok.dumbre@xilinx.com>
+ * Satish Kumar Nagireddy <satish.nagireddy.nagireddy@xilinx.com>
+ */
+
+#include <linux/of.h>
+#include <linux/xilinx-v4l2-events.h>
+
+#include <media/v4l2-async.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-subdev.h>
+
+#include "xilinx-scenechange.h"
+#include "xilinx-vip.h"
+
+#define XSCD_MAX_WIDTH 3840
+#define XSCD_MAX_HEIGHT 2160
+#define XSCD_MIN_WIDTH 640
+#define XSCD_MIN_HEIGHT 480
+
+#define XSCD_V_SUBSAMPLING 16
+#define XSCD_BYTE_ALIGN 16
+#define MULTIPLICATION_FACTOR 100
+#define SCENE_CHANGE_THRESHOLD 0.5
+
+#define XSCD_SCENE_CHANGE 1
+#define XSCD_NO_SCENE_CHANGE 0
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Pad Operations
+ */
+
+static int xscd_enum_mbus_code(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ return 0;
+}
+
+static int xscd_enum_frame_size(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ return 0;
+}
+
+static struct v4l2_mbus_framefmt *
+__xscd_get_pad_format(struct xscd_chan *chan,
+ struct v4l2_subdev_pad_config *cfg,
+ unsigned int pad, u32 which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_format(&chan->subdev, cfg, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &chan->format;
+ default:
+ return NULL;
+ }
+ return NULL;
+}
+
+static int xscd_get_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xscd_chan *chan = to_xscd_chan(subdev);
+
+ fmt->format = *__xscd_get_pad_format(chan, cfg, fmt->pad, fmt->which);
+ return 0;
+}
+
+static int xscd_set_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xscd_chan *chan = to_xscd_chan(subdev);
+ struct v4l2_mbus_framefmt *format;
+
+ format = __xscd_get_pad_format(chan, cfg, fmt->pad, fmt->which);
+ format->width = clamp_t(unsigned int, fmt->format.width,
+ XSCD_MIN_WIDTH, XSCD_MAX_WIDTH);
+ format->height = clamp_t(unsigned int, fmt->format.height,
+ XSCD_MIN_HEIGHT, XSCD_MAX_HEIGHT);
+ format->code = fmt->format.code;
+ fmt->format = *format;
+
+ return 0;
+}
+
+static int xscd_chan_get_vid_fmt(u32 media_bus_fmt, bool memory_based)
+{
+ u32 vid_fmt;
+
+ if (memory_based) {
+ switch (media_bus_fmt) {
+ case MEDIA_BUS_FMT_VYYUYY8_1X24:
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_VUY8_1X24:
+ vid_fmt = XSCD_VID_FMT_Y8;
+ break;
+ case MEDIA_BUS_FMT_VYYUYY10_4X20:
+ case MEDIA_BUS_FMT_UYVY10_1X20:
+ case MEDIA_BUS_FMT_VUY10_1X30:
+ vid_fmt = XSCD_VID_FMT_Y10;
+ break;
+ default:
+ vid_fmt = XSCD_VID_FMT_Y8;
+ }
+
+ return vid_fmt;
+ }
+
+ /* Streaming based */
+ switch (media_bus_fmt) {
+ case MEDIA_BUS_FMT_VYYUYY8_1X24:
+ case MEDIA_BUS_FMT_VYYUYY10_4X20:
+ vid_fmt = XSCD_VID_FMT_YUV_420;
+ break;
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_UYVY10_1X20:
+ vid_fmt = XSCD_VID_FMT_YUV_422;
+ break;
+ case MEDIA_BUS_FMT_VUY8_1X24:
+ case MEDIA_BUS_FMT_VUY10_1X30:
+ vid_fmt = XSCD_VID_FMT_YUV_444;
+ break;
+ case MEDIA_BUS_FMT_RBG888_1X24:
+ case MEDIA_BUS_FMT_RBG101010_1X30:
+ vid_fmt = XSCD_VID_FMT_RGB;
+ break;
+ default:
+ vid_fmt = XSCD_VID_FMT_YUV_420;
+ }
+
+ return vid_fmt;
+}
+
+/**
+ * xscd_chan_configure_params - Program parameters to HW registers
+ * @chan: Driver specific channel struct pointer
+ */
+static void xscd_chan_configure_params(struct xscd_chan *chan)
+{
+ u32 vid_fmt, stride;
+
+ xscd_write(chan->iomem, XSCD_WIDTH_OFFSET, chan->format.width);
+
+ /* Stride is required only for memory based IP, not for streaming IP */
+ if (chan->xscd->memory_based) {
+ stride = roundup(chan->format.width, XSCD_BYTE_ALIGN);
+ xscd_write(chan->iomem, XSCD_STRIDE_OFFSET, stride);
+ }
+
+ xscd_write(chan->iomem, XSCD_HEIGHT_OFFSET, chan->format.height);
+
+ /* Hardware video format */
+ vid_fmt = xscd_chan_get_vid_fmt(chan->format.code,
+ chan->xscd->memory_based);
+ xscd_write(chan->iomem, XSCD_VID_FMT_OFFSET, vid_fmt);
+
+ /*
+ * This is the vertical subsampling factor of the input image. Instead
+ * of sampling every line to calculate the histogram, IP uses this
+ * register value to sample only specific lines of the frame.
+ */
+ xscd_write(chan->iomem, XSCD_SUBSAMPLE_OFFSET, XSCD_V_SUBSAMPLING);
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Operations
+ */
+static int xscd_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+ struct xscd_chan *chan = to_xscd_chan(subdev);
+
+ if (enable)
+ xscd_chan_configure_params(chan);
+
+ xscd_dma_enable_channel(&chan->dmachan, enable);
+ return 0;
+}
+
+static int xscd_subscribe_event(struct v4l2_subdev *sd,
+ struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ int ret;
+ struct xscd_chan *chan = to_xscd_chan(sd);
+
+ mutex_lock(&chan->lock);
+
+ switch (sub->type) {
+ case V4L2_EVENT_XLNXSCD:
+ ret = v4l2_event_subscribe(fh, sub, 1, NULL);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ mutex_unlock(&chan->lock);
+
+ return ret;
+}
+
+static int xscd_unsubscribe_event(struct v4l2_subdev *sd,
+ struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ int ret;
+ struct xscd_chan *chan = to_xscd_chan(sd);
+
+ mutex_lock(&chan->lock);
+ ret = v4l2_event_unsubscribe(fh, sub);
+ mutex_unlock(&chan->lock);
+
+ return ret;
+}
+
+static int xscd_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ return 0;
+}
+
+static int xscd_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ return 0;
+}
+
+static const struct v4l2_subdev_core_ops xscd_core_ops = {
+ .subscribe_event = xscd_subscribe_event,
+ .unsubscribe_event = xscd_unsubscribe_event
+};
+
+static struct v4l2_subdev_video_ops xscd_video_ops = {
+ .s_stream = xscd_s_stream,
+};
+
+static struct v4l2_subdev_pad_ops xscd_pad_ops = {
+ .enum_mbus_code = xscd_enum_mbus_code,
+ .enum_frame_size = xscd_enum_frame_size,
+ .get_fmt = xscd_get_format,
+ .set_fmt = xscd_set_format,
+};
+
+static struct v4l2_subdev_ops xscd_ops = {
+ .core = &xscd_core_ops,
+ .video = &xscd_video_ops,
+ .pad = &xscd_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops xscd_internal_ops = {
+ .open = xscd_open,
+ .close = xscd_close,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media Operations
+ */
+
+static const struct media_entity_operations xscd_media_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+void xscd_chan_event_notify(struct xscd_chan *chan)
+{
+ u32 *eventdata;
+ u32 sad, scd_threshold;
+
+ sad = xscd_read(chan->iomem, XSCD_SAD_OFFSET);
+ sad = (sad * XSCD_V_SUBSAMPLING * MULTIPLICATION_FACTOR) /
+ (chan->format.width * chan->format.height);
+ eventdata = (u32 *)&chan->event.u.data;
+ scd_threshold = SCENE_CHANGE_THRESHOLD * MULTIPLICATION_FACTOR;
+
+ if (sad > scd_threshold)
+ eventdata[0] = XSCD_SCENE_CHANGE;
+ else
+ eventdata[0] = XSCD_NO_SCENE_CHANGE;
+
+ chan->event.type = V4L2_EVENT_XLNXSCD;
+ v4l2_subdev_notify_event(&chan->subdev, &chan->event);
+}
+
+/**
+ * xscd_chan_init - Initialize the V4L2 subdev for a channel
+ * @xscd: Pointer to the SCD device structure
+ * @chan_id: Channel id
+ * @node: device node
+ *
+ * Return: '0' on success and failure value on error
+ */
+int xscd_chan_init(struct xscd_device *xscd, unsigned int chan_id,
+ struct device_node *node)
+{
+ struct xscd_chan *chan = &xscd->chans[chan_id];
+ struct v4l2_subdev *subdev;
+ unsigned int num_pads;
+ int ret;
+
+ mutex_init(&chan->lock);
+ chan->xscd = xscd;
+ chan->id = chan_id;
+ chan->iomem = chan->xscd->iomem + chan->id * XSCD_CHAN_OFFSET;
+
+ /* Initialize V4L2 subdevice and media entity */
+ subdev = &chan->subdev;
+ v4l2_subdev_init(subdev, &xscd_ops);
+ subdev->dev = chan->xscd->dev;
+ subdev->fwnode = of_fwnode_handle(node);
+ subdev->internal_ops = &xscd_internal_ops;
+ snprintf(subdev->name, sizeof(subdev->name), "xlnx-scdchan.%u",
+ chan_id);
+ v4l2_set_subdevdata(subdev, chan);
+ subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
+
+ /* Initialize default format */
+ chan->format.code = MEDIA_BUS_FMT_VYYUYY8_1X24;
+ chan->format.field = V4L2_FIELD_NONE;
+ chan->format.width = XSCD_MAX_WIDTH;
+ chan->format.height = XSCD_MAX_HEIGHT;
+
+ /* Initialize media pads */
+ num_pads = xscd->memory_based ? 1 : 2;
+
+ chan->pads[XVIP_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ if (!xscd->memory_based)
+ chan->pads[XVIP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(&subdev->entity, num_pads, chan->pads);
+ if (ret < 0)
+ goto error;
+
+ subdev->entity.ops = &xscd_media_ops;
+ ret = v4l2_async_register_subdev(subdev);
+ if (ret < 0) {
+ dev_err(chan->xscd->dev, "failed to register subdev\n");
+ goto error;
+ }
+
+ dev_info(chan->xscd->dev, "Scene change detection channel found!\n");
+ return 0;
+
+error:
+ media_entity_cleanup(&subdev->entity);
+ return ret;
+}
diff --git a/drivers/media/platform/xilinx/xilinx-scenechange-dma.c b/drivers/media/platform/xilinx/xilinx-scenechange-dma.c
new file mode 100644
index 000000000000..58437a769605
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-scenechange-dma.c
@@ -0,0 +1,554 @@
+//SPDX-License-Identifier: GPL-2.0
+/*
+ * Xilinx Scene Change Detection DMA driver
+ *
+ * Copyright (C) 2018 Xilinx, Inc.
+ *
+ * Authors: Anand Ashok Dumbre <anand.ashok.dumbre@xilinx.com>
+ * Satish Kumar Nagireddy <satish.nagireddy.nagireddy@xilinx.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/of_dma.h>
+#include <linux/slab.h>
+
+#include "../../../dma/dmaengine.h"
+
+#include "xilinx-scenechange.h"
+
+/**
+ * xscd_dma_start - Start the SCD core
+ * @xscd: The SCD device
+ * @channels: Bitmask of enabled channels
+ */
+static void xscd_dma_start(struct xscd_device *xscd, unsigned int channels)
+{
+ xscd_write(xscd->iomem, XSCD_IE_OFFSET, XSCD_IE_AP_DONE);
+ xscd_write(xscd->iomem, XSCD_GIE_OFFSET, XSCD_GIE_EN);
+ xscd_write(xscd->iomem, XSCD_CHAN_EN_OFFSET, channels);
+
+ xscd_set(xscd->iomem, XSCD_CTRL_OFFSET,
+ xscd->memory_based ? XSCD_CTRL_AP_START
+ : XSCD_CTRL_AP_START |
+ XSCD_CTRL_AUTO_RESTART);
+
+ xscd->running = true;
+}
+
+/**
+ * xscd_dma_stop - Stop the SCD core
+ * @xscd: The SCD device
+ */
+static void xscd_dma_stop(struct xscd_device *xscd)
+{
+ xscd_clr(xscd->iomem, XSCD_CTRL_OFFSET,
+ xscd->memory_based ? XSCD_CTRL_AP_START
+ : XSCD_CTRL_AP_START |
+ XSCD_CTRL_AUTO_RESTART);
+
+ xscd->running = false;
+}
+
+/**
+ * xscd_dma_setup_channel - Setup a channel for transfer
+ * @chan: Driver specific channel struct pointer
+ *
+ * Return: 1 if the channel starts to run for a new transfer. Otherwise, 0.
+ */
+static int xscd_dma_setup_channel(struct xscd_dma_chan *chan)
+{
+ struct xscd_dma_tx_descriptor *desc;
+
+ if (!chan->enabled)
+ return 0;
+
+ if (list_empty(&chan->pending_list))
+ return 0;
+
+ desc = list_first_entry(&chan->pending_list,
+ struct xscd_dma_tx_descriptor, node);
+ list_del(&desc->node);
+
+ xscd_write(chan->iomem, XSCD_ADDR_OFFSET, desc->sw.luma_plane_addr);
+ chan->active_desc = desc;
+
+ return 1;
+}
+
+/**
+ * xscd_dma_kick - Start a run of the SCD core if channels are ready
+ * @xscd: The SCD device
+ *
+ * This function starts a single run of the SCD core when all the following
+ * conditions are met:
+ *
+ * - The SCD is not currently running
+ * - At least one channel is enabled and has buffers available
+ *
+ * It can be used to start the SCD when a buffer is queued, when a channel
+ * starts streaming, or to start the next run. Calling this function is only
+ * valid for memory-based mode and is not permitted for stream-based mode.
+ *
+ * The running state for all channels is updated. Channels that are being
+ * stopped are signalled through the channel wait queue.
+ *
+ * The function must be called with the xscd_device lock held.
+ */
+static void xscd_dma_kick(struct xscd_device *xscd)
+{
+ unsigned int channels = 0;
+ unsigned int i;
+
+ lockdep_assert_held(&xscd->lock);
+
+ if (xscd->running)
+ return;
+
+ for (i = 0; i < xscd->num_streams; i++) {
+ struct xscd_dma_chan *chan = xscd->channels[i];
+ unsigned long flags;
+ unsigned int running;
+ bool stopped;
+
+ spin_lock_irqsave(&chan->lock, flags);
+ running = xscd_dma_setup_channel(chan);
+ stopped = chan->running && !running;
+ chan->running = running;
+ spin_unlock_irqrestore(&chan->lock, flags);
+
+ channels |= running << chan->id;
+ if (stopped)
+ wake_up(&chan->wait);
+ }
+
+ if (channels)
+ xscd_dma_start(xscd, channels);
+ else
+ xscd_dma_stop(xscd);
+}
+
+/**
+ * xscd_dma_enable_channel - Enable/disable a channel
+ * @chan: Driver specific channel struct pointer
+ * @enable: True to enable the channel, false to disable it
+ *
+ * This function enables or disable a channel. When operating in memory-based
+ * mode, enabling a channel kicks processing if buffers are available for any
+ * enabled channel and the SCD core is idle. When operating in stream-based
+ * mode, the SCD core is started or stopped synchronously when then channel is
+ * enabled or disabled.
+ *
+ * This function must be called in non-atomic, non-interrupt context.
+ */
+void xscd_dma_enable_channel(struct xscd_dma_chan *chan, bool enable)
+{
+ struct xscd_device *xscd = chan->xscd;
+
+ if (enable) {
+ /*
+ * FIXME: Don't set chan->enabled to false here, it will be
+ * done in xscd_dma_terminate_all(). This works around a bug
+ * introduced in commit 2e77607047c6 ("xilinx: v4l2: dma: Add
+ * multiple output support") that stops all channels when the
+ * first one is stopped, even though they are part of
+ * independent pipelines. This workaround should be safe as
+ * long as dmaengine_terminate_all() is called after
+ * xvip_pipeline_set_stream().
+ */
+ spin_lock_irq(&chan->lock);
+ chan->enabled = true;
+ spin_unlock_irq(&chan->lock);
+ }
+
+ if (xscd->memory_based) {
+ if (enable) {
+ spin_lock_irq(&xscd->lock);
+ xscd_dma_kick(xscd);
+ spin_unlock_irq(&xscd->lock);
+ }
+ } else {
+ if (enable)
+ xscd_dma_start(xscd, BIT(chan->id));
+ else
+ xscd_dma_stop(xscd);
+ }
+}
+
+/**
+ * xscd_dma_irq_handler - scdma Interrupt handler
+ * @xscd: Pointer to the SCD device structure
+ */
+void xscd_dma_irq_handler(struct xscd_device *xscd)
+{
+ unsigned int i;
+
+ /*
+ * Mark the active descriptors as complete, move them to the done list
+ * and schedule the tasklet to clean them up.
+ */
+ for (i = 0; i < xscd->num_streams; ++i) {
+ struct xscd_dma_chan *chan = xscd->channels[i];
+ struct xscd_dma_tx_descriptor *desc = chan->active_desc;
+
+ if (!desc)
+ continue;
+
+ dma_cookie_complete(&desc->async_tx);
+ xscd_chan_event_notify(&xscd->chans[i]);
+
+ spin_lock(&chan->lock);
+ list_add_tail(&desc->node, &chan->done_list);
+ chan->active_desc = NULL;
+ spin_unlock(&chan->lock);
+
+ tasklet_schedule(&chan->tasklet);
+ }
+
+ /* Start the next run, if any. */
+ spin_lock(&xscd->lock);
+ xscd->running = false;
+ xscd_dma_kick(xscd);
+ spin_unlock(&xscd->lock);
+}
+
+/* -----------------------------------------------------------------------------
+ * DMA Engine
+ */
+
+/**
+ * xscd_dma_tx_submit - Submit DMA transaction
+ * @tx: Async transaction descriptor
+ *
+ * Return: cookie value on success and failure value on error
+ */
+static dma_cookie_t xscd_dma_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+ struct xscd_dma_tx_descriptor *desc = to_xscd_dma_tx_descriptor(tx);
+ struct xscd_dma_chan *chan = to_xscd_dma_chan(tx->chan);
+ dma_cookie_t cookie;
+ unsigned long flags;
+
+ spin_lock_irqsave(&chan->lock, flags);
+ cookie = dma_cookie_assign(tx);
+ list_add_tail(&desc->node, &chan->pending_list);
+ spin_unlock_irqrestore(&chan->lock, flags);
+
+ return cookie;
+}
+
+/**
+ * xscd_dma_free_desc_list - Free descriptors list
+ * @chan: Driver specific dma channel
+ * @list: List to parse and delete the descriptor
+ */
+static void xscd_dma_free_desc_list(struct xscd_dma_chan *chan,
+ struct list_head *list)
+{
+ struct xscd_dma_tx_descriptor *desc, *next;
+
+ list_for_each_entry_safe(desc, next, list, node) {
+ list_del(&desc->node);
+ kfree(desc);
+ }
+}
+
+/**
+ * xscd_dma_free_descriptors - Free channel descriptors
+ * @chan: Driver specific dma channel
+ */
+static void xscd_dma_free_descriptors(struct xscd_dma_chan *chan)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&chan->lock, flags);
+
+ xscd_dma_free_desc_list(chan, &chan->pending_list);
+ xscd_dma_free_desc_list(chan, &chan->done_list);
+ kfree(chan->active_desc);
+
+ chan->active_desc = NULL;
+ INIT_LIST_HEAD(&chan->pending_list);
+ INIT_LIST_HEAD(&chan->done_list);
+
+ spin_unlock_irqrestore(&chan->lock, flags);
+}
+
+/**
+ * scd_dma_chan_desc_cleanup - Clean channel descriptors
+ * @chan: Driver specific dma channel
+ */
+static void xscd_dma_chan_desc_cleanup(struct xscd_dma_chan *chan)
+{
+ struct xscd_dma_tx_descriptor *desc, *next;
+ unsigned long flags;
+
+ spin_lock_irqsave(&chan->lock, flags);
+
+ list_for_each_entry_safe(desc, next, &chan->done_list, node) {
+ dma_async_tx_callback callback;
+ void *callback_param;
+
+ list_del(&desc->node);
+
+ /* Run the link descriptor callback function */
+ callback = desc->async_tx.callback;
+ callback_param = desc->async_tx.callback_param;
+ if (callback) {
+ spin_unlock_irqrestore(&chan->lock, flags);
+ callback(callback_param);
+ spin_lock_irqsave(&chan->lock, flags);
+ }
+
+ kfree(desc);
+ }
+
+ spin_unlock_irqrestore(&chan->lock, flags);
+}
+
+/**
+ * xscd_dma_dma_prep_interleaved - prepare a descriptor for a
+ * DMA_SLAVE transaction
+ * @dchan: DMA channel
+ * @xt: Interleaved template pointer
+ * @flags: transfer ack flags
+ *
+ * Return: Async transaction descriptor on success and NULL on failure
+ */
+static struct dma_async_tx_descriptor *
+xscd_dma_prep_interleaved(struct dma_chan *dchan,
+ struct dma_interleaved_template *xt,
+ unsigned long flags)
+{
+ struct xscd_dma_chan *chan = to_xscd_dma_chan(dchan);
+ struct xscd_dma_tx_descriptor *desc;
+ struct xscd_dma_desc *sw;
+
+ desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+ if (!desc)
+ return NULL;
+
+ dma_async_tx_descriptor_init(&desc->async_tx, &chan->common);
+ desc->async_tx.tx_submit = xscd_dma_tx_submit;
+ async_tx_ack(&desc->async_tx);
+
+ sw = &desc->sw;
+ sw->vsize = xt->numf;
+ sw->hsize = xt->sgl[0].size;
+ sw->stride = xt->sgl[0].size + xt->sgl[0].icg;
+ sw->luma_plane_addr = xt->src_start;
+
+ return &desc->async_tx;
+}
+
+static bool xscd_dma_is_running(struct xscd_dma_chan *chan)
+{
+ bool running;
+
+ spin_lock_irq(&chan->lock);
+ running = chan->running;
+ spin_unlock_irq(&chan->lock);
+
+ return running;
+}
+
+/**
+ * xscd_dma_terminate_all - Halt the channel and free descriptors
+ * @dchan: Driver specific dma channel pointer
+ *
+ * Return: 0
+ */
+static int xscd_dma_terminate_all(struct dma_chan *dchan)
+{
+ struct xscd_dma_chan *chan = to_xscd_dma_chan(dchan);
+ int ret;
+
+ spin_lock_irq(&chan->lock);
+ chan->enabled = false;
+ spin_unlock_irq(&chan->lock);
+
+ /* Wait for any on-going transfer to complete. */
+ ret = wait_event_timeout(chan->wait, !xscd_dma_is_running(chan),
+ msecs_to_jiffies(100));
+ WARN_ON(ret == 0);
+
+ xscd_dma_free_descriptors(chan);
+ return 0;
+}
+
+/**
+ * xscd_dma_issue_pending - Issue pending transactions
+ * @dchan: DMA channel
+ */
+static void xscd_dma_issue_pending(struct dma_chan *dchan)
+{
+ struct xscd_dma_chan *chan = to_xscd_dma_chan(dchan);
+ struct xscd_device *xscd = chan->xscd;
+ unsigned long flags;
+
+ spin_lock_irqsave(&xscd->lock, flags);
+ xscd_dma_kick(xscd);
+ spin_unlock_irqrestore(&xscd->lock, flags);
+}
+
+static enum dma_status xscd_dma_tx_status(struct dma_chan *dchan,
+ dma_cookie_t cookie,
+ struct dma_tx_state *txstate)
+{
+ return dma_cookie_status(dchan, cookie, txstate);
+}
+
+/**
+ * xscd_dma_free_chan_resources - Free channel resources
+ * @dchan: DMA channel
+ */
+static void xscd_dma_free_chan_resources(struct dma_chan *dchan)
+{
+ struct xscd_dma_chan *chan = to_xscd_dma_chan(dchan);
+
+ xscd_dma_free_descriptors(chan);
+}
+
+/**
+ * xscd_dma_do_tasklet - Schedule completion tasklet
+ * @data: Pointer to the Xilinx scdma channel structure
+ */
+static void xscd_dma_do_tasklet(unsigned long data)
+{
+ struct xscd_dma_chan *chan = (struct xscd_dma_chan *)data;
+
+ xscd_dma_chan_desc_cleanup(chan);
+}
+
+/**
+ * xscd_dma_alloc_chan_resources - Allocate channel resources
+ * @dchan: DMA channel
+ *
+ * Return: '0' on success and failure value on error
+ */
+static int xscd_dma_alloc_chan_resources(struct dma_chan *dchan)
+{
+ dma_cookie_init(dchan);
+ return 0;
+}
+
+/**
+ * of_scdma_xilinx_xlate - Translation function
+ * @dma_spec: Pointer to DMA specifier as found in the device tree
+ * @ofdma: Pointer to DMA controller data
+ *
+ * Return: DMA channel pointer on success and NULL on error
+ */
+static struct dma_chan *of_scdma_xilinx_xlate(struct of_phandle_args *dma_spec,
+ struct of_dma *ofdma)
+{
+ struct xscd_device *xscd = ofdma->of_dma_data;
+ u32 chan_id = dma_spec->args[0];
+
+ if (chan_id >= xscd->num_streams)
+ return NULL;
+
+ if (!xscd->channels[chan_id])
+ return NULL;
+
+ return dma_get_slave_channel(&xscd->channels[chan_id]->common);
+}
+
+static void xscd_dma_chan_init(struct xscd_device *xscd, int chan_id)
+{
+ struct xscd_dma_chan *chan = &xscd->chans[chan_id].dmachan;
+
+ chan->id = chan_id;
+ chan->iomem = xscd->iomem + chan->id * XSCD_CHAN_OFFSET;
+ chan->xscd = xscd;
+
+ xscd->channels[chan->id] = chan;
+
+ spin_lock_init(&chan->lock);
+ INIT_LIST_HEAD(&chan->pending_list);
+ INIT_LIST_HEAD(&chan->done_list);
+ tasklet_init(&chan->tasklet, xscd_dma_do_tasklet,
+ (unsigned long)chan);
+ init_waitqueue_head(&chan->wait);
+
+ chan->common.device = &xscd->dma_device;
+ list_add_tail(&chan->common.device_node, &xscd->dma_device.channels);
+}
+
+/**
+ * xscd_dma_chan_remove - Per Channel remove function
+ * @chan: Driver specific DMA channel
+ */
+static void xscd_dma_chan_remove(struct xscd_dma_chan *chan)
+{
+ list_del(&chan->common.device_node);
+}
+
+/**
+ * xscd_dma_init - Initialize the SCD DMA engine
+ * @xscd: Pointer to the SCD device structure
+ *
+ * Return: '0' on success and failure value on error
+ */
+int xscd_dma_init(struct xscd_device *xscd)
+{
+ struct dma_device *ddev = &xscd->dma_device;
+ unsigned int chan_id;
+ int ret;
+
+ /* Initialize the DMA engine */
+ ddev->dev = xscd->dev;
+ dma_set_mask(xscd->dev, DMA_BIT_MASK(32));
+
+ INIT_LIST_HEAD(&ddev->channels);
+ dma_cap_set(DMA_SLAVE, ddev->cap_mask);
+ dma_cap_set(DMA_PRIVATE, ddev->cap_mask);
+ ddev->device_alloc_chan_resources = xscd_dma_alloc_chan_resources;
+ ddev->device_free_chan_resources = xscd_dma_free_chan_resources;
+ ddev->device_tx_status = xscd_dma_tx_status;
+ ddev->device_issue_pending = xscd_dma_issue_pending;
+ ddev->device_terminate_all = xscd_dma_terminate_all;
+ ddev->device_prep_interleaved_dma = xscd_dma_prep_interleaved;
+
+ for (chan_id = 0; chan_id < xscd->num_streams; chan_id++)
+ xscd_dma_chan_init(xscd, chan_id);
+
+ ret = dma_async_device_register(ddev);
+ if (ret) {
+ dev_err(xscd->dev, "failed to register the dma device\n");
+ goto error;
+ }
+
+ ret = of_dma_controller_register(xscd->dev->of_node,
+ of_scdma_xilinx_xlate, xscd);
+ if (ret) {
+ dev_err(xscd->dev, "failed to register DMA to DT DMA helper\n");
+ goto error_of_dma;
+ }
+
+ dev_info(xscd->dev, "Xilinx Scene Change DMA is initialized!\n");
+ return 0;
+
+error_of_dma:
+ dma_async_device_unregister(ddev);
+
+error:
+ for (chan_id = 0; chan_id < xscd->num_streams; chan_id++)
+ xscd_dma_chan_remove(xscd->channels[chan_id]);
+
+ return ret;
+}
+
+/**
+ * xscd_dma_cleanup - Clean up the SCD DMA engine
+ * @xscd: Pointer to the SCD device structure
+ *
+ * This function is the counterpart of xscd_dma_init() and cleans up the
+ * resources related to the DMA engine.
+ */
+void xscd_dma_cleanup(struct xscd_device *xscd)
+{
+ dma_async_device_unregister(&xscd->dma_device);
+ of_dma_controller_free(xscd->dev->of_node);
+}
diff --git a/drivers/media/platform/xilinx/xilinx-scenechange.c b/drivers/media/platform/xilinx/xilinx-scenechange.c
new file mode 100644
index 000000000000..9135355934fe
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-scenechange.c
@@ -0,0 +1,191 @@
+//SPDX-License-Identifier: GPL-2.0
+/*
+ * Xilinx Scene Change Detection driver
+ *
+ * Copyright (C) 2018 Xilinx, Inc.
+ *
+ * Authors: Anand Ashok Dumbre <anand.ashok.dumbre@xilinx.com>
+ * Satish Kumar Nagireddy <satish.nagireddy.nagireddy@xilinx.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "xilinx-scenechange.h"
+
+#define XSCD_RESET_DEASSERT (0)
+#define XSCD_RESET_ASSERT (1)
+
+static irqreturn_t xscd_irq_handler(int irq, void *data)
+{
+ struct xscd_device *xscd = (struct xscd_device *)data;
+ u32 status;
+
+ status = xscd_read(xscd->iomem, XSCD_ISR_OFFSET);
+ if (!(status & XSCD_IE_AP_DONE))
+ return IRQ_NONE;
+
+ xscd_write(xscd->iomem, XSCD_ISR_OFFSET, XSCD_IE_AP_DONE);
+
+ if (xscd->memory_based)
+ xscd_dma_irq_handler(xscd);
+ else
+ xscd_chan_event_notify(&xscd->chans[0]);
+
+ return IRQ_HANDLED;
+}
+
+static int xscd_init_resources(struct xscd_device *xscd)
+{
+ struct platform_device *pdev = to_platform_device(xscd->dev);
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ xscd->iomem = devm_ioremap_resource(xscd->dev, res);
+ if (IS_ERR(xscd->iomem))
+ return PTR_ERR(xscd->iomem);
+
+ xscd->irq = platform_get_irq(pdev, 0);
+ if (xscd->irq < 0) {
+ dev_err(xscd->dev, "No valid irq found\n");
+ return -EINVAL;
+ }
+
+ xscd->clk = devm_clk_get(xscd->dev, NULL);
+ if (IS_ERR(xscd->clk))
+ return PTR_ERR(xscd->clk);
+
+ clk_prepare_enable(xscd->clk);
+ return 0;
+}
+
+static int xscd_parse_of(struct xscd_device *xscd)
+{
+ struct device *dev = xscd->dev;
+ struct device_node *node = xscd->dev->of_node;
+ int ret;
+
+ xscd->memory_based = of_property_read_bool(node, "xlnx,memorybased");
+ xscd->rst_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(xscd->rst_gpio)) {
+ if (PTR_ERR(xscd->rst_gpio) != -EPROBE_DEFER)
+ dev_err(dev, "Reset GPIO not setup in DT\n");
+
+ return PTR_ERR(xscd->rst_gpio);
+ }
+
+ ret = of_property_read_u32(node, "xlnx,numstreams",
+ &xscd->num_streams);
+ if (ret < 0)
+ return ret;
+
+ if (!xscd->memory_based && xscd->num_streams != 1) {
+ dev_err(dev, "Stream-based mode only supports one stream\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int xscd_probe(struct platform_device *pdev)
+{
+ struct xscd_device *xscd;
+ struct device_node *subdev_node;
+ unsigned int id;
+ int ret;
+
+ xscd = devm_kzalloc(&pdev->dev, sizeof(*xscd), GFP_KERNEL);
+ if (!xscd)
+ return -ENOMEM;
+
+ spin_lock_init(&xscd->lock);
+
+ xscd->dev = &pdev->dev;
+ platform_set_drvdata(pdev, xscd);
+
+ ret = xscd_parse_of(xscd);
+ if (ret < 0)
+ return ret;
+
+ ret = xscd_init_resources(xscd);
+ if (ret < 0)
+ return ret;
+
+ /* Reset Scene Change Detection IP */
+ gpiod_set_value_cansleep(xscd->rst_gpio, XSCD_RESET_ASSERT);
+ gpiod_set_value_cansleep(xscd->rst_gpio, XSCD_RESET_DEASSERT);
+
+ /* Initialize the channels. */
+ xscd->chans = devm_kcalloc(xscd->dev, xscd->num_streams,
+ sizeof(*xscd->chans), GFP_KERNEL);
+ if (!xscd->chans)
+ return -ENOMEM;
+
+ id = 0;
+ for_each_child_of_node(xscd->dev->of_node, subdev_node) {
+ if (id >= xscd->num_streams) {
+ dev_warn(&pdev->dev,
+ "Too many channels, limiting to %u\n",
+ xscd->num_streams);
+ of_node_put(subdev_node);
+ break;
+ }
+
+ ret = xscd_chan_init(xscd, id, subdev_node);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to initialize channel %u\n",
+ id);
+ return ret;
+ }
+
+ id++;
+ }
+
+ /* Initialize the DMA engine. */
+ ret = xscd_dma_init(xscd);
+ if (ret < 0)
+ dev_err(&pdev->dev, "Failed to initialize the DMA\n");
+
+ ret = devm_request_irq(xscd->dev, xscd->irq, xscd_irq_handler,
+ IRQF_SHARED, dev_name(xscd->dev), xscd);
+ if (ret < 0)
+ dev_err(&pdev->dev, "Failed to request IRQ\n");
+
+ dev_info(xscd->dev, "scene change detect device found!\n");
+ return 0;
+}
+
+static int xscd_remove(struct platform_device *pdev)
+{
+ struct xscd_device *xscd = platform_get_drvdata(pdev);
+
+ xscd_dma_cleanup(xscd);
+ clk_disable_unprepare(xscd->clk);
+
+ return 0;
+}
+
+static const struct of_device_id xscd_of_id_table[] = {
+ { .compatible = "xlnx,v-scd" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, xscd_of_id_table);
+
+static struct platform_driver xscd_driver = {
+ .driver = {
+ .name = "xilinx-scd",
+ .of_match_table = xscd_of_id_table,
+ },
+ .probe = xscd_probe,
+ .remove = xscd_remove,
+};
+
+module_platform_driver(xscd_driver);
+
+MODULE_AUTHOR("Xilinx Inc.");
+MODULE_DESCRIPTION("Xilinx Scene Change Detection");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/xilinx/xilinx-scenechange.h b/drivers/media/platform/xilinx/xilinx-scenechange.h
new file mode 100644
index 000000000000..1573bf825217
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-scenechange.h
@@ -0,0 +1,234 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Xilinx Scene Change Detection driver
+ *
+ * Copyright (C) 2018 Xilinx, Inc.
+ *
+ * Authors: Anand Ashok Dumbre <anand.ashok.dumbre@xilinx.com>
+ * Satish Kumar Nagireddy <satish.nagireddy.nagireddy@xilinx.com>
+ */
+
+#ifndef _XILINX_SCENECHANGE_H_
+#define _XILINX_SCENECHANGE_H_
+
+#include <linux/bitops.h>
+#include <linux/dmaengine.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+
+#include <media/v4l2-subdev.h>
+
+struct clk;
+struct device;
+struct device_node;
+struct gpio_desc;
+
+/* Register/Descriptor Offsets */
+#define XSCD_CTRL_OFFSET 0x000
+#define XSCD_CTRL_AP_START BIT(0)
+#define XSCD_CTRL_AP_DONE BIT(1)
+#define XSCD_CTRL_AP_IDLE BIT(2)
+#define XSCD_CTRL_AP_READY BIT(3)
+#define XSCD_CTRL_AUTO_RESTART BIT(7)
+
+#define XSCD_GIE_OFFSET 0x004
+#define XSCD_GIE_EN BIT(0)
+
+#define XSCD_IE_OFFSET 0x008
+#define XSCD_IE_AP_DONE BIT(0)
+#define XSCD_IE_AP_READY BIT(1)
+
+#define XSCD_ISR_OFFSET 0x00c
+#define XSCD_WIDTH_OFFSET 0x010
+#define XSCD_HEIGHT_OFFSET 0x018
+#define XSCD_STRIDE_OFFSET 0x020
+#define XSCD_VID_FMT_OFFSET 0x028
+#define XSCD_VID_FMT_RGB 0
+#define XSCD_VID_FMT_YUV_444 1
+#define XSCD_VID_FMT_YUV_422 2
+#define XSCD_VID_FMT_YUV_420 3
+#define XSCD_VID_FMT_Y8 24
+#define XSCD_VID_FMT_Y10 25
+
+#define XSCD_SUBSAMPLE_OFFSET 0x030
+#define XSCD_SAD_OFFSET 0x038
+#define XSCD_ADDR_OFFSET 0x040
+#define XSCD_CHAN_OFFSET 0x100
+#define XSCD_CHAN_EN_OFFSET 0x780
+
+#define XSCD_MAX_CHANNELS 8
+
+/****************************** PROTOTYPES ************************************/
+
+struct xscd_device;
+
+/**
+ * struct xscd_dma_desc - DMA channel
+ * @luma_plane_addr: Luma plane buffer address
+ * @vsize: width of the luma frame
+ * @hsize: height of the luma frame
+ * @stride: stride of the luma frame
+ */
+struct xscd_dma_desc {
+ dma_addr_t luma_plane_addr;
+ u32 vsize;
+ u32 hsize;
+ u32 stride;
+};
+
+/**
+ * struct xscd_dma_tx_descriptor - Per Transaction structure
+ * @async_tx: Async transaction descriptor
+ * @sw: Software Descriptor
+ * @node: Node in the channel descriptor list
+ */
+struct xscd_dma_tx_descriptor {
+ struct dma_async_tx_descriptor async_tx;
+ struct xscd_dma_desc sw;
+ struct list_head node;
+};
+
+static inline struct xscd_dma_tx_descriptor *
+to_xscd_dma_tx_descriptor(struct dma_async_tx_descriptor *tx)
+{
+ return container_of(tx, struct xscd_dma_tx_descriptor, async_tx);
+}
+
+/**
+ * struct xscd_dma_chan - DMA Channel structure
+ * @xscd: SCD device
+ * @iomem: I/O memory address of the channel registers
+ * @id: scene change channel ID
+ * @common: DMA common channel
+ * @tasklet: Cleanup work after irq
+ * @lock: Protects pending_list, done_list, active_desc, enabled and running
+ * @pending_list: Descriptors waiting
+ * @done_list: Complete descriptors
+ * @active_desc: Currently active buffer being read/written to
+ * @enabled: Channel is enabled
+ * @running: Channel is running
+ * @wait: Wait queue to wait for the channel to stop
+ */
+struct xscd_dma_chan {
+ struct xscd_device *xscd;
+ void __iomem *iomem;
+ unsigned int id;
+
+ struct dma_chan common;
+ struct tasklet_struct tasklet;
+
+ spinlock_t lock;
+ struct list_head pending_list;
+ struct list_head done_list;
+ struct xscd_dma_tx_descriptor *active_desc;
+ unsigned int enabled;
+ unsigned int running;
+ wait_queue_head_t wait;
+};
+
+static inline struct xscd_dma_chan *to_xscd_dma_chan(struct dma_chan *chan)
+{
+ return container_of(chan, struct xscd_dma_chan, common);
+}
+
+/**
+ * struct xscd_chan - Video Stream structure
+ * @id: scene change channel ID
+ * @iomem: I/O memory address of the channel registers
+ * @xscd: SCD device
+ * @subdev: V4L2 subdevice
+ * @pads: media pads
+ * @format: active V4L2 media bus format for the pad
+ * @event: scene change event
+ * @dmachan: dma channel part of the scenechange stream
+ * @lock: lock to protect active stream count variable
+ */
+struct xscd_chan {
+ int id;
+ void __iomem *iomem;
+ struct xscd_device *xscd;
+ struct v4l2_subdev subdev;
+ struct media_pad pads[2];
+ struct v4l2_mbus_framefmt format;
+ struct v4l2_event event;
+ struct xscd_dma_chan dmachan;
+
+ /* Lock to protect active stream count */
+ struct mutex lock;
+};
+
+static inline struct xscd_chan *to_xscd_chan(struct v4l2_subdev *subdev)
+{
+ return container_of(subdev, struct xscd_chan, subdev);
+}
+
+/**
+ * struct xscd_device - Xilinx Scene Change Detection device structure
+ * @dev: (OF) device
+ * @iomem: device I/O register space remapped to kernel virtual memory
+ * @rst_gpio: reset GPIO
+ * @clk: video core clock
+ * @irq: Device IRQ
+ * @memory_based: Flag to identify memory based mode
+ * @num_streams: Number of streams in the design
+ * @chans: video stream instances
+ * @dma_device: DMA device structure
+ * @channels: DMA channels
+ * @lock: Protects the running field
+ * @running: True when the SCD core is running
+ */
+struct xscd_device {
+ struct device *dev;
+ void __iomem *iomem;
+ struct gpio_desc *rst_gpio;
+ struct clk *clk;
+ int irq;
+
+ u8 memory_based;
+ int num_streams;
+
+ struct xscd_chan *chans;
+
+ struct dma_device dma_device;
+ struct xscd_dma_chan *channels[XSCD_MAX_CHANNELS];
+
+ /* This lock is to protect the running field */
+ spinlock_t lock;
+ u8 running;
+};
+
+/*
+ * Register related operations
+ */
+static inline u32 xscd_read(void __iomem *iomem, u32 addr)
+{
+ return ioread32(iomem + addr);
+}
+
+static inline void xscd_write(void __iomem *iomem, u32 addr, u32 value)
+{
+ iowrite32(value, iomem + addr);
+}
+
+static inline void xscd_clr(void __iomem *iomem, u32 addr, u32 clr)
+{
+ xscd_write(iomem, addr, xscd_read(iomem, addr) & ~clr);
+}
+
+static inline void xscd_set(void __iomem *iomem, u32 addr, u32 set)
+{
+ xscd_write(iomem, addr, xscd_read(iomem, addr) | set);
+}
+
+void xscd_dma_enable_channel(struct xscd_dma_chan *chan, bool enable);
+void xscd_dma_irq_handler(struct xscd_device *xscd);
+int xscd_dma_init(struct xscd_device *xscd);
+void xscd_dma_cleanup(struct xscd_device *xscd);
+
+void xscd_chan_event_notify(struct xscd_chan *chan);
+int xscd_chan_init(struct xscd_device *xscd, unsigned int chan_id,
+ struct device_node *node);
+#endif
diff --git a/drivers/media/platform/xilinx/xilinx-sdirxss.c b/drivers/media/platform/xilinx/xilinx-sdirxss.c
new file mode 100644
index 000000000000..1ee54ce28d22
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-sdirxss.c
@@ -0,0 +1,1855 @@
+/*
+ * Xilinx SDI Rx Subsystem
+ *
+ * Copyright (C) 2017 Xilinx, Inc.
+ *
+ * Contacts: Vishal Sagar <vsagar@xilinx.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/media/xilinx-vip.h>
+#include <linux/bitops.h>
+#include <linux/compiler.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/spinlock_types.h>
+#include <linux/types.h>
+#include <linux/v4l2-subdev.h>
+#include <linux/xilinx-sdirxss.h>
+#include <linux/xilinx-v4l2-controls.h>
+#include <media/media-entity.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+#include "xilinx-vip.h"
+
+/*
+ * SDI Rx register map, bitmask and offsets
+ */
+#define XSDIRX_RST_CTRL_REG 0x00
+#define XSDIRX_MDL_CTRL_REG 0x04
+#define XSDIRX_GLBL_IER_REG 0x0C
+#define XSDIRX_ISR_REG 0x10
+#define XSDIRX_IER_REG 0x14
+#define XSDIRX_ST352_VALID_REG 0x18
+#define XSDIRX_ST352_DS1_REG 0x1C
+#define XSDIRX_ST352_DS3_REG 0x20
+#define XSDIRX_ST352_DS5_REG 0x24
+#define XSDIRX_ST352_DS7_REG 0x28
+#define XSDIRX_ST352_DS9_REG 0x2C
+#define XSDIRX_ST352_DS11_REG 0x30
+#define XSDIRX_ST352_DS13_REG 0x34
+#define XSDIRX_ST352_DS15_REG 0x38
+#define XSDIRX_VERSION_REG 0x3C
+#define XSDIRX_SS_CONFIG_REG 0x40
+#define XSDIRX_MODE_DET_STAT_REG 0x44
+#define XSDIRX_TS_DET_STAT_REG 0x48
+#define XSDIRX_EDH_STAT_REG 0x4C
+#define XSDIRX_EDH_ERRCNT_EN_REG 0x50
+#define XSDIRX_EDH_ERRCNT_REG 0x54
+#define XSDIRX_CRC_ERRCNT_REG 0x58
+#define XSDIRX_VID_LOCK_WINDOW_REG 0x5C
+#define XSDIRX_SB_RX_STS_REG 0x60
+
+#define XSDIRX_RST_CTRL_SS_EN_MASK BIT(0)
+#define XSDIRX_RST_CTRL_SRST_MASK BIT(1)
+#define XSDIRX_RST_CTRL_RST_CRC_ERRCNT_MASK BIT(2)
+#define XSDIRX_RST_CTRL_RST_EDH_ERRCNT_MASK BIT(3)
+#define XSDIRX_RST_CTRL_SDIRX_BRIDGE_ENB_MASK BIT(8)
+#define XSDIRX_RST_CTRL_VIDIN_AXI4S_MOD_ENB_MASK BIT(9)
+
+#define XSDIRX_MDL_CTRL_FRM_EN_MASK BIT(4)
+#define XSDIRX_MDL_CTRL_MODE_DET_EN_MASK BIT(5)
+#define XSDIRX_MDL_CTRL_MODE_HD_EN_MASK BIT(8)
+#define XSDIRX_MDL_CTRL_MODE_SD_EN_MASK BIT(9)
+#define XSDIRX_MDL_CTRL_MODE_3G_EN_MASK BIT(10)
+#define XSDIRX_MDL_CTRL_MODE_6G_EN_MASK BIT(11)
+#define XSDIRX_MDL_CTRL_MODE_12GI_EN_MASK BIT(12)
+#define XSDIRX_MDL_CTRL_MODE_12GF_EN_MASK BIT(13)
+#define XSDIRX_MDL_CTRL_MODE_AUTO_DET_MASK GENMASK(13, 8)
+
+#define XSDIRX_MDL_CTRL_FORCED_MODE_OFFSET 16
+#define XSDIRX_MDL_CTRL_FORCED_MODE_MASK GENMASK(18, 16)
+
+#define XSDIRX_GLBL_INTR_EN_MASK BIT(0)
+
+#define XSDIRX_INTR_VIDLOCK_MASK BIT(0)
+#define XSDIRX_INTR_VIDUNLOCK_MASK BIT(1)
+#define XSDIRX_INTR_OVERFLOW_MASK BIT(9)
+#define XSDIRX_INTR_UNDERFLOW_MASK BIT(10)
+
+#define XSDIRX_INTR_ALL_MASK (XSDIRX_INTR_VIDLOCK_MASK |\
+ XSDIRX_INTR_VIDUNLOCK_MASK |\
+ XSDIRX_INTR_OVERFLOW_MASK |\
+ XSDIRX_INTR_UNDERFLOW_MASK)
+
+#define XSDIRX_ST352_VALID_DS1_MASK BIT(0)
+#define XSDIRX_ST352_VALID_DS3_MASK BIT(1)
+#define XSDIRX_ST352_VALID_DS5_MASK BIT(2)
+#define XSDIRX_ST352_VALID_DS7_MASK BIT(3)
+#define XSDIRX_ST352_VALID_DS9_MASK BIT(4)
+#define XSDIRX_ST352_VALID_DS11_MASK BIT(5)
+#define XSDIRX_ST352_VALID_DS13_MASK BIT(6)
+#define XSDIRX_ST352_VALID_DS15_MASK BIT(7)
+
+#define XSDIRX_MODE_DET_STAT_RX_MODE_MASK GENMASK(2, 0)
+#define XSDIRX_MODE_DET_STAT_MODE_LOCK_MASK BIT(3)
+#define XSDIRX_MODE_DET_STAT_ACT_STREAM_MASK GENMASK(6, 4)
+#define XSDIRX_MODE_DET_STAT_ACT_STREAM_OFFSET 4
+#define XSDIRX_MODE_DET_STAT_LVLB_3G_MASK BIT(7)
+
+#define XSDIRX_ACTIVE_STREAMS_1 0x0
+#define XSDIRX_ACTIVE_STREAMS_2 0x1
+#define XSDIRX_ACTIVE_STREAMS_4 0x2
+#define XSDIRX_ACTIVE_STREAMS_8 0x3
+#define XSDIRX_ACTIVE_STREAMS_16 0x4
+
+#define XSDIRX_TS_DET_STAT_LOCKED_MASK BIT(0)
+#define XSDIRX_TS_DET_STAT_SCAN_MASK BIT(1)
+#define XSDIRX_TS_DET_STAT_SCAN_OFFSET (1)
+#define XSDIRX_TS_DET_STAT_FAMILY_MASK GENMASK(7, 4)
+#define XSDIRX_TS_DET_STAT_FAMILY_OFFSET (4)
+#define XSDIRX_TS_DET_STAT_RATE_MASK GENMASK(11, 8)
+#define XSDIRX_TS_DET_STAT_RATE_OFFSET (8)
+
+#define XSDIRX_TS_DET_STAT_RATE_NONE 0x0
+#define XSDIRX_TS_DET_STAT_RATE_23_98HZ 0x2
+#define XSDIRX_TS_DET_STAT_RATE_24HZ 0x3
+#define XSDIRX_TS_DET_STAT_RATE_47_95HZ 0x4
+#define XSDIRX_TS_DET_STAT_RATE_25HZ 0x5
+#define XSDIRX_TS_DET_STAT_RATE_29_97HZ 0x6
+#define XSDIRX_TS_DET_STAT_RATE_30HZ 0x7
+#define XSDIRX_TS_DET_STAT_RATE_48HZ 0x8
+#define XSDIRX_TS_DET_STAT_RATE_50HZ 0x9
+#define XSDIRX_TS_DET_STAT_RATE_59_94HZ 0xA
+#define XSDIRX_TS_DET_STAT_RATE_60HZ 0xB
+
+#define XSDIRX_EDH_STAT_EDH_AP_MASK BIT(0)
+#define XSDIRX_EDH_STAT_EDH_FF_MASK BIT(1)
+#define XSDIRX_EDH_STAT_EDH_ANC_MASK BIT(2)
+#define XSDIRX_EDH_STAT_AP_FLAG_MASK GENMASK(8, 4)
+#define XSDIRX_EDH_STAT_FF_FLAG_MASK GENMASK(13, 9)
+#define XSDIRX_EDH_STAT_ANC_FLAG_MASK GENMASK(18, 14)
+#define XSDIRX_EDH_STAT_PKT_FLAG_MASK GENMASK(22, 19)
+
+#define XSDIRX_EDH_ERRCNT_COUNT_MASK GENMASK(15, 0)
+
+#define XSDIRX_CRC_ERRCNT_COUNT_MASK GENMASK(31, 16)
+#define XSDIRX_CRC_ERRCNT_DS_CRC_MASK GENMASK(15, 0)
+
+#define XSDIRX_VERSION_REV_MASK GENMASK(7, 0)
+#define XSDIRX_VERSION_PATCHID_MASK GENMASK(11, 8)
+#define XSDIRX_VERSION_VER_REV_MASK GENMASK(15, 12)
+#define XSDIRX_VERSION_VER_MIN_MASK GENMASK(23, 16)
+#define XSDIRX_VERSION_VER_MAJ_MASK GENMASK(31, 24)
+
+#define XSDIRX_SS_CONFIG_EDH_INCLUDED_MASK BIT(1)
+
+#define XSDIRX_STAT_SB_RX_TDATA_CHANGE_DONE_MASK BIT(0)
+#define XSDIRX_STAT_SB_RX_TDATA_CHANGE_FAIL_MASK BIT(1)
+#define XSDIRX_STAT_SB_RX_TDATA_GT_RESETDONE_MASK BIT(2)
+#define XSDIRX_STAT_SB_RX_TDATA_GT_BITRATE_MASK BIT(3)
+
+/* Number of media pads */
+#define XSDIRX_MEDIA_PADS (1)
+
+#define XSDIRX_DEFAULT_WIDTH (1920)
+#define XSDIRX_DEFAULT_HEIGHT (1080)
+
+#define XSDIRX_MAX_STR_LENGTH 16
+
+#define XSDIRXSS_SDI_STD_3G 0
+#define XSDIRXSS_SDI_STD_6G 1
+#define XSDIRXSS_SDI_STD_12G_8DS 2
+
+#define XSDIRX_DEFAULT_VIDEO_LOCK_WINDOW 0x3000
+
+#define XSDIRX_MODE_HD_MASK 0x0
+#define XSDIRX_MODE_SD_MASK 0x1
+#define XSDIRX_MODE_3G_MASK 0x2
+#define XSDIRX_MODE_6G_MASK 0x4
+#define XSDIRX_MODE_12GI_MASK 0x5
+#define XSDIRX_MODE_12GF_MASK 0x6
+
+/*
+ * Maximum number of events per file handle.
+ */
+#define XSDIRX_MAX_EVENTS (128)
+
+/* ST352 related macros */
+#define XST352_PAYLOAD_BYTE_MASK 0xFF
+#define XST352_PAYLOAD_BYTE1_SHIFT 0
+#define XST352_PAYLOAD_BYTE2_SHIFT 8
+#define XST352_PAYLOAD_BYTE3_SHIFT 16
+#define XST352_PAYLOAD_BYTE4_SHIFT 24
+
+#define XST352_BYTE1_ST292_1x720L_1_5G 0x84
+#define XST352_BYTE1_ST292_1x1080L_1_5G 0x85
+#define XST352_BYTE1_ST425_2008_750L_3GB 0x88
+#define XST352_BYTE1_ST425_2008_1125L_3GA 0x89
+#define XST352_BYTE1_ST372_DL_3GB 0x8A
+#define XST352_BYTE1_ST372_2x720L_3GB 0x8B
+#define XST352_BYTE1_ST372_2x1080L_3GB 0x8C
+#define XST352_BYTE1_ST2081_10_2160L_6G 0xC0
+#define XST352_BYTE1_ST2081_10_DL_2160L_6G 0xC2
+#define XST352_BYTE1_ST2082_10_2160L_12G 0xCE
+
+#define XST352_BYTE2_TS_TYPE_MASK BIT(15)
+#define XST352_BYTE2_TS_TYPE_OFFSET 15
+#define XST352_BYTE2_PIC_TYPE_MASK BIT(14)
+#define XST352_BYTE2_PIC_TYPE_OFFSET 14
+#define XST352_BYTE2_TS_PIC_TYPE_INTERLACED 0
+#define XST352_BYTE2_TS_PIC_TYPE_PROGRESSIVE 1
+
+#define XST352_BYTE2_FPS_MASK 0xF
+#define XST352_BYTE2_FPS_SHIFT 8
+#define XST352_BYTE2_FPS_24F 0x2
+#define XST352_BYTE2_FPS_24 0x3
+#define XST352_BYTE2_FPS_48F 0x4
+#define XST352_BYTE2_FPS_25 0x5
+#define XST352_BYTE2_FPS_30F 0x6
+#define XST352_BYTE2_FPS_30 0x7
+#define XST352_BYTE2_FPS_48 0x8
+#define XST352_BYTE2_FPS_50 0x9
+#define XST352_BYTE2_FPS_60F 0xA
+#define XST352_BYTE2_FPS_60 0xB
+/* Table 4 ST 2081-10:2015 */
+#define XST352_BYTE2_FPS_96 0xC
+#define XST352_BYTE2_FPS_100 0xD
+#define XST352_BYTE2_FPS_120 0xE
+#define XST352_BYTE2_FPS_120F 0xF
+
+#define XST352_BYTE3_ACT_LUMA_COUNT_MASK BIT(22)
+#define XST352_BYTE3_ACT_LUMA_COUNT_OFFSET 22
+
+#define XST352_BYTE3_COLOR_FORMAT_MASK GENMASK(19, 16)
+#define XST352_BYTE3_COLOR_FORMAT_OFFSET 16
+#define XST352_BYTE3_COLOR_FORMAT_422 0x0
+#define XST352_BYTE3_COLOR_FORMAT_420 0x3
+
+/**
+ * enum sdi_family_enc - SDI Transport Video Format Detected with Active Pixels
+ * @XSDIRX_SMPTE_ST_274: SMPTE ST 274 detected with AP 1920x1080
+ * @XSDIRX_SMPTE_ST_296: SMPTE ST 296 detected with AP 1280x720
+ * @XSDIRX_SMPTE_ST_2048_2: SMPTE ST 2048-2 detected with AP 2048x1080
+ * @XSDIRX_SMPTE_ST_295: SMPTE ST 295 detected with AP 1920x1080
+ * @XSDIRX_NTSC: NTSC encoding detected with AP 720x486
+ * @XSDIRX_PAL: PAL encoding detected with AP 720x576
+ * @XSDIRX_TS_UNKNOWN: Unknown SMPTE Transport family type
+ */
+enum sdi_family_enc {
+ XSDIRX_SMPTE_ST_274 = 0,
+ XSDIRX_SMPTE_ST_296 = 1,
+ XSDIRX_SMPTE_ST_2048_2 = 2,
+ XSDIRX_SMPTE_ST_295 = 3,
+ XSDIRX_NTSC = 8,
+ XSDIRX_PAL = 9,
+ XSDIRX_TS_UNKNOWN = 15
+};
+
+/**
+ * struct xsdirxss_core - Core configuration SDI Rx Subsystem device structure
+ * @dev: Platform structure
+ * @iomem: Base address of subsystem
+ * @irq: requested irq number
+ * @include_edh: EDH processor presence
+ * @mode: 3G/6G/12G mode
+ * @axi_clk: Axi lite interface clock
+ * @sdirx_clk: SDI Rx GT clock
+ * @vidout_clk: Video clock
+ */
+struct xsdirxss_core {
+ struct device *dev;
+ void __iomem *iomem;
+ int irq;
+ bool include_edh;
+ int mode;
+ struct clk *axi_clk;
+ struct clk *sdirx_clk;
+ struct clk *vidout_clk;
+};
+
+/**
+ * struct xsdirxss_state - SDI Rx Subsystem device structure
+ * @core: Core structure for MIPI SDI Rx Subsystem
+ * @subdev: The v4l2 subdev structure
+ * @ctrl_handler: control handler
+ * @event: Holds the video unlock event
+ * @formats: Active V4L2 formats on each pad
+ * @default_format: default V4L2 media bus format
+ * @frame_interval: Captures the frame rate
+ * @vip_format: format information corresponding to the active format
+ * @pads: media pads
+ * @streaming: Flag for storing streaming state
+ * @vidlocked: Flag indicating SDI Rx has locked onto video stream
+ * @ts_is_interlaced: Flag indicating Transport Stream is interlaced.
+ *
+ * This structure contains the device driver related parameters
+ */
+struct xsdirxss_state {
+ struct xsdirxss_core core;
+ struct v4l2_subdev subdev;
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_event event;
+ struct v4l2_mbus_framefmt formats[XSDIRX_MEDIA_PADS];
+ struct v4l2_mbus_framefmt default_format;
+ struct v4l2_fract frame_interval;
+ const struct xvip_video_format *vip_format;
+ struct media_pad pads[XSDIRX_MEDIA_PADS];
+ bool streaming;
+ bool vidlocked;
+ bool ts_is_interlaced;
+};
+
+static inline struct xsdirxss_state *
+to_xsdirxssstate(struct v4l2_subdev *subdev)
+{
+ return container_of(subdev, struct xsdirxss_state, subdev);
+}
+
+/*
+ * Register related operations
+ */
+static inline u32 xsdirxss_read(struct xsdirxss_core *xsdirxss, u32 addr)
+{
+ return ioread32(xsdirxss->iomem + addr);
+}
+
+static inline void xsdirxss_write(struct xsdirxss_core *xsdirxss, u32 addr,
+ u32 value)
+{
+ iowrite32(value, xsdirxss->iomem + addr);
+}
+
+static inline void xsdirxss_clr(struct xsdirxss_core *xsdirxss, u32 addr,
+ u32 clr)
+{
+ xsdirxss_write(xsdirxss, addr, xsdirxss_read(xsdirxss, addr) & ~clr);
+}
+
+static inline void xsdirxss_set(struct xsdirxss_core *xsdirxss, u32 addr,
+ u32 set)
+{
+ xsdirxss_write(xsdirxss, addr, xsdirxss_read(xsdirxss, addr) | set);
+}
+
+static void xsdirx_core_disable(struct xsdirxss_core *core)
+{
+ xsdirxss_clr(core, XSDIRX_RST_CTRL_REG, XSDIRX_RST_CTRL_SS_EN_MASK);
+}
+
+static void xsdirx_core_enable(struct xsdirxss_core *core)
+{
+ xsdirxss_set(core, XSDIRX_RST_CTRL_REG, XSDIRX_RST_CTRL_SS_EN_MASK);
+}
+
+static int xsdirx_set_modedetect(struct xsdirxss_core *core, u16 mask)
+{
+ u32 i, val;
+
+ mask &= XSDIRX_DETECT_ALL_MODES;
+ if (!mask) {
+ dev_err(core->dev, "Invalid bit mask = 0x%08x\n", mask);
+ return -EINVAL;
+ }
+
+ dev_dbg(core->dev, "mask = 0x%x\n", mask);
+
+ val = xsdirxss_read(core, XSDIRX_MDL_CTRL_REG);
+ val &= ~(XSDIRX_MDL_CTRL_MODE_DET_EN_MASK);
+ val &= ~(XSDIRX_MDL_CTRL_MODE_AUTO_DET_MASK);
+ val &= ~(XSDIRX_MDL_CTRL_FORCED_MODE_MASK);
+
+ if (hweight16(mask) > 1) {
+ /* Multi mode detection as more than 1 bit set in mask */
+ dev_dbg(core->dev, "Detect multiple modes\n");
+ for (i = 0; i < XSDIRX_MODE_NUM_SUPPORTED; i++) {
+ switch (mask & (1 << i)) {
+ case BIT(XSDIRX_MODE_SD_OFFSET):
+ val |= XSDIRX_MDL_CTRL_MODE_SD_EN_MASK;
+ break;
+ case BIT(XSDIRX_MODE_HD_OFFSET):
+ val |= XSDIRX_MDL_CTRL_MODE_HD_EN_MASK;
+ break;
+ case BIT(XSDIRX_MODE_3G_OFFSET):
+ val |= XSDIRX_MDL_CTRL_MODE_3G_EN_MASK;
+ break;
+ case BIT(XSDIRX_MODE_6G_OFFSET):
+ val |= XSDIRX_MDL_CTRL_MODE_6G_EN_MASK;
+ break;
+ case BIT(XSDIRX_MODE_12GI_OFFSET):
+ val |= XSDIRX_MDL_CTRL_MODE_12GI_EN_MASK;
+ break;
+ case BIT(XSDIRX_MODE_12GF_OFFSET):
+ val |= XSDIRX_MDL_CTRL_MODE_12GF_EN_MASK;
+ break;
+ }
+ }
+ val |= XSDIRX_MDL_CTRL_MODE_DET_EN_MASK;
+ } else {
+ /* Fixed Mode */
+ u32 forced_mode_mask = 0;
+
+ dev_dbg(core->dev, "Detect fixed mode\n");
+
+ /* Find offset of first bit set */
+ switch (__ffs(mask)) {
+ case XSDIRX_MODE_SD_OFFSET:
+ forced_mode_mask = XSDIRX_MODE_SD_MASK;
+ break;
+ case XSDIRX_MODE_HD_OFFSET:
+ forced_mode_mask = XSDIRX_MODE_HD_MASK;
+ break;
+ case XSDIRX_MODE_3G_OFFSET:
+ forced_mode_mask = XSDIRX_MODE_3G_MASK;
+ break;
+ case XSDIRX_MODE_6G_OFFSET:
+ forced_mode_mask = XSDIRX_MODE_6G_MASK;
+ break;
+ case XSDIRX_MODE_12GI_OFFSET:
+ forced_mode_mask = XSDIRX_MODE_12GI_MASK;
+ break;
+ case XSDIRX_MODE_12GF_OFFSET:
+ forced_mode_mask = XSDIRX_MODE_12GF_MASK;
+ break;
+ }
+ dev_dbg(core->dev, "Forced Mode Mask : 0x%x\n",
+ forced_mode_mask);
+ val |= forced_mode_mask << XSDIRX_MDL_CTRL_FORCED_MODE_OFFSET;
+ }
+
+ dev_dbg(core->dev, "Modes to be detected : sdi ctrl reg = 0x%08x\n",
+ val);
+ xsdirxss_write(core, XSDIRX_MDL_CTRL_REG, val);
+
+ return 0;
+}
+
+static void xsdirx_framer(struct xsdirxss_core *core, bool flag)
+{
+ if (flag)
+ xsdirxss_set(core, XSDIRX_MDL_CTRL_REG,
+ XSDIRX_MDL_CTRL_FRM_EN_MASK);
+ else
+ xsdirxss_clr(core, XSDIRX_MDL_CTRL_REG,
+ XSDIRX_MDL_CTRL_FRM_EN_MASK);
+}
+
+static void xsdirx_setedherrcnttrigger(struct xsdirxss_core *core, u32 enable)
+{
+ u32 val = xsdirxss_read(core, XSDIRX_EDH_ERRCNT_EN_REG);
+
+ val = enable & XSDIRX_EDH_ALLERR_MASK;
+
+ xsdirxss_write(core, XSDIRX_EDH_ERRCNT_EN_REG, val);
+}
+
+static void xsdirx_setvidlockwindow(struct xsdirxss_core *core, u32 val)
+{
+ /*
+ * The video lock window is the amount of time for which the
+ * the mode and transport stream should be locked to get the
+ * video lock interrupt.
+ */
+ xsdirxss_write(core, XSDIRX_VID_LOCK_WINDOW_REG, val);
+}
+
+static void xsdirx_disableintr(struct xsdirxss_core *core, u32 mask)
+{
+ xsdirxss_clr(core, XSDIRX_IER_REG, mask);
+}
+
+static void xsdirx_enableintr(struct xsdirxss_core *core, u32 mask)
+{
+ xsdirxss_set(core, XSDIRX_IER_REG, mask);
+}
+
+static void xsdirx_globalintr(struct xsdirxss_core *core, bool flag)
+{
+ if (flag)
+ xsdirxss_set(core, XSDIRX_GLBL_IER_REG,
+ XSDIRX_GLBL_INTR_EN_MASK);
+ else
+ xsdirxss_clr(core, XSDIRX_GLBL_IER_REG,
+ XSDIRX_GLBL_INTR_EN_MASK);
+}
+
+static void xsdirx_clearintr(struct xsdirxss_core *core, u32 mask)
+{
+ xsdirxss_set(core, XSDIRX_ISR_REG, mask);
+}
+
+static void xsdirx_vid_bridge_control(struct xsdirxss_core *core, bool enable)
+{
+ if (enable)
+ xsdirxss_set(core, XSDIRX_RST_CTRL_REG,
+ XSDIRX_RST_CTRL_SDIRX_BRIDGE_ENB_MASK);
+ else
+ xsdirxss_clr(core, XSDIRX_RST_CTRL_REG,
+ XSDIRX_RST_CTRL_SDIRX_BRIDGE_ENB_MASK);
+}
+
+static void xsdirx_axis4_bridge_control(struct xsdirxss_core *core, bool enable)
+{
+ if (enable)
+ xsdirxss_set(core, XSDIRX_RST_CTRL_REG,
+ XSDIRX_RST_CTRL_VIDIN_AXI4S_MOD_ENB_MASK);
+ else
+ xsdirxss_clr(core, XSDIRX_RST_CTRL_REG,
+ XSDIRX_RST_CTRL_VIDIN_AXI4S_MOD_ENB_MASK);
+}
+
+static void xsdirx_streamflow_control(struct xsdirxss_core *core, bool enable)
+{
+ /* The sdi to native bridge is followed by native to axis4 bridge */
+ if (enable) {
+ xsdirx_axis4_bridge_control(core, enable);
+ xsdirx_vid_bridge_control(core, enable);
+ } else {
+ xsdirx_vid_bridge_control(core, enable);
+ xsdirx_axis4_bridge_control(core, enable);
+ }
+}
+
+static void xsdirx_streamdowncb(struct xsdirxss_core *core)
+{
+ xsdirx_streamflow_control(core, false);
+}
+
+static void xsdirxss_get_framerate(struct v4l2_fract *frame_interval,
+ u32 framerate)
+{
+ switch (framerate) {
+ case XSDIRX_TS_DET_STAT_RATE_23_98HZ:
+ frame_interval->numerator = 1001;
+ frame_interval->denominator = 24000;
+ break;
+ case XSDIRX_TS_DET_STAT_RATE_24HZ:
+ frame_interval->numerator = 1000;
+ frame_interval->denominator = 24000;
+ break;
+ case XSDIRX_TS_DET_STAT_RATE_25HZ:
+ frame_interval->numerator = 1000;
+ frame_interval->denominator = 25000;
+ break;
+ case XSDIRX_TS_DET_STAT_RATE_29_97HZ:
+ frame_interval->numerator = 1001;
+ frame_interval->denominator = 30000;
+ break;
+ case XSDIRX_TS_DET_STAT_RATE_30HZ:
+ frame_interval->numerator = 1000;
+ frame_interval->denominator = 30000;
+ break;
+ case XSDIRX_TS_DET_STAT_RATE_47_95HZ:
+ frame_interval->numerator = 1001;
+ frame_interval->denominator = 48000;
+ break;
+ case XSDIRX_TS_DET_STAT_RATE_48HZ:
+ frame_interval->numerator = 1000;
+ frame_interval->denominator = 48000;
+ break;
+ case XSDIRX_TS_DET_STAT_RATE_50HZ:
+ frame_interval->numerator = 1000;
+ frame_interval->denominator = 50000;
+ break;
+ case XSDIRX_TS_DET_STAT_RATE_59_94HZ:
+ frame_interval->numerator = 1001;
+ frame_interval->denominator = 60000;
+ break;
+ case XSDIRX_TS_DET_STAT_RATE_60HZ:
+ frame_interval->numerator = 1000;
+ frame_interval->denominator = 60000;
+ break;
+ default:
+ frame_interval->numerator = 1;
+ frame_interval->denominator = 1;
+ }
+}
+
+/**
+ * xsdirx_get_stream_properties - Get SDI Rx stream properties
+ * @state: pointer to driver state
+ *
+ * This function decodes the stream's ST352 payload (if available) to get
+ * stream properties like width, height, picture type (interlaced/progressive),
+ * etc.
+ *
+ * Return: 0 for success else errors
+ */
+static int xsdirx_get_stream_properties(struct xsdirxss_state *state)
+{
+ struct xsdirxss_core *core = &state->core;
+ u32 mode, payload = 0, val, family, valid, tscan;
+ u8 byte1 = 0, active_luma = 0, pic_type = 0, framerate = 0;
+ u8 sampling = XST352_BYTE3_COLOR_FORMAT_422;
+ struct v4l2_mbus_framefmt *format = &state->formats[0];
+
+ mode = xsdirxss_read(core, XSDIRX_MODE_DET_STAT_REG);
+ mode &= XSDIRX_MODE_DET_STAT_RX_MODE_MASK;
+
+ valid = xsdirxss_read(core, XSDIRX_ST352_VALID_REG);
+
+ if ((mode >= XSDIRX_MODE_3G_MASK) && !valid) {
+ dev_err(core->dev, "No valid ST352 payload present even for 3G mode and above\n");
+ return -EINVAL;
+ }
+
+ val = xsdirxss_read(core, XSDIRX_TS_DET_STAT_REG);
+ if (valid & XSDIRX_ST352_VALID_DS1_MASK) {
+ payload = xsdirxss_read(core, XSDIRX_ST352_DS1_REG);
+ byte1 = (payload >> XST352_PAYLOAD_BYTE1_SHIFT) &
+ XST352_PAYLOAD_BYTE_MASK;
+ active_luma = (payload & XST352_BYTE3_ACT_LUMA_COUNT_MASK) >>
+ XST352_BYTE3_ACT_LUMA_COUNT_OFFSET;
+ pic_type = (payload & XST352_BYTE2_PIC_TYPE_MASK) >>
+ XST352_BYTE2_PIC_TYPE_OFFSET;
+ framerate = (payload >> XST352_BYTE2_FPS_SHIFT) &
+ XST352_BYTE2_FPS_MASK;
+ tscan = (payload & XST352_BYTE2_TS_TYPE_MASK) >>
+ XST352_BYTE2_TS_TYPE_OFFSET;
+ sampling = (payload & XST352_BYTE3_COLOR_FORMAT_MASK) >>
+ XST352_BYTE3_COLOR_FORMAT_OFFSET;
+ } else {
+ dev_dbg(core->dev, "No ST352 payload available : Mode = %d\n",
+ mode);
+ framerate = (val & XSDIRX_TS_DET_STAT_RATE_MASK) >>
+ XSDIRX_TS_DET_STAT_RATE_OFFSET;
+ tscan = (val & XSDIRX_TS_DET_STAT_SCAN_MASK) >>
+ XSDIRX_TS_DET_STAT_SCAN_OFFSET;
+ }
+
+ family = (val & XSDIRX_TS_DET_STAT_FAMILY_MASK) >>
+ XSDIRX_TS_DET_STAT_FAMILY_OFFSET;
+ state->ts_is_interlaced = tscan ? false : true;
+
+ dev_dbg(core->dev, "ts_is_interlaced = %d, family = %d\n",
+ state->ts_is_interlaced, family);
+
+ switch (mode) {
+ case XSDIRX_MODE_HD_MASK:
+ if (!valid) {
+ /* No payload obtained */
+ dev_dbg(core->dev, "frame rate : %d, tscan = %d\n",
+ framerate, tscan);
+ /*
+ * NOTE : A progressive segmented frame pSF will be
+ * reported incorrectly as Interlaced as we rely on IP's
+ * transport scan locked bit.
+ */
+ dev_warn(core->dev, "pSF will be incorrectly reported as Interlaced\n");
+
+ switch (framerate) {
+ case XSDIRX_TS_DET_STAT_RATE_23_98HZ:
+ case XSDIRX_TS_DET_STAT_RATE_24HZ:
+ case XSDIRX_TS_DET_STAT_RATE_25HZ:
+ case XSDIRX_TS_DET_STAT_RATE_29_97HZ:
+ case XSDIRX_TS_DET_STAT_RATE_30HZ:
+ if (family == XSDIRX_SMPTE_ST_296) {
+ format->width = 1280;
+ format->height = 720;
+ format->field = V4L2_FIELD_NONE;
+ } else if (family == XSDIRX_SMPTE_ST_2048_2) {
+ format->width = 2048;
+ format->height = 1080;
+ if (tscan)
+ format->field = V4L2_FIELD_NONE;
+ else
+ format->field =
+ V4L2_FIELD_ALTERNATE;
+ } else {
+ format->width = 1920;
+ format->height = 1080;
+ if (tscan)
+ format->field = V4L2_FIELD_NONE;
+ else
+ format->field =
+ V4L2_FIELD_ALTERNATE;
+ }
+ break;
+ case XSDIRX_TS_DET_STAT_RATE_50HZ:
+ case XSDIRX_TS_DET_STAT_RATE_59_94HZ:
+ case XSDIRX_TS_DET_STAT_RATE_60HZ:
+ if (family == XSDIRX_SMPTE_ST_274) {
+ format->width = 1920;
+ format->height = 1080;
+ } else {
+ format->width = 1280;
+ format->height = 720;
+ }
+ format->field = V4L2_FIELD_NONE;
+ break;
+ default:
+ format->width = 1920;
+ format->height = 1080;
+ format->field = V4L2_FIELD_NONE;
+ }
+ } else {
+ dev_dbg(core->dev, "Got the payload\n");
+ switch (byte1) {
+ case XST352_BYTE1_ST292_1x720L_1_5G:
+ /* SMPTE ST 292-1 for 720 line payloads */
+ format->width = 1280;
+ format->height = 720;
+ break;
+ case XST352_BYTE1_ST292_1x1080L_1_5G:
+ /* SMPTE ST 292-1 for 1080 line payloads */
+ format->height = 1080;
+ if (active_luma)
+ format->width = 2048;
+ else
+ format->width = 1920;
+ break;
+ default:
+ dev_dbg(core->dev, "Unknown HD Mode SMPTE standard\n");
+ return -EINVAL;
+ }
+ }
+ break;
+ case XSDIRX_MODE_SD_MASK:
+ format->field = V4L2_FIELD_ALTERNATE;
+
+ switch (family) {
+ case XSDIRX_NTSC:
+ format->width = 720;
+ format->height = 486;
+ break;
+ case XSDIRX_PAL:
+ format->width = 720;
+ format->height = 576;
+ break;
+ default:
+ dev_dbg(core->dev, "Unknown SD Mode SMPTE standard\n");
+ return -EINVAL;
+ }
+ break;
+ case XSDIRX_MODE_3G_MASK:
+ switch (byte1) {
+ case XST352_BYTE1_ST425_2008_750L_3GB:
+ /* Sec 4.1.6.1 SMPTE 425-2008 */
+ case XST352_BYTE1_ST372_2x720L_3GB:
+ /* Table 13 SMPTE 425-2008 */
+ format->width = 1280;
+ format->height = 720;
+ break;
+ case XST352_BYTE1_ST425_2008_1125L_3GA:
+ /* ST352 Table SMPTE 425-1 */
+ case XST352_BYTE1_ST372_DL_3GB:
+ /* Table 13 SMPTE 425-2008 */
+ case XST352_BYTE1_ST372_2x1080L_3GB:
+ /* Table 13 SMPTE 425-2008 */
+ format->height = 1080;
+ if (active_luma)
+ format->width = 2048;
+ else
+ format->width = 1920;
+ break;
+ default:
+ dev_dbg(core->dev, "Unknown 3G Mode SMPTE standard\n");
+ return -EINVAL;
+ }
+ break;
+ case XSDIRX_MODE_6G_MASK:
+ switch (byte1) {
+ case XST352_BYTE1_ST2081_10_DL_2160L_6G:
+ /* Dual link 6G */
+ case XST352_BYTE1_ST2081_10_2160L_6G:
+ /* Table 3 SMPTE ST 2081-10 */
+ format->height = 2160;
+ if (active_luma)
+ format->width = 4096;
+ else
+ format->width = 3840;
+ break;
+ default:
+ dev_dbg(core->dev, "Unknown 6G Mode SMPTE standard\n");
+ return -EINVAL;
+ }
+ break;
+ case XSDIRX_MODE_12GI_MASK:
+ case XSDIRX_MODE_12GF_MASK:
+ switch (byte1) {
+ case XST352_BYTE1_ST2082_10_2160L_12G:
+ /* Section 4.3.1 SMPTE ST 2082-10 */
+ format->height = 2160;
+ if (active_luma)
+ format->width = 4096;
+ else
+ format->width = 3840;
+ break;
+ default:
+ dev_dbg(core->dev, "Unknown 12G Mode SMPTE standard\n");
+ return -EINVAL;
+ }
+ break;
+ default:
+ dev_err(core->dev, "Invalid Mode\n");
+ return -EINVAL;
+ }
+
+ if (valid) {
+ if (pic_type)
+ format->field = V4L2_FIELD_NONE;
+ else
+ format->field = V4L2_FIELD_ALTERNATE;
+ }
+
+ if (format->field == V4L2_FIELD_ALTERNATE)
+ format->height = format->height / 2;
+
+ switch (sampling) {
+ case XST352_BYTE3_COLOR_FORMAT_420:
+ format->code = MEDIA_BUS_FMT_VYYUYY10_4X20;
+ break;
+ case XST352_BYTE3_COLOR_FORMAT_422:
+ format->code = MEDIA_BUS_FMT_UYVY10_1X20;
+ break;
+ default:
+ dev_err(core->dev, "Unsupported color format : %d\n", sampling);
+ return -EINVAL;
+ }
+
+ xsdirxss_get_framerate(&state->frame_interval, framerate);
+
+ dev_dbg(core->dev, "Stream width = %d height = %d Field = %d payload = 0x%08x ts = 0x%08x\n",
+ format->width, format->height, format->field, payload, val);
+ dev_dbg(core->dev, "frame rate numerator = %d denominator = %d\n",
+ state->frame_interval.numerator,
+ state->frame_interval.denominator);
+ dev_dbg(core->dev, "Stream code = 0x%x\n", format->code);
+ return 0;
+}
+
+/**
+ * xsdirxss_irq_handler - Interrupt handler for SDI Rx
+ * @irq: IRQ number
+ * @dev_id: Pointer to device state
+ *
+ * The SDI Rx interrupts are cleared by first setting and then clearing the bits
+ * in the interrupt clear register. The interrupt status register is read only.
+ *
+ * Return: IRQ_HANDLED after handling interrupts
+ */
+static irqreturn_t xsdirxss_irq_handler(int irq, void *dev_id)
+{
+ struct xsdirxss_state *state = (struct xsdirxss_state *)dev_id;
+ struct xsdirxss_core *core = &state->core;
+ u32 status;
+
+ status = xsdirxss_read(core, XSDIRX_ISR_REG);
+ dev_dbg(core->dev, "interrupt status = 0x%08x\n", status);
+
+ if (!status)
+ return IRQ_NONE;
+
+ if (status & XSDIRX_INTR_VIDLOCK_MASK) {
+ u32 val1, val2;
+
+ dev_dbg(core->dev, "video lock interrupt\n");
+ xsdirx_clearintr(core, XSDIRX_INTR_VIDLOCK_MASK);
+
+ val1 = xsdirxss_read(core, XSDIRX_MODE_DET_STAT_REG);
+ val2 = xsdirxss_read(core, XSDIRX_TS_DET_STAT_REG);
+
+ if ((val1 & XSDIRX_MODE_DET_STAT_MODE_LOCK_MASK) &&
+ (val2 & XSDIRX_TS_DET_STAT_LOCKED_MASK)) {
+ u32 mask = XSDIRX_RST_CTRL_RST_CRC_ERRCNT_MASK |
+ XSDIRX_RST_CTRL_RST_EDH_ERRCNT_MASK;
+
+ dev_dbg(core->dev, "mode & ts lock occurred\n");
+
+ xsdirxss_set(core, XSDIRX_RST_CTRL_REG, mask);
+ xsdirxss_clr(core, XSDIRX_RST_CTRL_REG, mask);
+
+ val1 = xsdirxss_read(core, XSDIRX_ST352_VALID_REG);
+ val2 = xsdirxss_read(core, XSDIRX_ST352_DS1_REG);
+
+ dev_dbg(core->dev, "valid st352 mask = 0x%08x\n", val1);
+ dev_dbg(core->dev, "st352 payload = 0x%08x\n", val2);
+
+ if (!xsdirx_get_stream_properties(state)) {
+ memset(&state->event, 0, sizeof(state->event));
+ state->event.type = V4L2_EVENT_SOURCE_CHANGE;
+ state->event.u.src_change.changes =
+ V4L2_EVENT_SRC_CH_RESOLUTION;
+ v4l2_subdev_notify_event(&state->subdev,
+ &state->event);
+
+ state->vidlocked = true;
+ } else {
+ dev_err(core->dev, "Unable to get stream properties!\n");
+ state->vidlocked = false;
+ }
+ } else {
+ dev_dbg(core->dev, "video unlock before video lock!\n");
+ state->vidlocked = false;
+ }
+ }
+
+ if (status & XSDIRX_INTR_VIDUNLOCK_MASK) {
+ dev_dbg(core->dev, "video unlock interrupt\n");
+ xsdirx_clearintr(core, XSDIRX_INTR_VIDUNLOCK_MASK);
+ xsdirx_streamdowncb(core);
+
+ memset(&state->event, 0, sizeof(state->event));
+ state->event.type = V4L2_EVENT_XLNXSDIRX_VIDUNLOCK;
+ v4l2_subdev_notify_event(&state->subdev, &state->event);
+
+ state->vidlocked = false;
+ }
+
+ if (status & XSDIRX_INTR_UNDERFLOW_MASK) {
+ dev_dbg(core->dev, "Video in to AXI4 Stream core underflow interrupt\n");
+ xsdirx_clearintr(core, XSDIRX_INTR_UNDERFLOW_MASK);
+
+ memset(&state->event, 0, sizeof(state->event));
+ state->event.type = V4L2_EVENT_XLNXSDIRX_UNDERFLOW;
+ v4l2_subdev_notify_event(&state->subdev, &state->event);
+ }
+
+ if (status & XSDIRX_INTR_OVERFLOW_MASK) {
+ dev_dbg(core->dev, "Video in to AXI4 Stream core overflow interrupt\n");
+ xsdirx_clearintr(core, XSDIRX_INTR_OVERFLOW_MASK);
+
+ memset(&state->event, 0, sizeof(state->event));
+ state->event.type = V4L2_EVENT_XLNXSDIRX_OVERFLOW;
+ v4l2_subdev_notify_event(&state->subdev, &state->event);
+ }
+ return IRQ_HANDLED;
+}
+
+/**
+ * xsdirxss_subscribe_event - Subscribe to video lock and unlock event
+ * @sd: V4L2 Sub device
+ * @fh: V4L2 File Handle
+ * @sub: Subcribe event structure
+ *
+ * Return: 0 on success, errors otherwise
+ */
+static int xsdirxss_subscribe_event(struct v4l2_subdev *sd,
+ struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ int ret;
+ struct xsdirxss_state *xsdirxss = to_xsdirxssstate(sd);
+ struct xsdirxss_core *core = &xsdirxss->core;
+
+ switch (sub->type) {
+ case V4L2_EVENT_XLNXSDIRX_VIDUNLOCK:
+ case V4L2_EVENT_XLNXSDIRX_UNDERFLOW:
+ case V4L2_EVENT_XLNXSDIRX_OVERFLOW:
+ ret = v4l2_event_subscribe(fh, sub, XSDIRX_MAX_EVENTS, NULL);
+ break;
+ case V4L2_EVENT_SOURCE_CHANGE:
+ ret = v4l2_src_change_event_subscribe(fh, sub);
+ break;
+ default:
+ return -EINVAL;
+ }
+ dev_dbg(core->dev, "Event subscribed : 0x%08x\n", sub->type);
+ return ret;
+}
+
+/**
+ * xsdirxss_unsubscribe_event - Unsubscribe from all events registered
+ * @sd: V4L2 Sub device
+ * @fh: V4L2 file handle
+ * @sub: pointer to Event unsubscription structure
+ *
+ * Return: zero on success, else a negative error code.
+ */
+static int xsdirxss_unsubscribe_event(struct v4l2_subdev *sd,
+ struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ struct xsdirxss_state *xsdirxss = to_xsdirxssstate(sd);
+ struct xsdirxss_core *core = &xsdirxss->core;
+
+ dev_dbg(core->dev, "Event unsubscribe : 0x%08x\n", sub->type);
+ return v4l2_event_unsubscribe(fh, sub);
+}
+
+/**
+ * xsdirxss_s_ctrl - This is used to set the Xilinx SDI Rx V4L2 controls
+ * @ctrl: V4L2 control to be set
+ *
+ * This function is used to set the V4L2 controls for the Xilinx SDI Rx
+ * Subsystem.
+ *
+ * Return: 0 on success, errors otherwise
+ */
+static int xsdirxss_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ int ret = 0;
+ struct xsdirxss_state *xsdirxss =
+ container_of(ctrl->handler,
+ struct xsdirxss_state, ctrl_handler);
+ struct xsdirxss_core *core = &xsdirxss->core;
+
+ dev_dbg(core->dev, "set ctrl id = 0x%08x val = 0x%08x\n",
+ ctrl->id, ctrl->val);
+
+ if (xsdirxss->streaming) {
+ dev_err(core->dev, "Cannot set controls while streaming\n");
+ return -EINVAL;
+ }
+
+ xsdirx_core_disable(core);
+ switch (ctrl->id) {
+ case V4L2_CID_XILINX_SDIRX_FRAMER:
+ xsdirx_framer(core, ctrl->val);
+ break;
+ case V4L2_CID_XILINX_SDIRX_VIDLOCK_WINDOW:
+ xsdirx_setvidlockwindow(core, ctrl->val);
+ break;
+ case V4L2_CID_XILINX_SDIRX_EDH_ERRCNT_ENABLE:
+ xsdirx_setedherrcnttrigger(core, ctrl->val);
+ break;
+ case V4L2_CID_XILINX_SDIRX_SEARCH_MODES:
+ if (ctrl->val) {
+ if (core->mode == XSDIRXSS_SDI_STD_3G) {
+ dev_dbg(core->dev, "Upto 3G supported\n");
+ ctrl->val &= ~(BIT(XSDIRX_MODE_6G_OFFSET) |
+ BIT(XSDIRX_MODE_12GI_OFFSET) |
+ BIT(XSDIRX_MODE_12GF_OFFSET));
+ }
+
+ if (core->mode == XSDIRXSS_SDI_STD_6G) {
+ dev_dbg(core->dev, "Upto 6G supported\n");
+ ctrl->val &= ~(BIT(XSDIRX_MODE_12GI_OFFSET) |
+ BIT(XSDIRX_MODE_12GF_OFFSET));
+ }
+
+ ret = xsdirx_set_modedetect(core, ctrl->val);
+ } else {
+ dev_err(core->dev, "Select at least one mode!\n");
+ return -EINVAL;
+ }
+ break;
+ default:
+ xsdirxss_set(core, XSDIRX_RST_CTRL_REG,
+ XSDIRX_RST_CTRL_SS_EN_MASK);
+ return -EINVAL;
+ }
+ xsdirx_core_enable(core);
+ return ret;
+}
+
+/**
+ * xsdirxss_g_volatile_ctrl - get the Xilinx SDI Rx controls
+ * @ctrl: Pointer to V4L2 control
+ *
+ * Return: 0 on success, errors otherwise
+ */
+static int xsdirxss_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ u32 val;
+ struct xsdirxss_state *xsdirxss =
+ container_of(ctrl->handler,
+ struct xsdirxss_state, ctrl_handler);
+ struct xsdirxss_core *core = &xsdirxss->core;
+
+ switch (ctrl->id) {
+ case V4L2_CID_XILINX_SDIRX_MODE_DETECT:
+ if (!xsdirxss->vidlocked) {
+ dev_err(core->dev, "Can't get values when video not locked!\n");
+ return -EINVAL;
+ }
+ val = xsdirxss_read(core, XSDIRX_MODE_DET_STAT_REG);
+ val &= XSDIRX_MODE_DET_STAT_RX_MODE_MASK;
+
+ switch (val) {
+ case XSDIRX_MODE_SD_MASK:
+ ctrl->val = XSDIRX_MODE_SD_OFFSET;
+ break;
+ case XSDIRX_MODE_HD_MASK:
+ ctrl->val = XSDIRX_MODE_HD_OFFSET;
+ break;
+ case XSDIRX_MODE_3G_MASK:
+ ctrl->val = XSDIRX_MODE_3G_OFFSET;
+ break;
+ case XSDIRX_MODE_6G_MASK:
+ ctrl->val = XSDIRX_MODE_6G_OFFSET;
+ break;
+ case XSDIRX_MODE_12GI_MASK:
+ ctrl->val = XSDIRX_MODE_12GI_OFFSET;
+ break;
+ case XSDIRX_MODE_12GF_MASK:
+ ctrl->val = XSDIRX_MODE_12GF_OFFSET;
+ break;
+ }
+ break;
+ case V4L2_CID_XILINX_SDIRX_CRC:
+ ctrl->val = xsdirxss_read(core, XSDIRX_CRC_ERRCNT_REG);
+ xsdirxss_write(core, XSDIRX_CRC_ERRCNT_REG, 0xFFFF);
+ break;
+ case V4L2_CID_XILINX_SDIRX_EDH_ERRCNT:
+ val = xsdirxss_read(core, XSDIRX_MODE_DET_STAT_REG);
+ val &= XSDIRX_MODE_DET_STAT_RX_MODE_MASK;
+ if (val == XSDIRX_MODE_SD_MASK) {
+ ctrl->val = xsdirxss_read(core, XSDIRX_EDH_ERRCNT_REG);
+ } else {
+ dev_dbg(core->dev, "%d - not in SD mode\n", ctrl->id);
+ return -EINVAL;
+ }
+ break;
+ case V4L2_CID_XILINX_SDIRX_EDH_STATUS:
+ val = xsdirxss_read(core, XSDIRX_MODE_DET_STAT_REG);
+ val &= XSDIRX_MODE_DET_STAT_RX_MODE_MASK;
+ if (val == XSDIRX_MODE_SD_MASK) {
+ ctrl->val = xsdirxss_read(core, XSDIRX_EDH_STAT_REG);
+ } else {
+ dev_dbg(core->dev, "%d - not in SD mode\n", ctrl->id);
+ return -EINVAL;
+ }
+ break;
+ case V4L2_CID_XILINX_SDIRX_TS_IS_INTERLACED:
+ if (!xsdirxss->vidlocked) {
+ dev_err(core->dev, "Can't get values when video not locked!\n");
+ return -EINVAL;
+ }
+ ctrl->val = xsdirxss->ts_is_interlaced;
+ break;
+ case V4L2_CID_XILINX_SDIRX_ACTIVE_STREAMS:
+ if (!xsdirxss->vidlocked) {
+ dev_err(core->dev, "Can't get values when video not locked!\n");
+ return -EINVAL;
+ }
+ val = xsdirxss_read(core, XSDIRX_MODE_DET_STAT_REG);
+ val &= XSDIRX_MODE_DET_STAT_ACT_STREAM_MASK;
+ val >>= XSDIRX_MODE_DET_STAT_ACT_STREAM_OFFSET;
+ ctrl->val = 1 << val;
+ break;
+ case V4L2_CID_XILINX_SDIRX_IS_3GB:
+ if (!xsdirxss->vidlocked) {
+ dev_err(core->dev, "Can't get values when video not locked!\n");
+ return -EINVAL;
+ }
+ val = xsdirxss_read(core, XSDIRX_MODE_DET_STAT_REG);
+ val &= XSDIRX_MODE_DET_STAT_LVLB_3G_MASK;
+ ctrl->val = val ? true : false;
+ break;
+ default:
+ dev_err(core->dev, "Get Invalid control id 0x%0x\n", ctrl->id);
+ return -EINVAL;
+ }
+ dev_dbg(core->dev, "Get ctrl id = 0x%08x val = 0x%08x\n",
+ ctrl->id, ctrl->val);
+ return 0;
+}
+
+/**
+ * xsdirxss_log_status - Logs the status of the SDI Rx Subsystem
+ * @sd: Pointer to V4L2 subdevice structure
+ *
+ * This function prints the current status of Xilinx SDI Rx Subsystem
+ *
+ * Return: 0 on success
+ */
+static int xsdirxss_log_status(struct v4l2_subdev *sd)
+{
+ struct xsdirxss_state *xsdirxss = to_xsdirxssstate(sd);
+ struct xsdirxss_core *core = &xsdirxss->core;
+ u32 data, i;
+
+ v4l2_info(sd, "***** SDI Rx subsystem reg dump start *****\n");
+ for (i = 0; i < 0x28; i++) {
+ data = xsdirxss_read(core, i * 4);
+ v4l2_info(sd, "offset 0x%08x data 0x%08x\n",
+ i * 4, data);
+ }
+ v4l2_info(sd, "***** SDI Rx subsystem reg dump end *****\n");
+ return 0;
+}
+
+static void xsdirxss_start_stream(struct xsdirxss_state *xsdirxss)
+{
+ xsdirx_streamflow_control(&xsdirxss->core, true);
+}
+
+static void xsdirxss_stop_stream(struct xsdirxss_state *xsdirxss)
+{
+ xsdirx_streamflow_control(&xsdirxss->core, false);
+}
+
+/**
+ * xsdirxss_g_frame_interval - Get the frame interval
+ * @sd: V4L2 Sub device
+ * @fi: Pointer to V4l2 Sub device frame interval structure
+ *
+ * This function is used to get the frame interval.
+ * The frame rate can be integral or fractional.
+ * Integral frame rate e.g. numerator = 1000, denominator = 24000 => 24 fps
+ * Fractional frame rate e.g. numerator = 1001, denominator = 24000 => 23.97 fps
+ *
+ * Return: 0 on success
+ */
+static int xsdirxss_g_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ struct xsdirxss_state *xsdirxss = to_xsdirxssstate(sd);
+ struct xsdirxss_core *core = &xsdirxss->core;
+
+ if (!xsdirxss->vidlocked) {
+ dev_err(core->dev, "Video not locked!\n");
+ return -EINVAL;
+ }
+
+ fi->interval = xsdirxss->frame_interval;
+
+ dev_dbg(core->dev, "frame rate numerator = %d denominator = %d\n",
+ xsdirxss->frame_interval.numerator,
+ xsdirxss->frame_interval.denominator);
+ return 0;
+}
+
+/**
+ * xsdirxss_s_stream - It is used to start/stop the streaming.
+ * @sd: V4L2 Sub device
+ * @enable: Flag (True / False)
+ *
+ * This function controls the start or stop of streaming for the
+ * Xilinx SDI Rx Subsystem.
+ *
+ * Return: 0 on success, errors otherwise
+ */
+static int xsdirxss_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct xsdirxss_state *xsdirxss = to_xsdirxssstate(sd);
+ struct xsdirxss_core *core = &xsdirxss->core;
+
+ if (enable) {
+ if (!xsdirxss->vidlocked) {
+ dev_dbg(core->dev, "Video is not locked\n");
+ return -EINVAL;
+ }
+ if (xsdirxss->streaming) {
+ dev_dbg(core->dev, "Already streaming\n");
+ return -EINVAL;
+ }
+
+ xsdirxss_start_stream(xsdirxss);
+ xsdirxss->streaming = true;
+ dev_dbg(core->dev, "Streaming started\n");
+ } else {
+ if (!xsdirxss->streaming) {
+ dev_dbg(core->dev, "Stopped streaming already\n");
+ return -EINVAL;
+ }
+
+ xsdirxss_stop_stream(xsdirxss);
+ xsdirxss->streaming = false;
+ dev_dbg(core->dev, "Streaming stopped\n");
+ }
+
+ return 0;
+}
+
+static struct v4l2_mbus_framefmt *
+__xsdirxss_get_pad_format(struct xsdirxss_state *xsdirxss,
+ struct v4l2_subdev_pad_config *cfg,
+ unsigned int pad, u32 which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_format(&xsdirxss->subdev, cfg, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &xsdirxss->formats[pad];
+ default:
+ return NULL;
+ }
+}
+
+/**
+ * xsdirxss_get_format - Get the pad format
+ * @sd: Pointer to V4L2 Sub device structure
+ * @cfg: Pointer to sub device pad information structure
+ * @fmt: Pointer to pad level media bus format
+ *
+ * This function is used to get the pad format information.
+ *
+ * Return: 0 on success
+ */
+static int xsdirxss_get_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xsdirxss_state *xsdirxss = to_xsdirxssstate(sd);
+ struct xsdirxss_core *core = &xsdirxss->core;
+
+ if (!xsdirxss->vidlocked) {
+ dev_err(core->dev, "Video not locked!\n");
+ return -EINVAL;
+ }
+
+ fmt->format = *__xsdirxss_get_pad_format(xsdirxss, cfg,
+ fmt->pad, fmt->which);
+
+ dev_dbg(core->dev, "Stream width = %d height = %d Field = %d\n",
+ fmt->format.width, fmt->format.height, fmt->format.field);
+
+ return 0;
+}
+
+/**
+ * xsdirxss_set_format - This is used to set the pad format
+ * @sd: Pointer to V4L2 Sub device structure
+ * @cfg: Pointer to sub device pad information structure
+ * @fmt: Pointer to pad level media bus format
+ *
+ * This function is used to set the pad format.
+ * Since the pad format is fixed in hardware, it can't be
+ * modified on run time.
+ *
+ * Return: 0 on success
+ */
+static int xsdirxss_set_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct v4l2_mbus_framefmt *__format;
+ struct xsdirxss_state *xsdirxss = to_xsdirxssstate(sd);
+
+ dev_dbg(xsdirxss->core.dev,
+ "set width %d height %d code %d field %d colorspace %d\n",
+ fmt->format.width, fmt->format.height,
+ fmt->format.code, fmt->format.field,
+ fmt->format.colorspace);
+
+ __format = __xsdirxss_get_pad_format(xsdirxss, cfg,
+ fmt->pad, fmt->which);
+
+ /* Currently reset the code to one fixed in hardware */
+ /* TODO : Add checks for width height */
+ fmt->format.code = __format->code;
+
+ return 0;
+}
+
+/**
+ * xsdirxss_open - Called on v4l2_open()
+ * @sd: Pointer to V4L2 sub device structure
+ * @fh: Pointer to V4L2 File handle
+ *
+ * This function is called on v4l2_open(). It sets the default format for pad.
+ *
+ * Return: 0 on success
+ */
+static int xsdirxss_open(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ struct v4l2_mbus_framefmt *format;
+ struct xsdirxss_state *xsdirxss = to_xsdirxssstate(sd);
+
+ format = v4l2_subdev_get_try_format(sd, fh->pad, 0);
+ *format = xsdirxss->default_format;
+
+ return 0;
+}
+
+/**
+ * xsdirxss_close - Called on v4l2_close()
+ * @sd: Pointer to V4L2 sub device structure
+ * @fh: Pointer to V4L2 File handle
+ *
+ * This function is called on v4l2_close().
+ *
+ * Return: 0 on success
+ */
+static int xsdirxss_close(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Media Operations
+ */
+
+static const struct media_entity_operations xsdirxss_media_ops = {
+ .link_validate = v4l2_subdev_link_validate
+};
+
+static const struct v4l2_ctrl_ops xsdirxss_ctrl_ops = {
+ .g_volatile_ctrl = xsdirxss_g_volatile_ctrl,
+ .s_ctrl = xsdirxss_s_ctrl
+};
+
+static struct v4l2_ctrl_config xsdirxss_edh_ctrls[] = {
+ {
+ .ops = &xsdirxss_ctrl_ops,
+ .id = V4L2_CID_XILINX_SDIRX_EDH_ERRCNT_ENABLE,
+ .name = "SDI Rx : EDH Error Count Enable",
+ .type = V4L2_CTRL_TYPE_BITMASK,
+ .min = 0,
+ .max = XSDIRX_EDH_ALLERR_MASK,
+ .def = 0,
+ }, {
+ .ops = &xsdirxss_ctrl_ops,
+ .id = V4L2_CID_XILINX_SDIRX_EDH_ERRCNT,
+ .name = "SDI Rx : EDH Error Count",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = 0xFFFF,
+ .step = 1,
+ .def = 0,
+ .flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
+ }, {
+ .ops = &xsdirxss_ctrl_ops,
+ .id = V4L2_CID_XILINX_SDIRX_EDH_STATUS,
+ .name = "SDI Rx : EDH Status",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = 0xFFFFFFFF,
+ .step = 1,
+ .def = 0,
+ .flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
+ }
+};
+
+static struct v4l2_ctrl_config xsdirxss_ctrls[] = {
+ {
+ .ops = &xsdirxss_ctrl_ops,
+ .id = V4L2_CID_XILINX_SDIRX_FRAMER,
+ .name = "SDI Rx : Enable Framer",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = false,
+ .max = true,
+ .step = 1,
+ .def = true,
+ }, {
+ .ops = &xsdirxss_ctrl_ops,
+ .id = V4L2_CID_XILINX_SDIRX_VIDLOCK_WINDOW,
+ .name = "SDI Rx : Video Lock Window",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = 0xFFFFFFFF,
+ .step = 1,
+ .def = XSDIRX_DEFAULT_VIDEO_LOCK_WINDOW,
+ }, {
+ .ops = &xsdirxss_ctrl_ops,
+ .id = V4L2_CID_XILINX_SDIRX_SEARCH_MODES,
+ .name = "SDI Rx : Modes search Mask",
+ .type = V4L2_CTRL_TYPE_BITMASK,
+ .min = 0,
+ .max = XSDIRX_DETECT_ALL_MODES,
+ .def = XSDIRX_DETECT_ALL_MODES,
+ }, {
+ .ops = &xsdirxss_ctrl_ops,
+ .id = V4L2_CID_XILINX_SDIRX_MODE_DETECT,
+ .name = "SDI Rx : Mode Detect Status",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = XSDIRX_MODE_SD_OFFSET,
+ .max = XSDIRX_MODE_12GF_OFFSET,
+ .step = 1,
+ .flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
+ }, {
+ .ops = &xsdirxss_ctrl_ops,
+ .id = V4L2_CID_XILINX_SDIRX_CRC,
+ .name = "SDI Rx : CRC Error status",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = 0xFFFFFFFF,
+ .step = 1,
+ .def = 0,
+ .flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
+ }, {
+ .ops = &xsdirxss_ctrl_ops,
+ .id = V4L2_CID_XILINX_SDIRX_TS_IS_INTERLACED,
+ .name = "SDI Rx : TS is Interlaced",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = false,
+ .max = true,
+ .def = false,
+ .step = 1,
+ .flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
+ }, {
+ .ops = &xsdirxss_ctrl_ops,
+ .id = V4L2_CID_XILINX_SDIRX_ACTIVE_STREAMS,
+ .name = "SDI Rx : Active Streams",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 1,
+ .max = 16,
+ .def = 1,
+ .step = 1,
+ .flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
+ }, {
+ .ops = &xsdirxss_ctrl_ops,
+ .id = V4L2_CID_XILINX_SDIRX_IS_3GB,
+ .name = "SDI Rx : Is 3GB",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = false,
+ .max = true,
+ .def = false,
+ .step = 1,
+ .flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
+ }
+};
+
+static const struct v4l2_subdev_core_ops xsdirxss_core_ops = {
+ .log_status = xsdirxss_log_status,
+ .subscribe_event = xsdirxss_subscribe_event,
+ .unsubscribe_event = xsdirxss_unsubscribe_event
+};
+
+static struct v4l2_subdev_video_ops xsdirxss_video_ops = {
+ .g_frame_interval = xsdirxss_g_frame_interval,
+ .s_stream = xsdirxss_s_stream
+};
+
+static struct v4l2_subdev_pad_ops xsdirxss_pad_ops = {
+ .get_fmt = xsdirxss_get_format,
+ .set_fmt = xsdirxss_set_format,
+};
+
+static struct v4l2_subdev_ops xsdirxss_ops = {
+ .core = &xsdirxss_core_ops,
+ .video = &xsdirxss_video_ops,
+ .pad = &xsdirxss_pad_ops
+};
+
+static const struct v4l2_subdev_internal_ops xsdirxss_internal_ops = {
+ .open = xsdirxss_open,
+ .close = xsdirxss_close
+};
+
+/* -----------------------------------------------------------------------------
+ * Platform Device Driver
+ */
+
+static int xsdirxss_parse_of(struct xsdirxss_state *xsdirxss)
+{
+ struct device_node *node = xsdirxss->core.dev->of_node;
+ struct device_node *ports = NULL;
+ struct device_node *port = NULL;
+ unsigned int nports = 0;
+ struct xsdirxss_core *core = &xsdirxss->core;
+ int ret;
+ const char *sdi_std;
+
+ core->include_edh = of_property_read_bool(node, "xlnx,include-edh");
+ dev_dbg(core->dev, "EDH property = %s\n",
+ core->include_edh ? "Present" : "Absent");
+
+ ret = of_property_read_string(node, "xlnx,line-rate",
+ &sdi_std);
+ if (ret < 0) {
+ dev_err(core->dev, "xlnx,line-rate property not found\n");
+ return ret;
+ }
+
+ if (!strncmp(sdi_std, "12G_SDI_8DS", XSDIRX_MAX_STR_LENGTH)) {
+ core->mode = XSDIRXSS_SDI_STD_12G_8DS;
+ } else if (!strncmp(sdi_std, "6G_SDI", XSDIRX_MAX_STR_LENGTH)) {
+ core->mode = XSDIRXSS_SDI_STD_6G;
+ } else if (!strncmp(sdi_std, "3G_SDI", XSDIRX_MAX_STR_LENGTH)) {
+ core->mode = XSDIRXSS_SDI_STD_3G;
+ } else {
+ dev_err(core->dev, "Invalid Line Rate\n");
+ return -EINVAL;
+ }
+ dev_dbg(core->dev, "SDI Rx Line Rate = %s, mode = %d\n", sdi_std,
+ core->mode);
+
+ ports = of_get_child_by_name(node, "ports");
+ if (!ports)
+ ports = node;
+
+ for_each_child_of_node(ports, port) {
+ const struct xvip_video_format *format;
+ struct device_node *endpoint;
+
+ if (!port->name || of_node_cmp(port->name, "port"))
+ continue;
+
+ format = xvip_of_get_format(port);
+ if (IS_ERR(format)) {
+ dev_err(core->dev, "invalid format in DT");
+ return PTR_ERR(format);
+ }
+
+ dev_dbg(core->dev, "vf_code = %d bpc = %d bpp = %d\n",
+ format->vf_code, format->width, format->bpp);
+
+ if (format->vf_code != XVIP_VF_YUV_422 &&
+ format->vf_code != XVIP_VF_YUV_420) {
+ dev_err(core->dev, "Incorrect UG934 video format set.\n");
+ return -EINVAL;
+ }
+ xsdirxss->vip_format = format;
+
+ endpoint = of_get_next_child(port, NULL);
+ if (!endpoint) {
+ dev_err(core->dev, "No port at\n");
+ return -EINVAL;
+ }
+
+ /* Count the number of ports. */
+ nports++;
+ }
+
+ if (nports != 1) {
+ dev_err(core->dev, "invalid number of ports %u\n", nports);
+ return -EINVAL;
+ }
+
+ /* Register interrupt handler */
+ core->irq = irq_of_parse_and_map(node, 0);
+
+ ret = devm_request_irq(core->dev, core->irq, xsdirxss_irq_handler,
+ IRQF_SHARED, "xilinx-sdirxss", xsdirxss);
+ if (ret) {
+ dev_err(core->dev, "Err = %d Interrupt handler reg failed!\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int xsdirxss_probe(struct platform_device *pdev)
+{
+ struct v4l2_subdev *subdev;
+ struct xsdirxss_state *xsdirxss;
+ struct xsdirxss_core *core;
+ struct resource *res;
+ int ret;
+ unsigned int num_ctrls, num_edh_ctrls = 0, i;
+
+ xsdirxss = devm_kzalloc(&pdev->dev, sizeof(*xsdirxss), GFP_KERNEL);
+ if (!xsdirxss)
+ return -ENOMEM;
+
+ xsdirxss->core.dev = &pdev->dev;
+ core = &xsdirxss->core;
+
+ core->axi_clk = devm_clk_get(&pdev->dev, "s_axi_aclk");
+ if (IS_ERR(core->axi_clk)) {
+ ret = PTR_ERR(core->axi_clk);
+ dev_err(&pdev->dev, "failed to get s_axi_clk (%d)\n", ret);
+ return ret;
+ }
+
+ core->sdirx_clk = devm_clk_get(&pdev->dev, "sdi_rx_clk");
+ if (IS_ERR(core->sdirx_clk)) {
+ ret = PTR_ERR(core->sdirx_clk);
+ dev_err(&pdev->dev, "failed to get sdi_rx_clk (%d)\n", ret);
+ return ret;
+ }
+
+ core->vidout_clk = devm_clk_get(&pdev->dev, "video_out_clk");
+ if (IS_ERR(core->vidout_clk)) {
+ ret = PTR_ERR(core->vidout_clk);
+ dev_err(&pdev->dev, "failed to get video_out_aclk (%d)\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(core->axi_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable axi_clk (%d)\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(core->sdirx_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable sdirx_clk (%d)\n", ret);
+ goto rx_clk_err;
+ }
+
+ ret = clk_prepare_enable(core->vidout_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable vidout_clk (%d)\n", ret);
+ goto vidout_clk_err;
+ }
+
+ ret = xsdirxss_parse_of(xsdirxss);
+ if (ret < 0)
+ goto clk_err;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ xsdirxss->core.iomem = devm_ioremap_resource(xsdirxss->core.dev, res);
+ if (IS_ERR(xsdirxss->core.iomem)) {
+ ret = PTR_ERR(xsdirxss->core.iomem);
+ goto clk_err;
+ }
+
+ /* Reset the core */
+ xsdirx_streamflow_control(core, false);
+ xsdirx_core_disable(core);
+ xsdirx_clearintr(core, XSDIRX_INTR_ALL_MASK);
+ xsdirx_disableintr(core, XSDIRX_INTR_ALL_MASK);
+ xsdirx_enableintr(core, XSDIRX_INTR_ALL_MASK);
+ xsdirx_globalintr(core, true);
+ xsdirxss_write(core, XSDIRX_CRC_ERRCNT_REG, 0xFFFF);
+
+ /* Initialize V4L2 subdevice and media entity */
+ xsdirxss->pads[0].flags = MEDIA_PAD_FL_SOURCE;
+
+ /* Initialize the default format */
+ xsdirxss->default_format.code = xsdirxss->vip_format->code;
+ xsdirxss->default_format.field = V4L2_FIELD_NONE;
+ xsdirxss->default_format.colorspace = V4L2_COLORSPACE_DEFAULT;
+ xsdirxss->default_format.width = XSDIRX_DEFAULT_WIDTH;
+ xsdirxss->default_format.height = XSDIRX_DEFAULT_HEIGHT;
+
+ xsdirxss->formats[0] = xsdirxss->default_format;
+
+ /* Initialize V4L2 subdevice and media entity */
+ subdev = &xsdirxss->subdev;
+ v4l2_subdev_init(subdev, &xsdirxss_ops);
+
+ subdev->dev = &pdev->dev;
+ subdev->internal_ops = &xsdirxss_internal_ops;
+ strlcpy(subdev->name, dev_name(&pdev->dev), sizeof(subdev->name));
+
+ subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ subdev->entity.ops = &xsdirxss_media_ops;
+
+ v4l2_set_subdevdata(subdev, xsdirxss);
+
+ ret = media_entity_pads_init(&subdev->entity, 1, xsdirxss->pads);
+ if (ret < 0)
+ goto error;
+
+ /* Initialise and register the controls */
+ num_ctrls = ARRAY_SIZE(xsdirxss_ctrls);
+
+ if (xsdirxss->core.include_edh)
+ num_edh_ctrls = ARRAY_SIZE(xsdirxss_edh_ctrls);
+
+ v4l2_ctrl_handler_init(&xsdirxss->ctrl_handler,
+ (num_ctrls + num_edh_ctrls));
+
+ for (i = 0; i < num_ctrls; i++) {
+ struct v4l2_ctrl *ctrl;
+
+ dev_dbg(xsdirxss->core.dev, "%d %s ctrl = 0x%x\n",
+ i, xsdirxss_ctrls[i].name, xsdirxss_ctrls[i].id);
+
+ ctrl = v4l2_ctrl_new_custom(&xsdirxss->ctrl_handler,
+ &xsdirxss_ctrls[i], NULL);
+ if (!ctrl) {
+ dev_dbg(xsdirxss->core.dev, "Failed to add %s ctrl\n",
+ xsdirxss_ctrls[i].name);
+ goto error;
+ }
+ }
+
+ if (xsdirxss->core.include_edh) {
+ for (i = 0; i < num_edh_ctrls; i++) {
+ struct v4l2_ctrl *ctrl;
+
+ dev_dbg(xsdirxss->core.dev, "%d %s ctrl = 0x%x\n",
+ i, xsdirxss_edh_ctrls[i].name,
+ xsdirxss_edh_ctrls[i].id);
+
+ ctrl = v4l2_ctrl_new_custom(&xsdirxss->ctrl_handler,
+ &xsdirxss_edh_ctrls[i],
+ NULL);
+ if (!ctrl) {
+ dev_dbg(xsdirxss->core.dev, "Failed to add %s ctrl\n",
+ xsdirxss_edh_ctrls[i].name);
+ goto error;
+ }
+ }
+ } else {
+ dev_dbg(xsdirxss->core.dev, "Not registering the EDH controls as EDH is disabled in IP\n");
+ }
+
+ if (xsdirxss->ctrl_handler.error) {
+ dev_err(&pdev->dev, "failed to add controls\n");
+ ret = xsdirxss->ctrl_handler.error;
+ goto error;
+ }
+
+ subdev->ctrl_handler = &xsdirxss->ctrl_handler;
+
+ ret = v4l2_ctrl_handler_setup(&xsdirxss->ctrl_handler);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to set controls\n");
+ goto error;
+ }
+
+ platform_set_drvdata(pdev, xsdirxss);
+
+ ret = v4l2_async_register_subdev(subdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to register subdev\n");
+ goto error;
+ }
+
+ xsdirxss->streaming = false;
+
+ dev_info(xsdirxss->core.dev, "Xilinx SDI Rx Subsystem device found!\n");
+
+ xsdirx_core_enable(core);
+
+ return 0;
+error:
+ v4l2_ctrl_handler_free(&xsdirxss->ctrl_handler);
+ media_entity_cleanup(&subdev->entity);
+
+clk_err:
+ clk_disable_unprepare(core->vidout_clk);
+vidout_clk_err:
+ clk_disable_unprepare(core->sdirx_clk);
+rx_clk_err:
+ clk_disable_unprepare(core->axi_clk);
+ return ret;
+}
+
+static int xsdirxss_remove(struct platform_device *pdev)
+{
+ struct xsdirxss_state *xsdirxss = platform_get_drvdata(pdev);
+ struct v4l2_subdev *subdev = &xsdirxss->subdev;
+
+ v4l2_async_unregister_subdev(subdev);
+ v4l2_ctrl_handler_free(&xsdirxss->ctrl_handler);
+ media_entity_cleanup(&subdev->entity);
+ clk_disable_unprepare(xsdirxss->core.vidout_clk);
+ clk_disable_unprepare(xsdirxss->core.sdirx_clk);
+ clk_disable_unprepare(xsdirxss->core.axi_clk);
+ return 0;
+}
+
+static const struct of_device_id xsdirxss_of_id_table[] = {
+ { .compatible = "xlnx,v-smpte-uhdsdi-rx-ss" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, xsdirxss_of_id_table);
+
+static struct platform_driver xsdirxss_driver = {
+ .driver = {
+ .name = "xilinx-sdirxss",
+ .of_match_table = xsdirxss_of_id_table,
+ },
+ .probe = xsdirxss_probe,
+ .remove = xsdirxss_remove,
+};
+
+module_platform_driver(xsdirxss_driver);
+
+MODULE_AUTHOR("Vishal Sagar <vsagar@xilinx.com>");
+MODULE_DESCRIPTION("Xilinx SDI Rx Subsystem Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/xilinx/xilinx-switch.c b/drivers/media/platform/xilinx/xilinx-switch.c
new file mode 100644
index 000000000000..b0052a76c65d
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-switch.c
@@ -0,0 +1,460 @@
+/*
+ * Xilinx Video Switch
+ *
+ * Copyright (C) 2013-2015 Ideas on Board
+ * Copyright (C) 2013-2015 Xilinx, Inc.
+ *
+ * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
+ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include <media/media-device.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-subdev.h>
+
+#include "xilinx-vip.h"
+
+#define XSW_CORE_CH_CTRL 0x0100
+#define XSW_CORE_CH_CTRL_FORCE (1 << 3)
+
+#define XSW_SWITCH_STATUS 0x0104
+
+/**
+ * struct xswitch_device - Xilinx Video Switch device structure
+ * @xvip: Xilinx Video IP device
+ * @pads: media pads
+ * @nsinks: number of sink pads (2 to 8)
+ * @nsources: number of source pads (1 to 8)
+ * @routing: sink pad connected to each source pad (-1 if none)
+ * @formats: active V4L2 media bus formats on sink pads
+ */
+struct xswitch_device {
+ struct xvip_device xvip;
+
+ struct media_pad *pads;
+ unsigned int nsinks;
+ unsigned int nsources;
+
+ int routing[8];
+
+ struct v4l2_mbus_framefmt *formats;
+};
+
+static inline struct xswitch_device *to_xsw(struct v4l2_subdev *subdev)
+{
+ return container_of(subdev, struct xswitch_device, xvip.subdev);
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Video Operations
+ */
+
+static int xsw_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+ struct xswitch_device *xsw = to_xsw(subdev);
+ unsigned int unused_input;
+ unsigned int i;
+ u32 routing;
+
+ if (!enable) {
+ xvip_stop(&xsw->xvip);
+ return 0;
+ }
+
+ /*
+ * All outputs must be routed to an input. When less than 8 inputs are
+ * synthesized we can use input 7 for that purpose. Otherwise find an
+ * unused input to connect to unused outputs.
+ */
+ if (xsw->nsinks == 8) {
+ u32 mask;
+
+ for (i = 0, mask = 0xff; i < xsw->nsources; ++i) {
+ if (xsw->routing[i] != -1)
+ mask &= ~BIT(xsw->routing[i]);
+ }
+
+ /*
+ * If all inputs are used all outputs are also used. We don't
+ * need an unused input in that case, use a zero value.
+ */
+ unused_input = mask ? ffs(mask) - 1 : 0;
+ } else {
+ unused_input = 7;
+ }
+
+ /* Configure routing. */
+ for (i = 0, routing = 0; i < xsw->nsources; ++i) {
+ unsigned int route;
+
+ route = xsw->routing[i] == -1 ? unused_input : xsw->routing[i];
+ routing |= (XSW_CORE_CH_CTRL_FORCE | route)
+ << (i * 4);
+ }
+
+ xvip_write(&xsw->xvip, XSW_CORE_CH_CTRL, routing);
+
+ xvip_write(&xsw->xvip, XVIP_CTRL_CONTROL,
+ (((1 << xsw->nsources) - 1) << 4) |
+ XVIP_CTRL_CONTROL_SW_ENABLE);
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Pad Operations
+ */
+
+static struct v4l2_mbus_framefmt *
+xsw_get_pad_format(struct xswitch_device *xsw,
+ struct v4l2_subdev_pad_config *cfg,
+ unsigned int pad, u32 which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_format(&xsw->xvip.subdev, cfg, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &xsw->formats[pad];
+ default:
+ return NULL;
+ }
+}
+
+static int xsw_get_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xswitch_device *xsw = to_xsw(subdev);
+ int pad = fmt->pad;
+
+ if (pad >= xsw->nsinks) {
+ pad = xsw->routing[pad - xsw->nsinks];
+ if (pad < 0) {
+ memset(&fmt->format, 0, sizeof(fmt->format));
+ return 0;
+ }
+ }
+
+ fmt->format = *xsw_get_pad_format(xsw, cfg, pad, fmt->which);
+
+ return 0;
+}
+
+static int xsw_set_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xswitch_device *xsw = to_xsw(subdev);
+ struct v4l2_mbus_framefmt *format;
+
+ /* The source pad format is always identical to the sink pad format and
+ * can't be modified.
+ */
+ if (fmt->pad >= xsw->nsinks)
+ return xsw_get_format(subdev, cfg, fmt);
+
+ format = xsw_get_pad_format(xsw, cfg, fmt->pad, fmt->which);
+
+ format->code = fmt->format.code;
+ format->width = clamp_t(unsigned int, fmt->format.width,
+ XVIP_MIN_WIDTH, XVIP_MAX_WIDTH);
+ format->height = clamp_t(unsigned int, fmt->format.height,
+ XVIP_MIN_HEIGHT, XVIP_MAX_HEIGHT);
+ format->field = V4L2_FIELD_NONE;
+ format->colorspace = V4L2_COLORSPACE_SRGB;
+
+ fmt->format = *format;
+
+ return 0;
+}
+
+static int xsw_get_routing(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_routing *route)
+{
+ struct xswitch_device *xsw = to_xsw(subdev);
+ unsigned int i;
+
+ mutex_lock(&subdev->entity.graph_obj.mdev->graph_mutex);
+
+ for (i = 0; i < min(xsw->nsources, route->num_routes); ++i) {
+ route->routes[i].sink = xsw->routing[i];
+ route->routes[i].source = i;
+ }
+
+ route->num_routes = xsw->nsources;
+
+ mutex_unlock(&subdev->entity.graph_obj.mdev->graph_mutex);
+
+ return 0;
+}
+
+static int xsw_set_routing(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_routing *route)
+{
+ struct xswitch_device *xsw = to_xsw(subdev);
+ unsigned int i;
+ int ret = 0;
+
+ mutex_lock(&subdev->entity.graph_obj.mdev->graph_mutex);
+
+ if (subdev->entity.stream_count) {
+ ret = -EBUSY;
+ goto done;
+ }
+
+ for (i = 0; i < xsw->nsources; ++i)
+ xsw->routing[i] = -1;
+
+ for (i = 0; i < route->num_routes; ++i)
+ xsw->routing[route->routes[i].source - xsw->nsinks] =
+ route->routes[i].sink;
+
+done:
+ mutex_unlock(&subdev->entity.graph_obj.mdev->graph_mutex);
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Operations
+ */
+
+/**
+ * xsw_init_formats - Initialize formats on all pads
+ * @subdev: tpgper V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ *
+ * Initialize all pad formats with default values. If fh is not NULL, try
+ * formats are initialized on the file handle. Otherwise active formats are
+ * initialized on the device.
+ *
+ * The function sets the format on pad 0 only. In two pads mode, this is the
+ * sink pad and the set format handler will propagate the format to the source
+ * pad. In one pad mode this is the source pad.
+ */
+static void xsw_init_formats(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh)
+{
+ struct xswitch_device *xsw = to_xsw(subdev);
+ struct v4l2_subdev_format format;
+ unsigned int i;
+
+ for (i = 0; i < xsw->nsinks; ++i) {
+ memset(&format, 0, sizeof(format));
+
+ format.pad = 0;
+ format.which = fh ? V4L2_SUBDEV_FORMAT_TRY
+ : V4L2_SUBDEV_FORMAT_ACTIVE;
+ format.format.width = 1920;
+ format.format.height = 1080;
+
+ xsw_set_format(subdev, fh ? fh->pad : NULL, &format);
+ }
+}
+
+static int xsw_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ xsw_init_formats(subdev, fh);
+
+ return 0;
+}
+
+static int xsw_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ return 0;
+}
+
+static struct v4l2_subdev_video_ops xsw_video_ops = {
+ .s_stream = xsw_s_stream,
+};
+
+static struct v4l2_subdev_pad_ops xsw_pad_ops = {
+ .enum_mbus_code = xvip_enum_mbus_code,
+ .enum_frame_size = xvip_enum_frame_size,
+ .get_fmt = xsw_get_format,
+ .set_fmt = xsw_set_format,
+ .get_routing = xsw_get_routing,
+ .set_routing = xsw_set_routing,
+};
+
+static struct v4l2_subdev_ops xsw_ops = {
+ .video = &xsw_video_ops,
+ .pad = &xsw_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops xsw_internal_ops = {
+ .open = xsw_open,
+ .close = xsw_close,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media Operations
+ */
+
+static bool xsw_has_route(struct media_entity *entity, unsigned int pad0,
+ unsigned int pad1)
+{
+ struct xswitch_device *xsw = container_of(entity, struct xswitch_device,
+ xvip.subdev.entity);
+ unsigned int sink0, sink1;
+
+ /* Two sinks are never connected together. */
+ if (pad0 < xsw->nsinks && pad1 < xsw->nsinks)
+ return false;
+
+ sink0 = pad0 < xsw->nsinks ? pad0 : xsw->routing[pad0 - xsw->nsinks];
+ sink1 = pad1 < xsw->nsinks ? pad1 : xsw->routing[pad1 - xsw->nsinks];
+
+ return sink0 == sink1;
+}
+
+static const struct media_entity_operations xsw_media_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+ .has_route = xsw_has_route,
+};
+
+/* -----------------------------------------------------------------------------
+ * Platform Device Driver
+ */
+
+static int xsw_parse_of(struct xswitch_device *xsw)
+{
+ struct device_node *node = xsw->xvip.dev->of_node;
+ int ret;
+
+ ret = of_property_read_u32(node, "#xlnx,inputs", &xsw->nsinks);
+ if (ret < 0) {
+ dev_err(xsw->xvip.dev, "missing or invalid #xlnx,%s property\n",
+ "inputs");
+ return ret;
+ }
+
+ ret = of_property_read_u32(node, "#xlnx,outputs", &xsw->nsources);
+ if (ret < 0) {
+ dev_err(xsw->xvip.dev, "missing or invalid #xlnx,%s property\n",
+ "outputs");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int xsw_probe(struct platform_device *pdev)
+{
+ struct v4l2_subdev *subdev;
+ struct xswitch_device *xsw;
+ unsigned int npads;
+ unsigned int i;
+ int ret;
+
+ xsw = devm_kzalloc(&pdev->dev, sizeof(*xsw), GFP_KERNEL);
+ if (!xsw)
+ return -ENOMEM;
+
+ xsw->xvip.dev = &pdev->dev;
+
+ ret = xsw_parse_of(xsw);
+ if (ret < 0)
+ return ret;
+
+ ret = xvip_init_resources(&xsw->xvip);
+ if (ret < 0)
+ return ret;
+
+ /* Initialize V4L2 subdevice and media entity. Pad numbers depend on the
+ * number of pads.
+ */
+ npads = xsw->nsinks + xsw->nsources;
+ xsw->pads = devm_kzalloc(&pdev->dev, npads * sizeof(*xsw->pads),
+ GFP_KERNEL);
+ if (!xsw->pads)
+ goto error;
+
+ for (i = 0; i < xsw->nsinks; ++i)
+ xsw->pads[i].flags = MEDIA_PAD_FL_SINK;
+ for (; i < npads; ++i)
+ xsw->pads[i].flags = MEDIA_PAD_FL_SOURCE;
+
+ xsw->formats = devm_kzalloc(&pdev->dev,
+ xsw->nsinks * sizeof(*xsw->formats),
+ GFP_KERNEL);
+ if (!xsw->formats)
+ goto error;
+
+ for (i = 0; i < xsw->nsources; ++i)
+ xsw->routing[i] = i < xsw->nsinks ? i : -1;
+
+ subdev = &xsw->xvip.subdev;
+ v4l2_subdev_init(subdev, &xsw_ops);
+ subdev->dev = &pdev->dev;
+ subdev->internal_ops = &xsw_internal_ops;
+ strlcpy(subdev->name, dev_name(&pdev->dev), sizeof(subdev->name));
+ v4l2_set_subdevdata(subdev, xsw);
+ subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ subdev->entity.ops = &xsw_media_ops;
+
+ xsw_init_formats(subdev, NULL);
+
+ ret = media_entity_pads_init(&subdev->entity, npads, xsw->pads);
+ if (ret < 0)
+ goto error;
+
+ platform_set_drvdata(pdev, xsw);
+
+ xvip_print_version(&xsw->xvip);
+
+ ret = v4l2_async_register_subdev(subdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to register subdev\n");
+ goto error;
+ }
+
+ return 0;
+
+error:
+ media_entity_cleanup(&subdev->entity);
+ xvip_cleanup_resources(&xsw->xvip);
+ return ret;
+}
+
+static int xsw_remove(struct platform_device *pdev)
+{
+ struct xswitch_device *xsw = platform_get_drvdata(pdev);
+ struct v4l2_subdev *subdev = &xsw->xvip.subdev;
+
+ v4l2_async_unregister_subdev(subdev);
+ media_entity_cleanup(&subdev->entity);
+
+ xvip_cleanup_resources(&xsw->xvip);
+
+ return 0;
+}
+
+static const struct of_device_id xsw_of_id_table[] = {
+ { .compatible = "xlnx,v-switch-1.0" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, xsw_of_id_table);
+
+static struct platform_driver xsw_driver = {
+ .driver = {
+ .name = "xilinx-switch",
+ .of_match_table = xsw_of_id_table,
+ },
+ .probe = xsw_probe,
+ .remove = xsw_remove,
+};
+
+module_platform_driver(xsw_driver);
+
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_DESCRIPTION("Xilinx Video Switch Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/xilinx/xilinx-tpg.c b/drivers/media/platform/xilinx/xilinx-tpg.c
index ed01bedb5db6..f840bc098d9e 100644
--- a/drivers/media/platform/xilinx/xilinx-tpg.c
+++ b/drivers/media/platform/xilinx/xilinx-tpg.c
@@ -20,6 +20,7 @@
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
+#include "xilinx-hls-common.h"
#include "xilinx-vip.h"
#include "xilinx-vtc.h"
@@ -58,6 +59,36 @@
#define XTPG_BAYER_PHASE_BGGR 3
#define XTPG_BAYER_PHASE_OFF 4
+/* TPG v7 is a completely redesigned IP using Vivado HLS
+ * having a different AXI4-Lite interface
+ */
+#define XTPG_HLS_BG_PATTERN 0x0020
+#define XTPG_HLS_FG_PATTERN 0x0028
+#define XTPG_HLS_FG_PATTERN_CROSS_HAIR (1 << 1)
+#define XTPG_HLS_MASK_ID 0x0030
+#define XTPG_HLS_MOTION_SPEED 0x0038
+#define XTPG_HLS_COLOR_FORMAT 0x0040
+#define XTPG_HLS_COLOR_FORMAT_RGB 0
+#define XTPG_HLS_COLOR_FORMAT_YUV_444 1
+#define XTPG_HLS_COLOR_FORMAT_YUV_422 2
+#define XTPG_HLS_COLOR_FORMAT_YUV_420 3
+#define XTPG_HLS_CROSS_HAIR_HOR 0x0048
+#define XTPG_HLS_CROSS_HAIR_VER 0x0050
+#define XTPG_HLS_ZPLATE_HOR_CNTL_START 0x0058
+#define XTPG_HLS_ZPLATE_HOR_CNTL_DELTA 0x0060
+#define XTPG_HLS_ZPLATE_VER_CNTL_START 0x0068
+#define XTPG_HLS_ZPLATE_VER_CNTL_DELTA 0x0070
+#define XTPG_HLS_BOX_SIZE 0x0078
+#define XTPG_HLS_BOX_COLOR_RED_CB 0x0080
+#define XTPG_HLS_BOX_COLOR_GREEN_CR 0x0088
+#define XTPG_HLS_BOX_COLOR_BLUE_Y 0x0090
+#define XTPG_HLS_ENABLE_INPUT 0x0098
+#define XTPG_HLS_USE_INPUT_VID_STREAM (1 << 0)
+#define XTPG_HLS_PASS_THRU_START_X 0x00a0
+#define XTPG_HLS_PASS_THRU_START_Y 0x00a8
+#define XTPG_HLS_PASS_THRU_END_X 0x00b0
+#define XTPG_HLS_PASS_THRU_END_Y 0x00b8
+
/*
* The minimum blanking value is one clock cycle for the front porch, one clock
* cycle for the sync pulse and one clock cycle for the back porch.
@@ -67,6 +98,15 @@
#define XTPG_MIN_VBLANK 3
#define XTPG_MAX_VBLANK (XVTC_MAX_VSIZE - XVIP_MIN_HEIGHT)
+#define XTPG_MIN_WIDTH (64)
+#define XTPG_MIN_HEIGHT (64)
+#define XTPG_MAX_WIDTH (10328)
+#define XTPG_MAX_HEIGHT (7760)
+
+#define XTPG_MIN_PPC 1
+
+#define XTPG_MIN_FRM_INT 1
+
/**
* struct xtpg_device - Xilinx Test Pattern Generator device structure
* @xvip: Xilinx Video IP device
@@ -82,8 +122,15 @@
* @vblank: vertical blanking control
* @pattern: test pattern control
* @streaming: is the video stream active
+ * @is_hls: whether the IP core is HLS based
* @vtc: video timing controller
* @vtmux_gpio: video timing mux GPIO
+ * @rst_gpio: reset IP core GPIO
+ * @max_width: Maximum width supported by this instance
+ * @max_height: Maximum height supported by this instance
+ * @fi_d: frame interval denominator
+ * @fi_n: frame interval numerator
+ * @ppc: Pixels per clock control
*/
struct xtpg_device {
struct xvip_device xvip;
@@ -102,9 +149,17 @@ struct xtpg_device {
struct v4l2_ctrl *vblank;
struct v4l2_ctrl *pattern;
bool streaming;
+ bool is_hls;
struct xvtc_device *vtc;
struct gpio_desc *vtmux_gpio;
+ struct gpio_desc *rst_gpio;
+
+ u32 max_width;
+ u32 max_height;
+ u32 fi_d;
+ u32 fi_n;
+ u32 ppc;
};
static inline struct xtpg_device *to_tpg(struct v4l2_subdev *subdev)
@@ -128,6 +183,32 @@ static u32 xtpg_get_bayer_phase(unsigned int code)
}
}
+static void xtpg_config_vtc(struct xtpg_device *xtpg, int width, int height)
+{
+
+ struct xvtc_config config = {
+ .hblank_start = width / xtpg->ppc,
+ .hsync_start = width / xtpg->ppc + 1,
+ .vblank_start = height,
+ .vsync_start = height + 1,
+ .fps = xtpg->fi_d / xtpg->fi_n,
+ };
+ unsigned int htotal;
+ unsigned int vtotal;
+
+ htotal = min_t(unsigned int, XVTC_MAX_HSIZE,
+ (v4l2_ctrl_g_ctrl(xtpg->hblank) + width) / xtpg->ppc);
+ vtotal = min_t(unsigned int, XVTC_MAX_VSIZE,
+ v4l2_ctrl_g_ctrl(xtpg->vblank) + height);
+
+ config.hsync_end = htotal - 1;
+ config.hsize = htotal;
+ config.vsync_end = vtotal - 1;
+ config.vsize = vtotal;
+
+ xvtc_generator_start(xtpg->vtc, &config);
+}
+
static void __xtpg_update_pattern_control(struct xtpg_device *xtpg,
bool passthrough, bool pattern)
{
@@ -164,6 +245,33 @@ static void xtpg_update_pattern_control(struct xtpg_device *xtpg,
* V4L2 Subdevice Video Operations
*/
+static int xtpg_g_frame_interval(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ struct xtpg_device *xtpg = to_tpg(subdev);
+
+ fi->interval.numerator = xtpg->fi_n;
+ fi->interval.denominator = xtpg->fi_d;
+
+ return 0;
+}
+
+static int xtpg_s_frame_interval(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ struct xtpg_device *xtpg = to_tpg(subdev);
+
+ if (!fi->interval.numerator || !fi->interval.denominator) {
+ xtpg->fi_n = XTPG_MIN_FRM_INT;
+ xtpg->fi_d = XTPG_MIN_FRM_INT;
+ } else {
+ xtpg->fi_n = fi->interval.numerator;
+ xtpg->fi_d = fi->interval.denominator;
+ }
+
+ return 0;
+}
+
static int xtpg_s_stream(struct v4l2_subdev *subdev, int enable)
{
struct xtpg_device *xtpg = to_tpg(subdev);
@@ -173,7 +281,20 @@ static int xtpg_s_stream(struct v4l2_subdev *subdev, int enable)
u32 bayer_phase;
if (!enable) {
- xvip_stop(&xtpg->xvip);
+ if (!xtpg->is_hls) {
+ xvip_stop(&xtpg->xvip);
+ } else {
+ /*
+ * There is an known issue in TPG v7.0 that on
+ * resolution change it doesn't generates pattern
+ * correctly i.e some hor/ver offset is added.
+ * As a workaround issue reset on stop.
+ */
+ gpiod_set_value_cansleep(xtpg->rst_gpio, 0x1);
+ gpiod_set_value_cansleep(xtpg->rst_gpio, 0x0);
+ v4l2_ctrl_handler_setup(&xtpg->ctrl_handler);
+ }
+
if (xtpg->vtc)
xvtc_generator_stop(xtpg->vtc);
@@ -182,31 +303,36 @@ static int xtpg_s_stream(struct v4l2_subdev *subdev, int enable)
return 0;
}
- xvip_set_frame_size(&xtpg->xvip, &xtpg->formats[0]);
-
- if (xtpg->vtc) {
- struct xvtc_config config = {
- .hblank_start = width,
- .hsync_start = width + 1,
- .vblank_start = height,
- .vsync_start = height + 1,
- };
- unsigned int htotal;
- unsigned int vtotal;
-
- htotal = min_t(unsigned int, XVTC_MAX_HSIZE,
- v4l2_ctrl_g_ctrl(xtpg->hblank) + width);
- vtotal = min_t(unsigned int, XVTC_MAX_VSIZE,
- v4l2_ctrl_g_ctrl(xtpg->vblank) + height);
-
- config.hsync_end = htotal - 1;
- config.hsize = htotal;
- config.vsync_end = vtotal - 1;
- config.vsize = vtotal;
-
- xvtc_generator_start(xtpg->vtc, &config);
+ if (xtpg->is_hls) {
+ u32 fmt = 0;
+
+ switch (xtpg->formats[0].code) {
+ case MEDIA_BUS_FMT_VYYUYY8_1X24:
+ case MEDIA_BUS_FMT_VYYUYY10_4X20:
+ fmt = XTPG_HLS_COLOR_FORMAT_YUV_420;
+ break;
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_UYVY10_1X20:
+ fmt = XTPG_HLS_COLOR_FORMAT_YUV_422;
+ break;
+ case MEDIA_BUS_FMT_VUY8_1X24:
+ case MEDIA_BUS_FMT_VUY10_1X30:
+ fmt = XTPG_HLS_COLOR_FORMAT_YUV_444;
+ break;
+ case MEDIA_BUS_FMT_RBG888_1X24:
+ case MEDIA_BUS_FMT_RBG101010_1X30:
+ fmt = XTPG_HLS_COLOR_FORMAT_RGB;
+ break;
+ }
+ xvip_write(&xtpg->xvip, XTPG_HLS_COLOR_FORMAT, fmt);
+ xvip_write(&xtpg->xvip, XHLS_REG_COLS, width);
+ xvip_write(&xtpg->xvip, XHLS_REG_ROWS, height);
+ } else {
+ xvip_set_frame_size(&xtpg->xvip, &xtpg->formats[0]);
}
+ if (xtpg->vtc)
+ xtpg_config_vtc(xtpg, width, height);
/*
* Configure the bayer phase and video timing mux based on the
* operation mode (passthrough or test pattern generation). The test
@@ -215,7 +341,11 @@ static int xtpg_s_stream(struct v4l2_subdev *subdev, int enable)
*/
mutex_lock(xtpg->ctrl_handler.lock);
- xvip_clr_and_set(&xtpg->xvip, XTPG_PATTERN_CONTROL,
+ if (xtpg->is_hls)
+ xvip_write(&xtpg->xvip, XTPG_HLS_BG_PATTERN,
+ xtpg->pattern->cur.val);
+ else
+ xvip_clr_and_set(&xtpg->xvip, XTPG_PATTERN_CONTROL,
XTPG_PATTERN_MASK, xtpg->pattern->cur.val);
/*
@@ -229,18 +359,26 @@ static int xtpg_s_stream(struct v4l2_subdev *subdev, int enable)
mutex_unlock(xtpg->ctrl_handler.lock);
- /*
- * For TPG v5.0, the bayer phase needs to be off for the pass through
- * mode, otherwise the external input would be subsampled.
- */
- bayer_phase = passthrough ? XTPG_BAYER_PHASE_OFF
- : xtpg_get_bayer_phase(xtpg->formats[0].code);
- xvip_write(&xtpg->xvip, XTPG_BAYER_PHASE, bayer_phase);
-
if (xtpg->vtmux_gpio)
gpiod_set_value_cansleep(xtpg->vtmux_gpio, !passthrough);
- xvip_start(&xtpg->xvip);
+ if (xtpg->is_hls) {
+ xvip_set(&xtpg->xvip, XTPG_HLS_ENABLE_INPUT,
+ XTPG_HLS_USE_INPUT_VID_STREAM);
+ xvip_set(&xtpg->xvip, XVIP_CTRL_CONTROL,
+ XHLS_REG_CTRL_AUTO_RESTART |
+ XVIP_CTRL_CONTROL_SW_ENABLE);
+ } else {
+ /*
+ * For TPG v5.0, the bayer phase needs to be off for the pass
+ * through mode, otherwise the external input would
+ * be subsampled.
+ */
+ bayer_phase = passthrough ? XTPG_BAYER_PHASE_OFF
+ : xtpg_get_bayer_phase(xtpg->formats[0].code);
+ xvip_write(&xtpg->xvip, XTPG_BAYER_PHASE, bayer_phase);
+ xvip_start(&xtpg->xvip);
+ }
return 0;
}
@@ -300,7 +438,27 @@ static int xtpg_set_format(struct v4l2_subdev *subdev,
__format->code = fmt->format.code;
}
- xvip_set_format_size(__format, fmt);
+ if (xtpg->is_hls) {
+ switch (fmt->format.code) {
+ case MEDIA_BUS_FMT_VYYUYY8_1X24:
+ case MEDIA_BUS_FMT_VYYUYY10_4X20:
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_UYVY10_1X20:
+ case MEDIA_BUS_FMT_VUY8_1X24:
+ case MEDIA_BUS_FMT_VUY10_1X30:
+ case MEDIA_BUS_FMT_RBG888_1X24:
+ case MEDIA_BUS_FMT_RBG101010_1X30:
+ __format->code = fmt->format.code;
+ break;
+ default:
+ __format->code = xtpg->default_format.code;
+ }
+ }
+
+ __format->width = clamp_t(unsigned int, fmt->format.width,
+ XTPG_MIN_WIDTH, xtpg->max_width);
+ __format->height = clamp_t(unsigned int, fmt->format.height,
+ XTPG_MIN_HEIGHT, xtpg->max_height);
fmt->format = *__format;
@@ -322,6 +480,7 @@ static int xtpg_enum_frame_size(struct v4l2_subdev *subdev,
struct v4l2_subdev_frame_size_enum *fse)
{
struct v4l2_mbus_framefmt *format;
+ struct xtpg_device *xtpg = to_tpg(subdev);
format = v4l2_subdev_get_try_format(subdev, cfg, fse->pad);
@@ -330,12 +489,13 @@ static int xtpg_enum_frame_size(struct v4l2_subdev *subdev,
/* Min / max values for pad 0 is always fixed in both one and two pads
* modes. In two pads mode, the source pad(= 1) size is identical to
- * the sink pad size */
+ * the sink pad size.
+ */
if (fse->pad == 0) {
- fse->min_width = XVIP_MIN_WIDTH;
- fse->max_width = XVIP_MAX_WIDTH;
- fse->min_height = XVIP_MIN_HEIGHT;
- fse->max_height = XVIP_MAX_HEIGHT;
+ fse->min_width = XTPG_MIN_WIDTH;
+ fse->max_width = xtpg->max_width;
+ fse->min_height = XTPG_MIN_HEIGHT;
+ fse->max_height = xtpg->max_height;
} else {
fse->min_width = format->width;
fse->max_width = format->width;
@@ -374,8 +534,12 @@ static int xtpg_s_ctrl(struct v4l2_ctrl *ctrl)
ctrl_handler);
switch (ctrl->id) {
case V4L2_CID_TEST_PATTERN:
- xvip_clr_and_set(&xtpg->xvip, XTPG_PATTERN_CONTROL,
- XTPG_PATTERN_MASK, ctrl->val);
+ if (xtpg->is_hls)
+ xvip_write(&xtpg->xvip, XTPG_HLS_BG_PATTERN,
+ ctrl->val);
+ else
+ xvip_clr_and_set(&xtpg->xvip, XTPG_PATTERN_CONTROL,
+ XTPG_PATTERN_MASK, ctrl->val);
return 0;
case V4L2_CID_XILINX_TPG_CROSS_HAIRS:
xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL,
@@ -386,10 +550,13 @@ static int xtpg_s_ctrl(struct v4l2_ctrl *ctrl)
XTPG_PATTERN_CONTROL_MOVING_BOX, ctrl->val);
return 0;
case V4L2_CID_XILINX_TPG_COLOR_MASK:
- xvip_clr_and_set(&xtpg->xvip, XTPG_PATTERN_CONTROL,
- XTPG_PATTERN_CONTROL_COLOR_MASK_MASK,
- ctrl->val <<
- XTPG_PATTERN_CONTROL_COLOR_MASK_SHIFT);
+ if (xtpg->is_hls)
+ xvip_write(&xtpg->xvip, XTPG_HLS_MASK_ID, ctrl->val);
+ else
+ xvip_clr_and_set(&xtpg->xvip, XTPG_PATTERN_CONTROL,
+ XTPG_PATTERN_CONTROL_COLOR_MASK_MASK,
+ ctrl->val <<
+ XTPG_PATTERN_CONTROL_COLOR_MASK_SHIFT);
return 0;
case V4L2_CID_XILINX_TPG_STUCK_PIXEL:
xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL,
@@ -404,43 +571,85 @@ static int xtpg_s_ctrl(struct v4l2_ctrl *ctrl)
XTPG_PATTERN_CONTROL_MOTION, ctrl->val);
return 0;
case V4L2_CID_XILINX_TPG_MOTION_SPEED:
- xvip_write(&xtpg->xvip, XTPG_MOTION_SPEED, ctrl->val);
+ if (xtpg->is_hls)
+ xvip_write(&xtpg->xvip, XTPG_HLS_MOTION_SPEED,
+ ctrl->val);
+ else
+ xvip_write(&xtpg->xvip, XTPG_MOTION_SPEED, ctrl->val);
return 0;
case V4L2_CID_XILINX_TPG_CROSS_HAIR_ROW:
- xvip_clr_and_set(&xtpg->xvip, XTPG_CROSS_HAIRS,
- XTPG_CROSS_HAIRS_ROW_MASK,
- ctrl->val << XTPG_CROSS_HAIRS_ROW_SHIFT);
+ if (xtpg->is_hls)
+ xvip_write(&xtpg->xvip, XTPG_HLS_CROSS_HAIR_HOR,
+ ctrl->val);
+ else
+ xvip_clr_and_set(&xtpg->xvip, XTPG_CROSS_HAIRS,
+ XTPG_CROSS_HAIRS_ROW_MASK,
+ ctrl->val <<
+ XTPG_CROSS_HAIRS_ROW_SHIFT);
return 0;
case V4L2_CID_XILINX_TPG_CROSS_HAIR_COLUMN:
- xvip_clr_and_set(&xtpg->xvip, XTPG_CROSS_HAIRS,
- XTPG_CROSS_HAIRS_COLUMN_MASK,
- ctrl->val << XTPG_CROSS_HAIRS_COLUMN_SHIFT);
+ if (xtpg->is_hls)
+ xvip_write(&xtpg->xvip, XTPG_HLS_CROSS_HAIR_VER,
+ ctrl->val);
+ else
+ xvip_clr_and_set(&xtpg->xvip, XTPG_CROSS_HAIRS,
+ XTPG_CROSS_HAIRS_COLUMN_MASK,
+ ctrl->val <<
+ XTPG_CROSS_HAIRS_COLUMN_SHIFT);
return 0;
case V4L2_CID_XILINX_TPG_ZPLATE_HOR_START:
- xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_HOR_CONTROL,
- XTPG_ZPLATE_START_MASK,
- ctrl->val << XTPG_ZPLATE_START_SHIFT);
+ if (xtpg->is_hls)
+ xvip_write(&xtpg->xvip, XTPG_HLS_ZPLATE_HOR_CNTL_START,
+ ctrl->val);
+ else
+ xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_HOR_CONTROL,
+ XTPG_ZPLATE_START_MASK,
+ ctrl->val << XTPG_ZPLATE_START_SHIFT);
return 0;
case V4L2_CID_XILINX_TPG_ZPLATE_HOR_SPEED:
- xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_HOR_CONTROL,
- XTPG_ZPLATE_SPEED_MASK,
- ctrl->val << XTPG_ZPLATE_SPEED_SHIFT);
+ if (xtpg->is_hls)
+ xvip_write(&xtpg->xvip, XTPG_HLS_ZPLATE_HOR_CNTL_DELTA,
+ ctrl->val);
+ else
+ xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_HOR_CONTROL,
+ XTPG_ZPLATE_SPEED_MASK,
+ ctrl->val << XTPG_ZPLATE_SPEED_SHIFT);
return 0;
case V4L2_CID_XILINX_TPG_ZPLATE_VER_START:
- xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_VER_CONTROL,
- XTPG_ZPLATE_START_MASK,
- ctrl->val << XTPG_ZPLATE_START_SHIFT);
+ if (xtpg->is_hls)
+ xvip_write(&xtpg->xvip, XTPG_HLS_ZPLATE_VER_CNTL_START,
+ ctrl->val);
+ else
+ xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_VER_CONTROL,
+ XTPG_ZPLATE_START_MASK,
+ ctrl->val << XTPG_ZPLATE_START_SHIFT);
return 0;
case V4L2_CID_XILINX_TPG_ZPLATE_VER_SPEED:
- xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_VER_CONTROL,
- XTPG_ZPLATE_SPEED_MASK,
- ctrl->val << XTPG_ZPLATE_SPEED_SHIFT);
+ if (xtpg->is_hls)
+ xvip_write(&xtpg->xvip, XTPG_HLS_ZPLATE_VER_CNTL_DELTA,
+ ctrl->val);
+ else
+ xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_VER_CONTROL,
+ XTPG_ZPLATE_SPEED_MASK,
+ ctrl->val << XTPG_ZPLATE_SPEED_SHIFT);
return 0;
case V4L2_CID_XILINX_TPG_BOX_SIZE:
- xvip_write(&xtpg->xvip, XTPG_BOX_SIZE, ctrl->val);
+ if (xtpg->is_hls)
+ xvip_write(&xtpg->xvip, XTPG_HLS_BOX_SIZE, ctrl->val);
+ else
+ xvip_write(&xtpg->xvip, XTPG_BOX_SIZE, ctrl->val);
return 0;
case V4L2_CID_XILINX_TPG_BOX_COLOR:
- xvip_write(&xtpg->xvip, XTPG_BOX_COLOR, ctrl->val);
+ if (xtpg->is_hls) {
+ xvip_write(&xtpg->xvip, XTPG_HLS_BOX_COLOR_RED_CB,
+ ctrl->val >> 16);
+ xvip_write(&xtpg->xvip, XTPG_HLS_BOX_COLOR_GREEN_CR,
+ ctrl->val >> 8);
+ xvip_write(&xtpg->xvip, XTPG_HLS_BOX_COLOR_BLUE_Y,
+ ctrl->val);
+ } else {
+ xvip_write(&xtpg->xvip, XTPG_BOX_COLOR, ctrl->val);
+ }
return 0;
case V4L2_CID_XILINX_TPG_STUCK_PIXEL_THRESH:
xvip_write(&xtpg->xvip, XTPG_STUCK_PIXEL_THRESH, ctrl->val);
@@ -448,6 +657,9 @@ static int xtpg_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_XILINX_TPG_NOISE_GAIN:
xvip_write(&xtpg->xvip, XTPG_NOISE_GAIN, ctrl->val);
return 0;
+ case V4L2_CID_XILINX_TPG_HLS_FG_PATTERN:
+ xvip_write(&xtpg->xvip, XTPG_HLS_FG_PATTERN, ctrl->val);
+ return 0;
}
return 0;
@@ -461,6 +673,8 @@ static const struct v4l2_subdev_core_ops xtpg_core_ops = {
};
static const struct v4l2_subdev_video_ops xtpg_video_ops = {
+ .g_frame_interval = xtpg_g_frame_interval,
+ .s_frame_interval = xtpg_s_frame_interval,
.s_stream = xtpg_s_stream,
};
@@ -505,60 +719,51 @@ static const char *const xtpg_pattern_strings[] = {
"Black/White Checker Board",
};
-static struct v4l2_ctrl_config xtpg_ctrls[] = {
+static const char *const xtpg_hls_pattern_strings[] = {
+ "Passthrough",
+ "Horizontal Ramp",
+ "Vertical Ramp",
+ "Temporal Ramp",
+ "Solid Red",
+ "Solid Green",
+ "Solid Blue",
+ "Solid Black",
+ "Solid White",
+ "Color Bars",
+ "Zone Plate",
+ "Tartan Color Bars",
+ "Cross Hatch",
+ "Color Sweep",
+ "Vertical/Horizontal Ramps",
+ "Black/White Checker Board",
+ "PseudoRandom",
+};
+
+static const char *const xtpg_hls_fg_strings[] = {
+ "No Overlay",
+ "Moving Box",
+ "Cross Hairs",
+};
+
+static const struct v4l2_ctrl_config xtpg_hls_fg_ctrl = {
+ .ops = &xtpg_ctrl_ops,
+ .id = V4L2_CID_XILINX_TPG_HLS_FG_PATTERN,
+ .name = "Test Pattern: Foreground Pattern",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .min = 0,
+ .max = ARRAY_SIZE(xtpg_hls_fg_strings) - 1,
+ .qmenu = xtpg_hls_fg_strings,
+};
+
+static struct v4l2_ctrl_config xtpg_common_ctrls[] = {
{
- .ops = &xtpg_ctrl_ops,
- .id = V4L2_CID_XILINX_TPG_CROSS_HAIRS,
- .name = "Test Pattern: Cross Hairs",
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .min = false,
- .max = true,
- .step = 1,
- .def = 0,
- }, {
- .ops = &xtpg_ctrl_ops,
- .id = V4L2_CID_XILINX_TPG_MOVING_BOX,
- .name = "Test Pattern: Moving Box",
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .min = false,
- .max = true,
- .step = 1,
- .def = 0,
- }, {
- .ops = &xtpg_ctrl_ops,
- .id = V4L2_CID_XILINX_TPG_COLOR_MASK,
- .name = "Test Pattern: Color Mask",
- .type = V4L2_CTRL_TYPE_BITMASK,
- .min = 0,
- .max = 0xf,
- .def = 0,
- }, {
- .ops = &xtpg_ctrl_ops,
- .id = V4L2_CID_XILINX_TPG_STUCK_PIXEL,
- .name = "Test Pattern: Stuck Pixel",
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .min = false,
- .max = true,
- .step = 1,
- .def = 0,
- }, {
- .ops = &xtpg_ctrl_ops,
- .id = V4L2_CID_XILINX_TPG_NOISE,
- .name = "Test Pattern: Noise",
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .min = false,
- .max = true,
- .step = 1,
- .def = 0,
- }, {
- .ops = &xtpg_ctrl_ops,
- .id = V4L2_CID_XILINX_TPG_MOTION,
- .name = "Test Pattern: Motion",
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .min = false,
- .max = true,
- .step = 1,
- .def = 0,
+ .ops = &xtpg_ctrl_ops,
+ .id = V4L2_CID_XILINX_TPG_COLOR_MASK,
+ .name = "Test Pattern: Color Mask",
+ .type = V4L2_CTRL_TYPE_BITMASK,
+ .min = 0,
+ .max = 0x7,
+ .def = 0,
}, {
.ops = &xtpg_ctrl_ops,
.id = V4L2_CID_XILINX_TPG_MOTION_SPEED,
@@ -642,12 +847,61 @@ static struct v4l2_ctrl_config xtpg_ctrls[] = {
}, {
.ops = &xtpg_ctrl_ops,
.id = V4L2_CID_XILINX_TPG_BOX_COLOR,
- .name = "Test Pattern: Box Color(RGB)",
+ .name = "Test Pattern: Box Color(RGB/YCbCr)",
.type = V4L2_CTRL_TYPE_INTEGER,
.min = 0,
.max = (1 << 24) - 1,
.step = 1,
.def = 0,
+ },
+};
+
+static struct v4l2_ctrl_config xtpg_ctrls[] = {
+ {
+ .ops = &xtpg_ctrl_ops,
+ .id = V4L2_CID_XILINX_TPG_CROSS_HAIRS,
+ .name = "Test Pattern: Cross Hairs",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = false,
+ .max = true,
+ .step = 1,
+ .def = 0,
+ }, {
+ .ops = &xtpg_ctrl_ops,
+ .id = V4L2_CID_XILINX_TPG_MOVING_BOX,
+ .name = "Test Pattern: Moving Box",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = false,
+ .max = true,
+ .step = 1,
+ .def = 0,
+ }, {
+ .ops = &xtpg_ctrl_ops,
+ .id = V4L2_CID_XILINX_TPG_STUCK_PIXEL,
+ .name = "Test Pattern: Stuck Pixel",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = false,
+ .max = true,
+ .step = 1,
+ .def = 0,
+ }, {
+ .ops = &xtpg_ctrl_ops,
+ .id = V4L2_CID_XILINX_TPG_NOISE,
+ .name = "Test Pattern: Noise",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = false,
+ .max = true,
+ .step = 1,
+ .def = 0,
+ }, {
+ .ops = &xtpg_ctrl_ops,
+ .id = V4L2_CID_XILINX_TPG_MOTION,
+ .name = "Test Pattern: Motion",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = false,
+ .max = true,
+ .step = 1,
+ .def = 0,
}, {
.ops = &xtpg_ctrl_ops,
.id = V4L2_CID_XILINX_TPG_STUCK_PIXEL_THRESH,
@@ -713,6 +967,49 @@ static int xtpg_parse_of(struct xtpg_device *xtpg)
struct device_node *port;
unsigned int nports = 0;
bool has_endpoint = false;
+ int ret;
+
+ if (!of_device_is_compatible(dev->of_node, "xlnx,v-tpg-5.0"))
+ xtpg->is_hls = true;
+
+ ret = of_property_read_u32(node, "xlnx,max-height",
+ &xtpg->max_height);
+ if (ret < 0) {
+ if (of_device_is_compatible(dev->of_node, "xlnx,v-tpg-8.0")) {
+ dev_err(dev, "xlnx,max-height dt property is missing!");
+ return -EINVAL;
+ }
+ xtpg->max_height = XTPG_MAX_HEIGHT;
+ } else if (xtpg->max_height > XTPG_MAX_HEIGHT ||
+ xtpg->max_height < XTPG_MIN_HEIGHT) {
+ dev_err(dev, "Invalid height in dt");
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32(node, "xlnx,max-width",
+ &xtpg->max_width);
+ if (ret < 0) {
+ if (of_device_is_compatible(dev->of_node, "xlnx,v-tpg-8.0")) {
+ dev_err(dev, "xlnx,max-width dt property is missing!");
+ return -EINVAL;
+ }
+ xtpg->max_width = XTPG_MAX_WIDTH;
+ } else if (xtpg->max_width > XTPG_MAX_WIDTH ||
+ xtpg->max_width < XTPG_MIN_WIDTH) {
+ dev_err(dev, "Invalid width in dt");
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32(node, "xlnx,ppc",
+ &xtpg->ppc);
+ if (ret < 0) {
+ xtpg->ppc = XTPG_MIN_PPC;
+ dev_dbg(dev, "failed to read ppc in dt\n");
+ } else if ((xtpg->ppc != 1) && (xtpg->ppc != 2) &&
+ (xtpg->ppc != 4) && (xtpg->ppc != 8)) {
+ dev_err(dev, "Invalid ppc config in dt\n");
+ return -EINVAL;
+ }
ports = of_get_child_by_name(node, "ports");
if (ports == NULL)
@@ -769,6 +1066,7 @@ static int xtpg_probe(struct platform_device *pdev)
struct v4l2_subdev *subdev;
struct xtpg_device *xtpg;
u32 i, bayer_phase;
+ u32 npatterns;
int ret;
xtpg = devm_kzalloc(&pdev->dev, sizeof(*xtpg), GFP_KERNEL);
@@ -792,14 +1090,29 @@ static int xtpg_probe(struct platform_device *pdev)
goto error_resource;
}
+ if (xtpg->is_hls) {
+ xtpg->rst_gpio = devm_gpiod_get(&pdev->dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(xtpg->rst_gpio)) {
+ ret = PTR_ERR(xtpg->rst_gpio);
+ goto error_resource;
+ }
+ }
+
xtpg->vtc = xvtc_of_get(pdev->dev.of_node);
if (IS_ERR(xtpg->vtc)) {
ret = PTR_ERR(xtpg->vtc);
goto error_resource;
}
- /* Reset and initialize the core */
- xvip_reset(&xtpg->xvip);
+ /*
+ * Reset and initialize the core. For TPG HLS version there
+ * is no SW_RESET bit hence using GPIO based reset.
+ */
+ if (xtpg->is_hls)
+ gpiod_set_value_cansleep(xtpg->rst_gpio, 0x0);
+ else
+ xvip_reset(&xtpg->xvip);
/* Initialize V4L2 subdevice and media entity. Pad numbers depend on the
* number of pads.
@@ -815,11 +1128,23 @@ static int xtpg_probe(struct platform_device *pdev)
xtpg->default_format.code = xtpg->vip_format->code;
xtpg->default_format.field = V4L2_FIELD_NONE;
xtpg->default_format.colorspace = V4L2_COLORSPACE_SRGB;
- xvip_get_frame_size(&xtpg->xvip, &xtpg->default_format);
- bayer_phase = xtpg_get_bayer_phase(xtpg->vip_format->code);
- if (bayer_phase != XTPG_BAYER_PHASE_OFF)
- xtpg->bayer = true;
+ if (xtpg->is_hls) {
+ npatterns = ARRAY_SIZE(xtpg_hls_pattern_strings);
+ xtpg->default_format.width = xvip_read(&xtpg->xvip,
+ XHLS_REG_COLS);
+ xtpg->default_format.height = xvip_read(&xtpg->xvip,
+ XHLS_REG_ROWS);
+ } else {
+ npatterns = ARRAY_SIZE(xtpg_pattern_strings);
+ xvip_get_frame_size(&xtpg->xvip, &xtpg->default_format);
+ }
+
+ if (!xtpg->is_hls) {
+ bayer_phase = xtpg_get_bayer_phase(xtpg->vip_format->code);
+ if (bayer_phase != XTPG_BAYER_PHASE_OFF)
+ xtpg->bayer = true;
+ }
xtpg->formats[0] = xtpg->default_format;
if (xtpg->npads == 2)
@@ -839,7 +1164,13 @@ static int xtpg_probe(struct platform_device *pdev)
if (ret < 0)
goto error;
- v4l2_ctrl_handler_init(&xtpg->ctrl_handler, 3 + ARRAY_SIZE(xtpg_ctrls));
+ if (xtpg->is_hls)
+ v4l2_ctrl_handler_init(&xtpg->ctrl_handler, 4 +
+ ARRAY_SIZE(xtpg_common_ctrls));
+ else
+ v4l2_ctrl_handler_init(&xtpg->ctrl_handler, 3 +
+ ARRAY_SIZE(xtpg_common_ctrls) +
+ ARRAY_SIZE(xtpg_ctrls));
xtpg->vblank = v4l2_ctrl_new_std(&xtpg->ctrl_handler, &xtpg_ctrl_ops,
V4L2_CID_VBLANK, XTPG_MIN_VBLANK,
@@ -847,19 +1178,41 @@ static int xtpg_probe(struct platform_device *pdev)
xtpg->hblank = v4l2_ctrl_new_std(&xtpg->ctrl_handler, &xtpg_ctrl_ops,
V4L2_CID_HBLANK, XTPG_MIN_HBLANK,
XTPG_MAX_HBLANK, 1, 100);
- xtpg->pattern = v4l2_ctrl_new_std_menu_items(&xtpg->ctrl_handler,
- &xtpg_ctrl_ops, V4L2_CID_TEST_PATTERN,
- ARRAY_SIZE(xtpg_pattern_strings) - 1,
- 1, 9, xtpg_pattern_strings);
- for (i = 0; i < ARRAY_SIZE(xtpg_ctrls); i++)
- v4l2_ctrl_new_custom(&xtpg->ctrl_handler, &xtpg_ctrls[i], NULL);
+ if (xtpg->is_hls) {
+ xtpg->pattern =
+ v4l2_ctrl_new_std_menu_items(&xtpg->ctrl_handler,
+ &xtpg_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ npatterns - 1,
+ 1, 9,
+ xtpg_hls_pattern_strings);
+ v4l2_ctrl_new_custom(&xtpg->ctrl_handler,
+ &xtpg_hls_fg_ctrl, NULL);
+ } else {
+ xtpg->pattern =
+ v4l2_ctrl_new_std_menu_items(&xtpg->ctrl_handler,
+ &xtpg_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ npatterns - 1,
+ 1, 9,
+ xtpg_pattern_strings);
+
+ for (i = 0; i < ARRAY_SIZE(xtpg_ctrls); i++)
+ v4l2_ctrl_new_custom(&xtpg->ctrl_handler,
+ &xtpg_ctrls[i], NULL);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(xtpg_common_ctrls); i++)
+ v4l2_ctrl_new_custom(&xtpg->ctrl_handler,
+ &xtpg_common_ctrls[i], NULL);
if (xtpg->ctrl_handler.error) {
dev_err(&pdev->dev, "failed to add controls\n");
ret = xtpg->ctrl_handler.error;
goto error;
}
+
subdev->ctrl_handler = &xtpg->ctrl_handler;
xtpg_update_pattern_control(xtpg, true, true);
@@ -874,6 +1227,10 @@ static int xtpg_probe(struct platform_device *pdev)
xvip_print_version(&xtpg->xvip);
+ /* Initialize default frame interval */
+ xtpg->fi_n = 1;
+ xtpg->fi_d = 30;
+
ret = v4l2_async_register_subdev(subdev);
if (ret < 0) {
dev_err(&pdev->dev, "failed to register subdev\n");
@@ -909,6 +1266,8 @@ static SIMPLE_DEV_PM_OPS(xtpg_pm_ops, xtpg_pm_suspend, xtpg_pm_resume);
static const struct of_device_id xtpg_of_id_table[] = {
{ .compatible = "xlnx,v-tpg-5.0" },
+ { .compatible = "xlnx,v-tpg-7.0" },
+ { .compatible = "xlnx,v-tpg-8.0" },
{ }
};
MODULE_DEVICE_TABLE(of, xtpg_of_id_table);
diff --git a/drivers/media/platform/xilinx/xilinx-vip.c b/drivers/media/platform/xilinx/xilinx-vip.c
index 08a825c3a3f6..466d6f27af1d 100644
--- a/drivers/media/platform/xilinx/xilinx-vip.c
+++ b/drivers/media/platform/xilinx/xilinx-vip.c
@@ -24,22 +24,102 @@
*/
static const struct xvip_video_format xvip_video_formats[] = {
+ { XVIP_VF_YUV_420, 8, NULL, MEDIA_BUS_FMT_VYYUYY8_1X24,
+ 1, 12, V4L2_PIX_FMT_NV12, 2, 1, 1, 2, "4:2:0, semi-planar, YUV" },
+ { XVIP_VF_YUV_420, 8, NULL, MEDIA_BUS_FMT_VYYUYY8_1X24,
+ 1, 12, V4L2_PIX_FMT_NV12M, 2, 2, 1, 2, "4:2:0, 2-plane non-cont" },
+ { XVIP_VF_YUV_420, 10, NULL, MEDIA_BUS_FMT_VYYUYY10_4X20,
+ 1, 12, V4L2_PIX_FMT_XV15, 2, 1, 2, 2, "4:2:0, 10-bit 2-plane cont" },
+ { XVIP_VF_YUV_420, 10, NULL, MEDIA_BUS_FMT_VYYUYY10_4X20,
+ 1, 12, V4L2_PIX_FMT_XV15M, 2, 2, 1, 2, "4:2:0, 10-bit 2-plane non-cont" },
+ { XVIP_VF_YUV_420, 12, NULL, MEDIA_BUS_FMT_UYYVYY12_4X24,
+ 1, 12, V4L2_PIX_FMT_X012, 2, 1, 2, 2, "4:2:0, 12-bit 2-plane cont" },
+ { XVIP_VF_YUV_420, 12, NULL, MEDIA_BUS_FMT_UYYVYY12_4X24,
+ 1, 12, V4L2_PIX_FMT_X012M, 2, 2, 1, 2, "4:2:0, 12-bit 2-plane non-cont" },
+ { XVIP_VF_YUV_420, 16, NULL, MEDIA_BUS_FMT_UYYVYY16_4X32,
+ 2, 12, V4L2_PIX_FMT_X016, 2, 1, 2, 2, "4:2:0, 16-bit 2-plane cont" },
+ { XVIP_VF_YUV_420, 16, NULL, MEDIA_BUS_FMT_UYYVYY16_4X32,
+ 2, 12, V4L2_PIX_FMT_X016M, 2, 2, 1, 2, "4:2:0, 16-bit 2-plane non-cont" },
{ XVIP_VF_YUV_422, 8, NULL, MEDIA_BUS_FMT_UYVY8_1X16,
- 2, V4L2_PIX_FMT_YUYV, "4:2:2, packed, YUYV" },
+ 2, 16, V4L2_PIX_FMT_YUYV, 1, 1, 2, 1, "4:2:2, packed, YUYV" },
+ { XVIP_VF_VUY_422, 8, NULL, MEDIA_BUS_FMT_UYVY8_1X16,
+ 2, 16, V4L2_PIX_FMT_UYVY, 1, 1, 2, 1, "4:2:2, packed, UYVY" },
+ { XVIP_VF_YUV_422, 8, NULL, MEDIA_BUS_FMT_UYVY8_1X16,
+ 1, 16, V4L2_PIX_FMT_NV16, 2, 1, 1, 1, "4:2:2, semi-planar, YUV" },
+ { XVIP_VF_YUV_422, 8, NULL, MEDIA_BUS_FMT_UYVY8_1X16,
+ 1, 16, V4L2_PIX_FMT_NV16M, 2, 2, 1, 1, "4:2:2, 2-plane non-contiguous" },
+ { XVIP_VF_YUV_422, 10, NULL, MEDIA_BUS_FMT_UYVY10_1X20,
+ 1, 16, V4L2_PIX_FMT_XV20, 2, 1, 2, 1, "4:2:2, 10-bit 2-plane cont" },
+ { XVIP_VF_YUV_422, 10, NULL, MEDIA_BUS_FMT_UYVY10_1X20,
+ 1, 16, V4L2_PIX_FMT_XV20M, 2, 2, 1, 1, "4:2:2, 10-bit 2-plane non-cont" },
+ { XVIP_VF_YUV_422, 12, NULL, MEDIA_BUS_FMT_UYVY12_1X24,
+ 1, 16, V4L2_PIX_FMT_X212, 2, 1, 2, 1, "4:2:2, 12-bit 2-plane cont" },
+ { XVIP_VF_YUV_422, 12, NULL, MEDIA_BUS_FMT_UYVY12_1X24,
+ 1, 16, V4L2_PIX_FMT_X212M, 2, 2, 1, 1, "4:2:2, 12-bit 2-plane non-cont" },
+ { XVIP_VF_YUV_422, 16, NULL, MEDIA_BUS_FMT_UYVY12_1X24,
+ 2, 16, V4L2_PIX_FMT_X216, 2, 1, 2, 1, "4:2:2, 16-bit 2-plane cont" },
+ { XVIP_VF_YUV_422, 16, NULL, MEDIA_BUS_FMT_UYVY12_1X24,
+ 2, 16, V4L2_PIX_FMT_X216M, 2, 2, 1, 1, "4:2:2, 16-bit 2-plane non-cont" },
{ XVIP_VF_YUV_444, 8, NULL, MEDIA_BUS_FMT_VUY8_1X24,
- 3, V4L2_PIX_FMT_YUV444, "4:4:4, packed, YUYV" },
+ 3, 24, V4L2_PIX_FMT_VUY24, 1, 1, 1, 1, "4:4:4, packed, YUYV" },
+ { XVIP_VF_YUVX, 8, NULL, MEDIA_BUS_FMT_VUY8_1X24,
+ 4, 32, V4L2_PIX_FMT_XVUY32, 1, 1, 1, 1, "X:4:4:4, packed, YUYV" },
+ { XVIP_VF_YUVX, 10, NULL, MEDIA_BUS_FMT_VUY10_1X30,
+ 3, 32, V4L2_PIX_FMT_XVUY10, 1, 1, 1, 1, "2:10:10:10, packed, XVUY" },
+ { XVIP_VF_YUV_444, 12, NULL, MEDIA_BUS_FMT_VUY12_1X36,
+ 1, 24, V4L2_PIX_FMT_X412, 1, 1, 1, 1, "4:4:4, 12-bit 2-plane cont" },
+ { XVIP_VF_YUV_444, 12, NULL, MEDIA_BUS_FMT_VUY12_1X36,
+ 1, 24, V4L2_PIX_FMT_X412M, 1, 1, 1, 1, "4:4:4, 12-bit 2-plane non-cont" },
+ { XVIP_VF_YUV_444, 16, NULL, MEDIA_BUS_FMT_VUY16_1X48,
+ 2, 24, V4L2_PIX_FMT_X416, 1, 1, 1, 1, "4:4:4, 16-bit 2-plane cont" },
+ { XVIP_VF_YUV_444, 16, NULL, MEDIA_BUS_FMT_VUY16_1X48,
+ 2, 24, V4L2_PIX_FMT_X416M, 1, 1, 1, 1, "4:4:4, 16-bit 2-plane non-cont" },
+ { XVIP_VF_RBG, 8, NULL, MEDIA_BUS_FMT_RBG888_1X24,
+ 3, 24, V4L2_PIX_FMT_BGR24, 1, 1, 1, 1, "24-bit RGB" },
{ XVIP_VF_RBG, 8, NULL, MEDIA_BUS_FMT_RBG888_1X24,
- 3, 0, NULL },
+ 3, 24, V4L2_PIX_FMT_RGB24, 1, 1, 1, 1, "24-bit RGB" },
+ { XVIP_VF_BGRX, 8, NULL, MEDIA_BUS_FMT_RBG888_1X24,
+ 4, 32, V4L2_PIX_FMT_BGRX32, 1, 1, 1, 1, "x:8:8:8 RGB w/8 bits padding" },
+ { XVIP_VF_XRGB, 8, NULL, MEDIA_BUS_FMT_RBG888_1X24,
+ 4, 32, V4L2_PIX_FMT_XBGR32, 1, 1, 1, 1, "8:8:8:x RGBx w/8 bits padding" },
+ { XVIP_VF_XBGR, 10, NULL, MEDIA_BUS_FMT_RBG101010_1X30,
+ 3, 32, V4L2_PIX_FMT_XBGR30, 1, 1, 1, 1, "2:10:10:10, packed, XBGR" },
+ { XVIP_VF_XBGR, 12, NULL, MEDIA_BUS_FMT_RBG121212_1X36,
+ 3, 40, V4L2_PIX_FMT_XBGR40, 1, 1, 1, 1, "4:12:12:12, packed, XBGR" },
+ { XVIP_VF_RBG, 16, NULL, MEDIA_BUS_FMT_RBG161616_1X48,
+ 6, 48, V4L2_PIX_FMT_BGR48, 1, 1, 1, 1, "48-bit RGB" },
{ XVIP_VF_MONO_SENSOR, 8, "mono", MEDIA_BUS_FMT_Y8_1X8,
- 1, V4L2_PIX_FMT_GREY, "Greyscale 8-bit" },
+ 1, 8, V4L2_PIX_FMT_GREY, 1, 1, 1, 1, "Greyscale 8-bit" },
+ { XVIP_VF_Y_GREY, 10, NULL, MEDIA_BUS_FMT_Y10_1X10,
+ 4, 32, V4L2_PIX_FMT_XY10, 1, 1, 1, 1, "2:10:10:10, Grey, xY1Y2Y3Y4" },
+ { XVIP_VF_Y_GREY, 12, NULL, MEDIA_BUS_FMT_Y12_1X12,
+ 1, 12, V4L2_PIX_FMT_XY12, 1, 1, 1, 1, "4:12:12:12, packed, xY1Y2Y3" },
+ { XVIP_VF_Y_GREY, 16, NULL, MEDIA_BUS_FMT_Y16_1X16,
+ 2, 16, V4L2_PIX_FMT_Y16, 1, 1, 1, 1, "Greyscale 16-bit" },
{ XVIP_VF_MONO_SENSOR, 8, "rggb", MEDIA_BUS_FMT_SRGGB8_1X8,
- 1, V4L2_PIX_FMT_SRGGB8, "Bayer 8-bit RGGB" },
+ 1, 8, V4L2_PIX_FMT_SGRBG8, 1, 1, 1, 1, "Bayer 8-bit RGGB" },
{ XVIP_VF_MONO_SENSOR, 8, "grbg", MEDIA_BUS_FMT_SGRBG8_1X8,
- 1, V4L2_PIX_FMT_SGRBG8, "Bayer 8-bit GRBG" },
+ 1, 8, V4L2_PIX_FMT_SGRBG8, 1, 1, 1, 1, "Bayer 8-bit GRBG" },
{ XVIP_VF_MONO_SENSOR, 8, "gbrg", MEDIA_BUS_FMT_SGBRG8_1X8,
- 1, V4L2_PIX_FMT_SGBRG8, "Bayer 8-bit GBRG" },
+ 1, 8, V4L2_PIX_FMT_SGBRG8, 1, 1, 1, 1, "Bayer 8-bit GBRG" },
{ XVIP_VF_MONO_SENSOR, 8, "bggr", MEDIA_BUS_FMT_SBGGR8_1X8,
- 1, V4L2_PIX_FMT_SBGGR8, "Bayer 8-bit BGGR" },
+ 1, 8, V4L2_PIX_FMT_SBGGR8, 1, 1, 1, 1, "Bayer 8-bit BGGR" },
+ { XVIP_VF_MONO_SENSOR, 12, "rggb", MEDIA_BUS_FMT_SRGGB12_1X12,
+ 1, 12, V4L2_PIX_FMT_SRGGB12, 1, 1, 1, 1, "Bayer 12-bit RGGB" },
+ { XVIP_VF_MONO_SENSOR, 12, "grbg", MEDIA_BUS_FMT_SGRBG12_1X12,
+ 1, 12, V4L2_PIX_FMT_SGRBG12, 1, 1, 1, 1, "Bayer 12-bit GRBG" },
+ { XVIP_VF_MONO_SENSOR, 12, "gbrg", MEDIA_BUS_FMT_SGBRG12_1X12,
+ 1, 12, V4L2_PIX_FMT_SGBRG12, 1, 1, 1, 1, "Bayer 12-bit GBRG" },
+ { XVIP_VF_MONO_SENSOR, 12, "bggr", MEDIA_BUS_FMT_SBGGR12_1X12,
+ 1, 12, V4L2_PIX_FMT_SBGGR12, 1, 1, 1, 1, "Bayer 12-bit BGGR" },
+ { XVIP_VF_MONO_SENSOR, 16, "rggb", MEDIA_BUS_FMT_SRGGB16_1X16,
+ 1, 16, V4L2_PIX_FMT_SRGGB16, 1, 1, 1, 1, "Bayer 16-bit RGGB" },
+ { XVIP_VF_MONO_SENSOR, 16, "grbg", MEDIA_BUS_FMT_SGRBG16_1X16,
+ 1, 12, V4L2_PIX_FMT_SGRBG16, 1, 1, 1, 1, "Bayer 16-bit GRBG" },
+ { XVIP_VF_MONO_SENSOR, 16, "gbrg", MEDIA_BUS_FMT_SGBRG16_1X16,
+ 1, 12, V4L2_PIX_FMT_SGBRG16, 1, 1, 1, 1, "Bayer 16-bit GBRG" },
+ { XVIP_VF_MONO_SENSOR, 16, "bggr", MEDIA_BUS_FMT_SBGGR12_1X12,
+ 1, 12, V4L2_PIX_FMT_SBGGR16, 1, 1, 1, 1, "Bayer 16-bit BGGR" },
};
/**
@@ -89,6 +169,87 @@ const struct xvip_video_format *xvip_get_format_by_fourcc(u32 fourcc)
EXPORT_SYMBOL_GPL(xvip_get_format_by_fourcc);
/**
+ * xvip_bpl_scaling_factor - Retrieve bpl scaling factor for a 4CC
+ * @fourcc: the format 4CC
+ * @numerator: returning numerator of scaling factor
+ * @denominator: returning denominator of scaling factor
+ *
+ * Return: Return numerator and denominator values by address
+ */
+void xvip_bpl_scaling_factor(u32 fourcc, u32 *numerator, u32 *denominator)
+{
+ switch (fourcc) {
+ case V4L2_PIX_FMT_XY10:
+ case V4L2_PIX_FMT_XV15:
+ case V4L2_PIX_FMT_XV20:
+ case V4L2_PIX_FMT_XV15M:
+ case V4L2_PIX_FMT_XV20M:
+ case V4L2_PIX_FMT_XBGR30:
+ case V4L2_PIX_FMT_XVUY10:
+ *numerator = 10;
+ *denominator = 8;
+ break;
+ case V4L2_PIX_FMT_XBGR40:
+ case V4L2_PIX_FMT_XY12:
+ case V4L2_PIX_FMT_X012:
+ case V4L2_PIX_FMT_X012M:
+ case V4L2_PIX_FMT_X212:
+ case V4L2_PIX_FMT_X212M:
+ case V4L2_PIX_FMT_X412:
+ case V4L2_PIX_FMT_X412M:
+ *numerator = 12;
+ *denominator = 8;
+ break;
+ default:
+ *numerator = 1;
+ *denominator = 1;
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(xvip_bpl_scaling_factor);
+
+/**
+ * xvip_width_padding_factor - Retrieve width's padding factor for a 4CC
+ * @fourcc: the format 4CC
+ * @numerator: returning numerator of padding factor
+ * @denominator: returning denominator of padding factor
+ *
+ * Return: Return numerator and denominator values by address
+ */
+void xvip_width_padding_factor(u32 fourcc, u32 *numerator, u32 *denominator)
+{
+ switch (fourcc) {
+ case V4L2_PIX_FMT_XY10:
+ case V4L2_PIX_FMT_XV15:
+ case V4L2_PIX_FMT_XV20:
+ case V4L2_PIX_FMT_XV15M:
+ case V4L2_PIX_FMT_XV20M:
+ case V4L2_PIX_FMT_XBGR30:
+ case V4L2_PIX_FMT_XVUY10:
+ /* 32 bits are required per 30 bits of data */
+ *numerator = 32;
+ *denominator = 30;
+ break;
+ case V4L2_PIX_FMT_XBGR40:
+ case V4L2_PIX_FMT_XY12:
+ case V4L2_PIX_FMT_X012:
+ case V4L2_PIX_FMT_X012M:
+ case V4L2_PIX_FMT_X212:
+ case V4L2_PIX_FMT_X212M:
+ case V4L2_PIX_FMT_X412:
+ case V4L2_PIX_FMT_X412M:
+ *numerator = 40;
+ *denominator = 36;
+ break;
+ default:
+ *numerator = 1;
+ *denominator = 1;
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(xvip_width_padding_factor);
+
+/**
* xvip_of_get_format - Parse a device tree node and return format information
* @node: the device tree node
*
diff --git a/drivers/media/platform/xilinx/xilinx-vip.h b/drivers/media/platform/xilinx/xilinx-vip.h
index ba939dd52818..55b994f0c26e 100644
--- a/drivers/media/platform/xilinx/xilinx-vip.h
+++ b/drivers/media/platform/xilinx/xilinx-vip.h
@@ -106,8 +106,13 @@ struct xvip_device {
* @width: AXI4 format width in bits per component
* @pattern: CFA pattern for Mono/Sensor formats
* @code: media bus format code
- * @bpp: bytes per pixel (when stored in memory)
+ * @bpl_factor: Bytes per line factor
+ * @bpp: bits per pixel
* @fourcc: V4L2 pixel format FCC identifier
+ * @num_planes: number of planes w.r.t. color format
+ * @buffers: number of buffers per format
+ * @hsub: Horizontal sampling factor of Chroma
+ * @vsub: Vertical sampling factor of Chroma
* @description: format description, suitable for userspace
*/
struct xvip_video_format {
@@ -115,14 +120,21 @@ struct xvip_video_format {
unsigned int width;
const char *pattern;
unsigned int code;
+ unsigned int bpl_factor;
unsigned int bpp;
u32 fourcc;
+ u8 num_planes;
+ u8 buffers;
+ u8 hsub;
+ u8 vsub;
const char *description;
};
const struct xvip_video_format *xvip_get_format_by_code(unsigned int code);
const struct xvip_video_format *xvip_get_format_by_fourcc(u32 fourcc);
const struct xvip_video_format *xvip_of_get_format(struct device_node *node);
+void xvip_bpl_scaling_factor(u32 fourcc, u32 *numerator, u32 *denominator);
+void xvip_width_padding_factor(u32 fourcc, u32 *numerator, u32 *denominator);
void xvip_set_format_size(struct v4l2_mbus_framefmt *format,
const struct v4l2_subdev_format *fmt);
int xvip_enum_mbus_code(struct v4l2_subdev *subdev,
diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c
index edce0402155d..7890cc11632f 100644
--- a/drivers/media/platform/xilinx/xilinx-vipp.c
+++ b/drivers/media/platform/xilinx/xilinx-vipp.c
@@ -27,16 +27,27 @@
#define XVIPP_DMA_S2MM 0
#define XVIPP_DMA_MM2S 1
+/*
+ * This is for backward compatibility for existing applications,
+ * and planned to be deprecated
+ */
+static bool xvip_is_mplane = true;
+MODULE_PARM_DESC(is_mplane,
+ "v4l2 device capability to handle multi planar formats");
+module_param_named(is_mplane, xvip_is_mplane, bool, 0444);
+
/**
* struct xvip_graph_entity - Entity in the video graph
* @asd: subdev asynchronous registration information
* @entity: media entity, from the corresponding V4L2 subdev
* @subdev: V4L2 subdev
+ * @streaming: status of the V4L2 subdev if streaming or not
*/
struct xvip_graph_entity {
struct v4l2_async_subdev asd; /* must be first */
struct media_entity *entity;
struct v4l2_subdev *subdev;
+ bool streaming;
};
static inline struct xvip_graph_entity *
@@ -182,6 +193,38 @@ xvip_graph_find_dma(struct xvip_composite_device *xdev, unsigned int port)
return NULL;
}
+/**
+ * xvip_subdev_set_streaming - Find and update streaming status of subdev
+ * @xdev: Composite video device
+ * @subdev: V4L2 sub-device
+ * @enable: enable/disable streaming status
+ *
+ * Walk the xvip graph entities list and find if subdev is present. Returns
+ * streaming status of subdev and update the status as requested
+ *
+ * Return: streaming status (true or false) if successful or warn_on if subdev
+ * is not present and return false
+ */
+bool xvip_subdev_set_streaming(struct xvip_composite_device *xdev,
+ struct v4l2_subdev *subdev, bool enable)
+{
+ struct xvip_graph_entity *entity;
+ struct v4l2_async_subdev *asd;
+
+ list_for_each_entry(asd, &xdev->notifier.asd_list, asd_list) {
+ entity = to_xvip_entity(asd);
+ if (entity->asd.match.fwnode == of_fwnode_handle(subdev->dev->of_node)) {
+ bool status = entity->streaming;
+
+ entity->streaming = enable;
+ return status;
+ }
+ }
+
+ WARN(1, "Should never get here\n");
+ return false;
+}
+
static int xvip_graph_build_dma(struct xvip_composite_device *xdev)
{
u32 link_flags = MEDIA_LNK_FL_ENABLED;
@@ -276,7 +319,6 @@ static int xvip_graph_build_dma(struct xvip_composite_device *xdev)
}
}
- of_node_put(ep);
return ret;
}
@@ -442,9 +484,11 @@ static int xvip_graph_dma_init_one(struct xvip_composite_device *xdev,
return ret;
if (strcmp(direction, "input") == 0)
- type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ type = xvip_is_mplane ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
+ V4L2_BUF_TYPE_VIDEO_CAPTURE;
else if (strcmp(direction, "output") == 0)
- type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ type = xvip_is_mplane ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
+ V4L2_BUF_TYPE_VIDEO_OUTPUT;
else
return -EINVAL;
@@ -462,8 +506,14 @@ static int xvip_graph_dma_init_one(struct xvip_composite_device *xdev,
list_add_tail(&dma->list, &xdev->dmas);
- xdev->v4l2_caps |= type == V4L2_BUF_TYPE_VIDEO_CAPTURE
- ? V4L2_CAP_VIDEO_CAPTURE : V4L2_CAP_VIDEO_OUTPUT;
+ if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ xdev->v4l2_caps |= V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+ else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ xdev->v4l2_caps |= V4L2_CAP_VIDEO_CAPTURE;
+ else if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ xdev->v4l2_caps |= V4L2_CAP_VIDEO_OUTPUT;
+ else if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ xdev->v4l2_caps |= V4L2_CAP_VIDEO_OUTPUT_MPLANE;
return 0;
}
@@ -594,6 +644,7 @@ static int xvip_composite_probe(struct platform_device *pdev)
return -ENOMEM;
xdev->dev = &pdev->dev;
+ mutex_init(&xdev->lock);
INIT_LIST_HEAD(&xdev->dmas);
v4l2_async_notifier_init(&xdev->notifier);
@@ -620,6 +671,7 @@ static int xvip_composite_remove(struct platform_device *pdev)
{
struct xvip_composite_device *xdev = platform_get_drvdata(pdev);
+ mutex_destroy(&xdev->lock);
xvip_graph_cleanup(xdev);
xvip_composite_v4l2_cleanup(xdev);
diff --git a/drivers/media/platform/xilinx/xilinx-vipp.h b/drivers/media/platform/xilinx/xilinx-vipp.h
index e65fce9538f9..24934d57529b 100644
--- a/drivers/media/platform/xilinx/xilinx-vipp.h
+++ b/drivers/media/platform/xilinx/xilinx-vipp.h
@@ -27,6 +27,7 @@
* @notifier: V4L2 asynchronous subdevs notifier
* @dmas: list of DMA channels at the pipeline output and input
* @v4l2_caps: V4L2 capabilities of the whole device (see VIDIOC_QUERYCAP)
+ * @lock: This is to ensure all dma path entities acquire same pipeline object
*/
struct xvip_composite_device {
struct v4l2_device v4l2_dev;
@@ -37,6 +38,10 @@ struct xvip_composite_device {
struct list_head dmas;
u32 v4l2_caps;
+ struct mutex lock; /* lock to protect xvip pipeline instance */
};
+bool xvip_subdev_set_streaming(struct xvip_composite_device *xdev,
+ struct v4l2_subdev *subdev, bool enable);
+
#endif /* __XILINX_VIPP_H__ */
diff --git a/drivers/media/platform/xilinx/xilinx-vpss-csc.c b/drivers/media/platform/xilinx/xilinx-vpss-csc.c
new file mode 100644
index 000000000000..2c79b6ec1b8b
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-vpss-csc.c
@@ -0,0 +1,1169 @@
+/*
+ * Xilinx VPSS Color Space Converter
+ *
+ * Copyright (C) 2017 Xilinx, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/xilinx-v4l2-controls.h>
+
+#include <media/v4l2-async.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
+
+#include "xilinx-vip.h"
+
+#define XV_CSC_AP_CTRL (0x000)
+#define XV_CSC_INVIDEOFORMAT (0x010)
+#define XV_CSC_OUTVIDEOFORMAT (0x018)
+#define XV_CSC_WIDTH (0x020)
+#define XV_CSC_HEIGHT (0x028)
+#define XV_CSC_K11 (0x050)
+#define XV_CSC_K12 (0x058)
+#define XV_CSC_K13 (0x060)
+#define XV_CSC_K21 (0x068)
+#define XV_CSC_K22 (0x070)
+#define XV_CSC_K23 (0x078)
+#define XV_CSC_K31 (0x080)
+#define XV_CSC_K32 (0x088)
+#define XV_CSC_K33 (0x090)
+#define XV_CSC_ROFFSET (0x098)
+#define XV_CSC_GOFFSET (0x0a0)
+#define XV_CSC_BOFFSET (0x0a8)
+#define XV_CSC_CLAMPMIN (0x0b0)
+#define XV_CSC_CLIPMAX (0x0b8)
+
+#define XV_CSC_FRACTIONAL_BITS (12)
+#define XV_CSC_SCALE_FACTOR (4096)
+/* This a VPSS CSC specific macro used to calculate Contrast */
+#define XV_CSC_DIVISOR (10000)
+#define XV_CSC_DEFAULT_HEIGHT (720)
+#define XV_CSC_DEFAULT_WIDTH (1280)
+#define XV_CSC_K_MAX_ROWS (3)
+#define XV_CSC_K_MAX_COLUMNS (3)
+#define XV_CSC_MIN_WIDTH (64)
+#define XV_CSC_MAX_WIDTH (8192)
+#define XV_CSC_MIN_HEIGHT (64)
+#define XV_CSC_MAX_HEIGHT (4320)
+
+/* GPIO Reset Assert/De-assert */
+#define XCSC_RESET_ASSERT (1)
+#define XCSC_RESET_DEASSERT (0)
+/* Streaming Macros */
+#define XCSC_CLAMP_MIN_ZERO (0)
+#define XCSC_AP_START BIT(0)
+#define XCSC_AP_AUTO_RESTART BIT(7)
+#define XCSC_STREAM_ON (XCSC_AP_START | XCSC_AP_AUTO_RESTART)
+/* Color Control Macros */
+#define XCSC_COLOR_CTRL_COUNT (5)
+#define XCSC_COLOR_CTRL_DEFAULT (50)
+
+enum xcsc_color_fmt {
+ XVIDC_CSF_RGB = 0,
+ XVIDC_CSF_YCRCB_444,
+ XVIDC_CSF_YCRCB_422,
+ XVIDC_CSF_YCRCB_420,
+};
+
+enum xcsc_output_range {
+ XVIDC_CR_0_255 = 1,
+ XVIDC_CR_16_240,
+ XVIDC_CR_16_235
+};
+
+enum xcsc_color_depth {
+ XVIDC_BPC_8 = 8,
+ XVIDC_BPC_10 = 10,
+};
+
+static const s32
+rgb_unity_matrix[XV_CSC_K_MAX_ROWS][XV_CSC_K_MAX_COLUMNS + 1] = {
+ {XV_CSC_SCALE_FACTOR, 0, 0, 0},
+ {0, XV_CSC_SCALE_FACTOR, 0, 0},
+ {0, 0, XV_CSC_SCALE_FACTOR, 0},
+};
+
+static const s32
+ycrcb_to_rgb_unity[XV_CSC_K_MAX_ROWS][XV_CSC_K_MAX_COLUMNS + 1] = {
+ {
+ 11644 * XV_CSC_SCALE_FACTOR / XV_CSC_DIVISOR,
+ 0,
+ 17927 * XV_CSC_SCALE_FACTOR / XV_CSC_DIVISOR,
+ 0
+ },
+ {
+ 11644 * XV_CSC_SCALE_FACTOR / XV_CSC_DIVISOR,
+ -2132 * XV_CSC_SCALE_FACTOR / XV_CSC_DIVISOR,
+ -5329 * XV_CSC_SCALE_FACTOR / XV_CSC_DIVISOR,
+ 0
+ },
+ {
+ 11644 * XV_CSC_SCALE_FACTOR / XV_CSC_DIVISOR,
+ 21124 * XV_CSC_SCALE_FACTOR / XV_CSC_DIVISOR,
+ 0,
+ 0
+ },
+};
+
+static const s32
+rgb_to_ycrcb_unity[XV_CSC_K_MAX_ROWS][XV_CSC_K_MAX_COLUMNS + 1] = {
+ {
+ 1826 * XV_CSC_SCALE_FACTOR / XV_CSC_DIVISOR,
+ 6142 * XV_CSC_SCALE_FACTOR / XV_CSC_DIVISOR,
+ 620 * XV_CSC_SCALE_FACTOR / XV_CSC_DIVISOR,
+ 0
+ },
+ {
+ -1006 * XV_CSC_SCALE_FACTOR / XV_CSC_DIVISOR,
+ -3386 * XV_CSC_SCALE_FACTOR / XV_CSC_DIVISOR,
+ 4392 * XV_CSC_SCALE_FACTOR / XV_CSC_DIVISOR,
+ 0
+ },
+ {
+ 4392 * XV_CSC_SCALE_FACTOR / XV_CSC_DIVISOR,
+ -3989 * XV_CSC_SCALE_FACTOR / XV_CSC_DIVISOR,
+ -403 * XV_CSC_SCALE_FACTOR / XV_CSC_DIVISOR,
+ 0,
+ },
+};
+
+/**
+ * struct xcsc_dev - xilinx vpss csc device structure
+ * @xvip: Xilinx Video IP core struct
+ * @pads: Media bus pads for VPSS CSC
+ * @formats: Current media bus formats
+ * @default_formats: Default media bus formats for VPSS CSC
+ * @vip_formats: Pointer to DT specified media bus code info
+ * @ctrl_handler: V4L2 Control Handler struct
+ * @custom_ctrls: Array of pointers to various custom controls
+ * @cft_in: IP or Hardware specific input video format
+ * @cft_out: IP or Hardware specific output video format
+ * @output_range: Color range for Outgoing video
+ * @color_depth: Data width used to represent color
+ * @brightness: Expected brightness value
+ * @contrast: Expected contrast value
+ * @red_gain: Expected red gain
+ * @green_gain: Expect green gain
+ * @blue_gain: Expected blue gain
+ * @brightness_active: Current brightness value
+ * @contrast_active: Current contrast value
+ * @red_gain_active: Current red gain
+ * @green_gain_active: Current green gain
+ * @blue_gain_active: Current blue gain
+ * @k_hw : Coefficients to be written to IP/Hardware
+ * @shadow_coeff: Coefficients to track RGB equivalents for color controls
+ * @clip_max: Maximum value to clip output color range
+ * @rst_gpio: Handle to PS GPIO specifier to assert/de-assert the reset line
+ * @max_width: Maximum width supported by IP.
+ * @max_height: Maximum height supported by IP.
+ */
+struct xcsc_dev {
+ struct xvip_device xvip;
+ struct media_pad pads[2];
+ struct v4l2_mbus_framefmt formats[2];
+ struct v4l2_mbus_framefmt default_formats[2];
+ const struct xvip_video_format *vip_formats[2];
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_ctrl *custom_ctrls[XCSC_COLOR_CTRL_COUNT];
+
+ enum xcsc_color_fmt cft_in;
+ enum xcsc_color_fmt cft_out;
+ enum xcsc_output_range output_range;
+ enum xcsc_color_depth color_depth;
+ s32 brightness;
+ s32 contrast;
+ s32 red_gain;
+ s32 green_gain;
+ s32 blue_gain;
+ s32 brightness_active;
+ s32 contrast_active;
+ s32 red_gain_active;
+ s32 green_gain_active;
+ s32 blue_gain_active;
+ s32 k_hw[XV_CSC_K_MAX_ROWS][XV_CSC_K_MAX_COLUMNS + 1];
+ s32 shadow_coeff[XV_CSC_K_MAX_ROWS][XV_CSC_K_MAX_COLUMNS + 1];
+ s32 clip_max;
+ struct gpio_desc *rst_gpio;
+ u32 max_width;
+ u32 max_height;
+};
+
+#ifdef DEBUG
+static u32 xcsc_read(struct xcsc_dev *xcsc, u32 reg)
+{
+ u32 data;
+
+ data = xvip_read(&xcsc->xvip, reg);
+ return data;
+}
+
+static void xcsc_get_coeff(struct xcsc_dev *xcsc, s32 C[3][4])
+{
+ C[0][0] = xcsc_read(xcsc, XV_CSC_K11);
+ C[0][1] = xcsc_read(xcsc, XV_CSC_K12);
+ C[0][2] = xcsc_read(xcsc, XV_CSC_K13);
+ C[1][0] = xcsc_read(xcsc, XV_CSC_K21);
+ C[1][1] = xcsc_read(xcsc, XV_CSC_K22);
+ C[1][2] = xcsc_read(xcsc, XV_CSC_K23);
+ C[2][0] = xcsc_read(xcsc, XV_CSC_K31);
+ C[2][1] = xcsc_read(xcsc, XV_CSC_K32);
+ C[2][2] = xcsc_read(xcsc, XV_CSC_K33);
+ C[0][3] = xcsc_read(xcsc, XV_CSC_ROFFSET);
+ C[1][3] = xcsc_read(xcsc, XV_CSC_GOFFSET);
+ C[2][3] = xcsc_read(xcsc, XV_CSC_BOFFSET);
+}
+
+static void xcsc_print_coeff(struct xcsc_dev *xcsc)
+{
+ s32 C[3][4];
+
+ xcsc_get_coeff(xcsc, C);
+
+ dev_info(xcsc->xvip.dev,
+ "-------------CSC Coeff Dump Start------\n");
+ dev_info(xcsc->xvip.dev,
+ " R row : %5d %5d %5d\n",
+ (s16)C[0][0], (s16)C[0][1], (s16)C[0][2]);
+ dev_info(xcsc->xvip.dev,
+ " G row : %5d %5d %5d\n",
+ (s16)C[1][0], (s16)C[1][1], (s16)C[1][2]);
+ dev_info(xcsc->xvip.dev,
+ " B row : %5d %5d %5d\n",
+ (s16)C[2][0], (s16)C[2][1], (s16)C[2][2]);
+ dev_info(xcsc->xvip.dev,
+ "Offset : %5d %5d %5d\n",
+ (s16)C[0][3], (s16)C[1][3], (s16)C[2][3]);
+ dev_info(xcsc->xvip.dev,
+ "ClampMin: %3d ClipMax %3d",
+ xcsc_read(xcsc, XV_CSC_CLAMPMIN),
+ xcsc_read(xcsc, XV_CSC_CLIPMAX));
+ dev_info(xcsc->xvip.dev,
+ "-------------CSC Coeff Dump Stop-------\n");
+}
+
+static void
+xcsc_log_coeff(struct device *dev,
+ s32 coeff[XV_CSC_K_MAX_ROWS][XV_CSC_K_MAX_COLUMNS + 1])
+{
+ if (!dev)
+ return;
+ dev_dbg(dev, "--- %s : Start Coeff Log ---", __func__);
+ dev_dbg(dev, "R row : %5d %5d %5d\n",
+ coeff[0][0], coeff[0][1], coeff[0][2]);
+ dev_dbg(dev, "G row : %5d %5d %5d\n",
+ coeff[1][0], coeff[1][1], coeff[1][2]);
+ dev_dbg(dev, "B row : %5d %5d %5d\n",
+ coeff[2][0], coeff[2][1], coeff[2][2]);
+ dev_dbg(dev, "Offset: %5d %5d %5d\n",
+ coeff[0][3], coeff[1][3], coeff[2][3]);
+ dev_dbg(dev, "--- %s : Stop Coeff Log ---", __func__);
+}
+
+static void xcsc_print_k_hw(struct xcsc_dev *xcsc)
+{
+ dev_dbg(xcsc->xvip.dev,
+ "-------------CSC Driver k_hw[][] Dump------------\n");
+ xcsc_log_coeff(xcsc->xvip.dev, xcsc->k_hw);
+ dev_dbg(xcsc->xvip.dev,
+ "-------------------------------------------------\n");
+}
+#endif /* DEBUG */
+
+static void xcsc_write(struct xcsc_dev *xcsc, u32 reg, u32 data)
+{
+ xvip_write(&xcsc->xvip, reg, data);
+}
+
+static void xcsc_write_rgb_3x3(struct xcsc_dev *xcsc)
+{
+ /* Write Matrix Coefficients */
+ xcsc_write(xcsc, XV_CSC_K11, xcsc->k_hw[0][0]);
+ xcsc_write(xcsc, XV_CSC_K12, xcsc->k_hw[0][1]);
+ xcsc_write(xcsc, XV_CSC_K13, xcsc->k_hw[0][2]);
+ xcsc_write(xcsc, XV_CSC_K21, xcsc->k_hw[1][0]);
+ xcsc_write(xcsc, XV_CSC_K22, xcsc->k_hw[1][1]);
+ xcsc_write(xcsc, XV_CSC_K23, xcsc->k_hw[1][2]);
+ xcsc_write(xcsc, XV_CSC_K31, xcsc->k_hw[2][0]);
+ xcsc_write(xcsc, XV_CSC_K32, xcsc->k_hw[2][1]);
+ xcsc_write(xcsc, XV_CSC_K33, xcsc->k_hw[2][2]);
+}
+
+static void xcsc_write_rgb_offset(struct xcsc_dev *xcsc)
+{
+ /* Write RGB Offsets */
+ xcsc_write(xcsc, XV_CSC_ROFFSET, xcsc->k_hw[0][3]);
+ xcsc_write(xcsc, XV_CSC_GOFFSET, xcsc->k_hw[1][3]);
+ xcsc_write(xcsc, XV_CSC_BOFFSET, xcsc->k_hw[2][3]);
+}
+
+static void xcsc_write_coeff(struct xcsc_dev *xcsc)
+{
+ xcsc_write_rgb_3x3(xcsc);
+ xcsc_write_rgb_offset(xcsc);
+}
+
+static void xcsc_set_v4l2_ctrl_defaults(struct xcsc_dev *xcsc)
+{
+ unsigned int i;
+
+ mutex_lock(xcsc->ctrl_handler.lock);
+ for (i = 0; i < XCSC_COLOR_CTRL_COUNT; i++)
+ xcsc->custom_ctrls[i]->cur.val = XCSC_COLOR_CTRL_DEFAULT;
+ mutex_unlock(xcsc->ctrl_handler.lock);
+}
+
+static void xcsc_set_control_defaults(struct xcsc_dev *xcsc)
+{
+ /* These are VPSS CSC IP specific defaults */
+ xcsc->brightness = 120;
+ xcsc->contrast = 0;
+ xcsc->red_gain = 120;
+ xcsc->blue_gain = 120;
+ xcsc->green_gain = 120;
+ xcsc->brightness_active = 120;
+ xcsc->contrast_active = 0;
+ xcsc->red_gain_active = 120;
+ xcsc->blue_gain_active = 120;
+ xcsc->green_gain_active = 120;
+}
+
+static void xcsc_copy_coeff(
+ s32 dest[XV_CSC_K_MAX_ROWS][XV_CSC_K_MAX_COLUMNS + 1],
+ s32 const src[XV_CSC_K_MAX_ROWS][XV_CSC_K_MAX_COLUMNS + 1])
+{
+ unsigned int i, j;
+
+ for (i = 0; i < XV_CSC_K_MAX_ROWS; i++)
+ for (j = 0; j < XV_CSC_K_MAX_COLUMNS + 1; j++)
+ memcpy(&dest[i][j], &src[i][j], sizeof(dest[0][0]));
+}
+
+static void xcsc_set_unity_matrix(struct xcsc_dev *xcsc)
+{
+ xcsc_copy_coeff(xcsc->k_hw, rgb_unity_matrix);
+ xcsc_copy_coeff(xcsc->shadow_coeff, rgb_unity_matrix);
+}
+
+static void xcsc_set_default_state(struct xcsc_dev *xcsc)
+{
+ xcsc->cft_in = XVIDC_CSF_RGB;
+ xcsc->cft_out = XVIDC_CSF_RGB;
+ xcsc->output_range = XVIDC_CR_0_255;
+ /* Needed to add 10, 12 and 16 bit color depth support */
+ xcsc->clip_max = BIT(xcsc->color_depth) - 1;
+ xcsc_set_control_defaults(xcsc);
+ xcsc_set_unity_matrix(xcsc);
+ xcsc_write(xcsc, XV_CSC_INVIDEOFORMAT, xcsc->cft_in);
+ xcsc_write(xcsc, XV_CSC_OUTVIDEOFORMAT, xcsc->cft_out);
+ xcsc_write_coeff(xcsc);
+ xcsc_write(xcsc, XV_CSC_CLIPMAX, xcsc->clip_max);
+ xcsc_write(xcsc, XV_CSC_CLAMPMIN, XCSC_CLAMP_MIN_ZERO);
+}
+
+static void
+xcsc_ycrcb_to_rgb(struct xcsc_dev *xcsc, s32 *clip_max,
+ s32 temp[XV_CSC_K_MAX_ROWS][XV_CSC_K_MAX_COLUMNS + 1])
+{
+ u16 bpc_scale = BIT(xcsc->color_depth - 8);
+
+ /*
+ * See http://graficaobscura.com/matrix/index.html for
+ * how these numbers are derived. The VPSS CSC IP is
+ * derived from this Matrix style algorithm. And the
+ * 'magic' numbers here are derived from the algorithm.
+ *
+ * XV_CSC_DIVISOR is used to help with floating constants
+ * while performing multiplicative operations
+ *
+ * Coefficients valid only for BT 709
+ */
+ dev_dbg(xcsc->xvip.dev, "Performing YCrCb to RGB BT 709");
+ xcsc_copy_coeff(temp, ycrcb_to_rgb_unity);
+ temp[0][3] = -248 * bpc_scale;
+ temp[1][3] = 77 * bpc_scale;
+ temp[2][3] = -289 * bpc_scale;
+ *clip_max = BIT(xcsc->color_depth) - 1;
+}
+
+static void
+xcsc_matrix_multiply(s32 K1[XV_CSC_K_MAX_ROWS][XV_CSC_K_MAX_COLUMNS + 1],
+ s32 K2[XV_CSC_K_MAX_ROWS][XV_CSC_K_MAX_COLUMNS + 1],
+ s32 kout[XV_CSC_K_MAX_ROWS][XV_CSC_K_MAX_COLUMNS + 1])
+{
+ s32 A, B, C, D, E, F, G, H, I, J, K, L, M, N;
+ s32 O, P, Q, R, S, T, U, V, W, X;
+
+ A = K1[0][0]; B = K1[0][1]; C = K1[0][2]; J = K1[0][3];
+ D = K1[1][0]; E = K1[1][1]; F = K1[1][2]; K = K1[1][3];
+ G = K1[2][0]; H = K1[2][1]; I = K1[2][2]; L = K1[2][3];
+
+ M = K2[0][0]; N = K2[0][1]; O = K2[0][2]; V = K2[0][3];
+ P = K2[1][0]; Q = K2[1][1]; R = K2[1][2]; W = K2[1][3];
+ S = K2[2][0]; T = K2[2][1]; U = K2[2][2]; X = K2[2][3];
+
+ kout[0][0] = (M * A + N * D + O * G) / XV_CSC_SCALE_FACTOR;
+ kout[0][1] = (M * B + N * E + O * H) / XV_CSC_SCALE_FACTOR;
+ kout[0][2] = (M * C + N * F + O * I) / XV_CSC_SCALE_FACTOR;
+ kout[1][0] = (P * A + Q * D + R * G) / XV_CSC_SCALE_FACTOR;
+ kout[1][1] = (P * B + Q * E + R * H) / XV_CSC_SCALE_FACTOR;
+ kout[1][2] = (P * C + Q * F + R * I) / XV_CSC_SCALE_FACTOR;
+ kout[2][0] = (S * A + T * D + U * G) / XV_CSC_SCALE_FACTOR;
+ kout[2][1] = (S * B + T * E + U * H) / XV_CSC_SCALE_FACTOR;
+ kout[2][2] = (S * C + T * F + U * I) / XV_CSC_SCALE_FACTOR;
+ kout[0][3] = ((M * J + N * K + O * L) / XV_CSC_SCALE_FACTOR) + V;
+ kout[1][3] = ((P * J + Q * K + R * L) / XV_CSC_SCALE_FACTOR) + W;
+ kout[2][3] = ((S * J + T * K + U * L) / XV_CSC_SCALE_FACTOR) + X;
+}
+
+static void
+xcsc_rgb_to_ycrcb(struct xcsc_dev *xcsc, s32 *clip_max,
+ s32 temp[XV_CSC_K_MAX_ROWS][XV_CSC_K_MAX_COLUMNS + 1])
+{
+ u16 bpc_scale = BIT(xcsc->color_depth - 8);
+
+ /*
+ * See http://graficaobscura.com/matrix/index.html for
+ * how these numbers are derived. The VPSS CSC IP is
+ * derived from this Matrix style algorithm. And the
+ * 'magic' numbers here are derived from the algorithm.
+ *
+ * XV_CSC_DIVISOR is used to help with floating constants
+ * while performing multiplicative operations
+ *
+ * Coefficients valid only for BT 709
+ */
+ dev_dbg(xcsc->xvip.dev, "Performing RGB to YCrCb BT 709");
+ xcsc_copy_coeff(temp, rgb_to_ycrcb_unity);
+ temp[0][3] = 16 * bpc_scale;
+ temp[1][3] = 128 * bpc_scale;
+ temp[2][3] = 128 * bpc_scale;
+ *clip_max = BIT(xcsc->color_depth) - 1;
+}
+
+static int xcsc_update_formats(struct xcsc_dev *xcsc)
+{
+ u32 color_in, color_out;
+
+ /* Write In and Out Video Formats */
+ color_in = xcsc->formats[XVIP_PAD_SINK].code;
+ color_out = xcsc->formats[XVIP_PAD_SOURCE].code;
+
+ switch (color_in) {
+ case MEDIA_BUS_FMT_RBG888_1X24:
+ case MEDIA_BUS_FMT_RBG101010_1X30:
+ dev_dbg(xcsc->xvip.dev, "Media Format In : RGB");
+ xcsc->cft_in = XVIDC_CSF_RGB;
+ break;
+ case MEDIA_BUS_FMT_VUY8_1X24:
+ case MEDIA_BUS_FMT_VUY10_1X30:
+ dev_dbg(xcsc->xvip.dev, "Media Format In : YUV 444");
+ xcsc->cft_in = XVIDC_CSF_YCRCB_444;
+ break;
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_UYVY10_1X20:
+ dev_dbg(xcsc->xvip.dev, "Media Format In : YUV 422");
+ xcsc->cft_in = XVIDC_CSF_YCRCB_422;
+ break;
+ case MEDIA_BUS_FMT_VYYUYY8_1X24:
+ case MEDIA_BUS_FMT_VYYUYY10_4X20:
+ dev_dbg(xcsc->xvip.dev, "Media Format In : YUV 420");
+ xcsc->cft_in = XVIDC_CSF_YCRCB_420;
+ break;
+ }
+
+ switch (color_out) {
+ case MEDIA_BUS_FMT_RBG888_1X24:
+ case MEDIA_BUS_FMT_RBG101010_1X30:
+ xcsc->cft_out = XVIDC_CSF_RGB;
+ dev_dbg(xcsc->xvip.dev, "Media Format Out : RGB");
+ if (color_in != MEDIA_BUS_FMT_RBG888_1X24)
+ xcsc_ycrcb_to_rgb(xcsc, &xcsc->clip_max, xcsc->k_hw);
+ else
+ xcsc_set_unity_matrix(xcsc);
+ break;
+ case MEDIA_BUS_FMT_VUY8_1X24:
+ case MEDIA_BUS_FMT_VUY10_1X30:
+ xcsc->cft_out = XVIDC_CSF_YCRCB_444;
+ dev_dbg(xcsc->xvip.dev, "Media Format Out : YUV 444");
+ if (color_in == MEDIA_BUS_FMT_RBG888_1X24)
+ xcsc_rgb_to_ycrcb(xcsc, &xcsc->clip_max, xcsc->k_hw);
+ else
+ xcsc_set_unity_matrix(xcsc);
+ break;
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_UYVY10_1X20:
+ xcsc->cft_out = XVIDC_CSF_YCRCB_422;
+ dev_dbg(xcsc->xvip.dev, "Media Format Out : YUV 422");
+ if (color_in == MEDIA_BUS_FMT_RBG888_1X24)
+ xcsc_rgb_to_ycrcb(xcsc, &xcsc->clip_max, xcsc->k_hw);
+ else
+ xcsc_set_unity_matrix(xcsc);
+ break;
+ case MEDIA_BUS_FMT_VYYUYY8_1X24:
+ case MEDIA_BUS_FMT_VYYUYY10_4X20:
+ xcsc->cft_out = XVIDC_CSF_YCRCB_420;
+ dev_dbg(xcsc->xvip.dev, "Media Format Out : YUV 420");
+ if (color_in == MEDIA_BUS_FMT_RBG888_1X24)
+ xcsc_rgb_to_ycrcb(xcsc, &xcsc->clip_max, xcsc->k_hw);
+ else
+ xcsc_set_unity_matrix(xcsc);
+ break;
+ }
+
+ xcsc_write(xcsc, XV_CSC_INVIDEOFORMAT, xcsc->cft_in);
+ xcsc_write(xcsc, XV_CSC_OUTVIDEOFORMAT, xcsc->cft_out);
+
+ xcsc_write_coeff(xcsc);
+
+ xcsc_write(xcsc, XV_CSC_CLIPMAX, xcsc->clip_max);
+ xcsc_write(xcsc, XV_CSC_CLAMPMIN, XCSC_CLAMP_MIN_ZERO);
+#ifdef DEBUG
+ xcsc_print_k_hw(xcsc);
+ xcsc_print_coeff(xcsc);
+#endif
+ return 0;
+}
+
+static inline struct xcsc_dev *to_csc(struct v4l2_subdev *subdev)
+{
+ return container_of(subdev, struct xcsc_dev, xvip.subdev);
+}
+
+static struct v4l2_mbus_framefmt *
+__xcsc_get_pad_format(struct xcsc_dev *xcsc,
+ struct v4l2_subdev_pad_config *cfg,
+ unsigned int pad, u32 which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_format(&xcsc->xvip.subdev, cfg, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &xcsc->formats[pad];
+ default:
+ return NULL;
+ }
+}
+
+static void
+xcsc_correct_coeff(struct xcsc_dev *xcsc,
+ s32 temp[XV_CSC_K_MAX_ROWS][XV_CSC_K_MAX_COLUMNS + 1])
+{
+ s32 csc_change[XV_CSC_K_MAX_ROWS][XV_CSC_K_MAX_COLUMNS + 1] = { {0} };
+ s32 csc_extra[XV_CSC_K_MAX_ROWS][XV_CSC_K_MAX_COLUMNS + 1] = { {0} };
+ u32 mbus_in = xcsc->formats[XVIP_PAD_SINK].code;
+ u32 mbus_out = xcsc->formats[XVIP_PAD_SOURCE].code;
+
+#ifdef DEBUG
+ xcsc_log_coeff(xcsc->xvip.dev, temp);
+#endif
+ if (mbus_in == MEDIA_BUS_FMT_RBG888_1X24 && mbus_out == mbus_in) {
+ dev_dbg(xcsc->xvip.dev, "%s : RGB to RGB", __func__);
+ xcsc_copy_coeff(xcsc->k_hw,
+ (const s32 (*)[XV_CSC_K_MAX_COLUMNS + 1])temp);
+ } else if (mbus_in == MEDIA_BUS_FMT_RBG888_1X24 &&
+ mbus_out != MEDIA_BUS_FMT_RBG888_1X24) {
+ dev_dbg(xcsc->xvip.dev, "%s : RGB to YUV", __func__);
+ xcsc_rgb_to_ycrcb(xcsc, &xcsc->clip_max, csc_change);
+ xcsc_matrix_multiply(temp, csc_change, xcsc->k_hw);
+ } else if (mbus_in != MEDIA_BUS_FMT_RBG888_1X24 &&
+ mbus_out == MEDIA_BUS_FMT_RBG888_1X24) {
+ dev_dbg(xcsc->xvip.dev, "%s : YUV to RGB", __func__);
+ xcsc_ycrcb_to_rgb(xcsc, &xcsc->clip_max, csc_change);
+ xcsc_matrix_multiply(csc_change, temp, xcsc->k_hw);
+ } else if (mbus_in != MEDIA_BUS_FMT_RBG888_1X24 &&
+ mbus_out != MEDIA_BUS_FMT_RBG888_1X24) {
+ dev_dbg(xcsc->xvip.dev, "%s : YUV to YUV", __func__);
+ xcsc_ycrcb_to_rgb(xcsc, &xcsc->clip_max, csc_change);
+ xcsc_matrix_multiply(csc_change, temp, csc_extra);
+ xcsc_rgb_to_ycrcb(xcsc, &xcsc->clip_max, csc_change);
+ xcsc_matrix_multiply(csc_extra, csc_change, xcsc->k_hw);
+ } else {
+ /* Should never get here */
+ WARN_ON(1);
+ }
+}
+
+static void xcsc_set_brightness(struct xcsc_dev *xcsc)
+{
+ unsigned int i, j;
+
+ dev_dbg(xcsc->xvip.dev,
+ "%s : Brightness %d Brightness Active %d",
+ __func__,
+ ((xcsc->brightness - 20) / 2),
+ ((xcsc->brightness_active - 20) / 2));
+ if (xcsc->brightness == xcsc->brightness_active)
+ return;
+ for (i = 0; i < XV_CSC_K_MAX_ROWS; i++) {
+ for (j = 0; j < XV_CSC_K_MAX_COLUMNS; j++) {
+ xcsc->shadow_coeff[i][j] = (xcsc->shadow_coeff[i][j] *
+ xcsc->brightness) /
+ xcsc->brightness_active;
+ }
+ }
+ xcsc->brightness_active = xcsc->brightness;
+ xcsc_correct_coeff(xcsc, xcsc->shadow_coeff);
+ xcsc_write_coeff(xcsc);
+}
+
+static void xcsc_set_contrast(struct xcsc_dev *xcsc)
+{
+ s32 contrast;
+ u8 scale = BIT(xcsc->color_depth - 8);
+
+ contrast = xcsc->contrast - xcsc->contrast_active;
+ dev_dbg(xcsc->xvip.dev,
+ "%s : Contrast Difference %d scale = %d",
+ __func__, contrast, scale);
+ /* Avoid updates if same */
+ if (!contrast)
+ return;
+ /* Update RGB Offsets */
+ xcsc->shadow_coeff[0][3] += contrast * scale;
+ xcsc->shadow_coeff[1][3] += contrast * scale;
+ xcsc->shadow_coeff[2][3] += contrast * scale;
+ xcsc->contrast_active = xcsc->contrast;
+ xcsc_correct_coeff(xcsc, xcsc->shadow_coeff);
+ xcsc_write_coeff(xcsc);
+}
+
+static void xcsc_set_red_gain(struct xcsc_dev *xcsc)
+{
+ dev_dbg(xcsc->xvip.dev,
+ "%s: Red Gain %d Red Gain Active %d", __func__,
+ (xcsc->red_gain - 20) / 2,
+ (xcsc->red_gain_active - 20) / 2);
+
+ if (xcsc->red_gain != xcsc->red_gain_active) {
+ xcsc->shadow_coeff[0][0] = (xcsc->shadow_coeff[0][0] *
+ xcsc->red_gain) /
+ xcsc->red_gain_active;
+ xcsc->shadow_coeff[0][1] = (xcsc->shadow_coeff[0][1] *
+ xcsc->red_gain) /
+ xcsc->red_gain_active;
+ xcsc->shadow_coeff[0][2] = (xcsc->shadow_coeff[0][2] *
+ xcsc->red_gain) /
+ xcsc->red_gain_active;
+ xcsc->red_gain_active = xcsc->red_gain;
+ xcsc_correct_coeff(xcsc, xcsc->shadow_coeff);
+ xcsc_write_coeff(xcsc);
+ }
+}
+
+static void xcsc_set_green_gain(struct xcsc_dev *xcsc)
+{
+ dev_dbg(xcsc->xvip.dev,
+ "%s: Green Gain %d Green Gain Active %d", __func__,
+ (xcsc->green_gain - 20) / 2,
+ (xcsc->green_gain_active - 20) / 2);
+
+ if (xcsc->green_gain != xcsc->green_gain_active) {
+ xcsc->shadow_coeff[1][0] = (xcsc->shadow_coeff[1][0] *
+ xcsc->green_gain) /
+ xcsc->green_gain_active;
+ xcsc->shadow_coeff[1][1] = (xcsc->shadow_coeff[1][1] *
+ xcsc->green_gain) /
+ xcsc->green_gain_active;
+ xcsc->shadow_coeff[1][2] = (xcsc->shadow_coeff[1][2] *
+ xcsc->green_gain) /
+ xcsc->green_gain_active;
+ xcsc->green_gain_active = xcsc->green_gain;
+ xcsc_correct_coeff(xcsc, xcsc->shadow_coeff);
+ xcsc_write_coeff(xcsc);
+ }
+}
+
+static void xcsc_set_blue_gain(struct xcsc_dev *xcsc)
+{
+ dev_dbg(xcsc->xvip.dev,
+ "%s: Blue Gain %d Blue Gain Active %d", __func__,
+ (xcsc->blue_gain - 20) / 2,
+ (xcsc->blue_gain_active - 20) / 2);
+
+ if (xcsc->blue_gain != xcsc->blue_gain_active) {
+ xcsc->shadow_coeff[2][0] = (xcsc->shadow_coeff[2][0] *
+ xcsc->blue_gain) /
+ xcsc->blue_gain_active;
+ xcsc->shadow_coeff[2][1] = (xcsc->shadow_coeff[2][1] *
+ xcsc->blue_gain) /
+ xcsc->blue_gain_active;
+ xcsc->shadow_coeff[2][2] = (xcsc->shadow_coeff[2][2] *
+ xcsc->blue_gain) /
+ xcsc->blue_gain_active;
+ xcsc->blue_gain_active = xcsc->blue_gain;
+ xcsc_correct_coeff(xcsc, xcsc->shadow_coeff);
+ xcsc_write_coeff(xcsc);
+ }
+}
+
+static void xcsc_set_size(struct xcsc_dev *xcsc)
+{
+ u32 width, height;
+
+ width = xcsc->formats[XVIP_PAD_SINK].width;
+ height = xcsc->formats[XVIP_PAD_SINK].height;
+ dev_dbg(xcsc->xvip.dev, "%s : Setting width %d and height %d",
+ __func__, width, height);
+ xcsc_write(xcsc, XV_CSC_WIDTH, width);
+ xcsc_write(xcsc, XV_CSC_HEIGHT, height);
+}
+
+static int xcsc_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+ struct xcsc_dev *xcsc = to_csc(subdev);
+
+ dev_dbg(xcsc->xvip.dev, "%s : Stream %s", __func__,
+ enable ? "On" : "Off");
+ if (!enable) {
+ /* Reset the Global IP Reset through PS GPIO */
+ gpiod_set_value_cansleep(xcsc->rst_gpio, XCSC_RESET_ASSERT);
+ gpiod_set_value_cansleep(xcsc->rst_gpio, XCSC_RESET_DEASSERT);
+ return 0;
+ }
+ xcsc_write(xcsc, XV_CSC_INVIDEOFORMAT, xcsc->cft_in);
+ xcsc_write(xcsc, XV_CSC_OUTVIDEOFORMAT, xcsc->cft_out);
+ xcsc_write(xcsc, XV_CSC_CLIPMAX, xcsc->clip_max);
+ xcsc_write(xcsc, XV_CSC_CLAMPMIN, XCSC_CLAMP_MIN_ZERO);
+ xcsc_set_size(xcsc);
+ xcsc_write_coeff(xcsc);
+#ifdef DEBUG
+ xcsc_print_coeff(xcsc);
+ dev_dbg(xcsc->xvip.dev, "cft_in = %d cft_out = %d",
+ xcsc_read(xcsc, XV_CSC_INVIDEOFORMAT),
+ xcsc_read(xcsc, XV_CSC_OUTVIDEOFORMAT));
+ dev_dbg(xcsc->xvip.dev, "clipmax = %d clampmin = %d",
+ xcsc_read(xcsc, XV_CSC_CLIPMAX),
+ xcsc_read(xcsc, XV_CSC_CLAMPMIN));
+ dev_dbg(xcsc->xvip.dev, "height = %d width = %d",
+ xcsc_read(xcsc, XV_CSC_HEIGHT),
+ xcsc_read(xcsc, XV_CSC_WIDTH));
+#endif
+ /* Start VPSS CSC IP */
+ xcsc_write(xcsc, XV_CSC_AP_CTRL, XCSC_STREAM_ON);
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops xcsc_video_ops = {
+ .s_stream = xcsc_s_stream,
+};
+
+static int xcsc_get_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xcsc_dev *xcsc = to_csc(subdev);
+
+ fmt->format = *__xcsc_get_pad_format(xcsc, cfg, fmt->pad, fmt->which);
+ return 0;
+}
+
+static int xcsc_set_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xcsc_dev *xcsc = to_csc(subdev);
+ struct v4l2_mbus_framefmt *__format;
+ struct v4l2_mbus_framefmt *__propagate;
+
+ __format = __xcsc_get_pad_format(xcsc, cfg, fmt->pad, fmt->which);
+ /* Propagate to Source Pad */
+ __propagate = __xcsc_get_pad_format(xcsc, cfg,
+ XVIP_PAD_SOURCE, fmt->which);
+ *__format = fmt->format;
+
+ __format->width = clamp_t(unsigned int, fmt->format.width,
+ XV_CSC_MIN_WIDTH, xcsc->max_width);
+ __format->height = clamp_t(unsigned int, fmt->format.height,
+ XV_CSC_MIN_HEIGHT, xcsc->max_height);
+
+ switch (__format->code) {
+ case MEDIA_BUS_FMT_VUY8_1X24:
+ case MEDIA_BUS_FMT_RBG888_1X24:
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_VYYUYY8_1X24:
+ case MEDIA_BUS_FMT_VYYUYY10_4X20:
+ case MEDIA_BUS_FMT_UYVY10_1X20:
+ case MEDIA_BUS_FMT_VUY10_1X30:
+ break;
+ default:
+ /* Unsupported Format. Default to RGB */
+ __format->code = MEDIA_BUS_FMT_RBG888_1X24;
+ return -EINVAL;
+ }
+
+ /* Always propagate Sink image size to Source */
+ __propagate->width = __format->width;
+ __propagate->height = __format->height;
+
+ fmt->format = *__format;
+ xcsc_update_formats(xcsc);
+ xcsc_set_control_defaults(xcsc);
+ xcsc_set_v4l2_ctrl_defaults(xcsc);
+ dev_info(xcsc->xvip.dev, "VPSS CSC color controls reset to defaults");
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops xcsc_pad_ops = {
+ .enum_mbus_code = xvip_enum_mbus_code,
+ .enum_frame_size = xvip_enum_frame_size,
+ .get_fmt = xcsc_get_format,
+ .set_fmt = xcsc_set_format,
+};
+
+static const struct v4l2_subdev_ops xcsc_ops = {
+ .video = &xcsc_video_ops,
+ .pad = &xcsc_pad_ops
+};
+
+static int xcsc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct xcsc_dev *xcsc = container_of(ctrl->handler,
+ struct xcsc_dev,
+ ctrl_handler);
+
+ switch (ctrl->id) {
+ case V4L2_CID_XILINX_CSC_BRIGHTNESS:
+ xcsc->brightness = (2 * ctrl->val) + 20;
+ xcsc_set_brightness(xcsc);
+ break;
+ case V4L2_CID_XILINX_CSC_CONTRAST:
+ xcsc->contrast = (4 * ctrl->val) - 200;
+ xcsc_set_contrast(xcsc);
+ break;
+ case V4L2_CID_XILINX_CSC_RED_GAIN:
+ xcsc->red_gain = (2 * ctrl->val) + 20;
+ xcsc_set_red_gain(xcsc);
+ break;
+ case V4L2_CID_XILINX_CSC_BLUE_GAIN:
+ xcsc->blue_gain = (2 * ctrl->val) + 20;
+ xcsc_set_blue_gain(xcsc);
+ break;
+ case V4L2_CID_XILINX_CSC_GREEN_GAIN:
+ xcsc->green_gain = (2 * ctrl->val) + 20;
+ xcsc_set_green_gain(xcsc);
+ break;
+ }
+#ifdef DEBUG
+ xcsc_print_k_hw(xcsc);
+ xcsc_print_coeff(xcsc);
+#endif
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops xcsc_ctrl_ops = {
+ .s_ctrl = xcsc_s_ctrl,
+};
+
+static struct v4l2_ctrl_config xcsc_color_ctrls[XCSC_COLOR_CTRL_COUNT] = {
+ /* Brightness */
+ {
+ .ops = &xcsc_ctrl_ops,
+ .id = V4L2_CID_XILINX_CSC_BRIGHTNESS,
+ .name = "CSC Brightness",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = 100,
+ .step = 1,
+ .def = XCSC_COLOR_CTRL_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ },
+ /* Contrast */
+ {
+ .ops = &xcsc_ctrl_ops,
+ .id = V4L2_CID_XILINX_CSC_CONTRAST,
+ .name = "CSC Contrast",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = 100,
+ .step = 1,
+ .def = XCSC_COLOR_CTRL_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ },
+ /* Red Gain */
+ {
+ .ops = &xcsc_ctrl_ops,
+ .id = V4L2_CID_XILINX_CSC_RED_GAIN,
+ .name = "CSC Red Gain",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = 100,
+ .step = 1,
+ .def = XCSC_COLOR_CTRL_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ },
+ /* Blue Gain */
+ {
+ .ops = &xcsc_ctrl_ops,
+ .id = V4L2_CID_XILINX_CSC_BLUE_GAIN,
+ .name = "CSC Blue Gain",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = 100,
+ .step = 1,
+ .def = XCSC_COLOR_CTRL_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ },
+ /* Green Gain */
+ {
+ .ops = &xcsc_ctrl_ops,
+ .id = V4L2_CID_XILINX_CSC_GREEN_GAIN,
+ .name = "CSC Green Gain",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = 100,
+ .step = 1,
+ .def = XCSC_COLOR_CTRL_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ },
+};
+
+static int xcsc_open(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh)
+{
+ struct xcsc_dev *xcsc = to_csc(subdev);
+ struct v4l2_mbus_framefmt *format;
+
+ /* Initialize with default formats */
+ format = v4l2_subdev_get_try_format(subdev, fh->pad, XVIP_PAD_SINK);
+ *format = xcsc->default_formats[XVIP_PAD_SINK];
+
+ format = v4l2_subdev_get_try_format(subdev, fh->pad, XVIP_PAD_SOURCE);
+ *format = xcsc->default_formats[XVIP_PAD_SOURCE];
+
+ return 0;
+}
+
+static int xcsc_close(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh)
+{
+ return 0;
+}
+
+static const struct v4l2_subdev_internal_ops xcsc_internal_ops = {
+ .open = xcsc_open,
+ .close = xcsc_close,
+};
+
+static const struct media_entity_operations xcsc_media_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+static int xcsc_parse_of(struct xcsc_dev *xcsc)
+{
+ struct device *dev = xcsc->xvip.dev;
+ struct device_node *node = xcsc->xvip.dev->of_node;
+ const struct xvip_video_format *vip_format;
+ struct device_node *ports, *port;
+ int rval;
+ u32 port_id = 0;
+ u32 video_width[2];
+
+ rval = of_property_read_u32(node, "xlnx,max-height", &xcsc->max_height);
+ if (rval < 0) {
+ dev_err(dev, "xlnx,max-height is missing!");
+ return -EINVAL;
+ } else if (xcsc->max_height > XV_CSC_MAX_HEIGHT ||
+ xcsc->max_height < XV_CSC_MIN_HEIGHT) {
+ dev_err(dev, "Invalid height in dt");
+ return -EINVAL;
+ }
+
+ rval = of_property_read_u32(node, "xlnx,max-width", &xcsc->max_width);
+ if (rval < 0) {
+ dev_err(dev, "xlnx,max-width is missing!");
+ return -EINVAL;
+ } else if (xcsc->max_width > XV_CSC_MAX_WIDTH ||
+ xcsc->max_width < XV_CSC_MIN_WIDTH) {
+ dev_err(dev, "Invalid width in dt");
+ return -EINVAL;
+ }
+
+ ports = of_get_child_by_name(node, "ports");
+ if (!ports)
+ ports = node;
+
+ /* Get the format description for each pad */
+ for_each_child_of_node(ports, port) {
+ if (port->name && (of_node_cmp(port->name, "port") == 0)) {
+ vip_format = xvip_of_get_format(port);
+ if (IS_ERR(vip_format)) {
+ dev_err(dev, "Invalid media pad format in DT");
+ return PTR_ERR(vip_format);
+ }
+
+ rval = of_property_read_u32(port, "reg", &port_id);
+ if (rval < 0) {
+ dev_err(dev, "No reg in DT to specify pad");
+ return rval;
+ }
+
+ if (port_id != 0 && port_id != 1) {
+ dev_err(dev, "Invalid reg in DT");
+ return -EINVAL;
+ }
+ xcsc->vip_formats[port_id] = vip_format;
+
+ rval = of_property_read_u32(port, "xlnx,video-width",
+ &video_width[port_id]);
+ if (rval < 0) {
+ dev_err(dev,
+ "DT Port%d xlnx,video-width not found",
+ port_id);
+ return rval;
+ }
+ }
+ }
+ if (video_width[0] != video_width[1]) {
+ dev_err(dev, "Changing video width in DT not supported");
+ return -EINVAL;
+ }
+ switch (video_width[0]) {
+ case XVIDC_BPC_8:
+ case XVIDC_BPC_10:
+ xcsc->color_depth = video_width[0];
+ break;
+ default:
+ dev_err(dev, "Unsupported color depth %d", video_width[0]);
+ return -EINVAL;
+ }
+ /* Reset GPIO */
+ xcsc->rst_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(xcsc->rst_gpio)) {
+ if (PTR_ERR(xcsc->rst_gpio) != -EPROBE_DEFER)
+ dev_err(dev, "Reset GPIO not setup in DT");
+ return PTR_ERR(xcsc->rst_gpio);
+ }
+ return 0;
+}
+
+static int xcsc_probe(struct platform_device *pdev)
+{
+ struct xcsc_dev *xcsc;
+ struct v4l2_subdev *subdev;
+ struct v4l2_mbus_framefmt *def_fmt;
+ int rval, itr;
+
+ xcsc = devm_kzalloc(&pdev->dev, sizeof(*xcsc), GFP_KERNEL);
+ if (!xcsc)
+ return -ENOMEM;
+
+ xcsc->xvip.dev = &pdev->dev;
+
+ rval = xcsc_parse_of(xcsc);
+ if (rval < 0)
+ return rval;
+
+ /* Reset and initialize the core */
+ gpiod_set_value_cansleep(xcsc->rst_gpio, XCSC_RESET_DEASSERT);
+ rval = xvip_init_resources(&xcsc->xvip);
+ if (rval < 0)
+ return rval;
+
+ /* Init v4l2 subdev */
+ subdev = &xcsc->xvip.subdev;
+ v4l2_subdev_init(subdev, &xcsc_ops);
+ subdev->dev = &pdev->dev;
+ subdev->internal_ops = &xcsc_internal_ops;
+ strlcpy(subdev->name, dev_name(&pdev->dev), sizeof(subdev->name));
+ v4l2_set_subdevdata(subdev, xcsc);
+ subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ /* Default Formats Initialization */
+ xcsc_set_default_state(xcsc);
+ def_fmt = &xcsc->default_formats[XVIP_PAD_SINK];
+ def_fmt->code = xcsc->vip_formats[XVIP_PAD_SINK]->code;
+ def_fmt->field = V4L2_FIELD_NONE;
+ def_fmt->colorspace = V4L2_COLORSPACE_REC709;
+ def_fmt->width = XV_CSC_DEFAULT_WIDTH;
+ def_fmt->height = XV_CSC_DEFAULT_HEIGHT;
+ xcsc->formats[XVIP_PAD_SINK] = *def_fmt;
+ /* Source supports only YUV 444, YUV 422, and RGB */
+ def_fmt = &xcsc->default_formats[XVIP_PAD_SOURCE];
+ *def_fmt = xcsc->default_formats[XVIP_PAD_SINK];
+ def_fmt->code = xcsc->vip_formats[XVIP_PAD_SOURCE]->code;
+ def_fmt->width = XV_CSC_DEFAULT_WIDTH;
+ def_fmt->height = XV_CSC_DEFAULT_HEIGHT;
+ xcsc->formats[XVIP_PAD_SOURCE] = *def_fmt;
+ xcsc->pads[XVIP_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ xcsc->pads[XVIP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+ /* Init Media Entity */
+ subdev->entity.ops = &xcsc_media_ops;
+ rval = media_entity_pads_init(&subdev->entity, 2, xcsc->pads);
+ if (rval < 0)
+ goto media_error;
+ /* V4L2 Control Setup */
+ v4l2_ctrl_handler_init(&xcsc->ctrl_handler,
+ ARRAY_SIZE(xcsc_color_ctrls));
+ for (itr = 0; itr < ARRAY_SIZE(xcsc_color_ctrls); itr++) {
+ xcsc->custom_ctrls[itr] =
+ v4l2_ctrl_new_custom(&xcsc->ctrl_handler,
+ &xcsc_color_ctrls[itr], NULL);
+ }
+ if (xcsc->ctrl_handler.error) {
+ dev_err(&pdev->dev, "Failed to add v4l2 controls");
+ rval = xcsc->ctrl_handler.error;
+ goto ctrl_error;
+ }
+ subdev->ctrl_handler = &xcsc->ctrl_handler;
+ rval = v4l2_ctrl_handler_setup(&xcsc->ctrl_handler);
+ if (rval < 0) {
+ dev_err(xcsc->xvip.dev, "Failed to setup control handler");
+ goto ctrl_error;
+ }
+ platform_set_drvdata(pdev, xcsc);
+ rval = v4l2_async_register_subdev(subdev);
+ if (rval < 0) {
+ dev_err(&pdev->dev, "failed to register subdev\n");
+ goto ctrl_error;
+ }
+ dev_info(&pdev->dev, "VPSS CSC %d-bit Color Depth Probe Successful",
+ xcsc->color_depth);
+ return 0;
+ctrl_error:
+ v4l2_ctrl_handler_free(&xcsc->ctrl_handler);
+ media_entity_cleanup(&subdev->entity);
+media_error:
+ xvip_cleanup_resources(&xcsc->xvip);
+ return rval;
+}
+
+static int xcsc_remove(struct platform_device *pdev)
+{
+ struct xcsc_dev *xcsc = platform_get_drvdata(pdev);
+ struct v4l2_subdev *subdev = &xcsc->xvip.subdev;
+
+ v4l2_async_unregister_subdev(subdev);
+ v4l2_ctrl_handler_free(&xcsc->ctrl_handler);
+ media_entity_cleanup(&subdev->entity);
+ xvip_cleanup_resources(&xcsc->xvip);
+ return 0;
+}
+
+static const struct of_device_id xcsc_of_id_table[] = {
+ {.compatible = "xlnx,v-vpss-csc"},
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, xcsc_of_id_table);
+
+static struct platform_driver xcsc_driver = {
+ .driver = {
+ .name = "xilinx-vpss-csc",
+ .of_match_table = xcsc_of_id_table,
+ },
+ .probe = xcsc_probe,
+ .remove = xcsc_remove,
+};
+
+module_platform_driver(xcsc_driver);
+MODULE_DESCRIPTION("Xilinx VPSS CSC Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/xilinx/xilinx-vpss-scaler.c b/drivers/media/platform/xilinx/xilinx-vpss-scaler.c
new file mode 100644
index 000000000000..e07d7eaad259
--- /dev/null
+++ b/drivers/media/platform/xilinx/xilinx-vpss-scaler.c
@@ -0,0 +1,1878 @@
+/*
+ * Xilinx VPSS Scaler
+ *
+ * Copyright (C) 2017 Xilinx, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include <media/v4l2-async.h>
+#include <media/v4l2-subdev.h>
+#include "xilinx-vip.h"
+
+#define XSCALER_MIN_WIDTH (64)
+#define XSCALER_MAX_WIDTH (8192)
+#define XSCALER_MIN_HEIGHT (64)
+#define XSCALER_MAX_HEIGHT (4320)
+#define XSCALER_MAX_PHASES (64)
+
+/* Modify to defaults incase it is not configured from application */
+#define XSCALER_DEF_IN_HEIGHT (720)
+#define XSCALER_DEF_IN_WIDTH (1280)
+#define XSCALER_DEF_OUT_HEIGHT (1080)
+#define XSCALER_DEF_OUT_WIDTH (1920)
+
+#define XSCALER_HSF (0x0100)
+#define XSCALER_VSF (0x0104)
+#define XSCALER_SF_SHIFT (20)
+#define XSCALER_SF_MASK (0xffffff)
+#define XSCALER_SOURCE_SIZE (0x0108)
+#define XSCALER_SIZE_HORZ_SHIFT (0)
+#define XSCALER_SIZE_VERT_SHIFT (16)
+#define XSCALER_SIZE_MASK (0xfff)
+#define XSCALER_HAPERTURE (0x010c)
+#define XSCALER_VAPERTURE (0x0110)
+#define XSCALER_APERTURE_START_SHIFT (0)
+#define XSCALER_APERTURE_END_SHIFT (16)
+#define XSCALER_OUTPUT_SIZE (0x0114)
+#define XSCALER_COEF_DATA_IN (0x0134)
+#define XSCALER_BITSHIFT_16 (16)
+
+/* Video subsytems block offset */
+#define S_AXIS_RESET_OFF (0x00010000)
+#define V_HSCALER_OFF (0x00000000)
+#define V_VSCALER_OFF (0x00020000)
+
+/* HW Reset Network GPIO Channel */
+#define XGPIO_CH_RESET_SEL (1)
+#define XGPIO_RESET_MASK_VIDEO_IN BIT(0)
+#define XGPIO_RESET_MASK_IP_AXIS BIT(1)
+#define XGPIO_RESET_MASK_IP_AXIMM BIT(0)
+#define XGPIO_RESET_MASK_ALL_BLOCKS (XGPIO_RESET_MASK_VIDEO_IN | \
+ XGPIO_RESET_MASK_IP_AXIS)
+#define XGPIO_DATA_OFFSET (0x0)
+#define XGPIO_TRI_OFFSET (0x4)
+#define XGPIO_DATA2_OFFSET (0x8)
+#define XGPIO_TRI2_OFFSET (0xc)
+
+#define XGPIO_GIE_OFFSET (0x11c)
+#define XGPIO_ISR_OFFSET (0x120)
+#define XGPIO_IER_OFFSET (0x128)
+#define XGPIO_CHAN_OFFSET (8)
+#define STEP_PRECISION (65536)
+
+/* Video IP Formats */
+enum xscaler_vid_reg_fmts {
+ XVIDC_CSF_RGB = 0,
+ XVIDC_CSF_YCRCB_444,
+ XVIDC_CSF_YCRCB_422,
+ XVIDC_CSF_YCRCB_420,
+};
+
+/* Video IP PPC */
+#define XSCALER_PPC_1 (1)
+#define XSCALER_PPC_2 (2)
+
+#define XV_HSCALER_MAX_H_TAPS (12)
+#define XV_HSCALER_MAX_H_PHASES (64)
+#define XV_HSCALER_MAX_LINE_WIDTH (3840)
+#define XV_VSCALER_MAX_V_TAPS (12)
+#define XV_VSCALER_MAX_V_PHASES (64)
+
+#define XV_HSCALER_TAPS_2 (2)
+#define XV_HSCALER_TAPS_4 (4)
+#define XV_HSCALER_TAPS_6 (6)
+#define XV_HSCALER_TAPS_8 (8)
+#define XV_HSCALER_TAPS_10 (10)
+#define XV_HSCALER_TAPS_12 (12)
+#define XV_VSCALER_TAPS_2 (2)
+#define XV_VSCALER_TAPS_4 (4)
+#define XV_VSCALER_TAPS_6 (6)
+#define XV_VSCALER_TAPS_8 (8)
+#define XV_VSCALER_TAPS_10 (10)
+#define XV_VSCALER_TAPS_12 (12)
+
+/* 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)
+#define XHSC_STEP_PRECISION_SHIFT (16)
+#define XHSC_HPHASE_SHIFT_BY_6 (6)
+#define XHSC_HPHASE_MULTIPLIER (9)
+
+/* Mask definitions for Low and high 16 bits in a 32 bit number */
+#define XVSC_MASK_LOW_16BITS GENMASK(15, 0)
+#define XVSC_MASK_HIGH_16BITS GENMASK(31, 16)
+
+/* XSCALER POWER MACROS */
+#define XSCALER_RESET_ASSERT (0x1)
+#define XSCALER_RESET_DEASSERT (0x0)
+
+/* Scaler AP Control Registers */
+#define XSCALER_START BIT(0)
+#define XSCALER_AUTO_RESTART BIT(7)
+#define XSCALER_STREAM_ON (XSCALER_START | XSCALER_AUTO_RESTART)
+
+/* H-scaler registers */
+#define XV_HSCALER_CTRL_ADDR_AP_CTRL (0x0000)
+#define XV_HSCALER_CTRL_ADDR_GIE (0x0004)
+#define XV_HSCALER_CTRL_ADDR_IER (0x0008)
+#define XV_HSCALER_CTRL_ADDR_ISR (0x000c)
+#define XV_HSCALER_CTRL_ADDR_HWREG_HEIGHT_DATA (0x0010)
+#define XV_HSCALER_CTRL_ADDR_HWREG_WIDTHIN_DATA (0x0018)
+#define XV_HSCALER_CTRL_ADDR_HWREG_WIDTHOUT_DATA (0x0020)
+#define XV_HSCALER_CTRL_ADDR_HWREG_COLORMODE_DATA (0x0028)
+#define XV_HSCALER_CTRL_ADDR_HWREG_PIXELRATE_DATA (0x0030)
+#define XV_HSCALER_CTRL_ADDR_HWREG_COLORMODEOUT_DATA (0X0038)
+#define XV_HSCALER_CTRL_ADDR_HWREG_HFLTCOEFF_BASE (0x0800)
+#define XV_HSCALER_CTRL_ADDR_HWREG_HFLTCOEFF_HIGH (0x0bff)
+
+/* H-scaler coefficients for 6, 8, 10 and 12 tap filters */
+static const u16
+xhsc_coeff_taps6[XV_HSCALER_MAX_H_PHASES][XV_HSCALER_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[XV_HSCALER_MAX_H_PHASES][XV_HSCALER_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[XV_HSCALER_MAX_H_PHASES][XV_HSCALER_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[XV_HSCALER_MAX_H_PHASES][XV_HSCALER_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, },
+};
+
+#define XV_HSCALER_CTRL_WIDTH_HWREG_HFLTCOEFF (16)
+#define XV_HSCALER_CTRL_DEPTH_HWREG_HFLTCOEFF (384)
+#define XV_HSCALER_CTRL_ADDR_HWREG_PHASESH_V_BASE (0x2000)
+#define XV_HSCALER_CTRL_ADDR_HWREG_PHASESH_V_HIGH (0x3fff)
+#define XV_HSCALER_CTRL_WIDTH_HWREG_PHASESH_V (18)
+#define XV_HSCALER_CTRL_DEPTH_HWREG_PHASESH_V (1920)
+
+/* H-scaler masks */
+#define XV_HSCALER_PHASESH_V_OUTPUT_WR_EN BIT(8)
+
+/* V-scaler registers */
+#define XV_VSCALER_CTRL_ADDR_AP_CTRL (0x000)
+#define XV_VSCALER_CTRL_ADDR_GIE (0x004)
+#define XV_VSCALER_CTRL_ADDR_IER (0x008)
+#define XV_VSCALER_CTRL_ADDR_ISR (0x00c)
+#define XV_VSCALER_CTRL_ADDR_HWREG_HEIGHTIN_DATA (0x010)
+#define XV_VSCALER_CTRL_ADDR_HWREG_WIDTH_DATA (0x018)
+#define XV_VSCALER_CTRL_ADDR_HWREG_HEIGHTOUT_DATA (0x020)
+#define XV_VSCALER_CTRL_ADDR_HWREG_LINERATE_DATA (0x028)
+#define XV_VSCALER_CTRL_ADDR_HWREG_COLORMODE_DATA (0x030)
+#define XV_VSCALER_CTRL_ADDR_HWREG_VFLTCOEFF_BASE (0x800)
+#define XV_VSCALER_CTRL_ADDR_HWREG_VFLTCOEFF_HIGH (0xbff)
+
+/* V-scaler coefficients for 6, 8, 10 and 12 tap filters */
+static const u16
+xvsc_coeff_taps6[XV_VSCALER_MAX_V_PHASES][XV_VSCALER_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[XV_VSCALER_MAX_V_PHASES][XV_VSCALER_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[XV_VSCALER_MAX_V_PHASES][XV_VSCALER_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[XV_VSCALER_MAX_V_PHASES][XV_VSCALER_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, },
+};
+
+#define XV_VSCALER_CTRL_WIDTH_HWREG_VFLTCOEFF (16)
+#define XV_VSCALER_CTRL_DEPTH_HWREG_VFLTCOEFF (384)
+
+#define XSCALER_CLK_PROP BIT(0)
+
+/**
+ * struct xscaler_feature - dt or IP property structure
+ * @flags: Bitmask of properties enabled in IP or dt
+ */
+struct xscaler_feature {
+ u32 flags;
+};
+
+/**
+ * struct xscaler_device - Xilinx Scaler device structure
+ * @xvip: Xilinx Video IP device
+ * @pads: Scaler sub-device media pads
+ * @formats: V4L2 media bus formats at the sink and source pads
+ * @default_formats: default V4L2 media bus formats
+ * @vip_formats: Xilinx Video IP format retrieved from the DT
+ * @num_hori_taps: number of horizontal taps
+ * @num_vert_taps: number of vertical taps
+ * @max_num_phases: maximum number of phases
+ * @pix_per_clk: Pixels per Clock cycle the IP operates upon
+ * @max_pixels: The maximum number of pixels that the H-scaler examines
+ * @max_lines: The maximum number of lines that the V-scaler examines
+ * @H_phases: The phases needed to program the H-scaler for different taps
+ * @hscaler_coeff: The complete array of H-scaler coefficients
+ * @vscaler_coeff: The complete array of V-scaler coefficients
+ * @is_polyphase: Track if scaling algorithm is polyphase or not
+ * @rst_gpio: GPIO reset line to bring VPSS Scaler out of reset
+ * @cfg: Pointer to scaler config structure
+ * @aclk_axis: AXI4-Stream video interface clock
+ * @aclk_ctrl: AXI4-Lite control interface clock
+ */
+struct xscaler_device {
+ struct xvip_device xvip;
+
+ struct media_pad pads[2];
+ struct v4l2_mbus_framefmt formats[2];
+ struct v4l2_mbus_framefmt default_formats[2];
+ const struct xvip_video_format *vip_formats[2];
+
+ u32 num_hori_taps;
+ u32 num_vert_taps;
+ u32 max_num_phases;
+ u32 pix_per_clk;
+ u32 max_pixels;
+ u32 max_lines;
+ u32 H_phases[XV_HSCALER_MAX_LINE_WIDTH];
+ short hscaler_coeff[XV_HSCALER_MAX_H_PHASES][XV_HSCALER_MAX_H_TAPS];
+ short vscaler_coeff[XV_VSCALER_MAX_V_PHASES][XV_VSCALER_MAX_V_TAPS];
+ bool is_polyphase;
+
+ struct gpio_desc *rst_gpio;
+ const struct xscaler_feature *cfg;
+ struct clk *aclk_axis;
+ struct clk *aclk_ctrl;
+};
+
+static const struct xscaler_feature xlnx_scaler_v1_0 = {
+ .flags = XSCALER_CLK_PROP,
+};
+
+static const struct xscaler_feature xlnx_scaler = {
+ .flags = 0,
+};
+
+static const struct of_device_id xscaler_of_id_table[] = {
+ { .compatible = "xlnx,v-vpss-scaler",
+ .data = &xlnx_scaler},
+ { .compatible = "xlnx,v-vpss-scaler-1.0",
+ .data = &xlnx_scaler_v1_0},
+ { /* end of table */ }
+};
+MODULE_DEVICE_TABLE(of, xscaler_of_id_table);
+
+static inline struct xscaler_device *to_scaler(struct v4l2_subdev *subdev)
+{
+ return container_of(subdev, struct xscaler_device, xvip.subdev);
+}
+
+static void
+xv_hscaler_calculate_phases(struct xscaler_device *xscaler,
+ u32 width_in, u32 width_out, u32 pixel_rate)
+{
+ unsigned int loop_width;
+ unsigned int x, s;
+ int offset = 0;
+ int xwrite_pos = 0;
+ bool output_write_en;
+ bool get_new_pix;
+ u64 phaseH;
+ u32 array_idx = 0;
+ int nr_rds;
+ int nr_rds_clck;
+ unsigned int nphases = xscaler->max_num_phases;
+ unsigned int nppc = xscaler->pix_per_clk;
+ unsigned int shift = XHSC_STEP_PRECISION_SHIFT - ilog2(nphases);
+
+ loop_width = max_t(u32, width_in, width_out);
+ loop_width = ALIGN(loop_width + nppc - 1, nppc);
+
+ for (x = 0; x < loop_width; x++) {
+ nr_rds_clck = 0;
+ for (s = 0; s < nppc; s++) {
+ phaseH = (offset >> shift) & (nphases - 1);
+ get_new_pix = false;
+ output_write_en = false;
+ if ((offset >> XHSC_STEP_PRECISION_SHIFT) != 0) {
+ /* read a new input sample */
+ get_new_pix = true;
+ offset -= (1 << XHSC_STEP_PRECISION_SHIFT);
+ array_idx++;
+ }
+
+ if (((offset >> XHSC_STEP_PRECISION_SHIFT) == 0) &&
+ (xwrite_pos < width_out)) {
+ /* produce a new output sample */
+ offset += pixel_rate;
+ output_write_en = true;
+ xwrite_pos++;
+ }
+
+ /* Needs updates for 4 PPC */
+ xscaler->H_phases[x] |= (phaseH <<
+ (s * XHSC_HPHASE_MULTIPLIER));
+ xscaler->H_phases[x] |= (array_idx <<
+ (XHSC_HPHASE_SHIFT_BY_6 +
+ (s * XHSC_HPHASE_MULTIPLIER)));
+ if (output_write_en) {
+ xscaler->H_phases[x] |=
+ (XV_HSCALER_PHASESH_V_OUTPUT_WR_EN <<
+ (s * XHSC_HPHASE_MULTIPLIER));
+ }
+
+ if (get_new_pix)
+ nr_rds_clck++;
+ }
+ if (array_idx >= nppc)
+ array_idx &= (nppc - 1);
+
+ nr_rds += nr_rds_clck;
+ if (nr_rds >= nppc)
+ nr_rds -= nppc;
+ }
+}
+
+static void
+xv_hscaler_load_ext_coeff(struct xscaler_device *xscaler,
+ const short *coeff, u32 ntaps)
+{
+ unsigned int i, j, pad, offset;
+ u32 nphases = xscaler->max_num_phases;
+
+ /* Determine if coefficient needs padding (effective vs. max taps) */
+ pad = XV_HSCALER_MAX_H_TAPS - ntaps;
+ offset = pad >> 1;
+ dev_dbg(xscaler->xvip.dev,
+ "%s : Pad = %d Offset = %d Nphases = %d ntaps = %d",
+ __func__, pad, offset, nphases, ntaps);
+
+ /* 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];
+ }
+
+ if (pad) { /* effective taps < max_taps */
+ for (i = 0; i < nphases; i++) {
+ /* pad left */
+ for (j = 0; j < offset; j++)
+ xscaler->hscaler_coeff[i][j] = 0;
+ /* pad right */
+ j = ntaps + offset;
+ for (; j < XV_HSCALER_MAX_H_TAPS; j++)
+ xscaler->hscaler_coeff[i][j] = 0;
+ }
+ }
+}
+
+/**
+ * xv_hscaler_coeff_select - Selection of H-Scaler coefficients of operation
+ * @xscaler: VPSS Scaler device information
+ * @width_in: Width of input video
+ * @width_out: Width of desired output video
+ *
+ * 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 int
+xv_hscaler_select_coeff(struct xscaler_device *xscaler,
+ u32 width_in, u32 width_out)
+{
+ const short *coeff;
+ u16 hscale_ratio;
+ u32 ntaps = xscaler->num_hori_taps;
+
+ /*
+ * Scale Down Mode will use dynamic filter selection logic
+ * Scale Up Mode (including 1:1) will always use 6 tap filter
+ */
+ if (width_out < width_in) {
+ hscale_ratio = ((width_in * 10) / width_out);
+
+ switch (xscaler->num_hori_taps) {
+ case XV_HSCALER_TAPS_6:
+ coeff = &xhsc_coeff_taps6[0][0];
+ ntaps = XV_HSCALER_TAPS_6;
+ break;
+ case XV_HSCALER_TAPS_8:
+ if (hscale_ratio > 15) {
+ coeff = &xhsc_coeff_taps8[0][0];
+ ntaps = XV_HSCALER_TAPS_8;
+ } else {
+ coeff = &xhsc_coeff_taps6[0][0];
+ ntaps = XV_HSCALER_TAPS_6;
+ }
+ break;
+ case XV_HSCALER_TAPS_10:
+ if (hscale_ratio > 25) {
+ coeff = &xhsc_coeff_taps10[0][0];
+ ntaps = XV_HSCALER_TAPS_10;
+ } else if (hscale_ratio > 15) {
+ coeff = &xhsc_coeff_taps8[0][0];
+ ntaps = XV_HSCALER_TAPS_8;
+ } else {
+ coeff = &xhsc_coeff_taps6[0][0];
+ ntaps = XV_HSCALER_TAPS_6;
+ }
+ break;
+ case XV_HSCALER_TAPS_12:
+ if (hscale_ratio > 35) {
+ coeff = &xhsc_coeff_taps12[0][0];
+ ntaps = XV_HSCALER_TAPS_12;
+ } else if (hscale_ratio > 25) {
+ coeff = &xhsc_coeff_taps10[0][0];
+ ntaps = XV_HSCALER_TAPS_10;
+ } else if (hscale_ratio > 15) {
+ coeff = &xhsc_coeff_taps8[0][0];
+ ntaps = XV_HSCALER_TAPS_8;
+ } else {
+ coeff = &xhsc_coeff_taps6[0][0];
+ ntaps = XV_HSCALER_TAPS_6;
+ }
+ break;
+ default:
+ dev_err(xscaler->xvip.dev,
+ "Unsupported H-scaler number of taps = %d",
+ xscaler->num_hori_taps);
+ return -EINVAL;
+ }
+ } else {
+ dev_dbg(xscaler->xvip.dev, "H-scaler : scale up 6 tap");
+ coeff = &xhsc_coeff_taps6[0][0];
+ ntaps = XV_HSCALER_TAPS_6;
+ }
+ xv_hscaler_load_ext_coeff(xscaler, coeff, ntaps);
+ return 0;
+}
+
+static void xv_hscaler_set_coeff(struct xscaler_device *xscaler)
+{
+ int val, i, j, offset, rd_indx;
+ u32 ntaps = xscaler->num_hori_taps;
+ u32 nphases = xscaler->max_num_phases;
+ u32 base_addr;
+
+ offset = (XV_HSCALER_MAX_H_TAPS - ntaps) / 2;
+ base_addr = V_HSCALER_OFF + XV_HSCALER_CTRL_ADDR_HWREG_HFLTCOEFF_BASE;
+ 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->xvip, base_addr +
+ ((i * ntaps / 2 + j) * 4), val);
+ }
+ }
+}
+
+static void
+xv_vscaler_load_ext_coeff(struct xscaler_device *xscaler,
+ const short *coeff, u32 ntaps)
+{
+ int i, j, pad, offset;
+ u32 nphases = xscaler->max_num_phases;
+
+ /* Determine if coefficient needs padding (effective vs. max taps) */
+ pad = XV_VSCALER_MAX_V_TAPS - ntaps;
+ offset = pad ? (pad >> 1) : 0;
+
+ dev_dbg(xscaler->xvip.dev,
+ "%s : Pad = %d Offset = %d Nphases = %d ntaps = %d",
+ __func__, pad, offset, nphases, ntaps);
+
+ /* 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];
+ }
+
+ if (pad) { /* effective taps < max_taps */
+ for (i = 0; i < nphases; i++) {
+ /* pad left */
+ for (j = 0; j < offset; j++)
+ xscaler->vscaler_coeff[i][j] = 0;
+ /* pad right */
+ j = ntaps + offset;
+ for (; j < XV_VSCALER_MAX_V_TAPS; j++)
+ xscaler->vscaler_coeff[i][j] = 0;
+ }
+ }
+}
+
+static void xv_vscaler_set_coeff(struct xscaler_device *xscaler)
+{
+ u32 nphases = xscaler->max_num_phases;
+ u32 ntaps = xscaler->num_vert_taps;
+ int val, i, j, offset, rd_indx;
+ u32 base_addr;
+
+ offset = (XV_VSCALER_MAX_V_TAPS - ntaps) / 2;
+ base_addr = V_VSCALER_OFF + XV_VSCALER_CTRL_ADDR_HWREG_VFLTCOEFF_BASE;
+
+ 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->xvip,
+ base_addr + ((i * ntaps / 2 + j) * 4), val);
+ }
+ }
+}
+
+/**
+ * xv_vscaler_coeff_select - Selection of V-Scaler coefficients of operation
+ * @xscaler: VPSS Scaler device information
+ * @height_in: Height of input video
+ * @height_out: Height of desired output video
+ *
+ * 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 10-tap
+ * filter may operate with 6 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
+ * V-scaler number of taps.
+ */
+static int
+xv_vscaler_select_coeff(struct xscaler_device *xscaler,
+ u32 height_in, u32 height_out)
+{
+ const short *coeff;
+ u16 vscale_ratio;
+ u32 ntaps = xscaler->num_vert_taps;
+
+ /*
+ * Scale Down Mode will use dynamic filter selection logic
+ * Scale Up Mode (including 1:1) will always use 6 tap filter
+ */
+
+ if (height_out < height_in) {
+ vscale_ratio = ((height_in * 10) / height_out);
+
+ switch (xscaler->num_vert_taps) {
+ case XV_VSCALER_TAPS_6:
+ coeff = &xvsc_coeff_taps6[0][0];
+ ntaps = XV_VSCALER_TAPS_6;
+ break;
+ case XV_VSCALER_TAPS_8:
+ if (vscale_ratio > 15) {
+ coeff = &xvsc_coeff_taps8[0][0];
+ ntaps = XV_VSCALER_TAPS_8;
+ } else {
+ coeff = &xvsc_coeff_taps6[0][0];
+ ntaps = XV_VSCALER_TAPS_6;
+ }
+ break;
+ case XV_VSCALER_TAPS_10:
+ if (vscale_ratio > 25) {
+ coeff = &xvsc_coeff_taps10[0][0];
+ ntaps = XV_VSCALER_TAPS_10;
+ } else if (vscale_ratio > 15) {
+ coeff = &xvsc_coeff_taps8[0][0];
+ ntaps = XV_VSCALER_TAPS_8;
+ } else {
+ coeff = &xvsc_coeff_taps6[0][0];
+ ntaps = XV_VSCALER_TAPS_6;
+ }
+ break;
+ case XV_VSCALER_TAPS_12:
+ if (vscale_ratio > 35) {
+ coeff = &xvsc_coeff_taps12[0][0];
+ ntaps = XV_VSCALER_TAPS_12;
+ } else if (vscale_ratio > 25) {
+ coeff = &xvsc_coeff_taps10[0][0];
+ ntaps = XV_VSCALER_TAPS_10;
+ } else if (vscale_ratio > 15) {
+ coeff = &xvsc_coeff_taps8[0][0];
+ ntaps = XV_VSCALER_TAPS_8;
+ } else {
+ coeff = &xvsc_coeff_taps6[0][0];
+ ntaps = XV_VSCALER_TAPS_6;
+ }
+ break;
+ default:
+ dev_err(xscaler->xvip.dev,
+ "Unsupported V-scaler number of taps = %d",
+ xscaler->num_vert_taps);
+ return -EINVAL;
+ }
+ } else {
+ dev_dbg(xscaler->xvip.dev, "V-scaler : scale up 6 tap");
+ coeff = &xvsc_coeff_taps6[0][0];
+ ntaps = XV_VSCALER_TAPS_6;
+ }
+
+ xv_vscaler_load_ext_coeff(xscaler, coeff, ntaps);
+ return 0;
+}
+
+/*
+ * V4L2 Subdevice Video Operations
+ */
+
+static inline void
+xv_procss_disable_block(struct xvip_device *xvip, u32 channel, u32 ip_block)
+{
+ xvip_clr(xvip, ((channel - 1) * XGPIO_CHAN_OFFSET) +
+ XGPIO_DATA_OFFSET + S_AXIS_RESET_OFF,
+ ip_block);
+}
+
+static inline void
+xv_procss_enable_block(struct xvip_device *xvip, u32 channel, u32 ip_block)
+{
+ xvip_set(xvip, ((channel - 1) * XGPIO_CHAN_OFFSET) +
+ XGPIO_DATA_OFFSET + S_AXIS_RESET_OFF,
+ ip_block);
+}
+
+static void xscaler_reset(struct xscaler_device *xscaler)
+{
+ xv_procss_disable_block(&xscaler->xvip, XGPIO_CH_RESET_SEL,
+ XGPIO_RESET_MASK_ALL_BLOCKS);
+ xv_procss_enable_block(&xscaler->xvip, XGPIO_CH_RESET_SEL,
+ XGPIO_RESET_MASK_IP_AXIS);
+}
+
+static int
+xv_vscaler_setup_video_fmt(struct xscaler_device *xscaler, u32 code_in)
+{
+ u32 video_in;
+
+ switch (code_in) {
+ case MEDIA_BUS_FMT_VYYUYY8_1X24:
+ case MEDIA_BUS_FMT_VYYUYY10_4X20:
+ dev_dbg(xscaler->xvip.dev,
+ "Vscaler Input Media Format YUV 420");
+ video_in = XVIDC_CSF_YCRCB_420;
+ break;
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_UYVY10_1X20:
+ dev_dbg(xscaler->xvip.dev,
+ "Vscaler Input Media Format YUV 422");
+ video_in = XVIDC_CSF_YCRCB_422;
+ break;
+ case MEDIA_BUS_FMT_VUY8_1X24:
+ case MEDIA_BUS_FMT_VUY10_1X30:
+ dev_dbg(xscaler->xvip.dev,
+ "Vscaler Input Media Format YUV 444");
+ video_in = XVIDC_CSF_YCRCB_444;
+ break;
+ case MEDIA_BUS_FMT_RBG888_1X24:
+ case MEDIA_BUS_FMT_RBG101010_1X30:
+ dev_dbg(xscaler->xvip.dev,
+ "Vscaler Input Media Format RGB");
+ video_in = XVIDC_CSF_RGB;
+ break;
+ default:
+ dev_err(xscaler->xvip.dev,
+ "Vscaler Unsupported Input Media Format 0x%x",
+ code_in);
+ return -EINVAL;
+ }
+ xvip_write(&xscaler->xvip, V_VSCALER_OFF +
+ XV_VSCALER_CTRL_ADDR_HWREG_COLORMODE_DATA,
+ video_in);
+ /*
+ * Vscaler will upscale to YUV 422 before
+ * Hscaler starts operation
+ */
+ if (video_in == XVIDC_CSF_YCRCB_420)
+ return XVIDC_CSF_YCRCB_422;
+ return video_in;
+}
+
+static int xv_hscaler_setup_video_fmt(struct xscaler_device *xscaler,
+ u32 code_out, u32 vsc_out)
+{
+ u32 video_out;
+
+ switch (vsc_out) {
+ case XVIDC_CSF_YCRCB_422:
+ dev_dbg(xscaler->xvip.dev,
+ "Hscaler Input Media Format is YUV 422");
+ break;
+ case XVIDC_CSF_YCRCB_444:
+ dev_dbg(xscaler->xvip.dev,
+ "Hscaler Input Media Format is YUV 444");
+ break;
+ case XVIDC_CSF_RGB:
+ dev_dbg(xscaler->xvip.dev,
+ "Hscaler Input Media Format is RGB");
+ break;
+ default:
+ dev_err(xscaler->xvip.dev,
+ "Hscaler got unsupported format from Vscaler");
+ return -EINVAL;
+ }
+
+ xvip_write(&xscaler->xvip, V_HSCALER_OFF +
+ XV_HSCALER_CTRL_ADDR_HWREG_COLORMODE_DATA,
+ vsc_out);
+
+ switch (code_out) {
+ case MEDIA_BUS_FMT_VYYUYY8_1X24:
+ case MEDIA_BUS_FMT_VYYUYY10_4X20:
+ dev_dbg(xscaler->xvip.dev,
+ "Hscaler Output Media Format YUV 420\n");
+ video_out = XVIDC_CSF_YCRCB_420;
+ break;
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_UYVY10_1X20:
+ dev_dbg(xscaler->xvip.dev,
+ "Hscaler Output Media Format YUV 422\n");
+ video_out = XVIDC_CSF_YCRCB_422;
+ break;
+ case MEDIA_BUS_FMT_VUY8_1X24:
+ case MEDIA_BUS_FMT_VUY10_1X30:
+ dev_dbg(xscaler->xvip.dev,
+ "Hscaler Output Media Format YUV 444\n");
+ video_out = XVIDC_CSF_YCRCB_444;
+ break;
+ case MEDIA_BUS_FMT_RBG888_1X24:
+ case MEDIA_BUS_FMT_RBG101010_1X30:
+ dev_dbg(xscaler->xvip.dev,
+ "Hscaler Output Media Format RGB\n");
+ video_out = XVIDC_CSF_RGB;
+ break;
+ default:
+ dev_err(xscaler->xvip.dev,
+ "Hscaler Unsupported Output Media Format 0x%x",
+ code_out);
+ return -EINVAL;
+ }
+ xvip_write(&xscaler->xvip, V_HSCALER_OFF +
+ XV_HSCALER_CTRL_ADDR_HWREG_COLORMODEOUT_DATA,
+ video_out);
+ return 0;
+}
+
+static void
+xv_hscaler_set_phases(struct xscaler_device *xscaler)
+{
+ u32 loop_width;
+ u32 index, val;
+ u32 offset, i, lsb, msb;
+
+ loop_width = xscaler->max_pixels / xscaler->pix_per_clk;
+ offset = V_HSCALER_OFF + XV_HSCALER_CTRL_ADDR_HWREG_PHASESH_V_BASE;
+
+ switch (xscaler->pix_per_clk) {
+ case XSCALER_PPC_1:
+ /*
+ * phaseH is 64 bits but only lower 16 bits of each entry
+ * is valid .Form a 32 bit word with 16bit LSB from 2
+ * consecutive entries. Need 1 32b write to get 2 entries
+ * into IP registers (i is array loc and index is
+ * address offset)
+ */
+ index = 0;
+ for (i = 0; i < loop_width; i += 2) {
+ lsb = xscaler->H_phases[i] & XHSC_MASK_LOW_16BITS;
+ msb = xscaler->H_phases[i + 1] & XHSC_MASK_LOW_16BITS;
+ val = (msb << 16 | lsb);
+ xvip_write(&xscaler->xvip, offset + (index * 4), val);
+ ++index;
+ }
+ dev_dbg(xscaler->xvip.dev,
+ "%s : Operating in 1 PPC design", __func__);
+ return;
+ case XSCALER_PPC_2:
+ /*
+ * PhaseH is 64bits but only lower 32b of each entry is valid
+ * Need 1 32b write to get each entry into IP registers
+ */
+ for (i = 0; i < loop_width; i++) {
+ val = (xscaler->H_phases[i] &
+ XHSC_MASK_LOW_32BITS);
+ xvip_write(&xscaler->xvip, offset + (i * 4), val);
+ }
+ dev_dbg(xscaler->xvip.dev,
+ "%s : Operating in 2 PPC design", __func__);
+ return;
+ }
+}
+
+static int xscaler_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+ struct xscaler_device *xscaler = to_scaler(subdev);
+ u32 width_in, width_out;
+ u32 height_in, height_out;
+ u32 code_in, code_out;
+ u32 pixel_rate;
+ u32 line_rate;
+ int ret;
+
+ if (!enable) {
+ dev_dbg(xscaler->xvip.dev, "%s: Stream Off", __func__);
+ /* Reset the Global IP Reset through PS GPIO */
+ gpiod_set_value_cansleep(xscaler->rst_gpio,
+ XSCALER_RESET_ASSERT);
+ gpiod_set_value_cansleep(xscaler->rst_gpio,
+ XSCALER_RESET_DEASSERT);
+ xscaler_reset(xscaler);
+ memset(xscaler->H_phases, 0, sizeof(xscaler->H_phases));
+ return 0;
+ }
+
+ dev_dbg(xscaler->xvip.dev, "%s: Stream On", __func__);
+
+ /* Extract Sink Pad Information */
+ width_in = xscaler->formats[XVIP_PAD_SINK].width;
+ height_in = xscaler->formats[XVIP_PAD_SINK].height;
+ code_in = xscaler->formats[XVIP_PAD_SINK].code;
+
+ /* Extract Source Pad Information */
+ width_out = xscaler->formats[XVIP_PAD_SOURCE].width;
+ height_out = xscaler->formats[XVIP_PAD_SOURCE].height;
+ code_out = xscaler->formats[XVIP_PAD_SOURCE].code;
+
+ /*
+ * V Scaler is before H Scaler
+ * V-Scaler_setup
+ */
+ line_rate = (height_in * STEP_PRECISION) / height_out;
+
+ if (xscaler->is_polyphase) {
+ ret = xv_vscaler_select_coeff(xscaler, height_in, height_out);
+ if (ret < 0)
+ return ret;
+ xv_vscaler_set_coeff(xscaler);
+ }
+
+ xvip_write(&xscaler->xvip, V_VSCALER_OFF +
+ XV_VSCALER_CTRL_ADDR_HWREG_HEIGHTIN_DATA, height_in);
+ xvip_write(&xscaler->xvip, V_VSCALER_OFF +
+ XV_VSCALER_CTRL_ADDR_HWREG_WIDTH_DATA, width_in);
+ xvip_write(&xscaler->xvip, V_VSCALER_OFF +
+ XV_VSCALER_CTRL_ADDR_HWREG_HEIGHTOUT_DATA, height_out);
+ xvip_write(&xscaler->xvip, V_VSCALER_OFF +
+ XV_VSCALER_CTRL_ADDR_HWREG_LINERATE_DATA, line_rate);
+ ret = xv_vscaler_setup_video_fmt(xscaler, code_in);
+ if (ret < 0)
+ return ret;
+
+ /* H-Scaler_setup */
+ pixel_rate = (width_in * STEP_PRECISION) / width_out;
+
+ xvip_write(&xscaler->xvip, V_HSCALER_OFF +
+ XV_HSCALER_CTRL_ADDR_HWREG_HEIGHT_DATA, height_out);
+ xvip_write(&xscaler->xvip, V_HSCALER_OFF +
+ XV_HSCALER_CTRL_ADDR_HWREG_WIDTHIN_DATA, width_in);
+ xvip_write(&xscaler->xvip, V_HSCALER_OFF +
+ XV_HSCALER_CTRL_ADDR_HWREG_WIDTHOUT_DATA, width_out);
+ xvip_write(&xscaler->xvip, V_HSCALER_OFF +
+ XV_HSCALER_CTRL_ADDR_HWREG_PIXELRATE_DATA, pixel_rate);
+ ret = xv_hscaler_setup_video_fmt(xscaler, code_out, ret);
+ if (ret < 0)
+ return ret;
+
+ if (xscaler->is_polyphase) {
+ ret = xv_hscaler_select_coeff(xscaler, width_in, width_out);
+ if (ret < 0)
+ return ret;
+ xv_hscaler_set_coeff(xscaler);
+ }
+
+ xv_hscaler_calculate_phases(xscaler, width_in, width_out, pixel_rate);
+ xv_hscaler_set_phases(xscaler);
+
+ /* Start Scaler sub-cores */
+ xvip_write(&xscaler->xvip, V_HSCALER_OFF +
+ XV_HSCALER_CTRL_ADDR_AP_CTRL, XSCALER_STREAM_ON);
+ xvip_write(&xscaler->xvip, V_VSCALER_OFF +
+ XV_VSCALER_CTRL_ADDR_AP_CTRL, XSCALER_STREAM_ON);
+ xv_procss_enable_block(&xscaler->xvip, XGPIO_CH_RESET_SEL,
+ XGPIO_RESET_MASK_VIDEO_IN);
+ return 0;
+}
+
+/*
+ * V4L2 Subdevice Pad Operations
+ */
+
+static int xscaler_enum_frame_size(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct v4l2_mbus_framefmt *format;
+ struct xscaler_device *xscaler = to_scaler(subdev);
+
+ format = v4l2_subdev_get_try_format(subdev, cfg, fse->pad);
+ if (fse->index || fse->code != format->code)
+ return -EINVAL;
+
+ fse->min_width = XSCALER_MIN_WIDTH;
+ fse->max_width = xscaler->max_pixels;
+ fse->min_height = XSCALER_MIN_HEIGHT;
+ fse->max_height = xscaler->max_lines;
+
+ return 0;
+}
+
+static struct v4l2_mbus_framefmt *
+__xscaler_get_pad_format(struct xscaler_device *xscaler,
+ struct v4l2_subdev_pad_config *cfg,
+ unsigned int pad, u32 which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_format(&xscaler->xvip.subdev, cfg,
+ pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &xscaler->formats[pad];
+ default:
+ return NULL;
+ }
+}
+
+static int xscaler_get_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xscaler_device *xscaler = to_scaler(subdev);
+
+ fmt->format = *__xscaler_get_pad_format(xscaler, cfg, fmt->pad,
+ fmt->which);
+
+ return 0;
+}
+
+static int xscaler_set_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct xscaler_device *xscaler = to_scaler(subdev);
+ struct v4l2_mbus_framefmt *format;
+
+ format = __xscaler_get_pad_format(xscaler, cfg, fmt->pad, fmt->which);
+ *format = fmt->format;
+
+ format->width = clamp_t(unsigned int, fmt->format.width,
+ XSCALER_MIN_WIDTH, xscaler->max_pixels);
+ format->height = clamp_t(unsigned int, fmt->format.height,
+ XSCALER_MIN_HEIGHT, xscaler->max_lines);
+ format->code = fmt->format.code;
+ fmt->format = *format;
+ return 0;
+}
+
+/*
+ * V4L2 Subdevice Operations
+ */
+
+static int
+xscaler_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ struct xscaler_device *xscaler = to_scaler(subdev);
+ struct v4l2_mbus_framefmt *format;
+
+ /* Initialize with default formats */
+ format = v4l2_subdev_get_try_format(subdev, fh->pad, XVIP_PAD_SINK);
+ *format = xscaler->default_formats[XVIP_PAD_SINK];
+
+ format = v4l2_subdev_get_try_format(subdev, fh->pad, XVIP_PAD_SOURCE);
+ *format = xscaler->default_formats[XVIP_PAD_SOURCE];
+
+ return 0;
+}
+
+static int
+xscaler_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ return 0;
+}
+
+static struct v4l2_subdev_video_ops xscaler_video_ops = {
+ .s_stream = xscaler_s_stream,
+};
+
+static struct v4l2_subdev_pad_ops xscaler_pad_ops = {
+ .enum_mbus_code = xvip_enum_mbus_code,
+ .enum_frame_size = xscaler_enum_frame_size,
+ .get_fmt = xscaler_get_format,
+ .set_fmt = xscaler_set_format,
+};
+
+static struct v4l2_subdev_ops xscaler_ops = {
+ .video = &xscaler_video_ops,
+ .pad = &xscaler_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops xscaler_internal_ops = {
+ .open = xscaler_open,
+ .close = xscaler_close,
+};
+
+/*
+ * Media Operations
+ */
+
+static const struct media_entity_operations xscaler_media_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+/*
+ * Platform Device Driver
+ */
+
+static int xscaler_parse_of(struct xscaler_device *xscaler)
+{
+ struct device *dev = xscaler->xvip.dev;
+ struct device_node *node = xscaler->xvip.dev->of_node;
+ const struct xvip_video_format *vip_format;
+ struct device_node *ports;
+ struct device_node *port;
+ int ret;
+ u32 port_id, dt_ppc;
+
+ if (xscaler->cfg->flags & XSCALER_CLK_PROP) {
+ xscaler->aclk_axis = devm_clk_get(dev, "aclk_axis");
+ if (IS_ERR(xscaler->aclk_axis)) {
+ ret = PTR_ERR(xscaler->aclk_axis);
+ dev_err(dev, "failed to get aclk_axis (%d)\n", ret);
+ return ret;
+ }
+ xscaler->aclk_ctrl = devm_clk_get(dev, "aclk_ctrl");
+ if (IS_ERR(xscaler->aclk_ctrl)) {
+ ret = PTR_ERR(xscaler->aclk_ctrl);
+ dev_err(dev, "failed to get aclk_ctrl (%d)\n", ret);
+ return ret;
+ }
+ } else {
+ dev_info(dev, "assuming all required clocks are enabled!\n");
+ }
+
+ ret = of_property_read_u32(node, "xlnx,max-height",
+ &xscaler->max_lines);
+ if (ret < 0) {
+ dev_err(dev, "xlnx,max-height is missing!");
+ return -EINVAL;
+ } else if (xscaler->max_lines > XSCALER_MAX_HEIGHT ||
+ xscaler->max_lines < XSCALER_MIN_HEIGHT) {
+ dev_err(dev, "Invalid height in dt");
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32(node, "xlnx,max-width",
+ &xscaler->max_pixels);
+ if (ret < 0) {
+ dev_err(dev, "xlnx,max-width is missing!");
+ return -EINVAL;
+ } else if (xscaler->max_pixels > XSCALER_MAX_WIDTH ||
+ xscaler->max_pixels < XSCALER_MIN_WIDTH) {
+ dev_err(dev, "Invalid width in dt");
+ return -EINVAL;
+ }
+
+ ports = of_get_child_by_name(node, "ports");
+ if (!ports)
+ ports = node;
+
+ /* Get the format description for each pad */
+ for_each_child_of_node(ports, port) {
+ if (port->name && (of_node_cmp(port->name, "port") == 0)) {
+ vip_format = xvip_of_get_format(port);
+ if (IS_ERR(vip_format)) {
+ dev_err(dev, "invalid format in DT");
+ return PTR_ERR(vip_format);
+ }
+
+ ret = of_property_read_u32(port, "reg", &port_id);
+ if (ret < 0) {
+ dev_err(dev, "No reg in DT");
+ return ret;
+ }
+
+ if (port_id != 0 && port_id != 1) {
+ dev_err(dev, "Invalid reg in DT");
+ return -EINVAL;
+ }
+ xscaler->vip_formats[port_id] = vip_format;
+ }
+ }
+
+ ret = of_property_read_u32(node, "xlnx,num-hori-taps",
+ &xscaler->num_hori_taps);
+ if (ret < 0)
+ return ret;
+
+ switch (xscaler->num_hori_taps) {
+ case XV_HSCALER_TAPS_2:
+ case XV_HSCALER_TAPS_4:
+ xscaler->is_polyphase = false;
+ break;
+ case XV_HSCALER_TAPS_6:
+ case XV_HSCALER_TAPS_8:
+ case XV_HSCALER_TAPS_10:
+ case XV_HSCALER_TAPS_12:
+ xscaler->is_polyphase = true;
+ break;
+ default:
+ dev_err(dev, "Unsupported num-hori-taps %d",
+ xscaler->num_hori_taps);
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32(node, "xlnx,num-vert-taps",
+ &xscaler->num_vert_taps);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * For Bilinear and Bicubic case
+ * number of vertical and horizontal taps must match
+ */
+ switch (xscaler->num_vert_taps) {
+ case XV_HSCALER_TAPS_2:
+ case XV_VSCALER_TAPS_4:
+ if (xscaler->num_vert_taps != xscaler->num_hori_taps) {
+ dev_err(dev,
+ "H-scaler taps %d mismatches V-scaler taps %d",
+ xscaler->num_hori_taps,
+ xscaler->num_vert_taps);
+ return -EINVAL;
+ }
+ break;
+ case XV_VSCALER_TAPS_6:
+ case XV_VSCALER_TAPS_8:
+ case XV_VSCALER_TAPS_10:
+ case XV_VSCALER_TAPS_12:
+ xscaler->is_polyphase = true;
+ break;
+ default:
+ dev_err(dev, "Unsupported num-vert-taps %d",
+ xscaler->num_vert_taps);
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32(node, "xlnx,pix-per-clk", &dt_ppc);
+ if (ret < 0)
+ return ret;
+
+ /* Driver only supports 1 PPC and 2 PPC */
+ if (dt_ppc != XSCALER_PPC_1 && dt_ppc != XSCALER_PPC_2) {
+ dev_err(xscaler->xvip.dev,
+ "Unsupported xlnx,pix-per-clk(%d) value in DT", dt_ppc);
+ return -EINVAL;
+ }
+ xscaler->pix_per_clk = dt_ppc;
+
+ /* Reset GPIO */
+ xscaler->rst_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(xscaler->rst_gpio)) {
+ if (PTR_ERR(xscaler->rst_gpio) != -EPROBE_DEFER)
+ dev_err(dev, "Reset GPIO not setup in DT");
+ return PTR_ERR(xscaler->rst_gpio);
+ }
+
+ return 0;
+}
+
+static int xscaler_probe(struct platform_device *pdev)
+{
+ struct xscaler_device *xscaler;
+ struct v4l2_subdev *subdev;
+ struct v4l2_mbus_framefmt *default_format;
+ int ret;
+ const struct of_device_id *match;
+ struct device_node *node = pdev->dev.of_node;
+ struct resource *res;
+
+ xscaler = devm_kzalloc(&pdev->dev, sizeof(*xscaler), GFP_KERNEL);
+ if (!xscaler)
+ return -ENOMEM;
+
+ xscaler->xvip.dev = &pdev->dev;
+
+ match = of_match_node(xscaler_of_id_table, node);
+ if (!match)
+ return -ENODEV;
+
+ if (!strncmp(match->compatible, xscaler_of_id_table[0].compatible,
+ strlen(xscaler_of_id_table[0].compatible))) {
+ dev_warn(&pdev->dev,
+ "%s - compatible string is getting deprecated!\n",
+ match->compatible);
+ }
+
+ xscaler->cfg = match->data;
+
+ ret = xscaler_parse_of(xscaler);
+ if (ret < 0)
+ return ret;
+
+ /* Initialize coefficient parameters */
+ xscaler->max_num_phases = XSCALER_MAX_PHASES;
+
+ if (xscaler->cfg->flags & XSCALER_CLK_PROP) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ xscaler->xvip.iomem = devm_ioremap_resource(xscaler->xvip.dev,
+ res);
+ if (IS_ERR(xscaler->xvip.iomem))
+ return PTR_ERR(xscaler->xvip.iomem);
+
+ ret = clk_prepare_enable(xscaler->aclk_axis);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable aclk_axis (%d)\n",
+ ret);
+ goto res_cleanup;
+ }
+
+ ret = clk_prepare_enable(xscaler->aclk_ctrl);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable aclk_ctrl (%d)\n",
+ ret);
+ goto axis_clk_cleanup;
+ }
+ } else {
+ ret = xvip_init_resources(&xscaler->xvip);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Reset the Global IP Reset through a PS GPIO */
+ gpiod_set_value_cansleep(xscaler->rst_gpio, XSCALER_RESET_DEASSERT);
+ /* Reset internal GPIO within the IP */
+ xscaler_reset(xscaler);
+
+ /* Initialize V4L2 subdevice and media entity */
+ subdev = &xscaler->xvip.subdev;
+ v4l2_subdev_init(subdev, &xscaler_ops);
+ subdev->dev = &pdev->dev;
+ subdev->internal_ops = &xscaler_internal_ops;
+ strlcpy(subdev->name, dev_name(&pdev->dev), sizeof(subdev->name));
+ v4l2_set_subdevdata(subdev, xscaler);
+ subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ /* Initialize default and active formats */
+ default_format = &xscaler->default_formats[XVIP_PAD_SINK];
+ default_format->code = xscaler->vip_formats[XVIP_PAD_SINK]->code;
+ default_format->field = V4L2_FIELD_NONE;
+ default_format->colorspace = V4L2_COLORSPACE_SRGB;
+ default_format->width = XSCALER_DEF_IN_WIDTH;
+ default_format->height = XSCALER_DEF_IN_HEIGHT;
+ xscaler->formats[XVIP_PAD_SINK] = *default_format;
+
+ default_format = &xscaler->default_formats[XVIP_PAD_SOURCE];
+ *default_format = xscaler->default_formats[XVIP_PAD_SINK];
+ default_format->code = xscaler->vip_formats[XVIP_PAD_SOURCE]->code;
+ default_format->width = XSCALER_DEF_OUT_WIDTH;
+ default_format->height = XSCALER_DEF_OUT_HEIGHT;
+ xscaler->formats[XVIP_PAD_SOURCE] = *default_format;
+
+ xscaler->pads[XVIP_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ xscaler->pads[XVIP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ subdev->entity.ops = &xscaler_media_ops;
+
+ ret = media_entity_pads_init(&subdev->entity, 2, xscaler->pads);
+ if (ret < 0)
+ goto error;
+
+ platform_set_drvdata(pdev, xscaler);
+
+ ret = v4l2_async_register_subdev(subdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to register subdev");
+ goto error;
+ }
+ dev_info(xscaler->xvip.dev, "Num Hori Taps %d",
+ xscaler->num_hori_taps);
+ dev_info(xscaler->xvip.dev, "Num Vert Taps %d",
+ xscaler->num_vert_taps);
+ dev_info(&pdev->dev, "VPSS Scaler Probe Successful");
+ return 0;
+
+error:
+ media_entity_cleanup(&subdev->entity);
+ clk_disable_unprepare(xscaler->aclk_ctrl);
+axis_clk_cleanup:
+ clk_disable_unprepare(xscaler->aclk_axis);
+res_cleanup:
+ xvip_cleanup_resources(&xscaler->xvip);
+ return ret;
+}
+
+static int xscaler_remove(struct platform_device *pdev)
+{
+ struct xscaler_device *xscaler = platform_get_drvdata(pdev);
+ struct v4l2_subdev *subdev = &xscaler->xvip.subdev;
+
+ v4l2_async_unregister_subdev(subdev);
+ media_entity_cleanup(&subdev->entity);
+ clk_disable_unprepare(xscaler->aclk_ctrl);
+ clk_disable_unprepare(xscaler->aclk_axis);
+ xvip_cleanup_resources(&xscaler->xvip);
+
+ return 0;
+}
+
+static struct platform_driver xscaler_driver = {
+ .driver = {
+ .name = "xilinx-vpss-scaler",
+ .of_match_table = xscaler_of_id_table,
+ },
+ .probe = xscaler_probe,
+ .remove = xscaler_remove,
+};
+
+module_platform_driver(xscaler_driver);
+MODULE_DESCRIPTION("Xilinx Scaler VPSS Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/xilinx/xilinx-vtc.c b/drivers/media/platform/xilinx/xilinx-vtc.c
index 0ae0208d7529..d69f48dfdac4 100644
--- a/drivers/media/platform/xilinx/xilinx-vtc.c
+++ b/drivers/media/platform/xilinx/xilinx-vtc.c
@@ -141,6 +141,9 @@
#define XVTC_GENERATOR_GLOBAL_DELAY 0x0104
+/* Value of 1 = .01% */
+#define XVTC_CLK_MAX_PCT_ERR 1
+
/**
* struct xvtc_device - Xilinx Video Timing Controller device structure
* @xvip: Xilinx Video IP device
@@ -175,10 +178,25 @@ int xvtc_generator_start(struct xvtc_device *xvtc,
const struct xvtc_config *config)
{
int ret;
+ unsigned long s_rate;
+ unsigned long g_rate;
+ unsigned long clk_err;
if (!xvtc->has_generator)
return -ENXIO;
+ s_rate = config->fps * config->hsize * config->vsize;
+ ret = clk_set_rate(xvtc->xvip.clk, s_rate);
+ if (ret < 0)
+ return ret;
+
+ /* Verify that the clock is within a reasonable tolerance. */
+ g_rate = clk_get_rate(xvtc->xvip.clk);
+ clk_err = (abs(g_rate - s_rate) * 10000) / (s_rate);
+ if (clk_err > XVTC_CLK_MAX_PCT_ERR)
+ dev_warn(xvtc->xvip.dev, "Failed to set clk rate: %lu, actual rate: %lu\n",
+ s_rate, g_rate);
+
ret = clk_prepare_enable(xvtc->xvip.clk);
if (ret < 0)
return ret;
diff --git a/drivers/media/platform/xilinx/xilinx-vtc.h b/drivers/media/platform/xilinx/xilinx-vtc.h
index 90cf44245283..c2c744b03426 100644
--- a/drivers/media/platform/xilinx/xilinx-vtc.h
+++ b/drivers/media/platform/xilinx/xilinx-vtc.h
@@ -27,6 +27,7 @@ struct xvtc_config {
unsigned int vsync_start;
unsigned int vsync_end;
unsigned int vsize;
+ unsigned int fps;
};
struct xvtc_device *xvtc_of_get(struct device_node *np);