MLK-16675-1: drm: imx: add mscale DCSS core driver
authorLaurentiu Palcu <laurentiu.palcu@nxp.com>
Thu, 19 Oct 2017 09:27:23 +0000 (12:27 +0300)
committerLeonard Crestez <leonard.crestez@nxp.com>
Wed, 17 Apr 2019 23:51:34 +0000 (02:51 +0300)
This patch adds base suport for i.MX8M's Display Controller
subsystem(DCSS). It has built-in DPR, Scaler and HDR10 modules. Also, it
features a video Decompression and Tile to Raster Conversion (DTRC) unit,
as well as a graphics pixel decompression infrastracture (DEC400D).

Signed-off-by: Laurentiu Palcu <laurentiu.palcu@nxp.com>
18 files changed:
Documentation/devicetree/bindings/display/imx/fsl-imx-drm.txt
drivers/gpu/imx/Kconfig
drivers/gpu/imx/Makefile
drivers/gpu/imx/dcss/Kconfig [new file with mode: 0644]
drivers/gpu/imx/dcss/Makefile [new file with mode: 0644]
drivers/gpu/imx/dcss/dcss-blkctl.c [new file with mode: 0644]
drivers/gpu/imx/dcss/dcss-common.c [new file with mode: 0644]
drivers/gpu/imx/dcss/dcss-ctxld.c [new file with mode: 0644]
drivers/gpu/imx/dcss/dcss-dec400d.c [new file with mode: 0644]
drivers/gpu/imx/dcss/dcss-dpr.c [new file with mode: 0644]
drivers/gpu/imx/dcss/dcss-dtg.c [new file with mode: 0644]
drivers/gpu/imx/dcss/dcss-dtrc.c [new file with mode: 0644]
drivers/gpu/imx/dcss/dcss-hdr10.c [new file with mode: 0644]
drivers/gpu/imx/dcss/dcss-prv.h [new file with mode: 0644]
drivers/gpu/imx/dcss/dcss-scaler.c [new file with mode: 0644]
drivers/gpu/imx/dcss/dcss-ss.c [new file with mode: 0644]
drivers/gpu/imx/dcss/dcss-tables.h [new file with mode: 0644]
include/video/imx-dcss.h [new file with mode: 0644]

index b0e8234..13b5637 100644 (file)
@@ -160,6 +160,73 @@ example:
                };
        };
 
+
+NXP i.MX Display Controller Subsystem (DCSS)
+=============================================
+
+Required properties:
+- compatible: Should be "nxp,<chip>-dcss"
+- reg: should be register base and length as documented in the
+  datasheet.
+- interrupts, interrupt-names: Should contain interrupts and names as
+  documented in the datasheet.
+- interrupt-parent: contains the phandle to IRQ Steer module.
+- clocks, clock-names: phandles to the DCSS clocks described in
+  Documentation/devicetree/bindings/clock/clock-bindings.txt
+- disp-dev: can take following values:
+      - hdmi_disp: DCSS output goes to HDMI
+         - mipi_disp: DCSS output goes to MIPI_DSI
+Optional properties:
+- port@[0-1]: Port nodes with endpoint definitions as defined in
+  Documentation/devicetree/bindings/media/video-interfaces.txt.
+  ports 0 and 1 should correspond to display interface 0 and
+  display interface 1, respectively.
+
+
+example:
+
+dcss_drm: dcss@0x32e00000 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       compatible = "nxp,imx8mq-dcss";
+       reg = <0x0 0x32e00000 0x0 0x30000>;
+       interrupts = <3 IRQ_TYPE_LEVEL_HIGH>, <4 IRQ_TYPE_LEVEL_HIGH>, <5 IRQ_TYPE_LEVEL_HIGH>,
+                            <6 IRQ_TYPE_LEVEL_HIGH>, <8 IRQ_TYPE_EDGE_RISING>;
+       interrupt-names = "dpr_dc_ch0", "dpr_dc_ch1", "dpr_dc_ch2", "ctx_ld",
+                                         "dtg_prg1";
+       interrupt-parent = <&irqsteer_dcss>;
+       clocks = <&clk IMX8MQ_CLK_DISP_APB_ROOT>,
+                <&clk IMX8MQ_CLK_DISP_AXI_ROOT>,
+                <&clk IMX8MQ_CLK_DISP_RTRM_ROOT>,
+                <&clk IMX8MQ_CLK_DC_PIXEL_DIV>,
+                <&clk IMX8MQ_CLK_DISP_DTRC_DIV>;
+       clock-names = "apb", "axi", "rtrm", "pixel", "dtrc";
+       assigned-clocks = <&clk IMX8MQ_CLK_DISP_APB_SRC>,
+                         <&clk IMX8MQ_CLK_DISP_AXI_SRC>,
+                         <&clk IMX8MQ_CLK_DISP_RTRM_SRC>,
+                         <&clk IMX8MQ_CLK_DC_PIXEL_SRC>,
+                         <&clk IMX8MQ_CLK_DISP_DTRC_SRC>;
+       assigned-clock-parents = <&clk IMX8MQ_SYS1_PLL_800M>,
+                                <&clk IMX8MQ_SYS1_PLL_800M>,
+                                <&clk IMX8MQ_SYS1_PLL_800M>,
+                                <&clk IMX8MQ_VIDEO_PLL1_OUT>,
+                                <&clk IMX8MQ_CLK_25M>;
+       assigned-clock-rate = <800000000>, <800000000>, <800000000>, <594000000>, <25000000>;
+
+       disp-dev = "hdmi_disp";
+
+       status = "okay";
+
+       dcss_disp0: port@0 {
+               reg = <0>;
+
+               dcss_disp0_imx_stub: imx_stub_conenc {
+                       remote-endpoint = <&imx_stub_conenc0>;
+               };
+       };
+};
+
+
 Parallel display support
 ========================
 
index ffe0d30..8dccc19 100644 (file)
@@ -1,2 +1,3 @@
 source drivers/gpu/imx/ipu-v3/Kconfig
 source drivers/gpu/imx/lcdif/Kconfig
+source drivers/gpu/imx/dcss/Kconfig
index 8f2bd3c..9d772bb 100644 (file)
@@ -1,2 +1,3 @@
 obj-$(CONFIG_IMX_IPUV3_CORE)   += ipu-v3/
 obj-$(CONFIG_IMX_LCDIF_CORE)   += lcdif/
+obj-$(CONFIG_IMX_DCSS_CORE)    += dcss/
diff --git a/drivers/gpu/imx/dcss/Kconfig b/drivers/gpu/imx/dcss/Kconfig
new file mode 100644 (file)
index 0000000..57b0b67
--- /dev/null
@@ -0,0 +1,9 @@
+config IMX_DCSS_CORE
+       tristate "i.MX DCSS core support"
+       depends on ARCH_FSL_IMX8MQ
+       select RESET_CONTROLLER
+       select IMX_IRQSTEER
+       help
+         Choose this if you have a Freescale i.MX8MQ system and want to use the
+         Display Controller Sub System. This option only enables DCSS base
+         support.
diff --git a/drivers/gpu/imx/dcss/Makefile b/drivers/gpu/imx/dcss/Makefile
new file mode 100644 (file)
index 0000000..822aa7b
--- /dev/null
@@ -0,0 +1,6 @@
+obj-$(CONFIG_IMX_DCSS_CORE) += imx-dcss-core.o
+
+imx-dcss-core-objs := dcss-common.o dcss-blkctl.o dcss-ctxld.o \
+                     dcss-dpr.o dcss-dtg.o dcss-ss.o \
+                     dcss-hdr10.o dcss-scaler.o \
+                     dcss-dtrc.o dcss-dec400d.o
diff --git a/drivers/gpu/imx/dcss/dcss-blkctl.c b/drivers/gpu/imx/dcss/dcss-blkctl.c
new file mode 100644 (file)
index 0000000..4e6d46c
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/io.h>
+#include <linux/bitops.h>
+#include <linux/of.h>
+
+#include "dcss-prv.h"
+#include <video/imx-dcss.h>
+
+#define DCSS_BLKCTL_RESET_CTRL         0x00
+#define   B_CLK_RESETN                 BIT(0)
+#define   APB_CLK_RESETN               BIT(1)
+#define   P_CLK_RESETN                 BIT(2)
+#define   HDMI_RESETN                  BIT(3)
+#define   RTR_CLK_RESETN               BIT(4)
+#define DCSS_BLKCTL_CONTROL0           0x10
+#define   HDMI_MIPI_CLK_SEL            BIT(0)
+#define   DISPMIX_REFCLK_SEL_POS       4
+#define   DISPMIX_REFCLK_SEL_MASK      GENMASK(5, 4)
+#define   DISPMIX_PIXCLK_SEL           BIT(8)
+#define   HDMI_SRC_SECURE_EN           BIT(16)
+
+static void __iomem *dcss_blkctl_reg;
+static bool hdmi_output;
+
+static void dcss_blkctl_clk_reset(u32 assert, u32 deassert)
+{
+       if (assert)
+               dcss_clr(assert, dcss_blkctl_reg + DCSS_BLKCTL_RESET_CTRL);
+
+       if (deassert)
+               dcss_set(deassert, dcss_blkctl_reg + DCSS_BLKCTL_RESET_CTRL);
+}
+
+int dcss_blkctl_init(struct dcss_soc *dcss, unsigned long blkctl_base)
+{
+       struct device_node *node = dcss->dev->of_node;
+       int len;
+       const char *disp_dev;
+
+       hdmi_output = false;
+
+       dcss_blkctl_reg = devm_ioremap(dcss->dev, blkctl_base, SZ_4K);
+       if (!dcss_blkctl_reg) {
+               dev_err(dcss->dev, "unable to remap BLK CTRL base\n");
+               return -ENOMEM;
+       }
+
+       disp_dev = of_get_property(node, "disp-dev", &len);
+       if (!disp_dev || !strncmp(disp_dev, "hdmi_disp", 9))
+               hdmi_output = true;
+
+       if (hdmi_output)
+               dcss_writel(0, dcss_blkctl_reg + DCSS_BLKCTL_CONTROL0);
+       else
+               dcss_writel(HDMI_MIPI_CLK_SEL | DISPMIX_PIXCLK_SEL,
+                           dcss_blkctl_reg + DCSS_BLKCTL_CONTROL0);
+
+       /* deassert clock domains resets */
+       dcss_blkctl_clk_reset(0, B_CLK_RESETN | APB_CLK_RESETN |
+                                P_CLK_RESETN | HDMI_RESETN | RTR_CLK_RESETN);
+
+       return 0;
+}
+
+void dcss_blkctl_exit(struct dcss_soc *dcss)
+{
+       /* assert clock domains resets */
+       dcss_blkctl_clk_reset(B_CLK_RESETN | APB_CLK_RESETN | P_CLK_RESETN |
+                             HDMI_RESETN | RTR_CLK_RESETN, 0);
+}
+
+/* disabled only by cold reset/reboot */
+void dcss_blkctl_hdmi_secure_src_en(struct dcss_soc *dcss)
+{
+       writel(HDMI_SRC_SECURE_EN, dcss_blkctl_reg + SET);
+}
+EXPORT_SYMBOL(dcss_blkctl_hdmi_secure_src_en);
+
diff --git a/drivers/gpu/imx/dcss/dcss-common.c b/drivers/gpu/imx/dcss/dcss-common.c
new file mode 100644 (file)
index 0000000..ecc729a
--- /dev/null
@@ -0,0 +1,435 @@
+/*
+ * Copyright (C) 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/clk.h>
+#include <video/imx-dcss.h>
+
+#include <drm/drm_fourcc.h>
+
+#include <video/imx-dcss.h>
+#include "dcss-prv.h"
+
+struct dcss_devtype {
+       const char *name;
+       u32 blkctl_ofs;
+       u32 ctxld_ofs;
+       u32 rdsrc_ofs;
+       u32 wrscl_ofs;
+       u32 dtg_ofs;
+       u32 scaler_ofs;
+       u32 ss_ofs;
+       u32 dpr_ofs;
+       u32 dtrc_ofs;
+       u32 dec400d_ofs;
+       u32 hdr10_ofs;
+};
+
+static struct dcss_devtype dcss_type_imx8m = {
+       .name = "DCSS_imx8m",
+       .blkctl_ofs = 0x2F000,
+       .ctxld_ofs = 0x23000,
+       .rdsrc_ofs = 0x22000,
+       .wrscl_ofs = 0x21000,
+       .dtg_ofs = 0x20000,
+       .scaler_ofs = 0x1C000,
+       .ss_ofs = 0x1B000,
+       .dpr_ofs = 0x18000,
+       .dtrc_ofs = 0x16000,
+       .dec400d_ofs = 0x15000,
+       .hdr10_ofs = 0x00000,
+};
+
+enum dcss_color_space dcss_drm_fourcc_to_colorspace(u32 drm_fourcc)
+{
+       switch (drm_fourcc) {
+       case DRM_FORMAT_ARGB1555:
+       case DRM_FORMAT_ABGR1555:
+       case DRM_FORMAT_RGBA5551:
+       case DRM_FORMAT_BGRA5551:
+       case DRM_FORMAT_RGB565:
+       case DRM_FORMAT_BGR565:
+       case DRM_FORMAT_RGB888:
+       case DRM_FORMAT_BGR888:
+       case DRM_FORMAT_ARGB4444:
+       case DRM_FORMAT_XRGB8888:
+       case DRM_FORMAT_XBGR8888:
+       case DRM_FORMAT_RGBX8888:
+       case DRM_FORMAT_BGRX8888:
+       case DRM_FORMAT_ARGB8888:
+       case DRM_FORMAT_ABGR8888:
+       case DRM_FORMAT_RGBA8888:
+       case DRM_FORMAT_BGRA8888:
+       case DRM_FORMAT_XRGB2101010:
+       case DRM_FORMAT_XBGR2101010:
+       case DRM_FORMAT_RGBX1010102:
+       case DRM_FORMAT_BGRX1010102:
+       case DRM_FORMAT_ARGB2101010:
+       case DRM_FORMAT_ABGR2101010:
+       case DRM_FORMAT_RGBA1010102:
+       case DRM_FORMAT_BGRA1010102:
+               return DCSS_COLORSPACE_RGB;
+       case DRM_FORMAT_YUYV:
+       case DRM_FORMAT_UYVY:
+       case DRM_FORMAT_YVYU:
+       case DRM_FORMAT_VYUY:
+       case DRM_FORMAT_YUV420:
+       case DRM_FORMAT_YVU420:
+       case DRM_FORMAT_YUV422:
+       case DRM_FORMAT_YVU422:
+       case DRM_FORMAT_NV12:
+       case DRM_FORMAT_NV21:
+       case DRM_FORMAT_NV16:
+       case DRM_FORMAT_NV61:
+               return DCSS_COLORSPACE_YUV;
+       default:
+               return DCSS_COLORSPACE_UNKNOWN;
+       }
+}
+EXPORT_SYMBOL_GPL(dcss_drm_fourcc_to_colorspace);
+
+int dcss_vblank_irq_get(struct dcss_soc *dcss)
+{
+       struct platform_device *pdev = to_platform_device(dcss->dev);
+
+       return platform_get_irq_byname(pdev, "dtg_prg1");
+}
+EXPORT_SYMBOL(dcss_vblank_irq_get);
+
+void dcss_vblank_irq_enable(struct dcss_soc *dcss, bool en)
+{
+       dcss_dtg_vblank_irq_enable(dcss, en);
+}
+EXPORT_SYMBOL(dcss_vblank_irq_enable);
+
+void dcss_vblank_irq_clear(struct dcss_soc *dcss)
+{
+       dcss_dtg_vblank_irq_clear(dcss);
+}
+EXPORT_SYMBOL(dcss_vblank_irq_clear);
+
+static int dcss_submodules_init(struct dcss_soc *dcss, unsigned long dcss_base)
+{
+       int ret;
+
+       ret = dcss_blkctl_init(dcss, dcss_base + dcss->devtype->blkctl_ofs);
+       if (ret)
+               goto blkctl_err;
+
+       ret = dcss_ctxld_init(dcss, dcss_base + dcss->devtype->ctxld_ofs);
+       if (ret)
+               goto ctxld_err;
+
+       ret = dcss_dtrc_init(dcss, dcss_base + dcss->devtype->dtrc_ofs);
+       if (ret)
+               goto dtrc_err;
+
+       ret = dcss_dec400d_init(dcss, dcss_base + dcss->devtype->dec400d_ofs);
+       if (ret)
+               goto dec400d_err;
+
+       ret = dcss_dtg_init(dcss, dcss_base + dcss->devtype->dtg_ofs);
+       if (ret)
+               goto dtg_err;
+
+       ret = dcss_ss_init(dcss, dcss_base + dcss->devtype->ss_ofs);
+       if (ret)
+               goto ss_err;
+
+       ret = dcss_dpr_init(dcss, dcss_base + dcss->devtype->dpr_ofs);
+       if (ret)
+               goto dpr_err;
+
+       ret = dcss_scaler_init(dcss, dcss_base + dcss->devtype->scaler_ofs);
+       if (ret)
+               goto scaler_err;
+
+       ret = dcss_hdr10_init(dcss, dcss_base + dcss->devtype->hdr10_ofs);
+       if (ret)
+               goto hdr10_err;
+
+       return 0;
+
+hdr10_err:
+       dcss_hdr10_exit(dcss);
+
+scaler_err:
+       dcss_scaler_exit(dcss);
+
+dpr_err:
+       dcss_dpr_exit(dcss);
+
+ss_err:
+       dcss_ss_exit(dcss);
+
+dtg_err:
+       dcss_dtg_exit(dcss);
+
+dec400d_err:
+       dcss_dec400d_exit(dcss);
+
+dtrc_err:
+       dcss_dtrc_exit(dcss);
+
+ctxld_err:
+       dcss_ctxld_exit(dcss);
+
+blkctl_err:
+       dcss_blkctl_exit(dcss);
+
+       return ret;
+}
+
+struct dcss_platform_reg {
+       struct dcss_client_platformdata pdata;
+       const char *name;
+};
+
+static struct dcss_platform_reg client_reg = {
+               .pdata = { },
+               .name = "imx-dcss-crtc",
+};
+
+static int dcss_add_client_devices(struct dcss_soc *dcss)
+{
+       struct device *dev = dcss->dev;
+       struct platform_device *pdev;
+       struct device_node *of_node;
+       int ret;
+
+       of_node = of_graph_get_port_by_id(dev->of_node, 0);
+       if (!of_node) {
+               dev_err(dev, "no port@0 node in %s\n", dev->of_node->full_name);
+               return -ENODEV;
+       }
+
+       pdev = platform_device_alloc(client_reg.name, 0);
+       if (!pdev) {
+               dev_err(dev, "cannot allocate platform device\n");
+               return -ENOMEM;
+       }
+
+       pdev->dev.parent = dev;
+
+       client_reg.pdata.of_node = of_node;
+       ret = platform_device_add_data(pdev, &client_reg.pdata,
+                                      sizeof(client_reg.pdata));
+       if (!ret)
+               ret = platform_device_add(pdev);
+       if (ret) {
+               platform_device_put(pdev);
+               goto err_register;
+       }
+
+       pdev->dev.of_node = of_node;
+
+       return 0;
+
+err_register:
+       platform_device_unregister(pdev);
+       return ret;
+}
+
+/*
+ * TODO: Hardcode the clock rates for now. If they need to be changed,
+ * based on platform, they should end up in DT. For now, it'll do.
+ */
+static int dcss_clks_init(struct dcss_soc *dcss)
+{
+       int ret, i;
+       struct {
+               const char *id;
+               struct clk **clk;
+               u32 rate;
+       } clks[] = {
+               {"apb",   &dcss->apb_clk, 133000000},
+               {"axi",   &dcss->axi_clk, 800000000},
+               {"pixel", &dcss->p_clk,   0},
+               {"rtrm",  &dcss->apb_clk, 400000000},
+               {"dtrc",  &dcss->dtrc_clk, 25000000},
+       };
+
+       for (i = 0; i < ARRAY_SIZE(clks); i++) {
+               *clks[i].clk = devm_clk_get(dcss->dev, clks[i].id);
+               if (IS_ERR(*clks[i].clk)) {
+                       dev_err(dcss->dev, "failed to get %s clock\n",
+                               clks[i].id);
+                       return PTR_ERR(*clks[i].clk);
+               }
+
+               if (!clks[i].rate)
+                       continue;
+
+               ret = clk_set_rate(*clks[i].clk, clks[i].rate);
+               if (ret < 0) {
+                       dev_err(dcss->dev, "setting %s clk rate failed\n",
+                               clks[i].id);
+                       return ret;
+               }
+
+               clk_prepare_enable(*clks[i].clk);
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+
+static int dcss_dump_regs_show(struct seq_file *s, void *data)
+{
+       dcss_dtrc_dump_regs(s, s->private);
+       dcss_dpr_dump_regs(s, s->private);
+       dcss_scaler_dump_regs(s, s->private);
+       dcss_dtg_dump_regs(s, s->private);
+       dcss_ss_dump_regs(s, s->private);
+       dcss_hdr10_dump_regs(s, s->private);
+       dcss_ctxld_dump_regs(s, s->private);
+
+       return 0;
+}
+
+static int dcss_dump_ctx_show(struct seq_file *s, void *data)
+{
+       dcss_ctxld_dump(s, s->private);
+
+       return 0;
+}
+
+static int dcss_dump_regs_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, dcss_dump_regs_show, inode->i_private);
+}
+
+static int dcss_dump_ctx_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, dcss_dump_ctx_show, inode->i_private);
+}
+
+static const struct file_operations dcss_dump_regs_fops = {
+       .open           = dcss_dump_regs_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static const struct file_operations dcss_dump_ctx_fops = {
+       .open           = dcss_dump_ctx_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static void dcss_debugfs_init(struct dcss_soc *dcss)
+{
+       struct dentry *d, *root;
+
+       root = debugfs_create_dir("imx-dcss", NULL);
+       if (IS_ERR(root) || !root)
+               goto err;
+
+       d = debugfs_create_file("dump_registers", 0444, root, dcss,
+                               &dcss_dump_regs_fops);
+       if (!d)
+               goto err;
+
+       d = debugfs_create_file("dump_context", 0444, root, dcss,
+                               &dcss_dump_ctx_fops);
+       if (!d)
+               goto err;
+
+       return;
+
+err:
+       dev_err(dcss->dev, "Unable to create debugfs entries\n");
+}
+#else
+static void dcss_debugfs_init(struct dcss_soc *dcss)
+{
+}
+#endif
+
+static int dcss_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct resource *res;
+       struct dcss_soc *dcss;
+       const struct dcss_devtype *devtype;
+
+       devtype = of_device_get_match_data(&pdev->dev);
+       if (!devtype) {
+               dev_err(&pdev->dev, "no device match found\n");
+               return -ENODEV;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "cannot get memory resource\n");
+               return -EINVAL;
+       }
+
+       dcss = devm_kzalloc(&pdev->dev, sizeof(struct dcss_soc), GFP_KERNEL);
+       if (!dcss)
+               return -ENOMEM;
+
+       dcss->dev = &pdev->dev;
+       dcss->devtype = devtype;
+
+       platform_set_drvdata(pdev, dcss);
+
+       ret = dcss_clks_init(dcss);
+       if (ret) {
+               dev_err(&pdev->dev, "clocks initialization failed\n");
+               return ret;
+       }
+
+       ret = dcss_submodules_init(dcss, res->start);
+       if (ret) {
+               dev_err(&pdev->dev, "submodules initialization failed\n");
+               return ret;
+       }
+
+       dcss_debugfs_init(dcss);
+
+       return dcss_add_client_devices(dcss);
+}
+
+static int dcss_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static const struct of_device_id dcss_dt_ids[] = {
+       { .compatible = "nxp,imx8mq-dcss", .data = &dcss_type_imx8m, },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, dcss_dt_ids);
+
+static struct platform_driver dcss_driver = {
+       .driver = {
+               .name = "dcss-core",
+               .of_match_table = dcss_dt_ids,
+       },
+       .probe = dcss_probe,
+       .remove = dcss_remove,
+};
+
+module_platform_driver(dcss_driver);
+
+MODULE_DESCRIPTION("i.MX DCSS driver");
+MODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@nxp.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/imx/dcss/dcss-ctxld.c b/drivers/gpu/imx/dcss/dcss-ctxld.c
new file mode 100644 (file)
index 0000000..22404af
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+ * Copyright (C) 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/sizes.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/seq_file.h>
+#include <asm/cacheflush.h>
+
+#include "video/imx-dcss.h"
+#include "dcss-prv.h"
+
+#define DCSS_CTXLD_DEVNAME             "dcss_ctxld"
+
+#define DCSS_CTXLD_CONTROL_STATUS      0x0
+#define   CTXLD_ENABLE                 BIT(0)
+#define   ARB_SEL                      BIT(1)
+#define   RD_ERR_EN                    BIT(2)
+#define   DB_COMP_EN                   BIT(3)
+#define   SB_HP_COMP_EN                        BIT(4)
+#define   SB_LP_COMP_EN                        BIT(5)
+#define   DB_PEND_SB_REC_EN            BIT(6)
+#define   SB_PEND_DISP_ACTIVE_EN       BIT(7)
+#define   AHB_ERR_EN                   BIT(8)
+#define   RD_ERR                       BIT(16)
+#define   DB_COMP                      BIT(17)
+#define   SB_HP_COMP                   BIT(18)
+#define   SB_LP_COMP                   BIT(19)
+#define   DB_PEND_SB_REC               BIT(20)
+#define   SB_PEND_DISP_ACTIVE          BIT(21)
+#define   AHB_ERR                      BIT(22)
+#define DCSS_CTXLD_DB_BASE_ADDR                0x10
+#define DCSS_CTXLD_DB_COUNT            0x14
+#define DCSS_CTXLD_SB_BASE_ADDR                0x18
+#define DCSS_CTXLD_SB_COUNT            0x1C
+#define   SB_HP_COUNT_POS              0
+#define   SB_HP_COUNT_MASK             0xffff
+#define   SB_LP_COUNT_POS              16
+#define   SB_LP_COUNT_MASK             0xffff0000
+#define DCSS_AHB_ERR_ADDR              0x20
+
+#define CTXLD_IRQ_NAME                 "ctx_ld" /* irq steer irq name */
+#define CTXLD_IRQ_COMPLETION           (DB_COMP | SB_HP_COMP | SB_LP_COMP)
+#define CTXLD_IRQ_ERROR                        (RD_ERR | DB_PEND_SB_REC | \
+                                        SB_PEND_DISP_ACTIVE | AHB_ERR)
+
+/* The following sizes are in entries, 8 bytes each */
+#define CTXLD_DB_CTX_ENTRIES           1024    /* max 65536 */
+#define CTXLD_SB_LP_CTX_ENTRIES                10240   /* max 65536 */
+#define CTXLD_SB_HP_CTX_ENTRIES                20000   /* max 65536 */
+#define CTXLD_SB_CTX_ENTRIES           (CTXLD_SB_LP_CTX_ENTRIES + \
+                                        CTXLD_SB_HP_CTX_ENTRIES)
+
+static struct dcss_debug_reg ctxld_debug_reg[] = {
+       DCSS_DBG_REG(DCSS_CTXLD_CONTROL_STATUS),
+       DCSS_DBG_REG(DCSS_CTXLD_DB_BASE_ADDR),
+       DCSS_DBG_REG(DCSS_CTXLD_DB_COUNT),
+       DCSS_DBG_REG(DCSS_CTXLD_SB_BASE_ADDR),
+       DCSS_DBG_REG(DCSS_CTXLD_SB_COUNT),
+       DCSS_DBG_REG(DCSS_AHB_ERR_ADDR),
+};
+
+/* Sizes, in entries, of the DB, SB_HP and SB_LP context regions. */
+static u16 dcss_ctxld_ctx_size[3] = {
+       CTXLD_DB_CTX_ENTRIES,
+       CTXLD_SB_HP_CTX_ENTRIES,
+       CTXLD_SB_LP_CTX_ENTRIES
+};
+
+/* this represents an entry in the context loader map */
+struct dcss_ctxld_item {
+       u32 val;
+       u32 ofs;
+};
+
+#define CTX_ITEM_SIZE                  sizeof(struct dcss_ctxld_item)
+
+struct dcss_ctxld_priv {
+       struct dcss_soc *dcss;
+       void __iomem *ctxld_reg;
+       int irq;
+
+       struct dcss_ctxld_item *db[2];
+       struct dcss_ctxld_item *sb_hp[2];
+       struct dcss_ctxld_item *sb_lp[2];
+
+       dma_addr_t db_paddr[2];
+       dma_addr_t sb_paddr[2];
+
+       u16 ctx_size[2][3]; /* holds the sizes of DB, SB_HP and SB_LP ctx */
+       u8 current_ctx;
+
+       bool in_use;
+       bool run_again;
+
+       struct mutex mutex; /* protects concurent access to private data */
+};
+
+#ifdef CONFIG_DEBUG_FS
+void dcss_ctxld_dump_regs(struct seq_file *s, void *data)
+{
+       struct dcss_soc *dcss = data;
+       int j;
+
+       seq_puts(s, ">> Dumping CTXLD:\n");
+       for (j = 0; j < ARRAY_SIZE(ctxld_debug_reg); j++) {
+               seq_printf(s, "%-35s(0x%04x) -> 0x%08x\n",
+                          ctxld_debug_reg[j].name,
+                          ctxld_debug_reg[j].ofs,
+                          dcss_readl(dcss->ctxld_priv->ctxld_reg +
+                                     ctxld_debug_reg[j].ofs));
+       }
+}
+#endif
+
+static int __dcss_ctxld_enable(struct dcss_ctxld_priv *ctxld);
+
+static irqreturn_t dcss_ctxld_irq_handler_thread(int irq, void *data)
+{
+       struct dcss_ctxld_priv *ctxld = data;
+       u32 status;
+
+       status = dcss_readl(ctxld->ctxld_reg + DCSS_CTXLD_CONTROL_STATUS);
+
+       mutex_lock(&ctxld->mutex);
+       if (!(status & CTXLD_ENABLE) && ctxld->in_use) {
+               ctxld->in_use = false;
+
+               if (ctxld->run_again) {
+                       __dcss_ctxld_enable(ctxld);
+                       ctxld->run_again = false;
+                       goto exit;
+               }
+
+               if (ctxld->dcss->dcss_disable_callback) {
+                       struct dcss_dtg_priv *dtg = ctxld->dcss->dtg_priv;
+
+                       ctxld->dcss->dcss_disable_callback(dtg);
+               }
+       }
+
+exit:
+       mutex_unlock(&ctxld->mutex);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t dcss_ctxld_irq_handler(int irq, void *data)
+{
+       struct dcss_ctxld_priv *priv = data;
+       u32 irq_status;
+
+       irq_status = dcss_readl(priv->ctxld_reg + DCSS_CTXLD_CONTROL_STATUS);
+
+       if (irq_status & CTXLD_IRQ_COMPLETION) {
+               dcss_clr(irq_status & CTXLD_IRQ_COMPLETION,
+                        priv->ctxld_reg + DCSS_CTXLD_CONTROL_STATUS);
+
+               return IRQ_WAKE_THREAD;
+       } else if (irq_status & CTXLD_IRQ_ERROR) {
+               /*
+                * Except for throwing an error message and clearing the status
+                * register, there's not much we can do here.
+                */
+               dev_err(priv->dcss->dev, "ctxld: error encountered: %08x\n",
+                       irq_status);
+               dev_err(priv->dcss->dev, "ctxld: db=%d, sb_hp=%d, sb_lp=%d\n",
+                       priv->ctx_size[priv->current_ctx ^ 1][CTX_DB],
+                       priv->ctx_size[priv->current_ctx ^ 1][CTX_SB_HP],
+                       priv->ctx_size[priv->current_ctx ^ 1][CTX_SB_LP]);
+
+               /* clear the interrupts */
+               dcss_clr((irq_status & CTXLD_IRQ_ERROR),
+                        priv->ctxld_reg + DCSS_CTXLD_CONTROL_STATUS);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int dcss_ctxld_irq_config(struct dcss_ctxld_priv *ctxld)
+{
+       struct dcss_soc *dcss = ctxld->dcss;
+       struct platform_device *pdev = to_platform_device(dcss->dev);
+       int ret;
+
+       ctxld->irq = platform_get_irq_byname(pdev, CTXLD_IRQ_NAME);
+       if (ctxld->irq < 0) {
+               dev_err(dcss->dev, "ctxld: can't get irq number\n");
+               return ctxld->irq;
+       }
+
+       dcss_set(RD_ERR_EN | DB_COMP_EN | SB_HP_COMP_EN | SB_LP_COMP_EN |
+                DB_PEND_SB_REC_EN | SB_PEND_DISP_ACTIVE_EN | AHB_ERR_EN |
+                RD_ERR | AHB_ERR,
+                ctxld->ctxld_reg + DCSS_CTXLD_CONTROL_STATUS);
+
+       ret = devm_request_threaded_irq(dcss->dev, ctxld->irq,
+                                       dcss_ctxld_irq_handler,
+                                       dcss_ctxld_irq_handler_thread,
+                                       IRQF_ONESHOT | IRQF_TRIGGER_RISING,
+                                       DCSS_CTXLD_DEVNAME, ctxld);
+       if (ret) {
+               dev_err(dcss->dev, "ctxld: irq request failed.\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+/**
+ * dcss_ctxld_alloc_ctx - Allocate context memory.
+ *
+ * @ctxld: Pointer to ctxld.
+ *
+ * Returns:
+ * Zeron on success, negative errno on failure.
+ */
+static int dcss_ctxld_alloc_ctx(struct dcss_ctxld_priv *ctxld)
+{
+       struct dcss_soc *dcss = ctxld->dcss;
+       struct dcss_ctxld_item *ctx;
+       int i;
+       dma_addr_t dma_handle;
+
+       for (i = 0; i < 2; i++) {
+               ctx = dmam_alloc_coherent(dcss->dev,
+                                         CTXLD_DB_CTX_ENTRIES * sizeof(*ctx),
+                                         &dma_handle, GFP_KERNEL);
+               if (!ctx)
+                       return -ENOMEM;
+
+               ctxld->db[i] = ctx;
+               ctxld->db_paddr[i] = dma_handle;
+
+               ctx = dmam_alloc_coherent(dcss->dev,
+                                         CTXLD_SB_CTX_ENTRIES * sizeof(*ctx),
+                                         &dma_handle, GFP_KERNEL);
+               if (!ctx)
+                       return -ENOMEM;
+
+               ctxld->sb_hp[i] = ctx;
+               ctxld->sb_lp[i] = ctx + CTXLD_SB_HP_CTX_ENTRIES;
+
+               ctxld->sb_paddr[i] = dma_handle;
+       }
+
+       return 0;
+}
+
+int dcss_ctxld_init(struct dcss_soc *dcss, unsigned long ctxld_base)
+{
+       struct dcss_ctxld_priv *priv;
+       int ret;
+
+       priv = devm_kzalloc(dcss->dev, sizeof(struct dcss_ctxld_priv),
+                           GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       dcss->ctxld_priv = priv;
+       priv->dcss = dcss;
+
+       ret = dcss_ctxld_alloc_ctx(priv);
+       if (ret) {
+               dev_err(dcss->dev, "ctxld: cannot allocate context memory.\n");
+               return ret;
+       }
+
+       mutex_init(&priv->mutex);
+
+       priv->ctxld_reg = devm_ioremap(dcss->dev, ctxld_base, SZ_4K);
+       if (!priv->ctxld_reg) {
+               dev_err(dcss->dev, "ctxld: unable to remap ctxld base\n");
+               return -ENOMEM;
+       }
+
+       dcss_writel(0, priv->ctxld_reg + DCSS_CTXLD_CONTROL_STATUS);
+
+       ret = dcss_ctxld_irq_config(priv);
+       if (!ret)
+               return ret;
+
+       return 0;
+}
+
+void dcss_ctxld_exit(struct dcss_soc *dcss)
+{
+}
+
+static int __dcss_ctxld_enable(struct dcss_ctxld_priv *ctxld)
+{
+       int curr_ctx = ctxld->current_ctx;
+       u32 db_base, sb_base, sb_count;
+       u32 sb_hp_cnt, sb_lp_cnt, db_cnt;
+
+       sb_hp_cnt = ctxld->ctx_size[curr_ctx][CTX_SB_HP];
+       sb_lp_cnt = ctxld->ctx_size[curr_ctx][CTX_SB_LP];
+       db_cnt = ctxld->ctx_size[curr_ctx][CTX_DB];
+
+       /* make sure SB_LP context area comes after SB_HP */
+       if (sb_lp_cnt &&
+           ctxld->sb_lp[curr_ctx] != ctxld->sb_hp[curr_ctx] + sb_hp_cnt) {
+               struct dcss_ctxld_item *sb_lp_adjusted;
+
+               sb_lp_adjusted = ctxld->sb_hp[curr_ctx] + sb_hp_cnt;
+
+               memcpy(sb_lp_adjusted, ctxld->sb_lp[curr_ctx],
+                      sb_lp_cnt * CTX_ITEM_SIZE);
+       }
+
+       db_base = db_cnt ? ctxld->db_paddr[curr_ctx] : 0;
+
+       dcss_writel(db_base, ctxld->ctxld_reg + DCSS_CTXLD_DB_BASE_ADDR);
+       dcss_writel(db_cnt, ctxld->ctxld_reg + DCSS_CTXLD_DB_COUNT);
+
+       if (sb_hp_cnt)
+               sb_count = ((sb_hp_cnt << SB_HP_COUNT_POS) & SB_HP_COUNT_MASK) |
+                          ((sb_lp_cnt << SB_LP_COUNT_POS) & SB_LP_COUNT_MASK);
+       else
+               sb_count = (sb_lp_cnt << SB_HP_COUNT_POS) & SB_HP_COUNT_MASK;
+
+       sb_base = sb_count ? ctxld->sb_paddr[curr_ctx] : 0;
+
+       dcss_writel(sb_base, ctxld->ctxld_reg + DCSS_CTXLD_SB_BASE_ADDR);
+       dcss_writel(sb_count, ctxld->ctxld_reg + DCSS_CTXLD_SB_COUNT);
+
+       /* enable the context loader */
+       dcss_set(CTXLD_ENABLE, ctxld->ctxld_reg + DCSS_CTXLD_CONTROL_STATUS);
+
+       ctxld->in_use = true;
+
+       /*
+        * Toggle the current context to the alternate one so that any updates
+        * in the modules' settings take place there.
+        */
+       ctxld->current_ctx ^= 1;
+
+       ctxld->ctx_size[ctxld->current_ctx][CTX_DB] = 0;
+       ctxld->ctx_size[ctxld->current_ctx][CTX_SB_HP] = 0;
+       ctxld->ctx_size[ctxld->current_ctx][CTX_SB_LP] = 0;
+
+       return 0;
+}
+
+/**
+ * dcss_ctxld_enable - Enable context loader module.
+ *
+ * @dcss: pointer to dcss_soc.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int dcss_ctxld_enable(struct dcss_soc *dcss)
+{
+       struct dcss_ctxld_priv *ctxld = dcss->ctxld_priv;
+
+       mutex_lock(&ctxld->mutex);
+       if (ctxld->in_use) {
+               ctxld->run_again = true;
+               mutex_unlock(&ctxld->mutex);
+               return 0;
+       }
+
+       __dcss_ctxld_enable(ctxld);
+
+       mutex_unlock(&ctxld->mutex);
+
+       return 0;
+}
+EXPORT_SYMBOL(dcss_ctxld_enable);
+
+void dcss_ctxld_write(struct dcss_soc *dcss, u32 ctx_id, u32 val, u32 reg_ofs)
+{
+       struct dcss_ctxld_priv *ctxld = dcss->ctxld_priv;
+       int curr_ctx = ctxld->current_ctx;
+       struct dcss_ctxld_item *ctx[] = {
+               [CTX_DB] = ctxld->db[curr_ctx],
+               [CTX_SB_HP] = ctxld->sb_hp[curr_ctx],
+               [CTX_SB_LP] = ctxld->sb_lp[curr_ctx]
+       };
+       int item_idx = ctxld->ctx_size[curr_ctx][ctx_id];
+
+       /* if we hit this, we've got to increase the maximum context size */
+       BUG_ON(dcss_ctxld_ctx_size[ctx_id] - 1 < item_idx);
+
+       mutex_lock(&ctxld->mutex);
+       ctx[ctx_id][item_idx].val = val;
+       ctx[ctx_id][item_idx].ofs = reg_ofs;
+       ctxld->ctx_size[curr_ctx][ctx_id] += 1;
+       mutex_unlock(&ctxld->mutex);
+}
+
+#ifdef CONFIG_DEBUG_FS
+void dcss_ctxld_dump(struct seq_file *s, void *data)
+{
+       struct dcss_soc *dcss = data;
+       struct dcss_ctxld_priv *ctxld = dcss->ctxld_priv;
+       int curr_ctx = ctxld->current_ctx;
+       int i;
+       struct dcss_ctxld_item *ctx_db, *ctx_sb_hp, *ctx_sb_lp;
+       u32 ctx_db_size, ctx_sb_hp_size, ctx_sb_lp_size;
+
+       ctx_db_size = ctxld->ctx_size[curr_ctx ^ 1][CTX_DB];
+       ctx_sb_hp_size = ctxld->ctx_size[curr_ctx ^ 1][CTX_SB_HP];
+       ctx_sb_lp_size = ctxld->ctx_size[curr_ctx ^ 1][CTX_SB_LP];
+
+       ctx_db = ctxld->db[curr_ctx ^ 1];
+       ctx_sb_hp = ctxld->sb_hp[curr_ctx ^ 1];
+       ctx_sb_lp = ctxld->sb_hp[curr_ctx ^ 1] + ctx_sb_hp_size;
+
+       seq_puts(s, ">> Dumping loaded context:\n");
+       seq_puts(s, "\t>>Dumping CTX_DB:\n");
+       for (i = 0; i < ctx_db_size; i++)
+               seq_printf(s, "\t0x%16llx -> 0x%08x : 0x%08x\n",
+                          (u64)&ctx_db[i], ctx_db[i].ofs, ctx_db[i].val);
+       seq_puts(s, "\t>>Dumping CTX_DB_HP:\n");
+       for (i = 0; i < ctx_sb_hp_size; i++)
+               seq_printf(s, "\t0x%16llx -> 0x%08x : 0x%08x\n",
+                          (u64)&ctx_sb_hp[i], ctx_sb_hp[i].ofs,
+                          ctx_sb_hp[i].val);
+       seq_puts(s, "\t>>Dumping CTX_DB_LP:\n");
+       for (i = 0; i < ctx_sb_lp_size; i++)
+               seq_printf(s, "\t0x%16llx -> 0x%08x : 0x%08x\n",
+                          (u64)&ctx_sb_lp[i], ctx_sb_lp[i].ofs,
+                          ctx_sb_lp[i].val);
+}
+#endif
diff --git a/drivers/gpu/imx/dcss/dcss-dec400d.c b/drivers/gpu/imx/dcss/dcss-dec400d.c
new file mode 100644 (file)
index 0000000..645919e
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/bitops.h>
+#include <linux/io.h>
+
+#include <video/imx-dcss.h>
+#include "dcss-prv.h"
+
+struct dcss_dec400d_priv {
+       struct dcss_soc *dcss;
+       void __iomem *dec400d_reg;
+};
+
+int dcss_dec400d_init(struct dcss_soc *dcss, unsigned long dec400d_base)
+{
+       struct dcss_dec400d_priv *dec400d;
+
+       dec400d = devm_kzalloc(dcss->dev, sizeof(*dec400d), GFP_KERNEL);
+       if (!dec400d)
+               return -ENOMEM;
+
+       dcss->dec400d_priv = dec400d;
+       dec400d->dcss = dcss;
+
+       dec400d->dec400d_reg = devm_ioremap(dcss->dev, dec400d_base, SZ_4K);
+       if (!dec400d->dec400d_reg) {
+               dev_err(dcss->dev, "dec400d: unable to remap dec400d base\n");
+               return -ENOMEM;
+       }
+
+       /* PUT IN BYPASS FOR NOW */
+//[lp] dcss_writel(0, dec400d->dec400d_reg + 0x2c0);
+
+       return 0;
+}
+
+void dcss_dec400d_exit(struct dcss_soc *dcss)
+{
+}
diff --git a/drivers/gpu/imx/dcss/dcss-dpr.c b/drivers/gpu/imx/dcss/dcss-dpr.c
new file mode 100644 (file)
index 0000000..fd735cd
--- /dev/null
@@ -0,0 +1,579 @@
+/*
+ * Copyright (C) 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/sizes.h>
+#include <linux/io.h>
+#include <linux/seq_file.h>
+#include <drm/drm_fourcc.h>
+
+#include <video/imx-dcss.h>
+#include "dcss-prv.h"
+
+#define USE_CTXLD
+
+#define DCSS_DPR_DEV_NAME                      "dcss_dpr"
+
+#define DCSS_DPR_SYSTEM_CTRL0                  0x000
+#define   RUN_EN                               BIT(0)
+#define   SOFT_RESET                           BIT(1)
+#define   REPEAT_EN                            BIT(2)
+#define   SHADOW_LOAD_EN                       BIT(3)
+#define   SW_SHADOW_LOAD_SEL                   BIT(4)
+#define   BCMD2AXI_MSTR_ID_CTRL                        BIT(16)
+#define DCSS_DPR_IRQ_MASK                      0x020
+#define DCSS_DPR_IRQ_MASK_STATUS               0x030
+#define DCSS_DPR_IRQ_NONMASK_STATUS            0x040
+#define   IRQ_DPR_CTRL_DONE                    BIT(0)
+#define   IRQ_DPR_RUN                          BIT(1)
+#define   IRQ_DPR_SHADOW_LOADED                        BIT(2)
+#define   IRQ_AXI_READ_ERR                     BIT(3)
+#define   DPR2RTR_YRGB_FIFO_OVFL               BIT(4)
+#define   DPR2RTR_UV_FIFO_OVFL                 BIT(5)
+#define   DPR2RTR_FIFO_LD_BUF_RDY_YRGB_ERR     BIT(6)
+#define   DPR2RTR_FIFO_LD_BUF_RDY_UV_ERR       BIT(7)
+#define DCSS_DPR_MODE_CTRL0                    0x050
+#define   RTR_3BUF_EN                          BIT(0)
+#define   RTR_4LINE_BUF_EN                     BIT(1)
+#define   TILE_TYPE_POS                                2
+#define   TILE_TYPE_MASK                       GENMASK(4, 2)
+#define   YUV_EN                               BIT(6)
+#define   COMP_2PLANE_EN                       BIT(7)
+#define   PIX_SIZE_POS                         8
+#define   PIX_SIZE_MASK                                GENMASK(9, 8)
+#define   PIX_LUMA_UV_SWAP                     BIT(10)
+#define   PIX_UV_SWAP                          BIT(11)
+#define   B_COMP_SEL_POS                       12
+#define   B_COMP_SEL_MASK                      GENMASK(13, 12)
+#define   G_COMP_SEL_POS                       14
+#define   G_COMP_SEL_MASK                      GENMASK(15, 14)
+#define   R_COMP_SEL_POS                       16
+#define   R_COMP_SEL_MASK                      GENMASK(17, 16)
+#define   A_COMP_SEL_POS                       18
+#define   A_COMP_SEL_MASK                      GENMASK(19, 18)
+#define DCSS_DPR_FRAME_CTRL0                   0x070
+#define   HFLIP_EN                             BIT(0)
+#define   VFLIP_EN                             BIT(1)
+#define   ROT_ENC_POS                          2
+#define   ROT_ENC_MASK                         GENMASK(3, 2)
+#define   ROT_FLIP_ORDER_EN                    BIT(4)
+#define   PITCH_POS                            16
+#define   PITCH_MASK                           GENMASK(31, 16)
+#define DCSS_DPR_FRAME_1P_CTRL0                        0x090
+#define DCSS_DPR_FRAME_1P_PIX_X_CTRL           0x0A0
+#define DCSS_DPR_FRAME_1P_PIX_Y_CTRL           0x0B0
+#define DCSS_DPR_FRAME_1P_BASE_ADDR            0x0C0
+#define DCSS_DPR_FRAME_2P_CTRL0                        0x0E0
+#define DCSS_DPR_FRAME_2P_PIX_X_CTRL           0x0F0
+#define DCSS_DPR_FRAME_2P_PIX_Y_CTRL           0x100
+#define DCSS_DPR_FRAME_2P_BASE_ADDR            0x110
+#define DCSS_DPR_STATUS_CTRL0                  0x130
+#define   STATUS_MUX_SEL_MASK                  GENMASK(2, 0)
+#define   STATUS_SRC_SEL_POS                   16
+#define   STATUS_SRC_SEL_MASK                  GENMASK(18, 16)
+#define DCSS_DPR_STATUS_CTRL1                  0x140
+#define DCSS_DPR_RTRAM_CTRL0                   0x200
+#define   NUM_ROWS_ACTIVE                      BIT(0)
+#define   THRES_HIGH_POS                       1
+#define   THRES_HIGH_MASK                      GENMASK(3, 1)
+#define   THRES_LOW_POS                                4
+#define   THRES_LOW_MASK                       GENMASK(6, 4)
+#define   ABORT_SEL                            BIT(7)
+
+struct dcss_dpr_ch {
+       void __iomem *base_reg;
+       u32 base_ofs;
+       u32  ctx_id; /* an ID to the allocated region in context loader */
+
+       u32 pix_format;
+       u32 bpp;
+       u32 planes;
+       enum dcss_pix_size pix_size;
+       enum dcss_tile_type tile;
+       bool rtram_4line_en;
+       bool rtram_3buf_en;
+
+       u32 frame_ctrl;
+       u32 mode_ctrl;
+       u32 sys_ctrl;
+       u32 rtram_ctrl;
+};
+
+struct dcss_dpr_priv {
+       struct dcss_soc *dcss;
+       struct dcss_dpr_ch ch[3];
+};
+
+static void dcss_dpr_write(struct dcss_dpr_priv *dpr, int ch_num,
+                          u32 val, u32 ofs)
+{
+#if !defined(USE_CTXLD)
+       dcss_writel(val, dpr->ch[ch_num].base_reg + ofs);
+#else
+       dcss_ctxld_write(dpr->dcss, dpr->ch[ch_num].ctx_id,
+                        val, dpr->ch[ch_num].base_ofs + ofs);
+#endif
+}
+
+#ifdef CONFIG_DEBUG_FS
+static struct dcss_debug_reg dpr_debug_reg[] = {
+       DCSS_DBG_REG(DCSS_DPR_SYSTEM_CTRL0),
+       DCSS_DBG_REG(DCSS_DPR_IRQ_MASK),
+       DCSS_DBG_REG(DCSS_DPR_IRQ_MASK_STATUS),
+       DCSS_DBG_REG(DCSS_DPR_IRQ_NONMASK_STATUS),
+       DCSS_DBG_REG(DCSS_DPR_MODE_CTRL0),
+       DCSS_DBG_REG(DCSS_DPR_FRAME_CTRL0),
+       DCSS_DBG_REG(DCSS_DPR_FRAME_1P_CTRL0),
+       DCSS_DBG_REG(DCSS_DPR_FRAME_1P_PIX_X_CTRL),
+       DCSS_DBG_REG(DCSS_DPR_FRAME_1P_PIX_Y_CTRL),
+       DCSS_DBG_REG(DCSS_DPR_FRAME_1P_BASE_ADDR),
+       DCSS_DBG_REG(DCSS_DPR_FRAME_2P_CTRL0),
+       DCSS_DBG_REG(DCSS_DPR_FRAME_2P_PIX_X_CTRL),
+       DCSS_DBG_REG(DCSS_DPR_FRAME_2P_PIX_Y_CTRL),
+       DCSS_DBG_REG(DCSS_DPR_FRAME_2P_BASE_ADDR),
+       DCSS_DBG_REG(DCSS_DPR_STATUS_CTRL0),
+       DCSS_DBG_REG(DCSS_DPR_STATUS_CTRL1),
+       DCSS_DBG_REG(DCSS_DPR_RTRAM_CTRL0),
+};
+
+void dcss_dpr_dump_regs(struct seq_file *s, void *data)
+{
+       struct dcss_soc *dcss = data;
+       int i, j;
+
+       for (i = 0; i < 3; i++) {
+               seq_printf(s, ">> Dumping DPR CH %d:\n", i);
+               for (j = 0; j < ARRAY_SIZE(dpr_debug_reg); j++)
+                       seq_printf(s, "%-35s(0x%04x) -> 0x%08x\n",
+                                  dpr_debug_reg[j].name,
+                                  dpr_debug_reg[j].ofs,
+                                  dcss_readl(dcss->dpr_priv->ch[i].base_reg +
+                                             dpr_debug_reg[j].ofs));
+       }
+}
+#endif
+
+static int dcss_dpr_ch_init_all(struct dcss_soc *dcss, unsigned long dpr_base)
+{
+       struct dcss_dpr_priv *priv = dcss->dpr_priv;
+       struct dcss_dpr_ch *ch;
+       int i;
+
+       for (i = 0; i < 3; i++) {
+               ch = &priv->ch[i];
+
+               ch->base_ofs = dpr_base + i * 0x1000;
+
+               ch->base_reg = devm_ioremap(dcss->dev, ch->base_ofs, SZ_4K);
+               if (!ch->base_reg) {
+                       dev_err(dcss->dev, "dpr: unable to remap ch %d base\n",
+                               i);
+                       return -ENOMEM;
+               }
+
+#if defined(USE_CTXLD)
+               ch->ctx_id = CTX_SB_HP;
+#endif
+       }
+
+       return 0;
+}
+
+int dcss_dpr_init(struct dcss_soc *dcss, unsigned long dpr_base)
+{
+       struct dcss_dpr_priv *priv;
+
+       priv = devm_kzalloc(dcss->dev, sizeof(struct dcss_dpr_priv),
+                           GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       dcss->dpr_priv = priv;
+       priv->dcss = dcss;
+
+       return dcss_dpr_ch_init_all(dcss, dpr_base);
+}
+
+void dcss_dpr_exit(struct dcss_soc *dcss)
+{
+       struct dcss_dpr_priv *dpr = dcss->dpr_priv;
+       int ch_no;
+
+       /* stop DPR on all channels */
+       for (ch_no = 0; ch_no < 3; ch_no++) {
+               struct dcss_dpr_ch *ch = &dpr->ch[ch_no];
+
+               dcss_writel(0, ch->base_reg + DCSS_DPR_SYSTEM_CTRL0);
+       }
+}
+
+static u32 dcss_dpr_x_pix_wide_adjust(struct dcss_dpr_ch *ch, u32 pix_wide,
+                                     u32 pix_format)
+{
+       u8 pix_in_64byte_map[3][5] = {
+               /* LIN, GPU_STD, GPU_SUP, VPU_YUV420, VPU_VP9 */
+               {   64,       8,       8,          8,     16}, /* PIX_SIZE_8  */
+               {   32,       8,       8,          8,      8}, /* PIX_SIZE_16 */
+               {   16,       4,       4,          8,      8}, /* PIX_SIZE_32 */
+       };
+       u32 offset;
+       u32 div_64byte_mod, pix_in_64byte;
+
+       pix_in_64byte = pix_in_64byte_map[ch->pix_size][ch->tile];
+
+       div_64byte_mod = pix_wide % pix_in_64byte;
+       offset = (div_64byte_mod == 0) ? 0 : (pix_in_64byte - div_64byte_mod);
+
+       return pix_wide + offset;
+}
+
+static u32 dcss_dpr_y_pix_high_adjust(struct dcss_dpr_ch *ch, u32 pix_high,
+                                     u32 pix_format)
+{
+       u8 num_rows_buf = ch->rtram_4line_en ? 4 : 8;
+       u32 offset, pix_y_mod;
+
+       pix_y_mod = pix_high % num_rows_buf;
+       offset = pix_y_mod ? (num_rows_buf - pix_y_mod) : 0;
+
+       return pix_high + offset;
+}
+
+void dcss_dpr_set_res(struct dcss_soc *dcss, int ch_num, u32 xres, u32 yres)
+{
+       struct dcss_dpr_priv *dpr = dcss->dpr_priv;
+       struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
+       u32 pix_x_wide, pix_y_high;
+       int plane, max_planes = 1;
+       u32 gap = DCSS_DPR_FRAME_2P_BASE_ADDR - DCSS_DPR_FRAME_1P_BASE_ADDR;
+       u32 pix_format = dpr->ch[ch_num].pix_format;
+
+       if (pix_format == DRM_FORMAT_NV12 || pix_format == DRM_FORMAT_NV21)
+               max_planes = 2;
+
+       for (plane = 0; plane < max_planes; plane++) {
+               yres = plane == 1 ? yres >> 1 : yres;
+
+               pix_x_wide = dcss_dpr_x_pix_wide_adjust(ch, xres, pix_format);
+               pix_y_high = dcss_dpr_y_pix_high_adjust(ch, yres, pix_format);
+               dcss_dpr_write(dpr, ch_num, pix_x_wide,
+                              DCSS_DPR_FRAME_1P_PIX_X_CTRL + plane * gap);
+               dcss_dpr_write(dpr, ch_num, pix_y_high,
+                              DCSS_DPR_FRAME_1P_PIX_Y_CTRL + plane * gap);
+
+               dcss_dpr_write(dpr,
+                              ch_num, xres < 1920 ? 2 : xres > 1920 ? 6 : 5,
+                              DCSS_DPR_FRAME_1P_CTRL0 + plane * gap);
+       }
+}
+EXPORT_SYMBOL(dcss_dpr_set_res);
+
+void dcss_dpr_addr_set(struct dcss_soc *dcss, int ch_num, u32 luma_base_addr,
+                      u32 chroma_base_addr, u16 pitch)
+{
+       struct dcss_dpr_ch *ch = &dcss->dpr_priv->ch[ch_num];
+
+       dcss_dpr_write(dcss->dpr_priv, ch_num, luma_base_addr,
+                      DCSS_DPR_FRAME_1P_BASE_ADDR);
+
+       dcss_dpr_write(dcss->dpr_priv, ch_num, chroma_base_addr,
+                      DCSS_DPR_FRAME_2P_BASE_ADDR);
+
+       ch->frame_ctrl &= ~PITCH_MASK;
+       ch->frame_ctrl |= ((pitch << PITCH_POS) & PITCH_MASK);
+}
+EXPORT_SYMBOL(dcss_dpr_addr_set);
+
+static void dcss_dpr_argb_comp_sel(struct dcss_soc *dcss, int ch_num,
+                                  int a_sel, int r_sel, int g_sel, int b_sel)
+{
+       struct dcss_dpr_ch *ch = &dcss->dpr_priv->ch[ch_num];
+       u32 sel;
+
+       sel = ((a_sel << A_COMP_SEL_POS) & A_COMP_SEL_MASK) |
+             ((r_sel << R_COMP_SEL_POS) & R_COMP_SEL_MASK) |
+             ((g_sel << G_COMP_SEL_POS) & G_COMP_SEL_MASK) |
+             ((b_sel << B_COMP_SEL_POS) & B_COMP_SEL_MASK);
+
+       ch->mode_ctrl &= ~(A_COMP_SEL_MASK | R_COMP_SEL_MASK |
+                          G_COMP_SEL_MASK | B_COMP_SEL_MASK);
+       ch->mode_ctrl |= sel;
+}
+
+static void dcss_dpr_pix_size_set(struct dcss_soc *dcss, int ch_num,
+                                 int pix_size)
+{
+       u32 val;
+       struct dcss_dpr_ch *ch = &dcss->dpr_priv->ch[ch_num];
+
+       switch (pix_size) {
+       case 8:
+               val = 0;
+               break;
+       case 16:
+               val = 1;
+               break;
+       case 32:
+               val = 2;
+               break;
+       default:
+               val = 2;
+               break;
+       }
+
+       ch->pix_size = val;
+
+       ch->mode_ctrl &= ~PIX_SIZE_MASK;
+       ch->mode_ctrl |= ((val << PIX_SIZE_POS) & PIX_SIZE_MASK);
+}
+
+static void dcss_dpr_uv_swap(struct dcss_soc *dcss, int ch_num, bool swap)
+{
+       struct dcss_dpr_ch *ch = &dcss->dpr_priv->ch[ch_num];
+
+       ch->mode_ctrl &= ~PIX_UV_SWAP;
+       ch->mode_ctrl |= (swap ? PIX_UV_SWAP : 0);
+}
+
+static void dcss_dpr_y_uv_swap(struct dcss_soc *dcss, int ch_num, bool swap)
+{
+       struct dcss_dpr_ch *ch = &dcss->dpr_priv->ch[ch_num];
+
+       ch->mode_ctrl &= ~PIX_LUMA_UV_SWAP;
+       ch->mode_ctrl |= (swap ? PIX_LUMA_UV_SWAP : 0);
+}
+
+static void dcss_dpr_2plane_en(struct dcss_soc *dcss, int ch_num, bool en)
+{
+       struct dcss_dpr_ch *ch = &dcss->dpr_priv->ch[ch_num];
+
+       ch->mode_ctrl &= ~COMP_2PLANE_EN;
+       ch->mode_ctrl |= (en ? COMP_2PLANE_EN : 0);
+}
+
+static void dcss_dpr_yuv_en(struct dcss_soc *dcss, int ch_num, bool en)
+{
+       struct dcss_dpr_ch *ch = &dcss->dpr_priv->ch[ch_num];
+
+       ch->mode_ctrl &= ~YUV_EN;
+       ch->mode_ctrl |= (en ? YUV_EN : 0);
+}
+
+static void dcss_dpr_tile_set(struct dcss_soc *dcss, int ch_num,
+                             enum dcss_tile_type tile)
+{
+       struct dcss_dpr_ch *ch = &dcss->dpr_priv->ch[ch_num];
+
+       ch->mode_ctrl &= ~TILE_TYPE_MASK;
+       ch->mode_ctrl |= ((tile << TILE_TYPE_POS) & TILE_TYPE_MASK);
+}
+
+void dcss_dpr_enable(struct dcss_soc *dcss, int ch_num, bool en)
+{
+       struct dcss_dpr_priv *dpr = dcss->dpr_priv;
+       struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
+
+       ch->sys_ctrl &= ~(REPEAT_EN | RUN_EN);
+       ch->sys_ctrl |= (en ? REPEAT_EN | RUN_EN : 0);
+
+       if (en) {
+               dcss_dpr_write(dpr, ch_num, ch->mode_ctrl, DCSS_DPR_MODE_CTRL0);
+               dcss_dpr_write(dpr, ch_num, ch->frame_ctrl,
+                              DCSS_DPR_FRAME_CTRL0);
+               dcss_dpr_write(dpr, ch_num, ch->rtram_ctrl,
+                              DCSS_DPR_RTRAM_CTRL0);
+       }
+
+       dcss_dpr_write(dpr, ch_num, ch->sys_ctrl, DCSS_DPR_SYSTEM_CTRL0);
+}
+EXPORT_SYMBOL(dcss_dpr_enable);
+
+struct rgb_comp_sel {
+       u32 drm_format;
+       int a_sel;
+       int r_sel;
+       int g_sel;
+       int b_sel;
+};
+
+static struct rgb_comp_sel comp_sel_map[] = {
+       {DRM_FORMAT_ARGB8888, 3, 2, 1, 0},
+       {DRM_FORMAT_XRGB8888, 3, 2, 1, 0},
+       {DRM_FORMAT_ABGR8888, 3, 0, 1, 2},
+       {DRM_FORMAT_XBGR8888, 3, 0, 1, 2},
+       {DRM_FORMAT_RGBA8888, 0, 3, 2, 1},
+       {DRM_FORMAT_RGBX8888, 0, 3, 2, 1},
+       {DRM_FORMAT_BGRA8888, 0, 1, 2, 3},
+       {DRM_FORMAT_BGRX8888, 0, 1, 2, 3},
+};
+
+static int to_comp_sel(u32 pix_fmt, int *a_sel, int *r_sel, int *g_sel,
+                      int *b_sel)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(comp_sel_map); i++) {
+               if (comp_sel_map[i].drm_format == pix_fmt) {
+                       *a_sel = comp_sel_map[i].a_sel;
+                       *r_sel = comp_sel_map[i].r_sel;
+                       *g_sel = comp_sel_map[i].g_sel;
+                       *b_sel = comp_sel_map[i].b_sel;
+
+                       return 0;
+               }
+       }
+
+       return -1;
+}
+
+static void dcss_dpr_rtram_set(struct dcss_soc *dcss, int ch_num,
+                              u32 pix_format)
+{
+       u32 val, mask;
+       struct dcss_dpr_ch *ch = &dcss->dpr_priv->ch[ch_num];
+
+       switch (pix_format) {
+       case DRM_FORMAT_NV21:
+       case DRM_FORMAT_NV12:
+               ch->rtram_3buf_en = 1;
+               ch->rtram_4line_en = 0;
+               break;
+
+       default:
+               ch->rtram_3buf_en = 1;
+               ch->rtram_4line_en = 1;
+               break;
+       }
+
+       val = (ch->rtram_4line_en ? RTR_4LINE_BUF_EN : 0);
+       val |= (ch->rtram_3buf_en ? RTR_3BUF_EN : 0);
+       mask = RTR_4LINE_BUF_EN | RTR_3BUF_EN;
+
+       ch->mode_ctrl &= ~mask;
+       ch->mode_ctrl |= (val & mask);
+
+       /* TODO: Should the thresholds be hardcoded? */
+       val = (3 << THRES_LOW_POS) & THRES_LOW_MASK;
+       val |= (4 << THRES_HIGH_POS) & THRES_HIGH_MASK;
+       mask = THRES_LOW_MASK | THRES_HIGH_MASK;
+
+       ch->rtram_ctrl &= ~mask;
+       ch->rtram_ctrl |= (val & mask);
+}
+
+static void dcss_dpr_setup_components(struct dcss_soc *dcss, int ch_num,
+                                     u32 pix_format)
+{
+       enum dcss_color_space cs = dcss_drm_fourcc_to_colorspace(pix_format);
+       int a_sel, r_sel, g_sel, b_sel;
+       bool uv_swap, y_uv_swap;
+
+       switch (pix_format) {
+       case DRM_FORMAT_YVYU:
+               uv_swap = true;
+               y_uv_swap = true;
+               break;
+
+       case DRM_FORMAT_VYUY:
+       case DRM_FORMAT_NV21:
+               uv_swap = true;
+               y_uv_swap = false;
+               break;
+
+       case DRM_FORMAT_YUYV:
+               uv_swap = false;
+               y_uv_swap = true;
+               break;
+
+       default:
+               uv_swap = false;
+               y_uv_swap = false;
+               break;
+       }
+
+       dcss_dpr_uv_swap(dcss, ch_num, uv_swap);
+
+       dcss_dpr_y_uv_swap(dcss, ch_num, y_uv_swap);
+
+       if (cs == DCSS_COLORSPACE_RGB) {
+               if (!to_comp_sel(pix_format, &a_sel, &r_sel, &g_sel, &b_sel)) {
+                       dcss_dpr_argb_comp_sel(dcss, ch_num, a_sel, r_sel,
+                                              g_sel, b_sel);
+               } else {
+                       dcss_dpr_argb_comp_sel(dcss, ch_num, 3, 2, 1, 0);
+               }
+       } else {
+               dcss_dpr_argb_comp_sel(dcss, ch_num, 0, 0, 0, 0);
+       }
+}
+
+static int dcss_dpr_get_bpp(u32 pix_format)
+{
+       int bpp;
+
+       switch (pix_format) {
+       case DRM_FORMAT_NV12:
+       case DRM_FORMAT_NV21:
+               bpp = 8;
+               break;
+
+       case DRM_FORMAT_UYVY:
+       case DRM_FORMAT_VYUY:
+       case DRM_FORMAT_YUYV:
+       case DRM_FORMAT_YVYU:
+               bpp = 16;
+               break;
+
+       default:
+               bpp = drm_format_plane_cpp(pix_format, 0) * 8;
+               break;
+       }
+
+       return bpp;
+}
+
+void dcss_dpr_format_set(struct dcss_soc *dcss, int ch_num, u32 pix_format)
+{
+       struct dcss_dpr_ch *ch = &dcss->dpr_priv->ch[ch_num];
+       struct drm_format_name_buf format_name;
+       enum dcss_color_space dcss_cs;
+
+       dev_dbg(dcss->dev, "%s\n", __func__);
+
+       dcss_cs = dcss_drm_fourcc_to_colorspace(pix_format);
+       ch->planes = drm_format_num_planes(pix_format);
+       ch->bpp = dcss_dpr_get_bpp(pix_format);
+       ch->pix_format = pix_format;
+
+       dev_dbg(dcss->dev, "pix_format = %s, colorspace = %d, bpp = %d\n",
+               drm_get_format_name(pix_format, &format_name), dcss_cs, ch->bpp);
+
+       dcss_dpr_yuv_en(dcss, ch_num, dcss_cs == DCSS_COLORSPACE_YUV);
+
+       dcss_dpr_pix_size_set(dcss, ch_num, ch->bpp);
+
+       dcss_dpr_setup_components(dcss, ch_num, pix_format);
+
+       dcss_dpr_2plane_en(dcss, ch_num, ch->planes == 2 ? true : false);
+
+       dcss_dpr_rtram_set(dcss, ch_num, pix_format);
+
+       /* TODO: do not hardcode tile type */
+       dcss_dpr_tile_set(dcss, ch_num, TILE_LINEAR);
+       ch->tile = TILE_LINEAR;
+}
+EXPORT_SYMBOL(dcss_dpr_format_set);
diff --git a/drivers/gpu/imx/dcss/dcss-dtg.c b/drivers/gpu/imx/dcss/dcss-dtg.c
new file mode 100644 (file)
index 0000000..4198cb1
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ * Copyright (C) 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/bitops.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/seq_file.h>
+#include <drm/drm_fourcc.h>
+
+#include <video/imx-dcss.h>
+#include "dcss-prv.h"
+
+#define USE_CTXLD
+
+#define DCSS_DTG_TC_CONTROL_STATUS                     0x00
+#define   CH3_EN                                       BIT(0)
+#define   CH2_EN                                       BIT(1)
+#define   CH1_EN                                       BIT(2)
+#define   OVL_DATA_MODE                                        BIT(3)
+#define   BLENDER_VIDEO_ALPHA_SEL                      BIT(7)
+#define   DTG_START                                    BIT(8)
+#define   DBY_MODE_EN                                  BIT(9)
+#define   CH1_ALPHA_SEL                                        BIT(10)
+#define   CSS_PIX_COMP_SWAP_POS                                12
+#define   CSS_PIX_COMP_SWAP_MASK                       GENMASK(14, 12)
+#define   DEFAULT_FG_ALPHA_POS                         24
+#define   DEFAULT_FG_ALPHA_MASK                                GENMASK(31, 24)
+#define DCSS_DTG_TC_DTG                                        0x04
+#define DCSS_DTG_TC_DISP_TOP                           0x08
+#define DCSS_DTG_TC_DISP_BOT                           0x0C
+#define DCSS_DTG_TC_CH1_TOP                            0x10
+#define DCSS_DTG_TC_CH1_BOT                            0x14
+#define DCSS_DTG_TC_CH2_TOP                            0x18
+#define DCSS_DTG_TC_CH2_BOT                            0x1C
+#define DCSS_DTG_TC_CH3_TOP                            0x20
+#define DCSS_DTG_TC_CH3_BOT                            0x24
+#define   TC_X_POS                                     0
+#define   TC_X_MASK                                    GENMASK(12, 0)
+#define   TC_Y_POS                                     16
+#define   TC_Y_MASK                                    GENMASK(28, 16)
+#define DCSS_DTG_TC_CTXLD                              0x28
+#define   TC_CTXLD_DB_Y_POS                            0
+#define   TC_CTXLD_DB_Y_MASK                           GENMASK(12, 0)
+#define   TC_CTXLD_SB_Y_POS                            16
+#define   TC_CTXLD_SB_Y_MASK                           GENMASK(28, 16)
+#define DCSS_DTG_TC_CH1_BKRND                          0x2C
+#define DCSS_DTG_TC_CH2_BKRND                          0x30
+#define   BKRND_R_Y_COMP_POS                           20
+#define   BKRND_R_Y_COMP_MASK                          GENMASK(29, 20)
+#define   BKRND_G_U_COMP_POS                           10
+#define   BKRND_G_U_COMP_MASK                          GENMASK(19, 10)
+#define   BKRND_B_V_COMP_POS                           0
+#define   BKRND_B_V_COMP_MASK                          GENMASK(9, 0)
+#define DCSS_DTG_BLENDER_DBY_RANGEINV                  0x38
+#define DCSS_DTG_BLENDER_DBY_RANGEMIN                  0x3C
+#define DCSS_DTG_BLENDER_DBY_BDP                       0x40
+#define DCSS_DTG_BLENDER_BKRND_I                       0x44
+#define DCSS_DTG_BLENDER_BKRND_P                       0x48
+#define DCSS_DTG_BLENDER_BKRND_T                       0x4C
+#define DCSS_DTG_LINE0_INT                             0x50
+#define DCSS_DTG_LINE1_INT                             0x54
+#define DCSS_DTG_BG_ALPHA_DEFAULT                      0x58
+#define DCSS_DTG_INT_STATUS                            0x5C
+#define DCSS_DTG_INT_CONTROL                           0x60
+#define DCSS_DTG_TC_CH3_BKRND                          0x64
+#define DCSS_DTG_INT_MASK                              0x68
+#define   LINE0_IRQ                                    BIT(0)
+#define   LINE1_IRQ                                    BIT(1)
+#define   LINE2_IRQ                                    BIT(2)
+#define   LINE3_IRQ                                    BIT(3)
+#define DCSS_DTG_LINE2_INT                             0x6C
+#define DCSS_DTG_LINE3_INT                             0x70
+#define DCSS_DTG_DBY_OL                                        0x74
+#define DCSS_DTG_DBY_BL                                        0x78
+#define DCSS_DTG_DBY_EL                                        0x7C
+
+static struct dcss_debug_reg dtg_debug_reg[] = {
+       DCSS_DBG_REG(DCSS_DTG_TC_CONTROL_STATUS),
+       DCSS_DBG_REG(DCSS_DTG_TC_DTG),
+       DCSS_DBG_REG(DCSS_DTG_TC_DISP_TOP),
+       DCSS_DBG_REG(DCSS_DTG_TC_DISP_BOT),
+       DCSS_DBG_REG(DCSS_DTG_TC_CH1_TOP),
+       DCSS_DBG_REG(DCSS_DTG_TC_CH1_BOT),
+       DCSS_DBG_REG(DCSS_DTG_TC_CH2_TOP),
+       DCSS_DBG_REG(DCSS_DTG_TC_CH2_BOT),
+       DCSS_DBG_REG(DCSS_DTG_TC_CH3_TOP),
+       DCSS_DBG_REG(DCSS_DTG_TC_CH3_BOT),
+       DCSS_DBG_REG(DCSS_DTG_TC_CTXLD),
+       DCSS_DBG_REG(DCSS_DTG_TC_CH1_BKRND),
+       DCSS_DBG_REG(DCSS_DTG_TC_CH2_BKRND),
+       DCSS_DBG_REG(DCSS_DTG_BLENDER_DBY_RANGEINV),
+       DCSS_DBG_REG(DCSS_DTG_BLENDER_DBY_RANGEMIN),
+       DCSS_DBG_REG(DCSS_DTG_BLENDER_DBY_BDP),
+       DCSS_DBG_REG(DCSS_DTG_BLENDER_BKRND_I),
+       DCSS_DBG_REG(DCSS_DTG_BLENDER_BKRND_P),
+       DCSS_DBG_REG(DCSS_DTG_BLENDER_BKRND_T),
+       DCSS_DBG_REG(DCSS_DTG_LINE0_INT),
+       DCSS_DBG_REG(DCSS_DTG_LINE1_INT),
+       DCSS_DBG_REG(DCSS_DTG_BG_ALPHA_DEFAULT),
+       DCSS_DBG_REG(DCSS_DTG_INT_STATUS),
+       DCSS_DBG_REG(DCSS_DTG_INT_CONTROL),
+       DCSS_DBG_REG(DCSS_DTG_TC_CH3_BKRND),
+       DCSS_DBG_REG(DCSS_DTG_INT_MASK),
+       DCSS_DBG_REG(DCSS_DTG_LINE2_INT),
+       DCSS_DBG_REG(DCSS_DTG_LINE3_INT),
+       DCSS_DBG_REG(DCSS_DTG_DBY_OL),
+       DCSS_DBG_REG(DCSS_DTG_DBY_BL),
+       DCSS_DBG_REG(DCSS_DTG_DBY_EL),
+};
+
+struct dcss_dtg_priv {
+       struct dcss_soc *dcss;
+       void __iomem *base_reg;
+       u32 base_ofs;
+
+       u32 ctx_id;
+
+       bool in_use;
+
+       u32 dis_ulc_x;
+       u32 dis_ulc_y;
+
+       u32 control_status;
+       u32 alpha;
+};
+
+static void dcss_dtg_write(struct dcss_dtg_priv *dtg, u32 val, u32 ofs)
+{
+       if (!dtg->in_use)
+               dcss_writel(val, dtg->base_reg + ofs);
+#if defined(USE_CTXLD)
+       dcss_ctxld_write(dtg->dcss, dtg->ctx_id, val, dtg->base_ofs + ofs);
+#endif
+}
+
+#ifdef CONFIG_DEBUG_FS
+void dcss_dtg_dump_regs(struct seq_file *s, void *data)
+{
+       struct dcss_soc *dcss = data;
+       int j;
+
+       seq_puts(s, ">> Dumping DTG:\n");
+       for (j = 0; j < ARRAY_SIZE(dtg_debug_reg); j++)
+               seq_printf(s, "%-35s(0x%04x) -> 0x%08x\n",
+                          dtg_debug_reg[j].name,
+                          dtg_debug_reg[j].ofs,
+                          dcss_readl(dcss->dtg_priv->base_reg +
+                                     dtg_debug_reg[j].ofs));
+}
+#endif
+
+int dcss_dtg_init(struct dcss_soc *dcss, unsigned long dtg_base)
+{
+       struct dcss_dtg_priv *dtg;
+
+       dtg = devm_kzalloc(dcss->dev, sizeof(*dtg), GFP_KERNEL);
+       if (!dtg)
+               return -ENOMEM;
+
+       dcss->dtg_priv = dtg;
+       dtg->dcss = dcss;
+
+       dtg->base_reg = devm_ioremap(dcss->dev, dtg_base, SZ_4K);
+       if (!dtg->base_reg) {
+               dev_err(dcss->dev, "dtg: unable to remap dtg base\n");
+               return -ENOMEM;
+       }
+
+       dtg->base_ofs = dtg_base;
+
+#if defined(USE_CTXLD)
+       dtg->ctx_id = CTX_DB;
+#endif
+
+       dtg->alpha = 255;
+
+       dtg->control_status |= OVL_DATA_MODE | BLENDER_VIDEO_ALPHA_SEL |
+               ((0x5 << CSS_PIX_COMP_SWAP_POS) & CSS_PIX_COMP_SWAP_MASK) |
+               ((dtg->alpha << DEFAULT_FG_ALPHA_POS) & DEFAULT_FG_ALPHA_MASK);
+
+       return 0;
+}
+
+void dcss_dtg_exit(struct dcss_soc *dcss)
+{
+       struct dcss_dtg_priv *dtg = dcss->dtg_priv;
+
+       /* stop DTG */
+       dcss_writel(DTG_START, dtg->base_reg + DCSS_DTG_TC_CONTROL_STATUS);
+}
+
+void dcss_dtg_sync_set(struct dcss_soc *dcss, struct videomode *vm)
+{
+       struct dcss_dtg_priv *dtg = dcss->dtg_priv;
+       u16 dtg_lrc_x, dtg_lrc_y;
+       u16 dis_ulc_x, dis_ulc_y;
+       u16 dis_lrc_x, dis_lrc_y;
+
+       dev_dbg(dcss->dev, "hfront_porch = %d\n", vm->hfront_porch);
+       dev_dbg(dcss->dev, "hback_porch = %d\n", vm->hback_porch);
+       dev_dbg(dcss->dev, "hsync_len = %d\n", vm->hsync_len);
+       dev_dbg(dcss->dev, "hactive = %d\n", vm->hactive);
+       dev_dbg(dcss->dev, "vfront_porch = %d\n", vm->vfront_porch);
+       dev_dbg(dcss->dev, "vback_porch = %d\n", vm->vback_porch);
+       dev_dbg(dcss->dev, "vsync_len = %d\n", vm->vsync_len);
+       dev_dbg(dcss->dev, "vactive = %d\n", vm->vactive);
+
+       dtg_lrc_x = vm->hfront_porch + vm->hback_porch + vm->hsync_len +
+                   vm->hactive - 1;
+       dtg_lrc_y = vm->vfront_porch + vm->vback_porch + vm->vsync_len +
+                   vm->vactive - 1;
+       dis_ulc_x = vm->hsync_len + vm->hback_porch - 1;
+       dis_ulc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch - 1;
+       dis_lrc_x = vm->hsync_len + vm->hback_porch + vm->hactive - 1;
+       dis_lrc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch +
+                   vm->vactive - 1;
+
+       dcss_dtg_write(dtg, ((dtg_lrc_y << TC_Y_POS) | dtg_lrc_x),
+                      DCSS_DTG_TC_DTG);
+       dcss_dtg_write(dtg, ((dis_ulc_y << TC_Y_POS) | dis_ulc_x),
+                      DCSS_DTG_TC_DISP_TOP);
+       dcss_dtg_write(dtg, ((dis_lrc_y << TC_Y_POS) | dis_lrc_x),
+                      DCSS_DTG_TC_DISP_BOT);
+
+       dtg->dis_ulc_x = dis_ulc_x;
+       dtg->dis_ulc_y = dis_ulc_y;
+
+       dcss_dtg_write(dtg,
+                      ((dis_ulc_y << TC_CTXLD_DB_Y_POS) & TC_CTXLD_DB_Y_MASK),
+                      DCSS_DTG_TC_CTXLD);
+
+       clk_set_rate(dcss->p_clk, vm->pixelclock);
+}
+EXPORT_SYMBOL(dcss_dtg_sync_set);
+
+void dcss_dtg_plane_pos_set(struct dcss_soc *dcss, int ch_num,
+                           int px, int py, int pw, int ph)
+{
+       struct dcss_dtg_priv *dtg = dcss->dtg_priv;
+       u16 p_ulc_x, p_ulc_y;
+       u16 p_lrc_x, p_lrc_y;
+
+       p_ulc_x = dtg->dis_ulc_x + px;
+       p_ulc_y = dtg->dis_ulc_y + py;
+       p_lrc_x = p_ulc_x + pw;
+       p_lrc_y = p_ulc_y + ph;
+
+       if (!px && !py && !pw && !ph) {
+               dcss_dtg_write(dtg, 0, DCSS_DTG_TC_CH1_TOP + 0x8 * ch_num);
+               dcss_dtg_write(dtg, 0, DCSS_DTG_TC_CH1_BOT + 0x8 * ch_num);
+       } else {
+               dcss_dtg_write(dtg, ((p_ulc_y << TC_Y_POS) | p_ulc_x),
+                              DCSS_DTG_TC_CH1_TOP + 0x8 * ch_num);
+               dcss_dtg_write(dtg, ((p_lrc_y << TC_Y_POS) | p_lrc_x),
+                              DCSS_DTG_TC_CH1_BOT + 0x8 * ch_num);
+       }
+}
+EXPORT_SYMBOL(dcss_dtg_plane_pos_set);
+
+static bool dcss_dtg_global_alpha_needed(u32 pix_format)
+{
+       return pix_format == DRM_FORMAT_XRGB8888    ||
+              pix_format == DRM_FORMAT_XBGR8888    ||
+              pix_format == DRM_FORMAT_RGBX8888    ||
+              pix_format == DRM_FORMAT_BGRX8888    ||
+              pix_format == DRM_FORMAT_XRGB2101010 ||
+              pix_format == DRM_FORMAT_XBGR2101010 ||
+              pix_format == DRM_FORMAT_RGBX1010102 ||
+              pix_format == DRM_FORMAT_BGRX1010102 ||
+              pix_format == DRM_FORMAT_UYVY        ||
+              pix_format == DRM_FORMAT_VYUY        ||
+              pix_format == DRM_FORMAT_YUYV        ||
+              pix_format == DRM_FORMAT_YVYU        ||
+              pix_format == DRM_FORMAT_NV12        ||
+              pix_format == DRM_FORMAT_NV21;
+}
+
+bool dcss_dtg_global_alpha_changed(struct dcss_soc *dcss, int ch_num,
+                                  u32 pix_format, int alpha)
+{
+       struct dcss_dtg_priv *dtg = dcss->dtg_priv;
+
+       if (ch_num)
+               return false;
+
+       return dcss_dtg_global_alpha_needed(pix_format) && alpha != dtg->alpha;
+}
+EXPORT_SYMBOL(dcss_dtg_global_alpha_changed);
+
+void dcss_dtg_plane_alpha_set(struct dcss_soc *dcss, int ch_num,
+                             u32 pix_format, int alpha)
+{
+       struct dcss_dtg_priv *dtg = dcss->dtg_priv;
+       u32 alpha_val;
+
+       /* we care about alpha only when channel 0 is concerned */
+       if (ch_num)
+               return;
+
+       alpha_val = (alpha << DEFAULT_FG_ALPHA_POS) & DEFAULT_FG_ALPHA_MASK;
+
+       if (dcss_dtg_global_alpha_needed(pix_format)) {
+               dtg->control_status &= ~(CH1_ALPHA_SEL | DEFAULT_FG_ALPHA_MASK);
+               dtg->control_status |= alpha_val;
+       } else {
+               dtg->control_status |= CH1_ALPHA_SEL;
+       }
+
+       dtg->alpha = alpha;
+}
+EXPORT_SYMBOL(dcss_dtg_plane_alpha_set);
+
+static void dcss_dtg_disable_callback(void *data)
+{
+       struct dcss_dtg_priv *dtg = data;
+
+       dtg->control_status &= ~DTG_START;
+
+       dcss_writel(dtg->control_status,
+                   dtg->base_reg + DCSS_DTG_TC_CONTROL_STATUS);
+
+       dtg->in_use = false;
+}
+
+void dcss_dtg_enable(struct dcss_soc *dcss, bool en)
+{
+       struct dcss_dtg_priv *dtg = dcss->dtg_priv;
+
+       if (!en) {
+               dcss->dcss_disable_callback = dcss_dtg_disable_callback;
+               return;
+       }
+
+       dcss->dcss_disable_callback = NULL;
+
+       dtg->control_status |= DTG_START;
+
+       dcss_dtg_write(dtg, dtg->control_status, DCSS_DTG_TC_CONTROL_STATUS);
+
+       dtg->in_use = true;
+}
+EXPORT_SYMBOL(dcss_dtg_enable);
+
+bool dcss_dtg_is_enabled(struct dcss_soc *dcss)
+{
+       return dcss->dtg_priv->in_use;
+}
+EXPORT_SYMBOL(dcss_dtg_is_enabled);
+
+void dcss_dtg_ch_enable(struct dcss_soc *dcss, int ch_num, bool en)
+{
+       struct dcss_dtg_priv *dtg = dcss->dtg_priv;
+       u32 ch_en_map[] = {CH1_EN, CH2_EN, CH3_EN};
+
+       dtg->control_status &= ~ch_en_map[ch_num];
+       dtg->control_status |= en ? ch_en_map[ch_num] : 0;
+
+       dcss_dtg_write(dtg, dtg->control_status, DCSS_DTG_TC_CONTROL_STATUS);
+}
+EXPORT_SYMBOL(dcss_dtg_ch_enable);
+
+void dcss_dtg_vblank_irq_enable(struct dcss_soc *dcss, bool en)
+{
+       void __iomem *reg;
+       struct dcss_dtg_priv *dtg = dcss->dtg_priv;
+       u32 val = en ? LINE0_IRQ : 0;
+
+       reg = dtg->base_reg + DCSS_DTG_INT_MASK;
+
+       dcss_update(val, LINE0_IRQ, reg);
+}
+
+void dcss_dtg_vblank_irq_clear(struct dcss_soc *dcss)
+{
+       void __iomem *reg;
+       struct dcss_dtg_priv *dtg = dcss->dtg_priv;
+
+       reg = dtg->base_reg + DCSS_DTG_INT_CONTROL;
+
+       dcss_update(LINE0_IRQ, LINE0_IRQ, reg);
+}
diff --git a/drivers/gpu/imx/dcss/dcss-dtrc.c b/drivers/gpu/imx/dcss/dcss-dtrc.c
new file mode 100644 (file)
index 0000000..a6cd899
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/bitops.h>
+#include <linux/io.h>
+#include <linux/seq_file.h>
+#include <drm/drm_fourcc.h>
+
+#include <video/imx-dcss.h>
+#include "dcss-prv.h"
+
+#define USE_CTXLD
+
+#define DTRC_F0_OFS                    0x00
+#define DTRC_F1_OFS                    0x60
+
+#define DCSS_DTRC_DYDSADDR                     0x00
+#define DCSS_DTRC_DCDSADDR                     0x04
+#define DCSS_DTRC_DYTSADDR                     0x08
+#define DCSS_DTRC_DCTSADDR                     0x0C
+#define DCSS_DTRC_SIZE                         0x10
+#define   FRAME_WIDTH_POS                      0
+#define   FRAME_WIDTH_MASK                     GENMASK(9, 0)
+#define   FRAME_HEIGHT_POS                     16
+#define   FRAME_HEIGHT_MASK                    GENMASK(25, 16)
+#define DCSS_DTRC_SYSSA                                0x14
+#define DCSS_DTRC_SYSEA                                0x18
+#define DCSS_DTRC_SUVSSA                       0x1C
+#define DCSS_DTRC_SUVSEA                       0x20
+#define DCSS_DTRC_CROPORIG                     0x24
+#define DCSS_DTRC_CROPSIZE                     0x28
+#define DCSS_DTRC_DCTL                         0x2C
+#define DCSS_DTRC_DYDSADDR_EXT                 0x30
+#define DCSS_DTRC_DCDSADDR_EXT                 0x34
+#define DCSS_DTRC_DYTSADDR_EXT                 0x38
+#define DCSS_DTRC_DCTSADDR_EXT                 0x3C
+#define DCSS_DTRC_SYSSA_EXT                    0x40
+#define DCSS_DTRC_SYSEA_EXT                    0x44
+#define DCSS_DTRC_SUVSSA_EXT                   0x48
+#define DCSS_DTRC_SUVSEA_EXT                   0x4C
+
+#define DCSS_DTRC_INTEN                                0xC0
+#define DCSS_DTRC_FDINTR                       0xC4
+#define DCSS_DTRC_DTCTRL                       0xC8
+#define   CURRENT_FRAME                                BIT(31)
+#define   HOT_RESET                            BIT(2)
+#define DCSS_DTRC_ARIDR                                0xCC
+#define DCSS_DTRC_DTID2DDR                     0xD0
+#define DCSS_DTRC_CONFIG                       0xD4
+#define DCSS_DTRC_VER                          0xD8
+#define DCSS_DTRC_PFCTRL                       0xF0
+#define DCSS_DTRC_PFCR                         0xF4
+#define DCSS_DTRC_TOCR                         0xF8
+
+struct dcss_dtrc_ch {
+       void __iomem *base_reg;
+       u32 base_ofs;
+
+       u32 xres;
+       u32 yres;
+       u32 pix_format;
+
+       u32 ctx_id;
+
+       bool bypass;
+};
+
+struct dcss_dtrc_priv {
+       struct dcss_soc *dcss;
+       void __iomem *dtrc_reg;
+
+       struct dcss_dtrc_ch ch[2];
+};
+
+#ifdef CONFIG_DEBUG_FS
+static struct dcss_debug_reg dtrc_frame_debug_reg[] = {
+       DCSS_DBG_REG(DCSS_DTRC_DYDSADDR),
+       DCSS_DBG_REG(DCSS_DTRC_DCDSADDR),
+       DCSS_DBG_REG(DCSS_DTRC_DYTSADDR),
+       DCSS_DBG_REG(DCSS_DTRC_DCTSADDR),
+       DCSS_DBG_REG(DCSS_DTRC_SIZE),
+       DCSS_DBG_REG(DCSS_DTRC_SYSSA),
+       DCSS_DBG_REG(DCSS_DTRC_SYSEA),
+       DCSS_DBG_REG(DCSS_DTRC_SUVSSA),
+       DCSS_DBG_REG(DCSS_DTRC_SUVSEA),
+       DCSS_DBG_REG(DCSS_DTRC_CROPORIG),
+       DCSS_DBG_REG(DCSS_DTRC_CROPSIZE),
+       DCSS_DBG_REG(DCSS_DTRC_DCTL),
+       DCSS_DBG_REG(DCSS_DTRC_DYDSADDR_EXT),
+       DCSS_DBG_REG(DCSS_DTRC_DCDSADDR_EXT),
+       DCSS_DBG_REG(DCSS_DTRC_DYTSADDR_EXT),
+       DCSS_DBG_REG(DCSS_DTRC_DCTSADDR_EXT),
+       DCSS_DBG_REG(DCSS_DTRC_SYSSA_EXT),
+       DCSS_DBG_REG(DCSS_DTRC_SYSEA_EXT),
+       DCSS_DBG_REG(DCSS_DTRC_SUVSSA_EXT),
+       DCSS_DBG_REG(DCSS_DTRC_SUVSEA_EXT),
+};
+
+static struct dcss_debug_reg dtrc_ctrl_debug_reg[] = {
+       DCSS_DBG_REG(DCSS_DTRC_INTEN),
+       DCSS_DBG_REG(DCSS_DTRC_FDINTR),
+       DCSS_DBG_REG(DCSS_DTRC_DTCTRL),
+       DCSS_DBG_REG(DCSS_DTRC_ARIDR),
+       DCSS_DBG_REG(DCSS_DTRC_DTID2DDR),
+       DCSS_DBG_REG(DCSS_DTRC_CONFIG),
+       DCSS_DBG_REG(DCSS_DTRC_VER),
+       DCSS_DBG_REG(DCSS_DTRC_PFCTRL),
+       DCSS_DBG_REG(DCSS_DTRC_PFCR),
+       DCSS_DBG_REG(DCSS_DTRC_TOCR),
+};
+
+static void dcss_dtrc_dump_frame_regs(struct seq_file *s, void *data,
+                                     int ch, int frame)
+{
+       struct dcss_soc *dcss = data;
+       int i;
+
+       seq_printf(s, "\t>> Dumping F%d regs:\n", frame);
+       for (i = 0; i < ARRAY_SIZE(dtrc_frame_debug_reg); i++)
+               seq_printf(s, "\t%-35s(0x%04x) -> 0x%08x\n",
+                          dtrc_frame_debug_reg[i].name,
+                          dtrc_frame_debug_reg[i].ofs + frame * DTRC_F1_OFS,
+                          dcss_readl(dcss->dtrc_priv->ch[ch].base_reg +
+                                     dtrc_frame_debug_reg[i].ofs +
+                                     frame * DTRC_F1_OFS));
+}
+
+void dcss_dtrc_dump_regs(struct seq_file *s, void *data)
+{
+       struct dcss_soc *dcss = data;
+       int ch, fr, i;
+
+       for (ch = 0; ch < 2; ch++) {
+               seq_printf(s, ">> Dumping DTRC for CH %d:\n", ch + 1);
+               for (fr = 0; fr < 2; fr++)
+                       dcss_dtrc_dump_frame_regs(s, data, ch, fr);
+
+               seq_printf(s, "\t>> Dumping DTRC CTRL regs for CH %d:\n",
+                          ch + 1);
+               for (i = 0; i < ARRAY_SIZE(dtrc_ctrl_debug_reg); i++)
+                       seq_printf(s, "\t%-35s(0x%04x) -> 0x%08x\n",
+                                  dtrc_ctrl_debug_reg[i].name,
+                                  dtrc_ctrl_debug_reg[i].ofs,
+                                  dcss_readl(dcss->dtrc_priv->ch[ch].base_reg +
+                                             dtrc_ctrl_debug_reg[i].ofs));
+       }
+}
+#endif
+
+static int dcss_dtrc_ch_init_all(struct dcss_soc *dcss, unsigned long dtrc_base)
+{
+       struct dcss_dtrc_priv *dtrc = dcss->dtrc_priv;
+       struct dcss_dtrc_ch *ch;
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               ch = &dtrc->ch[i];
+
+               ch->base_ofs = dtrc_base + i * 0x1000;
+
+               ch->base_reg = devm_ioremap(dcss->dev, ch->base_ofs, SZ_4K);
+               if (!ch->base_reg) {
+                       dev_err(dcss->dev, "dtrc: unable to remap ch base\n");
+                       return -ENOMEM;
+               }
+       }
+
+       return 0;
+}
+
+static void dcss_dtrc_write(struct dcss_dtrc_priv *dtrc, int ch_num,
+                           u32 val, u32 ofs)
+{
+#if !defined(USE_CTXLD)
+       dcss_writel(val, dtrc->ch[ch_num].base_reg + ofs);
+#else
+       dcss_ctxld_write(dtrc->dcss, dtrc->ch[ch_num].ctx_id,
+                        val, dtrc->ch[ch_num].base_ofs + ofs);
+#endif
+}
+
+int dcss_dtrc_init(struct dcss_soc *dcss, unsigned long dtrc_base)
+{
+       struct dcss_dtrc_priv *dtrc;
+
+       dtrc = devm_kzalloc(dcss->dev, sizeof(*dtrc), GFP_KERNEL);
+       if (!dtrc)
+               return -ENOMEM;
+
+       dcss->dtrc_priv = dtrc;
+       dtrc->dcss = dcss;
+
+       return dcss_dtrc_ch_init_all(dcss, dtrc_base);
+}
+
+void dcss_dtrc_exit(struct dcss_soc *dcss)
+{
+       struct dcss_dtrc_priv *dtrc = dcss->dtrc_priv;
+
+       /* reset the module to default */
+       dcss_writel(HOT_RESET, dtrc->dtrc_reg + DCSS_DTRC_DTCTRL);
+}
+
+void dcss_dtrc_bypass(struct dcss_soc *dcss, int ch_num)
+{
+       struct dcss_dtrc_priv *dtrc = dcss->dtrc_priv;
+
+       if (ch_num == 0)
+               return;
+
+       ch_num -= 1;
+
+       if (dtrc->ch[ch_num].bypass)
+               return;
+
+       dcss_dtrc_write(dtrc, ch_num, 2, DCSS_DTRC_DTCTRL);
+       dcss_dtrc_write(dtrc, ch_num, 0, DCSS_DTRC_DYTSADDR);
+       dcss_dtrc_write(dtrc, ch_num, 0, DCSS_DTRC_DCTSADDR);
+       dcss_dtrc_write(dtrc, ch_num, 0x0f0e0100, DCSS_DTRC_ARIDR);
+       dcss_dtrc_write(dtrc, ch_num, 0x0f0e, DCSS_DTRC_DTID2DDR);
+
+       dtrc->ch[ch_num].bypass = true;
+}
+EXPORT_SYMBOL(dcss_dtrc_bypass);
+
+void dcss_dtrc_addr_set(struct dcss_soc *dcss, int ch_num, u32 p1_ba, u32 p2_ba)
+{
+       struct dcss_dtrc_priv *dtrc = dcss->dtrc_priv;
+       struct dcss_dtrc_ch *ch = &dtrc->ch[ch_num];
+       int curr_frame;
+
+       if (ch_num == 0)
+               return;
+
+       ch_num -= 1;
+
+       curr_frame = dcss_readl(dtrc->ch[ch_num].base_reg + DCSS_DTRC_DTCTRL);
+       curr_frame = (curr_frame & CURRENT_FRAME) >> 31;
+
+       dcss_dtrc_write(dtrc, ch_num, p1_ba, DCSS_DTRC_DYDSADDR);
+       dcss_dtrc_write(dtrc, ch_num, p2_ba, DCSS_DTRC_DCDSADDR);
+
+       dcss_dtrc_write(dtrc, ch_num, p1_ba, DTRC_F1_OFS + DCSS_DTRC_DYDSADDR);
+       dcss_dtrc_write(dtrc, ch_num, p2_ba, DTRC_F1_OFS + DCSS_DTRC_DCDSADDR);
+
+       dcss_dtrc_write(dtrc, ch_num, p1_ba, DCSS_DTRC_SYSSA);
+       dcss_dtrc_write(dtrc, ch_num, p1_ba + ch->xres * ch->yres,
+                       DCSS_DTRC_SYSEA);
+
+       dcss_dtrc_write(dtrc, ch_num, p1_ba, DTRC_F1_OFS + DCSS_DTRC_SYSSA);
+       dcss_dtrc_write(dtrc, ch_num, p1_ba + ch->xres * ch->yres,
+                       DTRC_F1_OFS + DCSS_DTRC_SYSEA);
+
+       dcss_dtrc_write(dtrc, ch_num, p2_ba, DCSS_DTRC_SUVSSA);
+       dcss_dtrc_write(dtrc, ch_num, p2_ba + ch->xres * ch->yres / 4,
+                       DCSS_DTRC_SUVSEA);
+
+       dcss_dtrc_write(dtrc, ch_num, p2_ba, DTRC_F1_OFS + DCSS_DTRC_SUVSSA);
+       dcss_dtrc_write(dtrc, ch_num, p2_ba + ch->xres * ch->yres / 4,
+                       DTRC_F1_OFS + DCSS_DTRC_SUVSEA);
+
+       dcss_dtrc_write(dcss->dtrc_priv, ch_num - 1, 0x0f0e0100,
+                       DCSS_DTRC_ARIDR);
+       dcss_dtrc_write(dcss->dtrc_priv, ch_num - 1, 0x0f0e,
+                       DCSS_DTRC_DTID2DDR);
+
+       dcss_dtrc_write(dtrc, ch_num, 0x50f00108, DCSS_DTRC_DTCTRL);
+
+       /* TODO: hardcoded this for testing purposes. */
+       dcss_dtrc_write(dtrc, ch_num, 0x20002,
+                       (curr_frame ^ 1) * DTRC_F1_OFS + DCSS_DTRC_DCTL);
+       dcss_dtrc_write(dtrc, ch_num, 0x20003,
+                       curr_frame * DTRC_F1_OFS + DCSS_DTRC_DCTL);
+
+       dtrc->ch[ch_num].bypass = false;
+}
+EXPORT_SYMBOL(dcss_dtrc_addr_set);
+
+void dcss_dtrc_set_res(struct dcss_soc *dcss, int ch_num, u32 xres, u32 yres)
+{
+       struct dcss_dtrc_priv *dtrc = dcss->dtrc_priv;
+       u32 frame_height, frame_width;
+
+       if (ch_num == 0)
+               return;
+
+       dtrc->ch[ch_num].xres = xres;
+       dtrc->ch[ch_num].yres = yres;
+
+       frame_height = ((yres >> 3) << FRAME_HEIGHT_POS) & FRAME_HEIGHT_MASK;
+       frame_width = ((xres >> 3) << FRAME_WIDTH_POS) & FRAME_WIDTH_MASK;
+
+       dcss_dtrc_write(dcss->dtrc_priv, ch_num - 1, frame_height | frame_width,
+                       DTRC_F0_OFS + DCSS_DTRC_SIZE);
+       dcss_dtrc_write(dcss->dtrc_priv, ch_num - 1, frame_height | frame_width,
+                       DTRC_F1_OFS + DCSS_DTRC_SIZE);
+}
+EXPORT_SYMBOL(dcss_dtrc_set_res);
diff --git a/drivers/gpu/imx/dcss/dcss-hdr10.c b/drivers/gpu/imx/dcss/dcss-hdr10.c
new file mode 100644 (file)
index 0000000..86d78a3
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/bitops.h>
+#include <linux/io.h>
+#include <linux/seq_file.h>
+
+#include <video/imx-dcss.h>
+#include "dcss-prv.h"
+#include "dcss-tables.h"
+
+#define USE_CTXLD
+
+#define DCSS_HDR10_A0_LUT              0x0000
+#define DCSS_HDR10_A1_LUT              0x1000
+#define DCSS_HDR10_A2_LUT              0x2000
+/* one CSCA and CSCB for each channel(pipe) */
+#define DCSS_HDR10_CSCA_BASE           0x3000
+#define DCSS_HDR10_CSCB_BASE           0x3800
+
+/* one CSCO for all channels(pipes) */
+#define DCSS_HDR10_CSCO_BASE           0x3000
+
+#define DCSS_HDR10_LUT_CONTROL         (DCSS_HDR10_CSCA_BASE + 0x80)
+#define   LUT_ENABLE                   BIT(0)
+#define   LUT_EN_FOR_ALL_PELS          BIT(1)
+#define DCSS_HDR10_FL2FX               (DCSS_HDR10_CSCB_BASE + 0x74)
+#define DCSS_HDR10_LTNL                        (DCSS_HDR10_CSCO_BASE + 0x74)
+#define   LTNL_PASS_THRU               BIT(0)
+#define   FIX2FLT_DISABLE              BIT(1)
+#define   LTNL_EN_FOR_ALL_PELS         BIT(2)
+#define   FIX2FLT_EN_FOR_ALL_PELS      BIT(3)
+
+/* following offsets are relative to CSC(A|B|O)_BASE */
+#define DCSS_HDR10_CSC_CONTROL         0x00
+#define   CSC_EN                       BIT(0)
+#define   CSC_ALL_PIX_EN               BIT(1)
+#define   CSC_BYPASS                   BIT(15)
+#define DCSS_HDR10_CSC_H00             0x04
+#define DCSS_HDR10_CSC_H10             0x08
+#define DCSS_HDR10_CSC_H20             0x0C
+#define DCSS_HDR10_CSC_H01             0x10
+#define DCSS_HDR10_CSC_H11             0x14
+#define DCSS_HDR10_CSC_H21             0x18
+#define DCSS_HDR10_CSC_H02             0x1C
+#define DCSS_HDR10_CSC_H12             0x20
+#define DCSS_HDR10_CSC_H22             0x24
+#define   H_COEF_MASK                  GENMASK(15, 0)
+#define DCSS_HDR10_CSC_IO0             0x28
+#define DCSS_HDR10_CSC_IO1             0x2C
+#define DCSS_HDR10_CSC_IO2             0x30
+#define   PRE_OFFSET_MASK              GENMASK(9, 0)
+#define DCSS_HDR10_CSC_IO_MIN0         0x34
+#define DCSS_HDR10_CSC_IO_MIN1         0x38
+#define DCSS_HDR10_CSC_IO_MIN2         0x3C
+#define DCSS_HDR10_CSC_IO_MAX0         0x40
+#define DCSS_HDR10_CSC_IO_MAX1         0x44
+#define DCSS_HDR10_CSC_IO_MAX2         0x48
+#define   IO_CLIP_MASK                 GENMASK(9, 0)
+#define DCSS_HDR10_CSC_NORM            0x4C
+#define   NORM_MASK                    GENMASK(4, 0)
+#define DCSS_HDR10_CSC_OO0             0x50
+#define DCSS_HDR10_CSC_OO1             0x54
+#define DCSS_HDR10_CSC_OO2             0x58
+#define   POST_OFFSET_MASK             GENMASK(27, 0)
+#define DCSS_HDR10_CSC_OMIN0           0x5C
+#define DCSS_HDR10_CSC_OMIN1           0x60
+#define DCSS_HDR10_CSC_OMIN2           0x64
+#define DCSS_HDR10_CSC_OMAX0           0x68
+#define DCSS_HDR10_CSC_OMAX1           0x6C
+#define DCSS_HDR10_CSC_OMAX2           0x70
+#define   POST_CLIP_MASK               GENMASK(9, 0)
+
+#define HDR10_LUT_MAX_ENTRIES          1024
+#define HDR10_CSC_MAX_REGS             28
+
+#define OPIPE_CH_NO                    3
+
+enum dcss_hdr10_csc {
+       HDR10_CSCA,
+       HDR10_CSCB,
+};
+
+struct dcss_hdr10_ch {
+       void __iomem *base_reg;
+       u32 base_ofs;
+
+       u32 ctx_id;
+
+       u32 old_in_cs;
+       u32 old_out_cs;
+};
+
+struct dcss_hdr10_priv {
+       struct dcss_soc *dcss;
+
+       struct dcss_hdr10_ch ch[4]; /* 4th channel is, actually, OPIPE */
+
+       u32 opipe_ctx_id;
+};
+
+static struct dcss_debug_reg hdr10_debug_reg[] = {
+       DCSS_DBG_REG(DCSS_HDR10_CSC_CONTROL),
+       DCSS_DBG_REG(DCSS_HDR10_CSC_H00),
+       DCSS_DBG_REG(DCSS_HDR10_CSC_H10),
+       DCSS_DBG_REG(DCSS_HDR10_CSC_H20),
+       DCSS_DBG_REG(DCSS_HDR10_CSC_H01),
+       DCSS_DBG_REG(DCSS_HDR10_CSC_H11),
+       DCSS_DBG_REG(DCSS_HDR10_CSC_H21),
+       DCSS_DBG_REG(DCSS_HDR10_CSC_H02),
+       DCSS_DBG_REG(DCSS_HDR10_CSC_H12),
+       DCSS_DBG_REG(DCSS_HDR10_CSC_H22),
+       DCSS_DBG_REG(DCSS_HDR10_CSC_IO0),
+       DCSS_DBG_REG(DCSS_HDR10_CSC_IO1),
+       DCSS_DBG_REG(DCSS_HDR10_CSC_IO2),
+       DCSS_DBG_REG(DCSS_HDR10_CSC_IO_MIN0),
+       DCSS_DBG_REG(DCSS_HDR10_CSC_IO_MIN1),
+       DCSS_DBG_REG(DCSS_HDR10_CSC_IO_MIN2),
+       DCSS_DBG_REG(DCSS_HDR10_CSC_IO_MAX0),
+       DCSS_DBG_REG(DCSS_HDR10_CSC_IO_MAX1),
+       DCSS_DBG_REG(DCSS_HDR10_CSC_IO_MAX2),
+       DCSS_DBG_REG(DCSS_HDR10_CSC_NORM),
+       DCSS_DBG_REG(DCSS_HDR10_CSC_OO0),
+       DCSS_DBG_REG(DCSS_HDR10_CSC_OO1),
+       DCSS_DBG_REG(DCSS_HDR10_CSC_OO2),
+       DCSS_DBG_REG(DCSS_HDR10_CSC_OMIN0),
+       DCSS_DBG_REG(DCSS_HDR10_CSC_OMIN1),
+       DCSS_DBG_REG(DCSS_HDR10_CSC_OMIN2),
+       DCSS_DBG_REG(DCSS_HDR10_CSC_OMAX0),
+       DCSS_DBG_REG(DCSS_HDR10_CSC_OMAX1),
+       DCSS_DBG_REG(DCSS_HDR10_CSC_OMAX2),
+};
+
+static void dcss_hdr10_write(struct dcss_soc *dcss, u32 ch_num,
+                            u32 val, u32 ofs)
+{
+       struct dcss_hdr10_priv *hdr10 = dcss->hdr10_priv;
+
+#if !defined(USE_CTXLD)
+       dcss_writel(val, hdr10->ch[ch_num].base_reg + ofs);
+#else
+       dcss_ctxld_write(dcss, hdr10->ch[ch_num].ctx_id, val,
+                        hdr10->ch[ch_num].base_ofs + ofs);
+#endif
+}
+
+#ifdef CONFIG_DEBUG_FS
+void dcss_hdr10_dump_regs(struct seq_file *s, void *data)
+{
+       struct dcss_soc *dcss = data;
+       int ch, csc, r;
+       int csc_no;
+
+       for (ch = 0; ch < 4; ch++) {
+               void __iomem *csc_base = dcss->hdr10_priv->ch[ch].base_reg +
+                                        DCSS_HDR10_CSCA_BASE;
+
+               if (ch < 3) {
+                       seq_printf(s, ">> Dumping HDR10 CH %d:\n", ch);
+                       csc_no = 2;
+               } else {
+                       seq_puts(s, ">> Dumping HDR10 OPIPE:\n");
+                       csc_no = 1;
+               }
+
+               for (csc = 0; csc < csc_no; csc++) {
+                       csc_base += csc * 0x800;
+
+                       if (ch < 3)
+                               seq_printf(s, "\t>> Dumping CSC%s of CH %d:\n",
+                                          csc ? "B" : "A", ch);
+                       else
+                               seq_puts(s, "\t>> Dumping CSC of OPIPE:\n");
+
+                       for (r = 0; r < ARRAY_SIZE(hdr10_debug_reg); r++)
+                               seq_printf(s, "\t%-35s(0x%04x) -> 0x%08x\n",
+                                          hdr10_debug_reg[r].name,
+                                          hdr10_debug_reg[r].ofs,
+                                          dcss_readl(csc_base +
+                                                     hdr10_debug_reg[r].ofs));
+               }
+       }
+}
+#endif
+
+static void dcss_hdr10_csc_fill(struct dcss_soc *dcss, int ch_num,
+                               enum dcss_hdr10_csc csc_to_use,
+                               u32 *map)
+{
+       int i;
+       u32 csc_base_ofs[] = {
+               DCSS_HDR10_CSCA_BASE + DCSS_HDR10_CSC_H00,
+               DCSS_HDR10_CSCB_BASE + DCSS_HDR10_CSC_H00,
+       };
+
+       for (i = 0; i < HDR10_CSC_MAX_REGS; i++) {
+               u32 reg_ofs = csc_base_ofs[csc_to_use] + i * sizeof(u32);
+
+               dcss_hdr10_write(dcss, ch_num, map[i], reg_ofs);
+       }
+}
+
+static void dcss_hdr10_lut_fill(struct dcss_soc *dcss, int ch_num,
+                               int comp, u16 *map)
+{
+       int i;
+       u32 lut_base_ofs;
+
+       lut_base_ofs = DCSS_HDR10_A0_LUT + comp * 0x1000;
+
+       for (i = 0; i < HDR10_LUT_MAX_ENTRIES; i++) {
+               u32 reg_ofs = lut_base_ofs + i * sizeof(u32);
+
+               dcss_hdr10_write(dcss, ch_num, map[i], reg_ofs);
+       }
+}
+
+static int dcss_hdr10_ch_init_all(struct dcss_soc *dcss,
+                                 unsigned long hdr10_base)
+{
+       struct dcss_hdr10_priv *hdr10 = dcss->hdr10_priv;
+       struct dcss_hdr10_ch *ch;
+       int i;
+       u16 *lut;
+
+       for (i = 0; i < 4; i++) {
+               ch = &hdr10->ch[i];
+
+               ch->base_ofs = hdr10_base + i * 0x4000;
+
+               ch->base_reg = devm_ioremap(dcss->dev, ch->base_ofs, SZ_16K);
+               if (!ch->base_reg) {
+                       dev_err(dcss->dev, "hdr10: unable to remap ch base\n");
+                       return -ENOMEM;
+               }
+
+#if defined(USE_CTXLD)
+               ch->ctx_id = CTX_SB_HP;
+#endif
+
+               lut = i < 3 ? dcss_hdr10_comp_lut : dcss_hdr10_opipe;
+
+               dcss_hdr10_lut_fill(dcss, i, 0, lut);
+               dcss_hdr10_lut_fill(dcss, i, 1, lut);
+               dcss_hdr10_lut_fill(dcss, i, 2, lut);
+
+               ch->old_out_cs = DCSS_COLORSPACE_UNKNOWN;
+               ch->old_in_cs = DCSS_COLORSPACE_UNKNOWN;
+       }
+
+       return 0;
+}
+
+int dcss_hdr10_init(struct dcss_soc *dcss, unsigned long hdr10_base)
+{
+       struct dcss_hdr10_priv *hdr10;
+
+       hdr10 = devm_kzalloc(dcss->dev, sizeof(*hdr10), GFP_KERNEL);
+       if (!hdr10)
+               return -ENOMEM;
+
+       dcss->hdr10_priv = hdr10;
+       hdr10->dcss = dcss;
+
+       return dcss_hdr10_ch_init_all(dcss, hdr10_base);
+}
+
+void dcss_hdr10_exit(struct dcss_soc *dcss)
+{
+}
+
+static void dcss_hdr10_csc_en(struct dcss_soc *dcss, int ch_num,
+                             enum dcss_hdr10_csc csc_to_en, bool en)
+{
+       u32 ctrl_reg[] = {
+               DCSS_HDR10_CSCA_BASE + DCSS_HDR10_CSC_CONTROL,
+               DCSS_HDR10_CSCB_BASE + DCSS_HDR10_CSC_CONTROL,
+       };
+
+       dcss_hdr10_write(dcss, ch_num, en ? CSC_EN | CSC_ALL_PIX_EN : 0,
+                        ctrl_reg[csc_to_en]);
+}
+
+static void dcss_hdr10_cs2rgb_setup(struct dcss_soc *dcss, int ch_num,
+                                   enum dcss_color_space in_cs)
+{
+       if (in_cs == DCSS_COLORSPACE_YUV) {
+               dcss_hdr10_csc_fill(dcss, ch_num, HDR10_CSCA,
+                                   dcss_hdr10_yuv2rgb_csca);
+               dcss_hdr10_csc_en(dcss, ch_num, HDR10_CSCA, true);
+               dcss_hdr10_csc_fill(dcss, ch_num, HDR10_CSCB,
+                                   dcss_hdr10_yuv2rgb_cscb);
+               dcss_hdr10_csc_en(dcss, ch_num, HDR10_CSCB, true);
+       } else {
+               dcss_hdr10_csc_fill(dcss, ch_num, HDR10_CSCA,
+                                   dcss_hdr10_rgb2rgb_csca);
+               dcss_hdr10_csc_en(dcss, ch_num, HDR10_CSCA, true);
+               dcss_hdr10_csc_fill(dcss, ch_num, HDR10_CSCB,
+                                   dcss_hdr10_rgb2rgb_cscb);
+               dcss_hdr10_csc_en(dcss, ch_num, HDR10_CSCB, true);
+       }
+
+       dcss_hdr10_write(dcss, ch_num, LUT_ENABLE | LUT_EN_FOR_ALL_PELS,
+                        DCSS_HDR10_LUT_CONTROL);
+       dcss_hdr10_write(dcss, OPIPE_CH_NO,
+                        LTNL_EN_FOR_ALL_PELS | FIX2FLT_EN_FOR_ALL_PELS,
+                        DCSS_HDR10_LTNL);
+}
+
+void dcss_hdr10_pipe_csc_setup(struct dcss_soc *dcss, int ch_num,
+                              enum dcss_color_space in_cs,
+                              enum dcss_color_space out_cs)
+{
+       struct dcss_hdr10_ch *ch = &dcss->hdr10_priv->ch[ch_num];
+       bool cs_chgd = (in_cs != ch->old_in_cs) || (out_cs != ch->old_out_cs);
+
+       if (out_cs == DCSS_COLORSPACE_RGB && cs_chgd)
+               dcss_hdr10_cs2rgb_setup(dcss, ch_num, in_cs);
+
+       ch->old_in_cs = in_cs;
+       ch->old_out_cs = out_cs;
+}
+EXPORT_SYMBOL(dcss_hdr10_pipe_csc_setup);
+
diff --git a/drivers/gpu/imx/dcss/dcss-prv.h b/drivers/gpu/imx/dcss/dcss-prv.h
new file mode 100644 (file)
index 0000000..aee7ec7
--- /dev/null
@@ -0,0 +1,102 @@
+#ifndef __DCSS_PRV_H__
+#define __DCSS_PRV_H__
+
+#define SET 0x04
+#define CLR 0x08
+#define TGL 0x0C
+
+#define dcss_writel(v, c)   writel((v), (c))
+#define dcss_readl(c)      readl(c)
+#define dcss_set(v, c)     writel((v), (c) + SET)
+#define dcss_clr(v, c)     writel((v), (c) + CLR)
+#define dcss_toggle(v, c)   writel((v), (c) + TGL)
+#define dcss_update(v, m, c) writel((readl(c) & ~(m)) | (v), (c))
+
+#define DCSS_DBG_REG(reg)      {.name = #reg, .ofs = reg}
+
+struct dcss_debug_reg {
+       char *name;
+       u32 ofs;
+};
+
+enum dcss_ctxld_ctx_type {
+       CTX_DB,
+       CTX_SB_HP, /* high-priority */
+       CTX_SB_LP, /* low-priority  */
+};
+
+struct dcss_soc;
+struct dcss_devtype;
+
+struct dcss_soc {
+       struct device *dev;
+       const struct dcss_devtype *devtype;
+
+       struct dcss_ctxld_priv *ctxld_priv;
+       struct dcss_dpr_priv *dpr_priv;
+       struct dcss_dtg_priv *dtg_priv;
+       struct dcss_ss_priv *ss_priv;
+       struct dcss_hdr10_priv *hdr10_priv;
+       struct dcss_scaler_priv *scaler_priv;
+       struct dcss_dtrc_priv *dtrc_priv;
+       struct dcss_dec400d_priv *dec400d_priv;
+
+       struct clk *apb_clk;
+       struct clk *axi_clk;
+       struct clk *p_clk;
+       struct clk *rtrm_clk;
+       struct clk *dtrc_clk;
+
+       void (*dcss_disable_callback)(void *data);
+};
+
+/* BLKCTL */
+int dcss_blkctl_init(struct dcss_soc *dcss, unsigned long blkctl_base);
+void dcss_blkctl_exit(struct dcss_soc *dcss);
+
+/* CTXLD */
+int dcss_ctxld_init(struct dcss_soc *dcss, unsigned long ctxld_base);
+void dcss_ctxld_exit(struct dcss_soc *dcss);
+void dcss_ctxld_write(struct dcss_soc *dcss, u32 ctx_id, u32 val, u32 reg_idx);
+void dcss_ctxld_update(struct dcss_soc *dcss, u32 ctx_id, u32 val, u32 mask,
+                      u32 reg_idx);
+void dcss_ctxld_dump(struct seq_file *s, void *data);
+
+/* DPR */
+int dcss_dpr_init(struct dcss_soc *dcss, unsigned long dpr_base);
+void dcss_dpr_exit(struct dcss_soc *dcss);
+
+/* DTG */
+int dcss_dtg_init(struct dcss_soc *dcss, unsigned long dtg_base);
+void dcss_dtg_exit(struct dcss_soc *dcss);
+void dcss_dtg_vblank_irq_enable(struct dcss_soc *dcss, bool en);
+void dcss_dtg_vblank_irq_clear(struct dcss_soc *dcss);
+
+/* SUBSAM */
+int dcss_ss_init(struct dcss_soc *dcss, unsigned long subsam_base);
+void dcss_ss_exit(struct dcss_soc *dcss);
+
+/* HDR10 */
+int dcss_hdr10_init(struct dcss_soc *dcss, unsigned long hdr10_base);
+void dcss_hdr10_exit(struct dcss_soc *dcss);
+
+/* SCALER */
+int dcss_scaler_init(struct dcss_soc *dcss, unsigned long scaler_base);
+void dcss_scaler_exit(struct dcss_soc *dcss);
+
+/* DTRC */
+int dcss_dtrc_init(struct dcss_soc *dcss, unsigned long dtrc_base);
+void dcss_dtrc_exit(struct dcss_soc *dcss);
+
+/* DEC400d */
+int dcss_dec400d_init(struct dcss_soc *dcss, unsigned long dec400d_base);
+void dcss_dec400d_exit(struct dcss_soc *dcss);
+
+void dcss_dtrc_dump_regs(struct seq_file *s, void *data);
+void dcss_dpr_dump_regs(struct seq_file *s, void *data);
+void dcss_dtg_dump_regs(struct seq_file *s, void *data);
+void dcss_ss_dump_regs(struct seq_file *s, void *data);
+void dcss_scaler_dump_regs(struct seq_file *s, void *data);
+void dcss_ctxld_dump_regs(struct seq_file *s, void *data);
+void dcss_hdr10_dump_regs(struct seq_file *s, void *data);
+#endif /* __DCSS_PRV_H__ */
diff --git a/drivers/gpu/imx/dcss/dcss-scaler.c b/drivers/gpu/imx/dcss/dcss-scaler.c
new file mode 100644 (file)
index 0000000..a16809a
--- /dev/null
@@ -0,0 +1,534 @@
+/*
+ * Copyright (C) 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/seq_file.h>
+#include <drm/drm_fourcc.h>
+
+#include <video/imx-dcss.h>
+#include "dcss-prv.h"
+
+#define USE_CTXLD
+
+#define DCSS_SCALER_CTRL                       0x00
+#define   SCALER_EN                            BIT(0)
+#define   REPEAT_EN                            BIT(4)
+#define   SCALE2MEM_EN                         BIT(8)
+#define   MEM2OFIFO_EN                         BIT(12)
+#define DCSS_SCALER_OFIFO_CTRL                 0x04
+#define   OFIFO_LOW_THRES_POS                  0
+#define   OFIFO_LOW_THRES_MASK                 GENMASK(9, 0)
+#define   OFIFO_HIGH_THRES_POS                 16
+#define   OFIFO_HIGH_THRES_MASK                        GENMASK(25, 16)
+#define   UNDERRUN_DETECT_CLR                  BIT(26)
+#define   LOW_THRES_DETECT_CLR                 BIT(27)
+#define   HIGH_THRES_DETECT_CLR                        BIT(28)
+#define   UNDERRUN_DETECT_EN                   BIT(29)
+#define   LOW_THRES_DETECT_EN                  BIT(30)
+#define   HIGH_THRES_DETECT_EN                 BIT(31)
+#define DCSS_SCALER_SDATA_CTRL                 0x08
+#define   YUV_EN                               BIT(0)
+#define   RTRAM_8LINES                         BIT(1)
+#define   Y_UV_BYTE_SWAP                       BIT(4)
+#define   A2R10G10B10_FORMAT_POS               8
+#define   A2R10G10B10_FORMAT_MASK              GENMASK(11, 8)
+#define DCSS_SCALER_BIT_DEPTH                  0x0C
+#define   LUM_BIT_DEPTH_POS                    0
+#define   LUM_BIT_DEPTH_MASK                   GENMASK(1, 0)
+#define   CHR_BIT_DEPTH_POS                    4
+#define   CHR_BIT_DEPTH_MASK                   GENMASK(5, 4)
+#define DCSS_SCALER_SRC_FORMAT                 0x10
+#define DCSS_SCALER_DST_FORMAT                 0x14
+#define   FORMAT_MASK                          GENMASK(1, 0)
+#define DCSS_SCALER_SRC_LUM_RES                        0x18
+#define DCSS_SCALER_SRC_CHR_RES                        0x1C
+#define DCSS_SCALER_DST_LUM_RES                        0x20
+#define DCSS_SCALER_DST_CHR_RES                        0x24
+#define   WIDTH_POS                            0
+#define   WIDTH_MASK                           GENMASK(11, 0)
+#define   HEIGHT_POS                           16
+#define   HEIGHT_MASK                          GENMASK(27, 16)
+#define DCSS_SCALER_V_LUM_START                        0x48
+#define   V_START_MASK                         GENMASK(15, 0)
+#define DCSS_SCALER_V_LUM_INC                  0x4C
+#define   V_INC_MASK                           GENMASK(15, 0)
+#define DCSS_SCALER_H_LUM_START                        0x50
+#define   H_START_MASK                         GENMASK(18, 0)
+#define DCSS_SCALER_H_LUM_INC                  0x54
+#define   H_INC_MASK                           GENMASK(15, 0)
+#define DCSS_SCALER_V_CHR_START                        0x58
+#define DCSS_SCALER_V_CHR_INC                  0x5C
+#define DCSS_SCALER_H_CHR_START                        0x60
+#define DCSS_SCALER_H_CHR_INC                  0x64
+#define DCSS_SCALER_COEF_VLUM                  0x80
+#define DCSS_SCALER_COEF_HLUM                  0x140
+#define DCSS_SCALER_COEF_VCHR                  0x200
+#define DCSS_SCALER_COEF_HCHR                  0x300
+
+static struct dcss_debug_reg scaler_debug_reg[] = {
+       DCSS_DBG_REG(DCSS_SCALER_CTRL),
+       DCSS_DBG_REG(DCSS_SCALER_OFIFO_CTRL),
+       DCSS_DBG_REG(DCSS_SCALER_SDATA_CTRL),
+       DCSS_DBG_REG(DCSS_SCALER_BIT_DEPTH),
+       DCSS_DBG_REG(DCSS_SCALER_SRC_FORMAT),
+       DCSS_DBG_REG(DCSS_SCALER_DST_FORMAT),
+       DCSS_DBG_REG(DCSS_SCALER_SRC_LUM_RES),
+       DCSS_DBG_REG(DCSS_SCALER_SRC_CHR_RES),
+       DCSS_DBG_REG(DCSS_SCALER_DST_LUM_RES),
+       DCSS_DBG_REG(DCSS_SCALER_DST_CHR_RES),
+       DCSS_DBG_REG(DCSS_SCALER_V_LUM_START),
+       DCSS_DBG_REG(DCSS_SCALER_V_LUM_INC),
+       DCSS_DBG_REG(DCSS_SCALER_H_LUM_START),
+       DCSS_DBG_REG(DCSS_SCALER_H_LUM_INC),
+       DCSS_DBG_REG(DCSS_SCALER_V_CHR_START),
+       DCSS_DBG_REG(DCSS_SCALER_V_CHR_INC),
+       DCSS_DBG_REG(DCSS_SCALER_H_CHR_START),
+       DCSS_DBG_REG(DCSS_SCALER_H_CHR_INC),
+};
+
+struct dcss_scaler_ch {
+       void __iomem *base_reg;
+       u32 base_ofs;
+
+       u32 ctx_id;
+
+       u32 sdata_ctrl;
+};
+
+struct dcss_scaler_priv {
+       struct dcss_soc *dcss;
+       struct dcss_scaler_ch ch[3];
+};
+
+static void dcss_scaler_write(struct dcss_scaler_priv *scl, int ch_num,
+                             u32 val, u32 ofs)
+{
+#if !defined(USE_CTXLD)
+       dcss_writel(val, scl->ch[ch_num].base_reg + ofs);
+#else
+       dcss_ctxld_write(scl->dcss, scl->ch[ch_num].ctx_id,
+                        val, scl->ch[ch_num].base_ofs + ofs);
+#endif
+}
+
+#ifdef CONFIG_DEBUG_FS
+void dcss_scaler_dump_regs(struct seq_file *s, void *data)
+{
+       struct dcss_soc *dcss = data;
+       int i, j;
+
+       for (i = 0; i < 3; i++) {
+               seq_printf(s, ">> Dumping SCALER CH %d:\n", i);
+               for (j = 0; j < ARRAY_SIZE(scaler_debug_reg); j++) {
+                       seq_printf(s, "%-35s(0x%04x) -> 0x%08x\n",
+                               scaler_debug_reg[j].name,
+                               scaler_debug_reg[j].ofs,
+                               dcss_readl(dcss->scaler_priv->ch[i].base_reg +
+                                          scaler_debug_reg[j].ofs));
+               }
+       }
+}
+#endif
+
+static int dcss_scaler_ch_init_all(struct dcss_soc *dcss,
+                                  unsigned long scaler_base)
+{
+       struct dcss_scaler_priv *scaler = dcss->scaler_priv;
+       struct dcss_scaler_ch *ch;
+       int i;
+
+       for (i = 0; i < 3; i++) {
+               ch = &scaler->ch[i];
+
+               ch->base_ofs = scaler_base + i * 0x400;
+
+               ch->base_reg = devm_ioremap(dcss->dev, ch->base_ofs, SZ_4K);
+               if (!ch->base_reg) {
+                       dev_err(dcss->dev, "scaler: unable to remap ch base\n");
+                       return -ENOMEM;
+               }
+
+#if defined(USE_CTXLD)
+               ch->ctx_id = CTX_SB_HP;
+#endif
+       }
+
+       return 0;
+}
+
+int dcss_scaler_init(struct dcss_soc *dcss, unsigned long scaler_base)
+{
+       struct dcss_scaler_priv *scaler;
+
+       scaler = devm_kzalloc(dcss->dev, sizeof(*scaler), GFP_KERNEL);
+       if (!scaler)
+               return -ENOMEM;
+
+       dcss->scaler_priv = scaler;
+       scaler->dcss = dcss;
+
+       return dcss_scaler_ch_init_all(dcss, scaler_base);
+}
+
+void dcss_scaler_exit(struct dcss_soc *dcss)
+{
+       struct dcss_scaler_priv *scaler = dcss->scaler_priv;
+       int ch_no;
+
+       for (ch_no = 0; ch_no < 3; ch_no++) {
+               struct dcss_scaler_ch *ch = &scaler->ch[ch_no];
+
+               dcss_writel(0, ch->base_reg + DCSS_SCALER_CTRL);
+       }
+}
+
+void dcss_scaler_enable(struct dcss_soc *dcss, int ch_num, bool en)
+{
+       struct dcss_scaler_ch *ch = &dcss->scaler_priv->ch[ch_num];
+       u32 scaler_ctrl;
+
+       scaler_ctrl = SCALER_EN | REPEAT_EN;
+
+       if (en)
+               dcss_scaler_write(dcss->scaler_priv, ch_num, ch->sdata_ctrl,
+                                 DCSS_SCALER_SDATA_CTRL);
+
+       dcss_scaler_write(dcss->scaler_priv, ch_num, en ? scaler_ctrl : 0,
+                         DCSS_SCALER_CTRL);
+}
+EXPORT_SYMBOL(dcss_scaler_enable);
+
+static void dcss_scaler_yuv_enable(struct dcss_soc *dcss, int ch_num, bool en)
+{
+       struct dcss_scaler_ch *ch = &dcss->scaler_priv->ch[ch_num];
+
+       ch->sdata_ctrl &= ~YUV_EN;
+       ch->sdata_ctrl |= en ? YUV_EN : 0;
+}
+
+static void dcss_scaler_rtr_8lines_enable(struct dcss_soc *dcss, int ch_num,
+                                         bool en)
+{
+       struct dcss_scaler_ch *ch = &dcss->scaler_priv->ch[ch_num];
+
+       ch->sdata_ctrl &= ~RTRAM_8LINES;
+       ch->sdata_ctrl |= en ? RTRAM_8LINES : 0;
+}
+
+static void dcss_scaler_bit_depth_set(struct dcss_soc *dcss, int ch_num,
+                                     int depth)
+{
+       u32 val;
+
+       val = depth == 30 ? 2 : 0;
+
+       dcss_scaler_write(dcss->scaler_priv, ch_num,
+                         ((val << CHR_BIT_DEPTH_POS) & CHR_BIT_DEPTH_MASK) |
+                         ((val << LUM_BIT_DEPTH_POS) & LUM_BIT_DEPTH_MASK),
+                         DCSS_SCALER_BIT_DEPTH);
+}
+
+enum buffer_format {
+       BUF_FMT_YUV420,
+       BUF_FMT_YUV422,
+       BUF_FMT_ARGB8888_YUV444,
+};
+
+static void dcss_scaler_format_set(struct dcss_soc *dcss, int ch_num,
+                                  enum buffer_format src_fmt,
+                                  enum buffer_format dst_fmt)
+{
+       dcss_scaler_write(dcss->scaler_priv, ch_num, src_fmt,
+                         DCSS_SCALER_SRC_FORMAT);
+       dcss_scaler_write(dcss->scaler_priv, ch_num, dst_fmt,
+                         DCSS_SCALER_DST_FORMAT);
+}
+
+static void dcss_scaler_res_set(struct dcss_soc *dcss, int ch_num,
+                               int src_xres, int src_yres,
+                               int dst_xres, int dst_yres,
+                               u32 pix_format)
+{
+       u32 lsrc_xres, lsrc_yres, csrc_xres, csrc_yres;
+       u32 ldst_xres, ldst_yres, cdst_xres, cdst_yres;
+
+       lsrc_xres = csrc_xres = src_xres;
+       lsrc_yres = csrc_yres = src_yres;
+       ldst_xres = cdst_xres = dst_xres;
+       ldst_yres = cdst_yres = dst_yres;
+
+       if (pix_format == DRM_FORMAT_UYVY || pix_format == DRM_FORMAT_VYUY ||
+           pix_format == DRM_FORMAT_YUYV || pix_format == DRM_FORMAT_YVYU)
+               csrc_xres >>= 1;
+       else if (pix_format == DRM_FORMAT_NV12 ||
+                pix_format == DRM_FORMAT_NV21) {
+               csrc_xres >>= 1;
+               csrc_yres >>= 1;
+       }
+
+       dcss_scaler_write(dcss->scaler_priv, ch_num,
+                         (((lsrc_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
+                         (((lsrc_xres - 1) << WIDTH_POS) & WIDTH_MASK),
+                         DCSS_SCALER_SRC_LUM_RES);
+       dcss_scaler_write(dcss->scaler_priv, ch_num,
+                         (((csrc_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
+                         (((csrc_xres - 1) << WIDTH_POS) & WIDTH_MASK),
+                         DCSS_SCALER_SRC_CHR_RES);
+       dcss_scaler_write(dcss->scaler_priv, ch_num,
+                         (((ldst_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
+                         (((ldst_xres - 1) << WIDTH_POS) & WIDTH_MASK),
+                         DCSS_SCALER_DST_LUM_RES);
+       dcss_scaler_write(dcss->scaler_priv, ch_num,
+                         (((cdst_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
+                         (((cdst_xres - 1) << WIDTH_POS) & WIDTH_MASK),
+                         DCSS_SCALER_DST_CHR_RES);
+}
+
+static void dcss_scaler_fractions_set(struct dcss_soc *dcss, int ch_num,
+                                     int src_xres, int src_yres,
+                                     int dst_xres, int dst_yres,
+                                     u32 pix_format)
+{
+       u32 l_vinc, l_hinc, c_vinc, c_hinc;
+
+       l_vinc = (src_yres << 13) / dst_yres;
+       c_vinc = (src_yres << 13) / dst_yres;
+       l_hinc = (src_xres << 13) / dst_xres;
+       c_hinc = (src_xres << 13) / dst_xres;
+
+       if (pix_format == DRM_FORMAT_UYVY || pix_format == DRM_FORMAT_VYUY ||
+           pix_format == DRM_FORMAT_YUYV || pix_format == DRM_FORMAT_YVYU) {
+               c_hinc >>= 1;
+       } else if (pix_format == DRM_FORMAT_NV12 ||
+                  pix_format == DRM_FORMAT_NV21) {
+               c_hinc >>= 1;
+               c_vinc >>= 1;
+       }
+
+       dcss_scaler_write(dcss->scaler_priv, ch_num, 0,
+                         DCSS_SCALER_V_LUM_START);
+       dcss_scaler_write(dcss->scaler_priv, ch_num, l_vinc,
+                         DCSS_SCALER_V_LUM_INC);
+
+       dcss_scaler_write(dcss->scaler_priv, ch_num, 0,
+                         DCSS_SCALER_H_LUM_START);
+       dcss_scaler_write(dcss->scaler_priv, ch_num, l_hinc,
+                         DCSS_SCALER_H_LUM_INC);
+
+       dcss_scaler_write(dcss->scaler_priv, ch_num, 0,
+                         DCSS_SCALER_V_CHR_START);
+       dcss_scaler_write(dcss->scaler_priv, ch_num, c_vinc,
+                         DCSS_SCALER_V_CHR_INC);
+
+       dcss_scaler_write(dcss->scaler_priv, ch_num, 0,
+                         DCSS_SCALER_H_CHR_START);
+       dcss_scaler_write(dcss->scaler_priv, ch_num, c_hinc,
+                         DCSS_SCALER_H_CHR_INC);
+}
+
+static void dcss_scaler_coef_clr(struct dcss_soc *dcss, int ch_num)
+{
+       int i;
+
+       for (i = 0; i < 48; i++) {
+               dcss_scaler_write(dcss->scaler_priv, ch_num,
+                                 0, DCSS_SCALER_COEF_VLUM + i * 4);
+               dcss_scaler_write(dcss->scaler_priv, ch_num,
+                                 0, DCSS_SCALER_COEF_HLUM + i * 4);
+               dcss_scaler_write(dcss->scaler_priv, ch_num,
+                                 0, DCSS_SCALER_COEF_VCHR + i * 4);
+               dcss_scaler_write(dcss->scaler_priv, ch_num,
+                                 0, DCSS_SCALER_COEF_HCHR + i * 4);
+       }
+}
+
+static void dcss_scaler_rgb_coef_set(struct dcss_soc *dcss, int ch_num)
+{
+       int i;
+
+       dcss_scaler_coef_clr(dcss, ch_num);
+
+       for (i = 0; i < 16; i++) {
+               u32 ofs = (16 + i) * sizeof(u32);
+
+               dcss_scaler_write(dcss->scaler_priv, ch_num, 0x40000,
+                                 DCSS_SCALER_COEF_VLUM + ofs);
+               dcss_scaler_write(dcss->scaler_priv, ch_num, 0x40000,
+                                 DCSS_SCALER_COEF_HLUM + ofs);
+               dcss_scaler_write(dcss->scaler_priv, ch_num, 0x40000,
+                                 DCSS_SCALER_COEF_VCHR + ofs);
+               dcss_scaler_write(dcss->scaler_priv, ch_num, 0x40000,
+                                 DCSS_SCALER_COEF_HCHR + ofs);
+       }
+}
+
+static u32 dcss_scaler_yuv_coef[] = {
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000061, 0x00000041, 0x00000031,
+       0x00000021, 0x00000010, 0x00000010, 0x00000000, 0x00040300, 0x05532208,
+       0x0413120a, 0x0312f80d, 0x0242d310, 0x01a2a614, 0x01327117, 0x00d2361b,
+       0x0091f81f, 0x0b923600, 0x07b27101, 0x0402a601, 0x00a2d302, 0x0da2f803,
+       0x0af31204, 0x08b32205, 0x00000000, 0x0b000000, 0x0f001000, 0x0a001000,
+       0x0a002000, 0x00003000, 0x0b004000, 0x09006000, 0x08009000, 0x0d000000,
+       0x03000000, 0x0a000000, 0x04000000, 0x01000000, 0x01000000, 0x05000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000061, 0x00000041, 0x00000031,
+       0x00000021, 0x00000010, 0x00000010, 0x00000000, 0x00040000, 0x05432008,
+       0x0403100a, 0x0302f50d, 0x0242d110, 0x01a2a413, 0x01326f17, 0x00d2351b,
+       0x0091f71f, 0x0b823500, 0x07a26f01, 0x03f2a401, 0x0092d102, 0x0d92f503,
+       0x0af31004, 0x08b32005, 0x00000000, 0x0b000000, 0x0f001000, 0x09001000,
+       0x09002000, 0x0f003000, 0x0a004000, 0x08006000, 0x07009000, 0x0d000000,
+       0x03000000, 0x0a000000, 0x04000000, 0x00000000, 0x00000000, 0x04000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000061, 0x00000041, 0x00000031,
+       0x00000021, 0x00000010, 0x00000010, 0x00000000, 0x00040300, 0x05532208,
+       0x0413120a, 0x0312f80d, 0x0242d310, 0x01a2a614, 0x01327117, 0x00d2361b,
+       0x0091f81f, 0x0b923600, 0x07b27101, 0x0402a601, 0x00a2d302, 0x0da2f803,
+       0x0af31204, 0x08b32205, 0x00000000, 0x0b000000, 0x0f001000, 0x0a001000,
+       0x0a002000, 0x00003000, 0x0b004000, 0x09006000, 0x08009000, 0x0d000000,
+       0x03000000, 0x0a000000, 0x04000000, 0x01000000, 0x01000000, 0x05000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000061, 0x00000041, 0x00000031,
+       0x00000021, 0x00000010, 0x00000010, 0x00000000, 0x00040000, 0x05432008,
+       0x0403100a, 0x0302f50d, 0x0242d110, 0x01a2a413, 0x01326f17, 0x00d2351b,
+       0x0091f71f, 0x0b823500, 0x07a26f01, 0x03f2a401, 0x0092d102, 0x0d92f503,
+       0x0af31004, 0x08b32005, 0x00000000, 0x0b000000, 0x0f001000, 0x09001000,
+       0x09002000, 0x0f003000, 0x0a004000, 0x08006000, 0x07009000, 0x0d000000,
+       0x03000000, 0x0a000000, 0x04000000, 0x00000000, 0x00000000, 0x04000000,
+};
+
+static void dcss_scaler_yuv_coef_set(struct dcss_soc *dcss, int ch_num)
+{
+       int i;
+
+       for (i = 0; i < 48; i++) {
+               dcss_scaler_write(dcss->scaler_priv, ch_num,
+                                 dcss_scaler_yuv_coef[i],
+                                 DCSS_SCALER_COEF_VLUM + i * sizeof(u32));
+               dcss_scaler_write(dcss->scaler_priv, ch_num,
+                                 dcss_scaler_yuv_coef[48 + i],
+                                 DCSS_SCALER_COEF_HLUM + i * sizeof(u32));
+               dcss_scaler_write(dcss->scaler_priv, ch_num,
+                                 dcss_scaler_yuv_coef[2 * 48 + i],
+                                 DCSS_SCALER_COEF_VCHR + i * sizeof(u32));
+               dcss_scaler_write(dcss->scaler_priv, ch_num,
+                                 dcss_scaler_yuv_coef[3 * 48 + i],
+                                 DCSS_SCALER_COEF_HCHR + i * sizeof(u32));
+       }
+}
+
+static void dcss_scaler_set_rgb10_order(struct dcss_soc *dcss, int ch_num,
+                                       u32 pix_format)
+{
+       struct dcss_scaler_ch *ch = &dcss->scaler_priv->ch[ch_num];
+       enum dcss_color_space dcss_cs;
+       const struct drm_format_info *format;
+       unsigned int pixel_depth;
+       u32 a2r10g10b10_format;
+
+       dcss_cs = dcss_drm_fourcc_to_colorspace(pix_format);
+
+       if (dcss_cs != DCSS_COLORSPACE_RGB)
+               return;
+
+       format = drm_format_info(pix_format);
+       pixel_depth = format->depth;
+
+       ch->sdata_ctrl &= ~A2R10G10B10_FORMAT_MASK;
+
+       if (pixel_depth != 30)
+               return;
+
+       switch (pix_format) {
+       case DRM_FORMAT_ARGB2101010:
+       case DRM_FORMAT_XRGB2101010:
+               a2r10g10b10_format = 0;
+               break;
+
+       case DRM_FORMAT_ABGR2101010:
+       case DRM_FORMAT_XBGR2101010:
+               a2r10g10b10_format = 5;
+               break;
+
+       case DRM_FORMAT_RGBA1010102:
+       case DRM_FORMAT_RGBX1010102:
+               a2r10g10b10_format = 6;
+               break;
+
+       case DRM_FORMAT_BGRA1010102:
+       case DRM_FORMAT_BGRX1010102:
+               a2r10g10b10_format = 11;
+               break;
+
+       default:
+               a2r10g10b10_format = 0;
+               break;
+       }
+
+       ch->sdata_ctrl |= a2r10g10b10_format << A2R10G10B10_FORMAT_POS;
+}
+
+void dcss_scaler_setup(struct dcss_soc *dcss, int ch_num, u32 pix_format,
+                      int src_xres, int src_yres, int dst_xres, int dst_yres)
+{
+       enum dcss_color_space dcss_cs;
+       int planes;
+       const struct drm_format_info *format;
+       unsigned int pixel_depth;
+       bool rtr_8line_en = false;
+       enum buffer_format src_format = BUF_FMT_ARGB8888_YUV444;
+       enum buffer_format dst_format = BUF_FMT_ARGB8888_YUV444;
+
+       dcss_cs = dcss_drm_fourcc_to_colorspace(pix_format);
+       planes = drm_format_num_planes(pix_format);
+
+       if (dcss_cs == DCSS_COLORSPACE_YUV) {
+               dcss_scaler_yuv_enable(dcss, ch_num, true);
+
+               if (pix_format == DRM_FORMAT_NV12 ||
+                   pix_format == DRM_FORMAT_NV21) {
+                       rtr_8line_en = true;
+                       src_format = BUF_FMT_YUV420;
+               } else if (pix_format == DRM_FORMAT_UYVY ||
+                          pix_format == DRM_FORMAT_VYUY ||
+                          pix_format == DRM_FORMAT_YUYV ||
+                          pix_format == DRM_FORMAT_YVYU) {
+                       src_format = BUF_FMT_YUV422;
+               }
+
+               dcss_scaler_yuv_coef_set(dcss, ch_num);
+
+               /* TODO: determine component depth for YUV */
+
+       } else if (dcss_cs == DCSS_COLORSPACE_RGB) {
+               dcss_scaler_yuv_enable(dcss, ch_num, false);
+
+               format = drm_format_info(pix_format);
+               pixel_depth = format->depth;
+
+               dcss_scaler_rgb_coef_set(dcss, ch_num);
+       }
+
+       dcss_scaler_rtr_8lines_enable(dcss, ch_num, rtr_8line_en);
+       dcss_scaler_bit_depth_set(dcss, ch_num, pixel_depth);
+       dcss_scaler_set_rgb10_order(dcss, ch_num, pix_format);
+       dcss_scaler_format_set(dcss, ch_num, src_format, dst_format);
+       dcss_scaler_res_set(dcss, ch_num, src_xres, src_yres,
+                           dst_xres, dst_yres, pix_format);
+       dcss_scaler_fractions_set(dcss, ch_num, src_xres, src_yres,
+                                 dst_xres, dst_yres, pix_format);
+}
+EXPORT_SYMBOL(dcss_scaler_setup);
diff --git a/drivers/gpu/imx/dcss/dcss-ss.c b/drivers/gpu/imx/dcss/dcss-ss.c
new file mode 100644 (file)
index 0000000..42895af
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/bitops.h>
+#include <linux/io.h>
+#include <linux/seq_file.h>
+#include <video/videomode.h>
+
+#include <video/imx-dcss.h>
+#include "dcss-prv.h"
+
+#define USE_CTXLD
+
+#define DCSS_SS_SYS_CTRL                       0x00
+#define   RUN_EN                               BIT(0)
+#define DCSS_SS_DISPLAY                                0x10
+#define   LRC_X_POS                            0
+#define   LRC_X_MASK                           GENMASK(12, 0)
+#define   LRC_Y_POS                            16
+#define   LRC_Y_MASK                           GENMASK(28, 16)
+#define DCSS_SS_HSYNC                          0x20
+#define DCSS_SS_VSYNC                          0x30
+#define   SYNC_START_POS                       0
+#define   SYNC_START_MASK                      GENMASK(12, 0)
+#define   SYNC_END_POS                         16
+#define   SYNC_END_MASK                                GENMASK(28, 16)
+#define   SYNC_POL                             BIT(31)
+#define DCSS_SS_DE_ULC                         0x40
+#define   ULC_X_POS                            0
+#define   ULC_X_MASK                           GENMASK(12, 0)
+#define   ULC_Y_POS                            16
+#define   ULC_Y_MASK                           GENMASK(28, 16)
+#define   ULC_POL                              BIT(31)
+#define DCSS_SS_DE_LRC                         0x50
+#define DCSS_SS_MODE                           0x60
+#define   PIPE_MODE_POS                                0
+#define   PIPE_MODE_MASK                       GENMASK(1, 0)
+#define DCSS_SS_COEFF                          0x70
+#define   HORIZ_A_POS                          0
+#define   HORIZ_A_MASK                         GENMASK(3, 0)
+#define   HORIZ_B_POS                          4
+#define   HORIZ_B_MASK                         GENMASK(7, 4)
+#define   HORIZ_C_POS                          8
+#define   HORIZ_C_MASK                         GENMASK(11, 8)
+#define   HORIZ_H_NORM_POS                     12
+#define   HORIZ_H_NORM_MASK                    GENMASK(14, 12)
+#define   VERT_A_POS                           16
+#define   VERT_A_MASK                          GENMASK(19, 16)
+#define   VERT_B_POS                           20
+#define   VERT_B_MASK                          GENMASK(23, 20)
+#define   VERT_C_POS                           24
+#define   VERT_C_MASK                          GENMASK(27, 24)
+#define   VERT_H_NORM_POS                      28
+#define   VERT_H_NORM_MASK                     GENMASK(30, 28)
+#define DCSS_SS_CLIP_CB                                0x80
+#define DCSS_SS_CLIP_CR                                0x90
+#define   CLIP_MIN_POS                         0
+#define   CLIP_MIN_MASK                                GENMASK(9, 0)
+#define   CLIP_MAX_POS                         0
+#define   CLIP_MAX_MASK                                GENMASK(23, 16)
+#define DCSS_SS_INTER_MODE                     0xA0
+#define   INT_EN                               BIT(0)
+#define   VSYNC_SHIFT                          BIT(1)
+
+static struct dcss_debug_reg ss_debug_reg[] = {
+       DCSS_DBG_REG(DCSS_SS_SYS_CTRL),
+       DCSS_DBG_REG(DCSS_SS_DISPLAY),
+       DCSS_DBG_REG(DCSS_SS_HSYNC),
+       DCSS_DBG_REG(DCSS_SS_VSYNC),
+       DCSS_DBG_REG(DCSS_SS_DE_ULC),
+       DCSS_DBG_REG(DCSS_SS_DE_LRC),
+       DCSS_DBG_REG(DCSS_SS_MODE),
+       DCSS_DBG_REG(DCSS_SS_COEFF),
+       DCSS_DBG_REG(DCSS_SS_CLIP_CB),
+       DCSS_DBG_REG(DCSS_SS_CLIP_CR),
+       DCSS_DBG_REG(DCSS_SS_INTER_MODE),
+};
+
+struct dcss_ss_priv {
+       struct dcss_soc *dcss;
+       void __iomem *base_reg;
+       u32 base_ofs;
+
+       u32 ctx_id;
+
+       bool in_use;
+};
+
+static void dcss_ss_write(struct dcss_ss_priv *ss, u32 val, u32 ofs)
+{
+       if (!ss->in_use)
+               dcss_writel(val, ss->base_reg + ofs);
+#if defined(USE_CTXLD)
+       dcss_ctxld_write(ss->dcss, ss->ctx_id, val,
+                        ss->base_ofs + ofs);
+#endif
+}
+
+#ifdef CONFIG_DEBUG_FS
+void dcss_ss_dump_regs(struct seq_file *s, void *data)
+{
+       struct dcss_soc *dcss = data;
+       int j;
+
+       seq_puts(s, ">> Dumping SUBSAM:\n");
+       for (j = 0; j < ARRAY_SIZE(ss_debug_reg); j++)
+               seq_printf(s, "%-35s(0x%04x) -> 0x%08x\n",
+                          ss_debug_reg[j].name,
+                          ss_debug_reg[j].ofs,
+                          dcss_readl(dcss->ss_priv->base_reg +
+                                     ss_debug_reg[j].ofs));
+}
+#endif
+
+int dcss_ss_init(struct dcss_soc *dcss, unsigned long ss_base)
+{
+       struct dcss_ss_priv *ss;
+
+       ss = devm_kzalloc(dcss->dev, sizeof(*ss), GFP_KERNEL);
+       if (!ss)
+               return -ENOMEM;
+
+       dcss->ss_priv = ss;
+       ss->dcss = dcss;
+
+       ss->base_reg = devm_ioremap(dcss->dev, ss_base, SZ_4K);
+       if (!ss->base_reg) {
+               dev_err(dcss->dev, "ss: unable to remap ss base\n");
+               return -ENOMEM;
+       }
+
+       ss->base_ofs = ss_base;
+
+#if defined(USE_CTXLD)
+       ss->ctx_id = CTX_SB_HP;
+#endif
+
+       /* TODO: should these be hardcoded? */
+       dcss_ss_write(dcss->ss_priv, 0x41614161, DCSS_SS_COEFF);
+       dcss_ss_write(dcss->ss_priv, 0x03ff0000, DCSS_SS_CLIP_CB);
+       dcss_ss_write(dcss->ss_priv, 0x03ff0000, DCSS_SS_CLIP_CR);
+
+       return 0;
+}
+
+void dcss_ss_exit(struct dcss_soc *dcss)
+{
+       dcss_writel(0, dcss->ss_priv->base_reg + DCSS_SS_SYS_CTRL);
+}
+
+void dcss_ss_sync_set(struct dcss_soc *dcss, struct videomode *vm,
+                     bool phsync, bool pvsync)
+{
+       struct dcss_ss_priv *ss = dcss->ss_priv;
+       u16 lrc_x, lrc_y;
+       u16 hsync_start, hsync_end;
+       u16 vsync_start, vsync_end;
+       u16 de_ulc_x, de_ulc_y;
+       u16 de_lrc_x, de_lrc_y;
+
+       lrc_x = vm->hfront_porch + vm->hback_porch + vm->hsync_len +
+               vm->hactive - 1;
+       lrc_y = vm->vfront_porch + vm->vback_porch + vm->vsync_len +
+               vm->vactive - 1;
+
+       dcss_ss_write(ss, (lrc_y << LRC_Y_POS) | lrc_x, DCSS_SS_DISPLAY);
+
+       hsync_start = vm->hfront_porch + vm->hback_porch + vm->hsync_len +
+                     vm->hactive - 1;
+       hsync_end = vm->hsync_len - 1;
+
+       dcss_ss_write(ss, (phsync ? SYNC_POL : 0) |
+                     (hsync_end << SYNC_END_POS) | hsync_start,
+                     DCSS_SS_HSYNC);
+
+       vsync_start = vm->vfront_porch - 1;
+       vsync_end = vm->vfront_porch + vm->vsync_len - 1;
+
+       dcss_ss_write(ss, (pvsync ? SYNC_POL : 0) |
+                     (vsync_end << SYNC_END_POS) | vsync_start, DCSS_SS_VSYNC);
+
+       de_ulc_x = vm->hsync_len + vm->hback_porch - 1;
+       de_ulc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch;
+
+       dcss_ss_write(ss, SYNC_POL | (de_ulc_y << ULC_Y_POS) | de_ulc_x,
+                     DCSS_SS_DE_ULC);
+
+       de_lrc_x = vm->hsync_len + vm->hback_porch + vm->hactive - 1;
+       de_lrc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch +
+                  vm->vactive - 1;
+
+       dcss_ss_write(ss, (de_lrc_y << LRC_Y_POS) | de_lrc_x, DCSS_SS_DE_LRC);
+}
+EXPORT_SYMBOL(dcss_ss_sync_set);
+
+void dcss_ss_enable(struct dcss_soc *dcss, bool en)
+{
+       struct dcss_ss_priv *ss = dcss->ss_priv;
+
+       dcss_ss_write(ss, en ? RUN_EN : 0, DCSS_SS_SYS_CTRL);
+}
+EXPORT_SYMBOL(dcss_ss_enable);
diff --git a/drivers/gpu/imx/dcss/dcss-tables.h b/drivers/gpu/imx/dcss/dcss-tables.h
new file mode 100644 (file)
index 0000000..4fb80f2
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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.
+ */
+
+#ifndef DCSS_TABLES_H
+#define DCSS_TABLES_H
+
+static u16 dcss_hdr10_comp_lut[] = {
+       0x0000, 0x0003, 0x0007, 0x000a, 0x000e, 0x0011, 0x0015, 0x0018, 0x001c,
+       0x0020, 0x0023, 0x0027, 0x002a, 0x002e, 0x0031, 0x0035, 0x0038, 0x003c,
+       0x0040, 0x0043, 0x0047, 0x004a, 0x004e, 0x0051, 0x0055, 0x0058, 0x005c,
+       0x0060, 0x0063, 0x0067, 0x006a, 0x006e, 0x0071, 0x0075, 0x0078, 0x007c,
+       0x0080, 0x0083, 0x0087, 0x008a, 0x008e, 0x0091, 0x0095, 0x0099, 0x009c,
+       0x00a0, 0x00a3, 0x00a7, 0x00aa, 0x00ae, 0x00b1, 0x00b5, 0x00b9, 0x00bc,
+       0x00c0, 0x00c3, 0x00c7, 0x00ca, 0x00ce, 0x00d1, 0x00d5, 0x00d9, 0x00dc,
+       0x00e0, 0x00e3, 0x00e7, 0x00ea, 0x00ee, 0x00f1, 0x00f5, 0x00f9, 0x00fc,
+       0x0100, 0x0103, 0x0107, 0x010a, 0x010e, 0x0112, 0x0115, 0x0119, 0x011c,
+       0x0120, 0x0123, 0x0126, 0x012a, 0x012d, 0x0131, 0x0134, 0x0138, 0x013c,
+       0x013f, 0x0143, 0x0147, 0x014b, 0x014e, 0x0152, 0x0156, 0x015a, 0x015e,
+       0x0162, 0x0166, 0x016a, 0x016e, 0x0172, 0x0176, 0x017a, 0x017e, 0x0182,
+       0x0186, 0x018a, 0x018f, 0x0193, 0x0197, 0x019b, 0x01a0, 0x01a4, 0x01a8,
+       0x01ad, 0x01b1, 0x01b5, 0x01ba, 0x01be, 0x01c3, 0x01c7, 0x01cc, 0x01d0,
+       0x01d5, 0x01d9, 0x01de, 0x01e3, 0x01e7, 0x01ec, 0x01f1, 0x01f6, 0x01fa,
+       0x01ff, 0x0204, 0x0209, 0x020e, 0x0213, 0x0217, 0x021c, 0x0221, 0x0226,
+       0x022b, 0x0230, 0x0236, 0x023b, 0x0240, 0x0245, 0x024a, 0x024f, 0x0255,
+       0x025a, 0x025f, 0x0264, 0x026a, 0x026f, 0x0274, 0x027a, 0x027f, 0x0285,
+       0x028a, 0x0290, 0x0295, 0x029b, 0x02a0, 0x02a6, 0x02ac, 0x02b1, 0x02b7,
+       0x02bd, 0x02c2, 0x02c8, 0x02ce, 0x02d4, 0x02da, 0x02df, 0x02e5, 0x02eb,
+       0x02f1, 0x02f7, 0x02fd, 0x0303, 0x0309, 0x030f, 0x0315, 0x031c, 0x0322,
+       0x0328, 0x032e, 0x0334, 0x033b, 0x0341, 0x0347, 0x034d, 0x0354, 0x035a,
+       0x0361, 0x0367, 0x036d, 0x0374, 0x037a, 0x0381, 0x0388, 0x038e, 0x0395,
+       0x039b, 0x03a2, 0x03a9, 0x03b0, 0x03b6, 0x03bd, 0x03c4, 0x03cb, 0x03d2,
+       0x03d8, 0x03df, 0x03e6, 0x03ed, 0x03f4, 0x03fb, 0x0402, 0x0409, 0x0411,
+       0x0418, 0x041f, 0x0426, 0x042d, 0x0434, 0x043c, 0x0443, 0x044a, 0x0452,
+       0x0459, 0x0460, 0x0468, 0x046f, 0x0477, 0x047e, 0x0486, 0x048d, 0x0495,
+       0x049c, 0x04a4, 0x04ac, 0x04b3, 0x04bb, 0x04c3, 0x04cb, 0x04d3, 0x04da,
+       0x04e2, 0x04ea, 0x04f2, 0x04fa, 0x0502, 0x050a, 0x0512, 0x051a, 0x0522,
+       0x052a, 0x0532, 0x053a, 0x0543, 0x054b, 0x0553, 0x055b, 0x0564, 0x056c,
+       0x0574, 0x057d, 0x0585, 0x058d, 0x0596, 0x059e, 0x05a7, 0x05af, 0x05b8,
+       0x05c1, 0x05c9, 0x05d2, 0x05db, 0x05e3, 0x05ec, 0x05f5, 0x05fe, 0x0606,
+       0x060f, 0x0618, 0x0621, 0x062a, 0x0633, 0x063c, 0x0645, 0x064e, 0x0657,
+       0x0660, 0x0669, 0x0672, 0x067b, 0x0685, 0x068e, 0x0697, 0x06a0, 0x06aa,
+       0x06b3, 0x06bd, 0x06c6, 0x06cf, 0x06d9, 0x06e2, 0x06ec, 0x06f5, 0x06ff,
+       0x0709, 0x0712, 0x071c, 0x0726, 0x072f, 0x0739, 0x0743, 0x074d, 0x0756,
+       0x0760, 0x076a, 0x0774, 0x077e, 0x0788, 0x0792, 0x079c, 0x07a6, 0x07b0,
+       0x07ba, 0x07c4, 0x07cf, 0x07d9, 0x07e3, 0x07ed, 0x07f7, 0x0802, 0x080c,
+       0x0816, 0x0821, 0x082b, 0x0836, 0x0840, 0x084b, 0x0855, 0x0860, 0x086a,
+       0x0875, 0x0880, 0x088a, 0x0895, 0x08a0, 0x08ab, 0x08b5, 0x08c0, 0x08cb,
+       0x08d6, 0x08e1, 0x08ec, 0x08f7, 0x0902, 0x090d, 0x0918, 0x0923, 0x092e,
+       0x0939, 0x0944, 0x0950, 0x095b, 0x0966, 0x0971, 0x097d, 0x0988, 0x0993,
+       0x099f, 0x09aa, 0x09b6, 0x09c1, 0x09cd, 0x09d8, 0x09e4, 0x09f0, 0x09fb,
+       0x0a07, 0x0a13, 0x0a1e, 0x0a2a, 0x0a36, 0x0a42, 0x0a4e, 0x0a59, 0x0a65,
+       0x0a71, 0x0a7d, 0x0a89, 0x0a95, 0x0aa1, 0x0aad, 0x0ab9, 0x0ac6, 0x0ad2,
+       0x0ade, 0x0aea, 0x0af6, 0x0b03, 0x0b0f, 0x0b1b, 0x0b28, 0x0b34, 0x0b41,
+       0x0b4d, 0x0b5a, 0x0b66, 0x0b73, 0x0b7f, 0x0b8c, 0x0b98, 0x0ba5, 0x0bb2,
+       0x0bbf, 0x0bcb, 0x0bd8, 0x0be5, 0x0bf2, 0x0bff, 0x0c0c, 0x0c19, 0x0c25,
+       0x0c32, 0x0c40, 0x0c4d, 0x0c5a, 0x0c67, 0x0c74, 0x0c81, 0x0c8e, 0x0c9c,
+       0x0ca9, 0x0cb6, 0x0cc3, 0x0cd1, 0x0cde, 0x0cec, 0x0cf9, 0x0d07, 0x0d14,
+       0x0d22, 0x0d2f, 0x0d3d, 0x0d4a, 0x0d58, 0x0d66, 0x0d73, 0x0d81, 0x0d8f,
+       0x0d9d, 0x0dab, 0x0db8, 0x0dc6, 0x0dd4, 0x0de2, 0x0df0, 0x0dfe, 0x0e0c,
+       0x0e1a, 0x0e29, 0x0e37, 0x0e45, 0x0e53, 0x0e61, 0x0e70, 0x0e7e, 0x0e8c,
+       0x0e9a, 0x0ea9, 0x0eb7, 0x0ec6, 0x0ed4, 0x0ee3, 0x0ef1, 0x0f00, 0x0f0e,
+       0x0f1d, 0x0f2c, 0x0f3a, 0x0f49, 0x0f58, 0x0f67, 0x0f75, 0x0f84, 0x0f93,
+       0x0fa2, 0x0fb1, 0x0fc0, 0x0fcf, 0x0fde, 0x0fed, 0x0ffc, 0x100b, 0x101a,
+       0x102a, 0x1039, 0x1048, 0x1057, 0x1067, 0x1076, 0x1085, 0x1095, 0x10a4,
+       0x10b4, 0x10c3, 0x10d3, 0x10e2, 0x10f2, 0x1101, 0x1111, 0x1121, 0x1130,
+       0x1140, 0x1150, 0x1160, 0x116f, 0x117f, 0x118f, 0x119f, 0x11af, 0x11bf,
+       0x11cf, 0x11df, 0x11ef, 0x11ff, 0x120f, 0x121f, 0x1230, 0x1240, 0x1250,
+       0x1260, 0x1271, 0x1281, 0x1291, 0x12a2, 0x12b2, 0x12c3, 0x12d3, 0x12e4,
+       0x12f4, 0x1305, 0x1316, 0x1326, 0x1337, 0x1348, 0x1359, 0x1369, 0x137a,
+       0x138b, 0x139c, 0x13ad, 0x13be, 0x13cf, 0x13e0, 0x13f1, 0x1402, 0x1413,
+       0x1424, 0x1435, 0x1446, 0x1458, 0x1469, 0x147a, 0x148b, 0x149d, 0x14ae,
+       0x14c0, 0x14d1, 0x14e3, 0x14f4, 0x1506, 0x1517, 0x1529, 0x153a, 0x154c,
+       0x155e, 0x156f, 0x1581, 0x1593, 0x15a5, 0x15b7, 0x15c9, 0x15db, 0x15ec,
+       0x15fe, 0x1610, 0x1623, 0x1635, 0x1647, 0x1659, 0x166b, 0x167d, 0x168f,
+       0x16a2, 0x16b4, 0x16c6, 0x16d9, 0x16eb, 0x16fe, 0x1710, 0x1722, 0x1735,
+       0x1748, 0x175a, 0x176d, 0x177f, 0x1792, 0x17a5, 0x17b8, 0x17ca, 0x17dd,
+       0x17f0, 0x1803, 0x1816, 0x1829, 0x183c, 0x184f, 0x1862, 0x1875, 0x1888,
+       0x189b, 0x18ae, 0x18c1, 0x18d5, 0x18e8, 0x18fb, 0x190e, 0x1922, 0x1935,
+       0x1949, 0x195c, 0x196f, 0x1983, 0x1996, 0x19aa, 0x19be, 0x19d1, 0x19e5,
+       0x19f9, 0x1a0c, 0x1a20, 0x1a34, 0x1a48, 0x1a5c, 0x1a70, 0x1a84, 0x1a97,
+       0x1aab, 0x1ac0, 0x1ad4, 0x1ae8, 0x1afc, 0x1b10, 0x1b24, 0x1b38, 0x1b4d,
+       0x1b61, 0x1b75, 0x1b8a, 0x1b9e, 0x1bb2, 0x1bc7, 0x1bdb, 0x1bf0, 0x1c04,
+       0x1c19, 0x1c2e, 0x1c42, 0x1c57, 0x1c6c, 0x1c80, 0x1c95, 0x1caa, 0x1cbf,
+       0x1cd4, 0x1ce8, 0x1cfd, 0x1d12, 0x1d27, 0x1d3c, 0x1d51, 0x1d67, 0x1d7c,
+       0x1d91, 0x1da6, 0x1dbb, 0x1dd1, 0x1de6, 0x1dfb, 0x1e10, 0x1e26, 0x1e3b,
+       0x1e51, 0x1e66, 0x1e7c, 0x1e91, 0x1ea7, 0x1ebd, 0x1ed2, 0x1ee8, 0x1efe,
+       0x1f13, 0x1f29, 0x1f3f, 0x1f55, 0x1f6b, 0x1f81, 0x1f96, 0x1fac, 0x1fc2,
+       0x1fd9, 0x1fef, 0x2005, 0x201b, 0x2031, 0x2047, 0x205d, 0x2074, 0x208a,
+       0x20a0, 0x20b7, 0x20cd, 0x20e4, 0x20fa, 0x2111, 0x2127, 0x213e, 0x2154,
+       0x216b, 0x2182, 0x2198, 0x21af, 0x21c6, 0x21dd, 0x21f3, 0x220a, 0x2221,
+       0x2238, 0x224f, 0x2266, 0x227d, 0x2294, 0x22ab, 0x22c2, 0x22da, 0x22f1,
+       0x2308, 0x231f, 0x2337, 0x234e, 0x2365, 0x237d, 0x2394, 0x23ac, 0x23c3,
+       0x23db, 0x23f2, 0x240a, 0x2421, 0x2439, 0x2451, 0x2469, 0x2480, 0x2498,
+       0x24b0, 0x24c8, 0x24e0, 0x24f8, 0x2510, 0x2528, 0x2540, 0x2558, 0x2570,
+       0x2588, 0x25a0, 0x25b8, 0x25d0, 0x25e9, 0x2601, 0x2619, 0x2632, 0x264a,
+       0x2663, 0x267b, 0x2693, 0x26ac, 0x26c5, 0x26dd, 0x26f6, 0x270e, 0x2727,
+       0x2740, 0x2759, 0x2771, 0x278a, 0x27a3, 0x27bc, 0x27d5, 0x27ee, 0x2807,
+       0x2820, 0x2839, 0x2852, 0x286b, 0x2884, 0x289e, 0x28b7, 0x28d0, 0x28e9,
+       0x2903, 0x291c, 0x2936, 0x294f, 0x2968, 0x2982, 0x299c, 0x29b5, 0x29cf,
+       0x29e8, 0x2a02, 0x2a1c, 0x2a35, 0x2a4f, 0x2a69, 0x2a83, 0x2a9d, 0x2ab7,
+       0x2ad1, 0x2aeb, 0x2b05, 0x2b1f, 0x2b39, 0x2b53, 0x2b6d, 0x2b87, 0x2ba1,
+       0x2bbc, 0x2bd6, 0x2bf0, 0x2c0b, 0x2c25, 0x2c3f, 0x2c5a, 0x2c74, 0x2c8f,
+       0x2ca9, 0x2cc4, 0x2cdf, 0x2cf9, 0x2d14, 0x2d2f, 0x2d49, 0x2d64, 0x2d7f,
+       0x2d9a, 0x2db5, 0x2dd0, 0x2deb, 0x2e06, 0x2e21, 0x2e3c, 0x2e57, 0x2e72,
+       0x2e8d, 0x2ea8, 0x2ec4, 0x2edf, 0x2efa, 0x2f16, 0x2f31, 0x2f4c, 0x2f68,
+       0x2f83, 0x2f9f, 0x2fba, 0x2fd6, 0x2ff1, 0x300d, 0x3029, 0x3044, 0x3060,
+       0x307c, 0x3098, 0x30b4, 0x30d0, 0x30eb, 0x3107, 0x3123, 0x313f, 0x315b,
+       0x3178, 0x3194, 0x31b0, 0x31cc, 0x31e8, 0x3205, 0x3221, 0x323d, 0x325a,
+       0x3276, 0x3292, 0x32af, 0x32cb, 0x32e8, 0x3304, 0x3321, 0x333e, 0x335a,
+       0x3377, 0x3394, 0x33b1, 0x33cd, 0x33ea, 0x3407, 0x3424, 0x3441, 0x345e,
+       0x347b, 0x3498, 0x34b5, 0x34d2, 0x34ef, 0x350d, 0x352a, 0x3547, 0x3564,
+       0x3582, 0x359f, 0x35bc, 0x35da, 0x35f7, 0x3615, 0x3632, 0x3650, 0x366e,
+       0x368b, 0x36a9, 0x36c7, 0x36e4, 0x3702, 0x3720, 0x373e, 0x375c, 0x377a,
+       0x3798, 0x37b6, 0x37d4, 0x37f2, 0x3810, 0x382e, 0x384c, 0x386a, 0x3888,
+       0x38a7, 0x38c5, 0x38e3, 0x3902, 0x3920, 0x393f, 0x395d, 0x397c, 0x399a,
+       0x39b9, 0x39d7, 0x39f6, 0x3a15, 0x3a33, 0x3a52, 0x3a71, 0x3a90, 0x3aaf,
+       0x3acd, 0x3aec, 0x3b0b, 0x3b2a, 0x3b49, 0x3b68, 0x3b87, 0x3ba7, 0x3bc6,
+       0x3be5, 0x3c04, 0x3c24, 0x3c43, 0x3c62, 0x3c82, 0x3ca1, 0x3cc0, 0x3ce0,
+       0x3cff, 0x3d1f, 0x3d3f, 0x3d5e, 0x3d7e, 0x3d9e, 0x3dbd, 0x3ddd, 0x3dfd,
+       0x3e1d, 0x3e3d, 0x3e5d, 0x3e7c, 0x3e9c, 0x3ebc, 0x3edc, 0x3efd, 0x3f1d,
+       0x3f3d, 0x3f5d, 0x3f7d, 0x3f9e, 0x3fbe, 0x3fde, 0x3fff,
+};
+
+static u16 dcss_hdr10_opipe[] = {
+       0x3612, 0x3612, 0x327c, 0x3840, 0x2fb2, 0x3475, 0x3728, 0x390e, 0x2d7f,
+       0x3134, 0x3397, 0x353d, 0x3695, 0x37cb, 0x38a2, 0x3982, 0x2b71, 0x2ea4,
+       0x3079, 0x3204, 0x3302, 0x341c, 0x34d5, 0x35ad, 0x3651, 0x36dc, 0x3778,
+       0x3811, 0x3870, 0x38d7, 0x3946, 0x39bf, 0x2955, 0x2c9c, 0x2e31, 0x2f25,
+       0x3026, 0x30d3, 0x319b, 0x323e, 0x32bd, 0x334b, 0x33e6, 0x3448, 0x34a4,
+       0x3508, 0x3574, 0x35e7, 0x3631, 0x3672, 0x36b8, 0x3702, 0x374f, 0x37a1,
+       0x37f7, 0x3828, 0x3857, 0x3889, 0x38bc, 0x38f2, 0x392a, 0x3964, 0x39a0,
+       0x39de, 0x271c, 0x2a8e, 0x2c2a, 0x2d0e, 0x2df1, 0x2e69, 0x2ee3, 0x2f6a,
+       0x2ffe, 0x304f, 0x30a5, 0x3102, 0x3166, 0x31d1, 0x3221, 0x325d, 0x329c,
+       0x32df, 0x3326, 0x3370, 0x33be, 0x3407, 0x3432, 0x345e, 0x348c, 0x34bd,
+       0x34ef, 0x3522, 0x3558, 0x3590, 0x35ca, 0x3602, 0x3621, 0x3641, 0x3662,
+       0x3683, 0x36a6, 0x36ca, 0x36ef, 0x3715, 0x373b, 0x3763, 0x378c, 0x37b6,
+       0x37e1, 0x3806, 0x381d, 0x3834, 0x384b, 0x3864, 0x387c, 0x3895, 0x38af,
+       0x38c9, 0x38e4, 0x3900, 0x391c, 0x3938, 0x3955, 0x3973, 0x3991, 0x39af,
+       0x39cf, 0x39ee, 0x24aa, 0x2871, 0x2a1c, 0x2aff, 0x2be3, 0x2c63, 0x2cd5,
+       0x2d47, 0x2db8, 0x2e15, 0x2e4c, 0x2e86, 0x2ec4, 0x2f04, 0x2f47, 0x2f8e,
+       0x2fd8, 0x3012, 0x303a, 0x3064, 0x308f, 0x30bc, 0x30eb, 0x311b, 0x314d,
+       0x3180, 0x31b5, 0x31ec, 0x3212, 0x322f, 0x324d, 0x326c, 0x328c, 0x32ad,
+       0x32ce, 0x32f1, 0x3314, 0x3338, 0x335d, 0x3383, 0x33aa, 0x33d2, 0x33fb,
+       0x3412, 0x3427, 0x343d, 0x3453, 0x346a, 0x3481, 0x3498, 0x34b0, 0x34c9,
+       0x34e2, 0x34fb, 0x3515, 0x3530, 0x354b, 0x3566, 0x3582, 0x359e, 0x35bb,
+       0x35d8, 0x35f6, 0x360a, 0x3619, 0x3629, 0x3639, 0x3649, 0x3659, 0x366a,
+       0x367b, 0x368c, 0x369d, 0x36af, 0x36c1, 0x36d3, 0x36e6, 0x36f8, 0x370b,
+       0x371e, 0x3732, 0x3745, 0x3759, 0x376d, 0x3782, 0x3797, 0x37ac, 0x37c1,
+       0x37d6, 0x37ec, 0x3801, 0x380c, 0x3817, 0x3823, 0x382e, 0x383a, 0x3846,
+       0x3851, 0x385e, 0x386a, 0x3876, 0x3883, 0x388f, 0x389c, 0x38a9, 0x38b6,
+       0x38c3, 0x38d0, 0x38de, 0x38eb, 0x38f9, 0x3907, 0x3915, 0x3923, 0x3931,
+       0x393f, 0x394e, 0x395c, 0x396b, 0x397a, 0x3989, 0x3998, 0x39a8, 0x39b7,
+       0x39c7, 0x39d6, 0x39e6, 0x39f6, 0x218e, 0x2638, 0x27ff, 0x28e3, 0x29c7,
+       0x2a55, 0x2ac7, 0x2b38, 0x2baa, 0x2c0e, 0x2c47, 0x2c7f, 0x2cb8, 0x2cf1,
+       0x2d2a, 0x2d63, 0x2d9c, 0x2dd5, 0x2e07, 0x2e23, 0x2e3f, 0x2e5a, 0x2e77,
+       0x2e95, 0x2eb4, 0x2ed3, 0x2ef4, 0x2f14, 0x2f36, 0x2f59, 0x2f7c, 0x2fa0,
+       0x2fc5, 0x2feb, 0x3008, 0x301c, 0x3030, 0x3044, 0x3059, 0x306e, 0x3084,
+       0x309a, 0x30b1, 0x30c7, 0x30df, 0x30f6, 0x310f, 0x3127, 0x3140, 0x3159,
+       0x3173, 0x318d, 0x31a8, 0x31c3, 0x31de, 0x31fa, 0x320b, 0x3219, 0x3228,
+       0x3237, 0x3246, 0x3255, 0x3265, 0x3274, 0x3284, 0x3294, 0x32a5, 0x32b5,
+       0x32c6, 0x32d7, 0x32e8, 0x32f9, 0x330b, 0x331d, 0x332f, 0x3341, 0x3354,
+       0x3367, 0x337a, 0x338d, 0x33a0, 0x33b4, 0x33c8, 0x33dc, 0x33f0, 0x3402,
+       0x340d, 0x3417, 0x3422, 0x342c, 0x3437, 0x3442, 0x344d, 0x3459, 0x3464,
+       0x346f, 0x347b, 0x3487, 0x3492, 0x349e, 0x34aa, 0x34b6, 0x34c3, 0x34cf,
+       0x34dc, 0x34e8, 0x34f5, 0x3502, 0x350f, 0x351c, 0x3529, 0x3536, 0x3544,
+       0x3551, 0x355f, 0x356d, 0x357b, 0x3589, 0x3597, 0x35a5, 0x35b4, 0x35c2,
+       0x35d1, 0x35e0, 0x35ef, 0x35fe, 0x3606, 0x360e, 0x3616, 0x361d, 0x3625,
+       0x362d, 0x3635, 0x363d, 0x3645, 0x364d, 0x3655, 0x365e, 0x3666, 0x366e,
+       0x3677, 0x367f, 0x3688, 0x3690, 0x3699, 0x36a2, 0x36ab, 0x36b4, 0x36bc,
+       0x36c5, 0x36cf, 0x36d8, 0x36e1, 0x36ea, 0x36f3, 0x36fd, 0x3706, 0x3710,
+       0x3719, 0x3723, 0x372d, 0x3737, 0x3740, 0x374a, 0x3754, 0x375e, 0x3768,
+       0x3772, 0x377d, 0x3787, 0x3791, 0x379c, 0x37a6, 0x37b1, 0x37bb, 0x37c6,
+       0x37d1, 0x37dc, 0x37e7, 0x37f1, 0x37fc, 0x3804, 0x3809, 0x380f, 0x3814,
+       0x381a, 0x3820, 0x3825, 0x382b, 0x3831, 0x3837, 0x383d, 0x3843, 0x3848,
+       0x384e, 0x3854, 0x385a, 0x3861, 0x3867, 0x386d, 0x3873, 0x3879, 0x387f,
+       0x3886, 0x388c, 0x3892, 0x3899, 0x389f, 0x38a5, 0x38ac, 0x38b2, 0x38b9,
+       0x38c0, 0x38c6, 0x38cd, 0x38d3, 0x38da, 0x38e1, 0x38e8, 0x38ee, 0x38f5,
+       0x38fc, 0x3903, 0x390a, 0x3911, 0x3918, 0x391f, 0x3926, 0x392d, 0x3934,
+       0x393c, 0x3943, 0x394a, 0x3951, 0x3959, 0x3960, 0x3967, 0x396f, 0x3976,
+       0x397e, 0x3985, 0x398d, 0x3995, 0x399c, 0x39a4, 0x39ac, 0x39b3, 0x39bb,
+       0x39c3, 0x39cb, 0x39d3, 0x39da, 0x39e2, 0x39ea, 0x39f2, 0x39fa, 0x0000,
+       0x238e, 0x258e, 0x26aa, 0x278e, 0x2838, 0x28aa, 0x291c, 0x298e, 0x29ff,
+       0x2a38, 0x2a71, 0x2aaa, 0x2ae3, 0x2b1c, 0x2b55, 0x2b8e, 0x2bc7, 0x2bff,
+       0x2c1c, 0x2c38, 0x2c55, 0x2c71, 0x2c8e, 0x2caa, 0x2cc7, 0x2ce3, 0x2cff,
+       0x2d1c, 0x2d38, 0x2d55, 0x2d71, 0x2d8e, 0x2daa, 0x2dc7, 0x2de3, 0x2dff,
+       0x2e0e, 0x2e1c, 0x2e2a, 0x2e38, 0x2e47, 0x2e53, 0x2e61, 0x2e70, 0x2e7f,
+       0x2e8e, 0x2e9d, 0x2eac, 0x2ebc, 0x2ecb, 0x2edb, 0x2eeb, 0x2efc, 0x2f0c,
+       0x2f1d, 0x2f2e, 0x2f3f, 0x2f50, 0x2f61, 0x2f73, 0x2f85, 0x2f97, 0x2fa9,
+       0x2fbc, 0x2fce, 0x2fe1, 0x2ff4, 0x3003, 0x300d, 0x3017, 0x3021, 0x302b,
+       0x3035, 0x303f, 0x304a, 0x3054, 0x305f, 0x3069, 0x3074, 0x307f, 0x308a,
+       0x3095, 0x30a0, 0x30ab, 0x30b6, 0x30c2, 0x30cd, 0x30d9, 0x30e5, 0x30f1,
+       0x30fc, 0x3109, 0x3115, 0x3121, 0x312d, 0x313a, 0x3146, 0x3153, 0x3160,
+       0x316d, 0x317a, 0x3187, 0x3194, 0x31a1, 0x31af, 0x31bc, 0x31ca, 0x31d8,
+       0x31e5, 0x31f3, 0x3200, 0x3208, 0x320f, 0x3216, 0x321d, 0x3224, 0x322c,
+       0x3233, 0x323b, 0x3242, 0x324a, 0x3251, 0x3259, 0x3261, 0x3268, 0x3270,
+       0x3278, 0x3280, 0x3288, 0x3290, 0x3298, 0x32a0, 0x32a9, 0x32b1, 0x32b9,
+       0x32c2, 0x32ca, 0x32d3, 0x32db, 0x32e4, 0x32ec, 0x32f5, 0x32fe, 0x3307,
+       0x3310, 0x3318, 0x3321, 0x332a, 0x3334, 0x333d, 0x3346, 0x334f, 0x3359,
+       0x3362, 0x336b, 0x3375, 0x337e, 0x3388, 0x3392, 0x339b, 0x33a5, 0x33af,
+       0x33b9, 0x33c3, 0x33cd, 0x33d7, 0x33e1, 0x33eb, 0x33f5, 0x3400, 0x3405,
+       0x340a, 0x340f, 0x3414, 0x341a, 0x341f, 0x3424, 0x342a, 0x342f, 0x3435,
+       0x343a, 0x3440, 0x3445, 0x344b, 0x3450, 0x3456, 0x345b, 0x3461, 0x3467,
+       0x346d, 0x3472, 0x3478, 0x347e, 0x3484, 0x348a, 0x348f, 0x3495, 0x349b,
+       0x34a1, 0x34a7, 0x34ad, 0x34b3, 0x34ba, 0x34c0, 0x34c6, 0x34cc, 0x34d2,
+       0x34d8, 0x34df, 0x34e5, 0x34eb, 0x34f2, 0x34f8, 0x34ff, 0x3505, 0x350c,
+       0x3512, 0x3519, 0x351f, 0x3526, 0x352c, 0x3533, 0x353a, 0x3540, 0x3547,
+       0x354e, 0x3555, 0x355c, 0x3563, 0x3569, 0x3570, 0x3577, 0x357e, 0x3585,
+       0x358c, 0x3594, 0x359b, 0x35a2, 0x35a9, 0x35b0, 0x35b7, 0x35bf, 0x35c6,
+       0x35cd, 0x35d5, 0x35dc, 0x35e4, 0x35eb, 0x35f2, 0x35fa, 0x3600, 0x3604,
+       0x3608, 0x360c, 0x3610, 0x3614, 0x3617, 0x361b, 0x361f, 0x3623, 0x3627,
+       0x362b, 0x362f, 0x3633, 0x3637, 0x363b, 0x363f, 0x3643, 0x3647, 0x364b,
+       0x364f, 0x3653, 0x3657, 0x365b, 0x3660, 0x3664, 0x3668, 0x366c, 0x3670,
+       0x3675, 0x3679, 0x367d, 0x3681, 0x3686, 0x368a, 0x368e, 0x3693, 0x3697,
+       0x369b, 0x36a0, 0x36a4, 0x36a8, 0x36ad, 0x36b1, 0x36b6, 0x36ba, 0x36bf,
+       0x36c3, 0x36c8, 0x36cc, 0x36d1, 0x36d5, 0x36da, 0x36df, 0x36e3, 0x36e8,
+       0x36ec, 0x36f1, 0x36f6, 0x36fb, 0x36ff, 0x3704, 0x3709, 0x370d, 0x3712,
+       0x3717, 0x371c, 0x3721, 0x3725, 0x372a, 0x372f, 0x3734, 0x3739, 0x373e,
+       0x3743, 0x3748, 0x374d, 0x3752, 0x3757, 0x375c, 0x3761, 0x3766, 0x376b,
+       0x3770, 0x3775, 0x377a, 0x377f, 0x3784, 0x378a, 0x378f, 0x3794, 0x3799,
+       0x379e, 0x37a4, 0x37a9, 0x37ae, 0x37b3, 0x37b9, 0x37be, 0x37c3, 0x37c9,
+       0x37ce, 0x37d4, 0x37d9, 0x37de, 0x37e4, 0x37e9, 0x37ef, 0x37f4, 0x37fa,
+       0x37ff, 0x3802, 0x3805, 0x3808, 0x380a, 0x380d, 0x3810, 0x3813, 0x3816,
+       0x3819, 0x381b, 0x381e, 0x3821, 0x3824, 0x3827, 0x382a, 0x382d, 0x3830,
+       0x3832, 0x3835, 0x3838, 0x383b, 0x383e, 0x3841, 0x3844, 0x3847, 0x384a,
+       0x384d, 0x3850, 0x3853, 0x3856, 0x3859, 0x385c, 0x385f, 0x3862, 0x3865,
+       0x3868, 0x386b, 0x386e, 0x3871, 0x3874, 0x3878, 0x387b, 0x387e, 0x3881,
+       0x3884, 0x3887, 0x388a, 0x388e, 0x3891, 0x3894, 0x3897, 0x389a, 0x389d,
+       0x38a1, 0x38a4, 0x38a7, 0x38aa, 0x38ae, 0x38b1, 0x38b4, 0x38b7, 0x38bb,
+       0x38be, 0x38c1, 0x38c4, 0x38c8, 0x38cb, 0x38ce, 0x38d2, 0x38d5, 0x38d8,
+       0x38dc, 0x38df, 0x38e3, 0x38e6, 0x38e9, 0x38ed, 0x38f0, 0x38f4, 0x38f7,
+       0x38fa, 0x38fe, 0x3901, 0x3905, 0x3908, 0x390c, 0x390f, 0x3913, 0x3916,
+       0x391a, 0x391d, 0x3921, 0x3924, 0x3928, 0x392b, 0x392f, 0x3933, 0x3936,
+       0x393a, 0x393d, 0x3941, 0x3945, 0x3948, 0x394c, 0x3950, 0x3953, 0x3957,
+       0x395b, 0x395e, 0x3962, 0x3966, 0x3969, 0x396d, 0x3971, 0x3974, 0x3978,
+       0x397c, 0x3980, 0x3983, 0x3987, 0x398b, 0x398f, 0x3993, 0x3996, 0x399a,
+       0x399e, 0x39a2, 0x39a6, 0x39aa, 0x39ad, 0x39b1, 0x39b5, 0x39b9, 0x39bd,
+       0x39c1, 0x39c5, 0x39c9, 0x39cd, 0x39d1, 0x39d5, 0x39d8, 0x39dc, 0x39e0,
+       0x39e4, 0x39e8, 0x39ec, 0x39f0, 0x39f4, 0x39f8, 0x39fc,
+};
+
+static u32 dcss_hdr10_rgb2rgb_csca[] = {
+       0x00004000, 0x00000000, 0x00000000, 0x00000000, 0x00004000, 0x00000000,
+       0x00000000, 0x00000000, 0x00004000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x000003ff, 0x000003ff, 0x000003ff,
+       0x0000000e, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x000003ff, 0x000003ff, 0x000003ff,
+};
+
+static u32 dcss_hdr10_rgb2rgb_cscb[] = {
+       0x00007fe2, 0x00000000, 0x00000000, 0x00000000, 0x00007fe2, 0x00000000,
+       0x00000000, 0x00000000, 0x00007fe2, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00003fff, 0x00003fff, 0x00003fff,
+       0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x0ffc0000, 0x0ffc0000, 0x0ffc0000,
+};
+
+static u32 dcss_hdr10_yuv2rgb_csca[] = {
+       0x0000255f, 0x00000000, 0x00003989, 0x0000255f, 0x0000f928, 0x0000eee6,
+       0x0000255f, 0x000043cc, 0x00000000, 0x000003c0, 0x00000200, 0x00000200,
+       0x00000000, 0x00000240, 0x00000240, 0x0000036c, 0x000001c0, 0x000001c0,
+       0x0000000d, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x000003ff, 0x000003ff, 0x000003ff,
+};
+
+static u32 dcss_hdr10_yuv2rgb_cscb[] = {
+       0x00007fe2, 0x00000000, 0x00000000, 0x00000000, 0x00007fe2, 0x00000000,
+       0x00000000, 0x00000000, 0x00007fe2, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00003fff, 0x00003fff, 0x00003fff,
+       0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x0ffc0000, 0x0ffc0000, 0x0ffc0000,
+};
+#endif /* DCSS_TABLES_H */
+
diff --git a/include/video/imx-dcss.h b/include/video/imx-dcss.h
new file mode 100644 (file)
index 0000000..690da53
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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.
+ */
+
+#ifndef __IMX_DCSS_H__
+#define __IMX_DCSS_H__
+
+#include <linux/types.h>
+#include <video/videomode.h>
+
+struct dcss_soc;
+
+struct dcss_client_platformdata {
+       struct device_node *of_node;
+};
+
+/* COMMON */
+int dcss_vblank_irq_get(struct dcss_soc *dcss);
+void dcss_vblank_irq_enable(struct dcss_soc *dcss, bool en);
+void dcss_vblank_irq_clear(struct dcss_soc *dcss);
+enum dcss_color_space dcss_drm_fourcc_to_colorspace(u32 drm_fourcc);
+
+/* BLKCTL */
+void dcss_blkctl_hdmi_secure_src_en(struct dcss_soc *dcss);
+
+/* DPR */
+enum dcss_tile_type {
+       TILE_LINEAR = 0,
+       TILE_GPU_STANDARD,
+       TILE_GPU_SUPER,
+       TILE_VPU_YUV420,
+       TILE_VPU_VP9,
+};
+
+enum dcss_pix_size {
+       PIX_SIZE_8,
+       PIX_SIZE_16,
+       PIX_SIZE_32,
+};
+
+void dcss_dpr_set_res(struct dcss_soc *dcss, int ch_num, u32 xres, u32 yres);
+void dcss_dpr_addr_set(struct dcss_soc *dcss, int ch_num, u32 luma_base_addr,
+                      u32 chroma_base_addr, u16 pitch);
+void dcss_dpr_enable(struct dcss_soc *dcss, int ch_num, bool en);
+void dcss_dpr_format_set(struct dcss_soc *dcss, int ch_num, u32 pix_format);
+
+/* DTG */
+void dcss_dtg_sync_set(struct dcss_soc *dcss, struct videomode *vm);
+void dcss_dtg_plane_pos_set(struct dcss_soc *dcss, int ch_num,
+                           int px, int py, int pw, int ph);
+void dcss_dtg_enable(struct dcss_soc *dcss, bool en);
+bool dcss_dtg_is_enabled(struct dcss_soc *dcss);
+void dcss_dtg_ch_enable(struct dcss_soc *dcss, int ch_num, bool en);
+void dcss_dtg_plane_alpha_set(struct dcss_soc *dcss, int ch_num,
+                             u32 pix_format, int alpha);
+bool dcss_dtg_global_alpha_changed(struct dcss_soc *dcss, int ch_num,
+                                  u32 pix_format, int alpha);
+
+/* SUBSAM */
+void dcss_ss_sync_set(struct dcss_soc *dcss, struct videomode *vm,
+                     bool phsync, bool pvsync);
+void dcss_ss_enable(struct dcss_soc *dcss, bool en);
+
+/* SCALER */
+void dcss_scaler_enable(struct dcss_soc *dcss, int ch_num, bool en);
+void dcss_scaler_setup(struct dcss_soc *dcss, int ch_num, u32 pix_format,
+                      int src_xres, int src_yres, int dst_xres, int dst_yres);
+
+/* CTXLD */
+int dcss_ctxld_enable(struct dcss_soc *dcss);
+
+/* HDR10 */
+void dcss_hdr10_pipe_csc_setup(struct dcss_soc *dcss, int ch_num,
+                              enum dcss_color_space in_cs,
+                              enum dcss_color_space out_cs);
+
+/* DTRC */
+void dcss_dtrc_bypass(struct dcss_soc *dcss, int ch_num);
+void dcss_dtrc_set_res(struct dcss_soc *dcss, int ch_num, u32 xres, u32 yres);
+void dcss_dtrc_addr_set(struct dcss_soc *dcss, int ch_num, u32 p1_ba, u32 p2_ba);
+
+enum dcss_color_space {
+       DCSS_COLORSPACE_RGB,
+       DCSS_COLORSPACE_YUV,
+       DCSS_COLORSPACE_UNKNOWN,
+};
+#endif /* __IMX_DCSS_H__ */