summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/display/imx/nxp,imx8mq-dcss.yaml93
-rw-r--r--drivers/gpu/drm/Makefile2
-rw-r--r--drivers/gpu/drm/imx/Kconfig2
-rw-r--r--drivers/gpu/drm/imx/Makefile1
-rw-r--r--drivers/gpu/drm/imx/dcss/Kconfig7
-rw-r--r--drivers/gpu/drm/imx/dcss/Makefile7
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-blkctl.c75
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-crtc.c256
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-ctxld.c452
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-dec400d.c270
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-dev.c369
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-dev.h359
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-dpr.c571
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-drv.c187
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-dtg.c454
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-dtrc.c514
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-hdr10-tables.h1311
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-hdr10.c585
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-kms.c429
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-kms.h64
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-plane.c673
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-rdsrc.c119
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-scaler.c911
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-ss.c179
-rw-r--r--drivers/gpu/drm/imx/dcss/dcss-wrscl.c158
-rw-r--r--include/linux/busfreq-imx.h77
26 files changed, 8124 insertions, 1 deletions
diff --git a/Documentation/devicetree/bindings/display/imx/nxp,imx8mq-dcss.yaml b/Documentation/devicetree/bindings/display/imx/nxp,imx8mq-dcss.yaml
new file mode 100644
index 000000000000..04a8a3e21c7b
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/imx/nxp,imx8mq-dcss.yaml
@@ -0,0 +1,93 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright 2019 NXP
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/display/imx/nxp,imx8mq-dcss.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: iMX8MQ Display Controller Subsystem (DCSS)
+
+maintainers:
+ - Laurentiu Palcu <laurentiu.palcu@nxp.com>
+
+description:
+
+ The DCSS (display controller sub system) is used to source up to three
+ display buffers, compose them, and drive a display using HDMI 2.0a(with HDCP
+ 2.2) or MIPI-DSI. The DCSS is intended to support up to 4kp60 displays. HDR10
+ image processing capabilities are included to provide a solution capable of
+ driving next generation high dynamic range displays.
+
+properties:
+ compatible:
+ const: nxp,imx8mq-dcss
+
+ reg:
+ maxItems: 2
+
+ interrupts:
+ maxItems: 3
+ items:
+ - description: Context loader completion and error interrupt
+ - description: DTG interrupt used to signal context loader trigger time
+ - description: DTG interrupt for Vblank
+
+ interrupt-names:
+ maxItems: 3
+ items:
+ - const: ctx_ld
+ - const: ctxld_kick
+ - const: vblank
+ - const: dtrc_ch1
+ - const: dtrc_ch2
+
+ clocks:
+ maxItems: 5
+ items:
+ - description: Display APB clock for all peripheral PIO access interfaces
+ - description: Display AXI clock needed by DPR, Scaler, RTRAM_CTRL
+ - description: RTRAM clock
+ - description: Pixel clock, can be driver either by HDMI phy clock or MIPI
+ - description: DTRC clock, needed by video decompressor
+ - description: PLL source clock, usually VIDEO2_PLL, used when output is HDMI;
+ - description: PLL PHY reference clock, used when output is HDMI;
+
+ clock-names:
+ items:
+ - const: apb
+ - const: axi
+ - const: rtrm
+ - const: pix
+ - const: dtrc
+ - const: pll_src
+ - const: pll_phy_ref
+
+ port@0:
+ type: object
+ description: A port node pointing to a hdmi_in or mipi_in port node.
+
+examples:
+ - |
+ dcss: display-controller@32e00000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "nxp,imx8mq-dcss";
+ reg = <0x32e00000 0x2d000>, <0x32e2f000 0x1000>;
+ interrupts = <6>, <8>, <9>, <16>, <17>;
+ interrupt-names = "ctx_ld", "ctxld_kick", "vblank", "dtrc_ch1", "dtrc_ch2";
+ interrupt-parent = <&irqsteer>;
+ clocks = <&clk 248>, <&clk 247>, <&clk 249>,
+ <&clk 254>,<&clk 122>, <&clk 266>, <&clk 267>;
+ clock-names = "apb", "axi", "rtrm", "pix", "dtrc",
+ "pll_src", "pll_phy_ref";
+ assigned-clocks = <&clk 107>, <&clk 109>, <&clk 266>;
+ assigned-clock-parents = <&clk 78>, <&clk 78>, <&clk 3>;
+ assigned-clock-rates = <800000000>,
+ <400000000>;
+ port@0 {
+ dcss_out: endpoint {
+ remote-endpoint = <&hdmi_in>;
+ };
+ };
+ };
+
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 82ff826b33cc..a6191f8d58fa 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -98,7 +98,7 @@ obj-$(CONFIG_DRM_MSM) += msm/
obj-$(CONFIG_DRM_TEGRA) += tegra/
obj-$(CONFIG_DRM_STM) += stm/
obj-$(CONFIG_DRM_STI) += sti/
-obj-$(CONFIG_DRM_IMX) += imx/
+obj-y += imx/
obj-$(CONFIG_DRM_INGENIC) += ingenic/
obj-$(CONFIG_DRM_MEDIATEK) += mediatek/
obj-$(CONFIG_DRM_MESON) += meson/
diff --git a/drivers/gpu/drm/imx/Kconfig b/drivers/gpu/drm/imx/Kconfig
index 207bf7409dfb..6231048aa5aa 100644
--- a/drivers/gpu/drm/imx/Kconfig
+++ b/drivers/gpu/drm/imx/Kconfig
@@ -39,3 +39,5 @@ config DRM_IMX_HDMI
depends on DRM_IMX
help
Choose this if you want to use HDMI on i.MX6.
+
+source "drivers/gpu/drm/imx/dcss/Kconfig"
diff --git a/drivers/gpu/drm/imx/Makefile b/drivers/gpu/drm/imx/Makefile
index 21cdcc2faabc..b644deffe948 100644
--- a/drivers/gpu/drm/imx/Makefile
+++ b/drivers/gpu/drm/imx/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o
+obj-$(CONFIG_DRM_IMX_DCSS) += dcss/
diff --git a/drivers/gpu/drm/imx/dcss/Kconfig b/drivers/gpu/drm/imx/dcss/Kconfig
new file mode 100644
index 000000000000..6399c12d4a1f
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/Kconfig
@@ -0,0 +1,7 @@
+config DRM_IMX_DCSS
+ tristate "i.MX8MQ DCSS"
+ select RESET_CONTROLLER
+ select IMX_IRQSTEER
+ help
+ Choose this if you have a NXP i.MX8MQ based system and want to use the
+ Display Controller Subsystem. This option enables DCSS support.
diff --git a/drivers/gpu/drm/imx/dcss/Makefile b/drivers/gpu/drm/imx/dcss/Makefile
new file mode 100644
index 000000000000..eb3a1860edd0
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/Makefile
@@ -0,0 +1,7 @@
+imx-dcss-objs := dcss-drv.o dcss-dev.o dcss-blkctl.o dcss-ctxld.o dcss-dtg.o \
+ dcss-ss.o dcss-dpr.o dcss-scaler.o dcss-kms.o dcss-crtc.o \
+ dcss-plane.o dcss-dec400d.o dcss-hdr10.o dcss-wrscl.o \
+ dcss-rdsrc.o dcss-dtrc.o
+
+obj-$(CONFIG_DRM_IMX_DCSS) += imx-dcss.o
+
diff --git a/drivers/gpu/drm/imx/dcss/dcss-blkctl.c b/drivers/gpu/drm/imx/dcss/dcss-blkctl.c
new file mode 100644
index 000000000000..ee7ffa18dd6d
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/dcss-blkctl.c
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/device.h>
+#include <linux/of.h>
+
+#include "dcss-dev.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 RTR_CLK_RESETN BIT(3)
+#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)
+
+struct dcss_blkctl {
+ struct device *dev;
+ void __iomem *base_reg;
+
+ bool hdmi_output;
+};
+
+void dcss_blkctl_cfg(struct dcss_blkctl *blkctl)
+{
+ if (blkctl->hdmi_output)
+ dcss_writel(0, blkctl->base_reg + DCSS_BLKCTL_CONTROL0);
+ else
+ dcss_writel(DISPMIX_PIXCLK_SEL,
+ blkctl->base_reg + DCSS_BLKCTL_CONTROL0);
+
+ dcss_set(B_CLK_RESETN | APB_CLK_RESETN | P_CLK_RESETN | RTR_CLK_RESETN,
+ blkctl->base_reg + DCSS_BLKCTL_RESET_CTRL);
+}
+
+int dcss_blkctl_init(struct dcss_dev *dcss, unsigned long blkctl_base)
+{
+ struct dcss_blkctl *blkctl;
+
+ blkctl = devm_kzalloc(dcss->dev, sizeof(*blkctl), GFP_KERNEL);
+ if (!blkctl)
+ return -ENOMEM;
+
+ blkctl->base_reg = devm_ioremap(dcss->dev, blkctl_base, SZ_4K);
+ if (!blkctl->base_reg) {
+ dev_err(dcss->dev, "unable to remap BLK CTRL base\n");
+ devm_kfree(dcss->dev, blkctl);
+ return -ENOMEM;
+ }
+
+ dcss->blkctl = blkctl;
+ blkctl->dev = dcss->dev;
+ blkctl->hdmi_output = dcss->hdmi_output;
+
+ dcss_blkctl_cfg(blkctl);
+
+ return 0;
+}
+
+void dcss_blkctl_exit(struct dcss_blkctl *blkctl)
+{
+ dcss_clr(P_CLK_RESETN | RTR_CLK_RESETN,
+ blkctl->base_reg + DCSS_BLKCTL_RESET_CTRL);
+
+ if (blkctl->base_reg)
+ devm_iounmap(blkctl->dev, blkctl->base_reg);
+
+ devm_kfree(blkctl->dev, blkctl);
+}
diff --git a/drivers/gpu/drm/imx/dcss/dcss-crtc.c b/drivers/gpu/drm/imx/dcss/dcss-crtc.c
new file mode 100644
index 000000000000..f902db364325
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/dcss-crtc.c
@@ -0,0 +1,256 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <linux/pm_runtime.h>
+
+#include "dcss-dev.h"
+#include "dcss-kms.h"
+
+static int dcss_enable_vblank(struct drm_crtc *crtc)
+{
+ struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
+ base);
+ struct dcss_dev *dcss = crtc->dev->dev_private;
+
+ if (dcss_crtc->irq_enabled)
+ return 0;
+
+ dcss_crtc->irq_enabled = true;
+
+ dcss_dtg_vblank_irq_enable(dcss->dtg, true);
+
+ dcss_dtg_ctxld_kick_irq_enable(dcss->dtg, true);
+
+ enable_irq(dcss_crtc->irq);
+
+ return 0;
+}
+
+static void dcss_disable_vblank(struct drm_crtc *crtc)
+{
+ struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
+ base);
+ struct dcss_dev *dcss = dcss_crtc->base.dev->dev_private;
+
+ disable_irq_nosync(dcss_crtc->irq);
+
+ dcss_dtg_vblank_irq_enable(dcss->dtg, false);
+
+ if (!dcss_dtrc_is_running(dcss->dtrc))
+ dcss_dtg_ctxld_kick_irq_enable(dcss->dtg, false);
+
+ dcss_crtc->irq_enabled = false;
+}
+
+static const struct drm_crtc_funcs dcss_crtc_funcs = {
+ .set_config = drm_atomic_helper_set_config,
+ .destroy = drm_crtc_cleanup,
+ .page_flip = drm_atomic_helper_page_flip,
+ .reset = drm_atomic_helper_crtc_reset,
+ .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+ .enable_vblank = dcss_enable_vblank,
+ .disable_vblank = dcss_disable_vblank,
+};
+
+static void dcss_crtc_atomic_begin(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state)
+{
+ drm_crtc_vblank_on(crtc);
+
+ spin_lock_irq(&crtc->dev->event_lock);
+ if (crtc->state->event) {
+ WARN_ON(drm_crtc_vblank_get(crtc));
+ drm_crtc_arm_vblank_event(crtc, crtc->state->event);
+ crtc->state->event = NULL;
+ }
+ spin_unlock_irq(&crtc->dev->event_lock);
+}
+
+static void dcss_crtc_atomic_flush(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state)
+{
+ struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
+ base);
+ struct dcss_dev *dcss = dcss_crtc->base.dev->dev_private;
+
+ if (dcss_dtg_is_enabled(dcss->dtg))
+ dcss_ctxld_enable(dcss->ctxld);
+}
+
+static void dcss_crtc_atomic_enable(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state)
+{
+ struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
+ base);
+ struct dcss_dev *dcss = dcss_crtc->base.dev->dev_private;
+ struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+ struct videomode vm;
+
+ drm_display_mode_to_videomode(mode, &vm);
+
+ pm_runtime_get_sync(dcss->dev);
+
+ dcss_enable_vblank(crtc);
+
+ vm.pixelclock = mode->crtc_clock * 1000;
+
+ dcss_dtg_sync_set(dcss->dtg, &vm);
+
+ dcss_ss_subsam_set(dcss->ss, dcss_crtc->output_is_yuv);
+ dcss_ss_sync_set(dcss->ss, &vm, mode->flags & DRM_MODE_FLAG_PHSYNC,
+ mode->flags & DRM_MODE_FLAG_PVSYNC);
+
+ dcss_dtg_css_set(dcss->dtg, dcss_crtc->output_is_yuv);
+
+ dcss_ss_enable(dcss->ss);
+ dcss_dtg_enable(dcss->dtg, true, NULL);
+ dcss_ctxld_enable(dcss->ctxld);
+
+ reinit_completion(&dcss_crtc->en_completion);
+ wait_for_completion_timeout(&dcss_crtc->en_completion,
+ msecs_to_jiffies(500));
+}
+
+static void dcss_crtc_atomic_disable(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state)
+{
+ struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
+ base);
+ struct dcss_dev *dcss = dcss_crtc->base.dev->dev_private;
+
+ drm_atomic_helper_disable_planes_on_crtc(old_crtc_state, false);
+
+ spin_lock_irq(&crtc->dev->event_lock);
+ if (crtc->state->event) {
+ drm_crtc_send_vblank_event(crtc, crtc->state->event);
+ crtc->state->event = NULL;
+ }
+ spin_unlock_irq(&crtc->dev->event_lock);
+
+ dcss_dtg_ctxld_kick_irq_enable(dcss->dtg, true);
+
+ dcss_ss_disable(dcss->ss);
+ dcss_dtg_enable(dcss->dtg, false, &dcss_crtc->dis_completion);
+ dcss_ctxld_enable(dcss->ctxld);
+
+ reinit_completion(&dcss_crtc->dis_completion);
+ wait_for_completion_timeout(&dcss_crtc->dis_completion,
+ msecs_to_jiffies(100));
+
+ drm_crtc_vblank_off(crtc);
+
+ dcss_dtg_ctxld_kick_irq_enable(dcss->dtg, false);
+
+ pm_runtime_put_sync(dcss->dev);
+}
+
+static const struct drm_crtc_helper_funcs dcss_helper_funcs = {
+ .atomic_begin = dcss_crtc_atomic_begin,
+ .atomic_flush = dcss_crtc_atomic_flush,
+ .atomic_enable = dcss_crtc_atomic_enable,
+ .atomic_disable = dcss_crtc_atomic_disable,
+};
+
+static irqreturn_t dcss_crtc_irq_handler(int irq, void *dev_id)
+{
+ struct dcss_crtc *dcss_crtc = dev_id;
+ struct dcss_dev *dcss = dcss_crtc->base.dev->dev_private;
+
+ if (!dcss_dtg_vblank_irq_valid(dcss->dtg))
+ return IRQ_HANDLED;
+
+ complete(&dcss_crtc->en_completion);
+
+ if (dcss_ctxld_is_flushed(dcss->ctxld))
+ drm_crtc_handle_vblank(&dcss_crtc->base);
+
+ dcss_dtg_vblank_irq_clear(dcss->dtg);
+
+ return IRQ_HANDLED;
+}
+
+int dcss_crtc_init(struct dcss_crtc *crtc, struct drm_device *drm)
+{
+ struct dcss_dev *dcss = drm->dev_private;
+ struct platform_device *pdev = to_platform_device(dcss->dev);
+ int ret;
+
+ crtc->plane[0] = dcss_plane_init(drm, drm_crtc_mask(&crtc->base),
+ DRM_PLANE_TYPE_PRIMARY, 2);
+ if (IS_ERR(crtc->plane[0]))
+ return PTR_ERR(crtc->plane[0]);
+
+ crtc->base.port = dcss->of_port;
+
+ drm_crtc_helper_add(&crtc->base, &dcss_helper_funcs);
+ ret = drm_crtc_init_with_planes(drm, &crtc->base, &crtc->plane[0]->base,
+ NULL, &dcss_crtc_funcs, NULL);
+ if (ret) {
+ dev_err(dcss->dev, "failed to init crtc\n");
+ return ret;
+ }
+
+ crtc->plane[1] = dcss_plane_init(drm, drm_crtc_mask(&crtc->base),
+ DRM_PLANE_TYPE_OVERLAY, 1);
+ if (IS_ERR(crtc->plane[1]))
+ crtc->plane[1] = NULL;
+
+ crtc->plane[2] = dcss_plane_init(drm, drm_crtc_mask(&crtc->base),
+ DRM_PLANE_TYPE_OVERLAY, 0);
+ if (IS_ERR(crtc->plane[2]))
+ crtc->plane[2] = NULL;
+
+ drm_plane_create_alpha_property(&crtc->plane[0]->base);
+
+ crtc->irq = platform_get_irq_byname(pdev, "vblank");
+ if (crtc->irq < 0) {
+ dev_err(dcss->dev, "unable to get vblank interrupt\n");
+ return crtc->irq;
+ }
+
+ init_completion(&crtc->en_completion);
+ init_completion(&crtc->dis_completion);
+
+ ret = devm_request_irq(dcss->dev, crtc->irq, dcss_crtc_irq_handler,
+ IRQF_TRIGGER_RISING, "dcss_drm", crtc);
+ if (ret) {
+ dev_err(dcss->dev, "irq request failed with %d.\n", ret);
+ return ret;
+ }
+
+ disable_irq(crtc->irq);
+
+ return 0;
+}
+
+void dcss_crtc_attach_color_mgmt_properties(struct dcss_crtc *crtc)
+{
+ int i;
+
+ /* create color management properties only for video planes */
+ for (i = 1; i < 3; i++) {
+ if (crtc->plane[i]->type == DRM_PLANE_TYPE_PRIMARY)
+ return;
+
+ drm_plane_create_color_properties(&crtc->plane[i]->base,
+ BIT(DRM_COLOR_YCBCR_BT601) |
+ BIT(DRM_COLOR_YCBCR_BT709) |
+ BIT(DRM_COLOR_YCBCR_BT2020),
+ BIT(DRM_COLOR_YCBCR_FULL_RANGE) |
+ BIT(DRM_COLOR_YCBCR_LIMITED_RANGE),
+ DRM_COLOR_YCBCR_BT709,
+ DRM_COLOR_YCBCR_FULL_RANGE);
+ }
+}
+
+void dcss_crtc_deinit(struct dcss_crtc *crtc, struct drm_device *drm)
+{
+ struct dcss_dev *dcss = drm->dev_private;
+
+ devm_free_irq(dcss->dev, crtc->irq, crtc);
+}
diff --git a/drivers/gpu/drm/imx/dcss/dcss-ctxld.c b/drivers/gpu/drm/imx/dcss/dcss-ctxld.c
new file mode 100644
index 000000000000..74617ceb5ddb
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/dcss-ctxld.c
@@ -0,0 +1,452 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include "dcss-dev.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"
+#define CTXLD_IRQ_COMPLETION (DB_COMP | SB_HP_COMP | SB_LP_COMP)
+#define CTXLD_IRQ_ERROR (RD_ERR | DB_PEND_SB_REC | AHB_ERR)
+
+/* The following sizes are in context loader 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)
+
+/* 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 {
+ struct device *dev;
+ void __iomem *ctxld_reg;
+ int irq;
+ bool irq_en;
+
+ 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 armed;
+
+ spinlock_t lock; /* protects concurent access to private data */
+
+ void (*dtg_disable_cb)(void *data);
+ void *dtg_disable_data;
+};
+
+static int __dcss_ctxld_enable(struct dcss_ctxld *ctxld);
+
+static irqreturn_t dcss_ctxld_irq_handler(int irq, void *data)
+{
+ struct dcss_ctxld *ctxld = data;
+ u32 irq_status;
+
+ irq_status = dcss_readl(ctxld->ctxld_reg + DCSS_CTXLD_CONTROL_STATUS);
+
+ if (irq_status & CTXLD_IRQ_COMPLETION &&
+ !(irq_status & CTXLD_ENABLE) && ctxld->in_use) {
+ ctxld->in_use = false;
+
+ if (ctxld->dtg_disable_cb) {
+ ctxld->dtg_disable_cb(ctxld->dtg_disable_data);
+ ctxld->dtg_disable_cb = NULL;
+ ctxld->dtg_disable_data = NULL;
+ }
+ } 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(ctxld->dev, "ctxld: error encountered: %08x\n",
+ irq_status);
+ dev_err(ctxld->dev, "ctxld: db=%d, sb_hp=%d, sb_lp=%d\n",
+ ctxld->ctx_size[ctxld->current_ctx ^ 1][CTX_DB],
+ ctxld->ctx_size[ctxld->current_ctx ^ 1][CTX_SB_HP],
+ ctxld->ctx_size[ctxld->current_ctx ^ 1][CTX_SB_LP]);
+ }
+
+ dcss_clr(irq_status & (CTXLD_IRQ_ERROR | CTXLD_IRQ_COMPLETION),
+ ctxld->ctxld_reg + DCSS_CTXLD_CONTROL_STATUS);
+
+ return IRQ_HANDLED;
+}
+
+static int dcss_ctxld_irq_config(struct dcss_ctxld *ctxld,
+ struct platform_device *pdev)
+{
+ int ret;
+
+ ctxld->irq = platform_get_irq_byname(pdev, CTXLD_IRQ_NAME);
+ if (ctxld->irq < 0) {
+ dev_err(ctxld->dev, "ctxld: can't get irq number\n");
+ return ctxld->irq;
+ }
+
+ ret = devm_request_irq(ctxld->dev, ctxld->irq,
+ dcss_ctxld_irq_handler,
+ IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
+ DCSS_CTXLD_DEVNAME, ctxld);
+ if (ret) {
+ dev_err(ctxld->dev, "ctxld: irq request failed.\n");
+ return ret;
+ }
+
+ ctxld->irq_en = true;
+
+ return 0;
+}
+
+void dcss_ctxld_hw_cfg(struct dcss_ctxld *ctxld)
+{
+ dcss_writel(RD_ERR_EN | SB_HP_COMP_EN |
+ DB_PEND_SB_REC_EN | AHB_ERR_EN | RD_ERR | AHB_ERR,
+ ctxld->ctxld_reg + DCSS_CTXLD_CONTROL_STATUS);
+}
+
+static void dcss_ctxld_free_ctx(struct dcss_ctxld *ctxld)
+{
+ struct dcss_ctxld_item *ctx;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ if (ctxld->db[i]) {
+ dmam_free_coherent(ctxld->dev,
+ CTXLD_DB_CTX_ENTRIES * sizeof(*ctx),
+ ctxld->db[i], ctxld->db_paddr[i]);
+ ctxld->db[i] = NULL;
+ ctxld->db_paddr[i] = 0;
+ }
+
+ if (ctxld->sb_hp[i]) {
+ dmam_free_coherent(ctxld->dev,
+ CTXLD_SB_CTX_ENTRIES * sizeof(*ctx),
+ ctxld->sb_hp[i], ctxld->sb_paddr[i]);
+ ctxld->sb_hp[i] = NULL;
+ ctxld->sb_paddr[i] = 0;
+ }
+ }
+}
+
+static int dcss_ctxld_alloc_ctx(struct dcss_ctxld *ctxld)
+{
+ struct dcss_ctxld_item *ctx;
+ int i;
+ dma_addr_t dma_handle;
+
+ for (i = 0; i < 2; i++) {
+ ctx = dmam_alloc_coherent(ctxld->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(ctxld->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_dev *dcss, unsigned long ctxld_base)
+{
+ struct dcss_ctxld *ctxld;
+ int ret;
+
+ ctxld = devm_kzalloc(dcss->dev, sizeof(struct dcss_ctxld),
+ GFP_KERNEL);
+ if (!ctxld)
+ return -ENOMEM;
+
+ dcss->ctxld = ctxld;
+ ctxld->dev = dcss->dev;
+
+ spin_lock_init(&ctxld->lock);
+
+ ret = dcss_ctxld_alloc_ctx(ctxld);
+ if (ret) {
+ dev_err(dcss->dev, "ctxld: cannot allocate context memory.\n");
+ goto err;
+ }
+
+ ctxld->ctxld_reg = devm_ioremap(dcss->dev, ctxld_base, SZ_4K);
+ if (!ctxld->ctxld_reg) {
+ dev_err(dcss->dev, "ctxld: unable to remap ctxld base\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ret = dcss_ctxld_irq_config(ctxld, to_platform_device(dcss->dev));
+ if (ret)
+ goto err_irq;
+
+ dcss_ctxld_hw_cfg(ctxld);
+
+ return 0;
+
+err_irq:
+ devm_iounmap(ctxld->dev, ctxld->ctxld_reg);
+
+err:
+ dcss_ctxld_free_ctx(ctxld);
+ devm_kfree(ctxld->dev, ctxld);
+
+ return ret;
+}
+
+void dcss_ctxld_exit(struct dcss_ctxld *ctxld)
+{
+ devm_free_irq(ctxld->dev, ctxld->irq, ctxld);
+
+ if (ctxld->ctxld_reg)
+ devm_iounmap(ctxld->dev, ctxld->ctxld_reg);
+
+ dcss_ctxld_free_ctx(ctxld);
+ devm_kfree(ctxld->dev, ctxld);
+}
+
+static int __dcss_ctxld_enable(struct dcss_ctxld *ctxld)
+{
+ int curr_ctx = ctxld->current_ctx;
+ u32 db_base, sb_base, sb_count;
+ u32 sb_hp_cnt, sb_lp_cnt, db_cnt;
+ struct dcss_dev *dcss = dcss_drv_dev_to_dcss(ctxld->dev);
+
+ dcss_dpr_write_sysctrl(dcss->dpr);
+
+ dcss_scaler_write_sclctrl(dcss->scaler);
+
+ if (dcss_dtrc_is_running(dcss->dtrc)) {
+ dcss_dtrc_switch_banks(dcss->dtrc);
+ ctxld->armed = true;
+ }
+
+ 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;
+}
+
+int dcss_ctxld_enable(struct dcss_ctxld *ctxld)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctxld->lock, flags);
+ ctxld->armed = true;
+ spin_unlock_irqrestore(&ctxld->lock, flags);
+
+ return 0;
+}
+
+void dcss_ctxld_kick(struct dcss_ctxld *ctxld)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctxld->lock, flags);
+ if (ctxld->armed && !ctxld->in_use) {
+ ctxld->armed = false;
+ __dcss_ctxld_enable(ctxld);
+ }
+ spin_unlock_irqrestore(&ctxld->lock, flags);
+}
+
+void dcss_ctxld_write_irqsafe(struct dcss_ctxld *ctxld, u32 ctx_id, u32 val,
+ u32 reg_ofs)
+{
+ 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 (item_idx + 1 > dcss_ctxld_ctx_size[ctx_id]) {
+ WARN_ON(1);
+ return;
+ }
+
+ ctx[ctx_id][item_idx].val = val;
+ ctx[ctx_id][item_idx].ofs = reg_ofs;
+ ctxld->ctx_size[curr_ctx][ctx_id] += 1;
+}
+
+void dcss_ctxld_write(struct dcss_ctxld *ctxld, u32 ctx_id,
+ u32 val, u32 reg_ofs)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctxld->lock, flags);
+ dcss_ctxld_write_irqsafe(ctxld, ctx_id, val, reg_ofs);
+ spin_unlock_irqrestore(&ctxld->lock, flags);
+}
+
+bool dcss_ctxld_is_flushed(struct dcss_ctxld *ctxld)
+{
+ return 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;
+}
+
+int dcss_ctxld_resume(struct dcss_ctxld *ctxld)
+{
+ dcss_ctxld_hw_cfg(ctxld);
+
+ if (!ctxld->irq_en) {
+ enable_irq(ctxld->irq);
+ ctxld->irq_en = true;
+ }
+
+ return 0;
+}
+
+int dcss_ctxld_suspend(struct dcss_ctxld *ctxld)
+{
+ int ret = 0;
+ int wait_time_ms = 0;
+ unsigned long flags;
+
+ dcss_ctxld_kick(ctxld);
+
+ while (ctxld->in_use && wait_time_ms < 500) {
+ msleep(20);
+ wait_time_ms += 20;
+ }
+
+ if (wait_time_ms > 500)
+ return -ETIMEDOUT;
+
+ spin_lock_irqsave(&ctxld->lock, flags);
+
+ if (ctxld->irq_en) {
+ disable_irq_nosync(ctxld->irq);
+ ctxld->irq_en = false;
+ }
+
+ /* reset context region and sizes */
+ ctxld->current_ctx = 0;
+ ctxld->ctx_size[0][CTX_DB] = 0;
+ ctxld->ctx_size[0][CTX_SB_HP] = 0;
+ ctxld->ctx_size[0][CTX_SB_LP] = 0;
+
+ spin_unlock_irqrestore(&ctxld->lock, flags);
+
+ return ret;
+}
+
+void dcss_ctxld_register_dtg_disable_cb(struct dcss_ctxld *ctxld,
+ void (*cb)(void *),
+ void *data)
+{
+ ctxld->dtg_disable_cb = cb;
+ ctxld->dtg_disable_data = data;
+}
diff --git a/drivers/gpu/drm/imx/dcss/dcss-dec400d.c b/drivers/gpu/drm/imx/dcss/dcss-dec400d.c
new file mode 100644
index 000000000000..44675b686228
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/dcss-dec400d.c
@@ -0,0 +1,270 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/device.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <drm/drm_fourcc.h>
+
+#include "dcss-dev.h"
+
+/* DEC400D registers offsets */
+#define DEC400D_READCONFIG_BASE 0x800
+#define DEC400D_READCONFIG(i) (DEC400D_READCONFIG_BASE + ((i) << 2))
+#define COMPRESSION_ENABLE_BIT BIT(0)
+#define COMPRESSION_FORMAT_POS 3
+#define COMPRESSION_ALIGN_MODE_POS 16
+#define TILE_ALIGN_MODE_POS 22
+#define TILE_MODE_POS 25
+#define DEC400D_READBUFFERBASE0 0x900
+#define DEC400D_READCACHEBASE0 0x980
+#define DEC400D_CONTROL 0xB00
+#define DEC400D_CLEAR 0xB80
+#define DEC400D_READBUFFERBASE0 0x900
+#define DEC400D_READCACHEBASE0 0x980
+#define DEC400D_CONTROL 0xB00
+#define DISABLE_COMPRESSION_BIT BIT(1)
+#define SHADOW_TRIGGER_BIT BIT(29)
+#define DEC400_CFMT_ARGB8 0x0
+#define DEC400_CFMT_XRGB8 0x1
+#define DEC400_CFMT_AYUV 0x2
+#define DEC400_CFMT_UYVY 0x3
+#define DEC400_CFMT_YUY2 0x4
+#define DEC400_CFMT_YUV_ONLY 0x5
+#define DEC400_CFMT_UV_MIX 0x6
+#define DEC400_CFMT_ARGB4 0x7
+#define DEC400_CFMT_XRGB4 0x8
+#define DEC400_CFMT_A1R5G5B5 0x9
+#define DEC400_CFMT_X1R5G5B5 0xA
+#define DEC400_CFMT_R5G6B5 0xB
+#define DEC400_CFMT_Z24S8 0xC
+#define DEC400_CFMT_Z24 0xD
+#define DEC400_CFMT_Z16 0xE
+#define DEC400_CFMT_A2R10G10B10 0xF
+#define DEC400_CFMT_BAYER 0x10
+#define DEC400_CFMT_SIGNED_BAYER 0x11
+
+struct dcss_dec400d {
+ struct device *dev;
+ void __iomem *base_reg;
+ u32 base_ofs;
+ struct dcss_ctxld *ctxld;
+ u32 ctx_id;
+ bool bypass; /* bypass or decompress */
+};
+
+static void dcss_dec400d_write(struct dcss_dec400d *dec400d,
+ u32 value,
+ u32 offset)
+{
+ dcss_ctxld_write(dec400d->ctxld, dec400d->ctx_id,
+ value, dec400d->base_ofs + offset);
+}
+
+int dcss_dec400d_init(struct dcss_dev *dcss, unsigned long dec400d_base)
+{
+ struct dcss_dec400d *dec400d;
+ int ret;
+
+ dec400d = devm_kzalloc(dcss->dev, sizeof(*dec400d), GFP_KERNEL);
+ if (!dec400d)
+ return -ENOMEM;
+
+ dcss->dec400d = dec400d;
+ dec400d->dev = dcss->dev;
+ dec400d->ctxld = dcss->ctxld;
+
+ dec400d->base_reg = devm_ioremap(dcss->dev, dec400d_base, SZ_4K);
+ if (!dec400d->base_reg) {
+ dev_err(dcss->dev, "dec400d: unable to remap dec400d base\n");
+ ret = -ENOMEM;
+ goto free_mem;
+ }
+
+ dec400d->base_ofs = dec400d_base;
+
+ dec400d->ctx_id = CTX_SB_HP;
+
+ return 0;
+
+free_mem:
+ devm_kfree(dcss->dev, dcss->dec400d);
+ return ret;
+}
+
+void dcss_dec400d_exit(struct dcss_dec400d *dec400d)
+{
+ if (dec400d->base_reg)
+ devm_iounmap(dec400d->dev, dec400d->base_reg);
+
+ devm_kfree(dec400d->dev, dec400d);
+}
+
+void dcss_dec400d_read_config(struct dcss_dec400d *dec400d,
+ u32 read_id,
+ bool compress_en,
+ u32 compress_format)
+{
+ u32 cformat = 0;
+ u32 read_config = 0x0;
+
+ /* TODO: using 'read_id' 0 by default */
+ if (read_id) {
+ WARN_ON(1);
+ return;
+ }
+
+ if (!compress_en)
+ goto config;
+
+ switch (compress_format) {
+ case _VIV_CFMT_ARGB8:
+ cformat = DEC400_CFMT_ARGB8;
+ break;
+ case _VIV_CFMT_XRGB8:
+ cformat = DEC400_CFMT_XRGB8;
+ break;
+ case _VIV_CFMT_AYUV:
+ cformat = DEC400_CFMT_AYUV;
+ break;
+ case _VIV_CFMT_UYVY:
+ cformat = DEC400_CFMT_UYVY;
+ break;
+ case _VIV_CFMT_YUY2:
+ cformat = DEC400_CFMT_YUY2;
+ break;
+ case _VIV_CFMT_YUV_ONLY:
+ cformat = DEC400_CFMT_YUV_ONLY;
+ break;
+ case _VIV_CFMT_UV_MIX:
+ cformat = DEC400_CFMT_UV_MIX;
+ break;
+ case _VIV_CFMT_ARGB4:
+ cformat = DEC400_CFMT_ARGB4;
+ break;
+ case _VIV_CFMT_XRGB4:
+ cformat = DEC400_CFMT_XRGB4;
+ break;
+ case _VIV_CFMT_A1R5G5B5:
+ cformat = DEC400_CFMT_A1R5G5B5;
+ break;
+ case _VIV_CFMT_X1R5G5B5:
+ cformat = DEC400_CFMT_X1R5G5B5;
+ break;
+ case _VIV_CFMT_R5G6B5:
+ cformat = DEC400_CFMT_R5G6B5;
+ break;
+ case _VIV_CFMT_Z24S8:
+ cformat = DEC400_CFMT_Z24S8;
+ break;
+ case _VIV_CFMT_Z24:
+ cformat = DEC400_CFMT_Z24;
+ break;
+ case _VIV_CFMT_Z16:
+ cformat = DEC400_CFMT_Z16;
+ break;
+ case _VIV_CFMT_A2R10G10B10:
+ cformat = DEC400_CFMT_A2R10G10B10;
+ break;
+ case _VIV_CFMT_BAYER:
+ cformat = DEC400_CFMT_BAYER;
+ break;
+ case _VIV_CFMT_SIGNED_BAYER:
+ cformat = DEC400_CFMT_SIGNED_BAYER;
+ break;
+ default:
+ /* TODO: not support yet */
+ WARN_ON(1);
+ return;
+ }
+
+ /* Dec compress format */
+ read_config |= cformat << COMPRESSION_FORMAT_POS;
+
+ /* ALIGN32_BYTE */
+ read_config |= 0x2 << COMPRESSION_ALIGN_MODE_POS;
+
+ /* TILE1_ALIGN */
+ read_config |= 0x0 << TILE_ALIGN_MODE_POS;
+
+ /* TILE8x4 */
+ read_config |= 0x3 << TILE_MODE_POS;
+
+ /* Compression Enable */
+ read_config |= COMPRESSION_ENABLE_BIT;
+
+config:
+ dcss_dec400d_write(dec400d, read_config, DEC400D_READCONFIG(read_id));
+}
+
+void dcss_dec400d_bypass(struct dcss_dec400d *dec400d)
+{
+ u32 control;
+
+ dcss_dec400d_read_config(dec400d, 0, false, 0);
+
+ control = dcss_readl(dec400d->base_reg + DEC400D_CONTROL);
+ dev_dbg(dec400d->dev, "%s: dec400d control = %#x\n", __func__, control);
+
+ control |= DISABLE_COMPRESSION_BIT;
+ dcss_dec400d_write(dec400d, control, DEC400D_CONTROL);
+
+ /* Trigger shadow registers */
+ control |= SHADOW_TRIGGER_BIT;
+ dcss_dec400d_write(dec400d, control, DEC400D_CONTROL);
+
+ dec400d->bypass = true;
+}
+
+void dcss_dec400d_shadow_trig(struct dcss_dec400d *dec400d)
+{
+ u32 control;
+
+ /* do nothing */
+ if (dec400d->bypass)
+ return;
+
+ control = dcss_readl(dec400d->base_reg + DEC400D_CONTROL);
+
+ /* Trigger shadow registers */
+ control |= SHADOW_TRIGGER_BIT;
+ dcss_dec400d_write(dec400d, control, DEC400D_CONTROL);
+}
+
+void dcss_dec400d_addr_set(struct dcss_dec400d *dec400d, u32 baddr, u32 caddr)
+{
+ /* set frame buffer base addr */
+ dcss_dec400d_write(dec400d, baddr, DEC400D_READBUFFERBASE0);
+
+ /* set tile status cache addr */
+ dcss_dec400d_write(dec400d, caddr, DEC400D_READCACHEBASE0);
+
+ dec400d->bypass = false;
+}
+
+void dcss_dec400d_fast_clear_config(struct dcss_dec400d *dec400d,
+ u32 fc_value,
+ bool enable)
+{
+ dcss_dec400d_write(dec400d, fc_value, DEC400D_CLEAR);
+}
+
+void dcss_dec400d_enable(struct dcss_dec400d *dec400d)
+{
+ u32 control;
+
+ if (dec400d->bypass)
+ return;
+
+ control = dcss_readl(dec400d->base_reg + DEC400D_CONTROL);
+
+ /* enable compression */
+ control &= ~(DISABLE_COMPRESSION_BIT);
+ dcss_dec400d_write(dec400d, control, DEC400D_CONTROL);
+
+ /* Trigger shadow registers */
+ control |= SHADOW_TRIGGER_BIT;
+ dcss_dec400d_write(dec400d, control, DEC400D_CONTROL);
+}
diff --git a/drivers/gpu/drm/imx/dcss/dcss-dev.c b/drivers/gpu/drm/imx/dcss/dcss-dev.c
new file mode 100644
index 000000000000..53b578d7785c
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/dcss-dev.c
@@ -0,0 +1,369 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/clk.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_qos.h>
+#include <linux/busfreq-imx.h>
+#include <drm/drm_modeset_helper.h>
+
+#include "dcss-dev.h"
+
+static void dcss_clocks_enable(struct dcss_dev *dcss)
+{
+ if (dcss->clks_on)
+ return;
+
+ if (dcss->hdmi_output) {
+ clk_prepare_enable(dcss->pll_phy_ref_clk);
+ clk_prepare_enable(dcss->pll_src_clk);
+ }
+
+ clk_prepare_enable(dcss->axi_clk);
+ clk_prepare_enable(dcss->apb_clk);
+ clk_prepare_enable(dcss->rtrm_clk);
+ clk_prepare_enable(dcss->dtrc_clk);
+ clk_prepare_enable(dcss->pix_clk);
+
+ dcss->clks_on = true;
+}
+
+static void dcss_clocks_disable(struct dcss_dev *dcss)
+{
+ if (!dcss->clks_on)
+ return;
+
+ clk_disable_unprepare(dcss->pix_clk);
+ clk_disable_unprepare(dcss->dtrc_clk);
+ clk_disable_unprepare(dcss->rtrm_clk);
+ clk_disable_unprepare(dcss->apb_clk);
+ clk_disable_unprepare(dcss->axi_clk);
+
+ if (dcss->hdmi_output) {
+ clk_disable_unprepare(dcss->pll_src_clk);
+ clk_disable_unprepare(dcss->pll_phy_ref_clk);
+ }
+
+ dcss->clks_on = false;
+}
+
+static void dcss_busfreq_enable(struct dcss_dev *dcss)
+{
+ if (dcss->bus_freq_on)
+ return;
+
+ request_bus_freq(BUS_FREQ_HIGH);
+
+ dcss->bus_freq_on = true;
+}
+
+static void dcss_busfreq_disable(struct dcss_dev *dcss)
+{
+ if (!dcss->bus_freq_on)
+ return;
+
+ release_bus_freq(BUS_FREQ_HIGH);
+
+ dcss->bus_freq_on = false;
+}
+
+static int dcss_submodules_init(struct dcss_dev *dcss)
+{
+ int ret = 0;
+ u32 base_addr = dcss->start_addr;
+ const struct dcss_type_data *devtype = dcss->devtype;
+
+ dcss_clocks_enable(dcss);
+
+ ret = dcss_blkctl_init(dcss, base_addr + devtype->blkctl_ofs);
+ if (ret)
+ return ret;
+
+ ret = dcss_ctxld_init(dcss, base_addr + devtype->ctxld_ofs);
+ if (ret)
+ goto ctxld_err;
+
+ ret = dcss_dtg_init(dcss, base_addr + devtype->dtg_ofs);
+ if (ret)
+ goto dtg_err;
+
+ ret = dcss_ss_init(dcss, base_addr + devtype->ss_ofs);
+ if (ret)
+ goto ss_err;
+
+ ret = dcss_dtrc_init(dcss, base_addr + devtype->dtrc_ofs);
+ if (ret)
+ goto dtrc_err;
+
+ ret = dcss_dpr_init(dcss, base_addr + devtype->dpr_ofs);
+ if (ret)
+ goto dpr_err;
+
+ ret = dcss_wrscl_init(dcss, base_addr + devtype->wrscl_ofs);
+ if (ret)
+ goto wrscl_err;
+
+ ret = dcss_rdsrc_init(dcss, base_addr + devtype->rdsrc_ofs);
+ if (ret)
+ goto rdsrc_err;
+
+ ret = dcss_scaler_init(dcss, base_addr + devtype->scaler_ofs);
+ if (ret)
+ goto scaler_err;
+
+ ret = dcss_dec400d_init(dcss, base_addr + devtype->dec400d_ofs);
+ if (ret)
+ goto dec400d_err;
+
+ ret = dcss_hdr10_init(dcss, base_addr + devtype->hdr10_ofs);
+ if (ret)
+ goto hdr10_err;
+
+ return 0;
+
+hdr10_err:
+ dcss_dec400d_exit(dcss->dec400d);
+
+dec400d_err:
+ dcss_scaler_exit(dcss->scaler);
+
+scaler_err:
+ dcss_rdsrc_exit(dcss->rdsrc);
+
+rdsrc_err:
+ dcss_wrscl_exit(dcss->wrscl);
+
+wrscl_err:
+ dcss_dpr_exit(dcss->dpr);
+
+dpr_err:
+ dcss_dtrc_exit(dcss->dtrc);
+
+dtrc_err:
+ dcss_ss_exit(dcss->ss);
+
+ss_err:
+ dcss_dtg_exit(dcss->dtg);
+
+dtg_err:
+ dcss_ctxld_exit(dcss->ctxld);
+
+ctxld_err:
+ dcss_blkctl_exit(dcss->blkctl);
+
+ dcss_clocks_disable(dcss);
+
+ return ret;
+}
+
+static void dcss_submodules_stop(struct dcss_dev *dcss)
+{
+ dcss_clocks_enable(dcss);
+ dcss_hdr10_exit(dcss->hdr10);
+ dcss_dec400d_exit(dcss->dec400d);
+ dcss_scaler_exit(dcss->scaler);
+ dcss_rdsrc_exit(dcss->rdsrc);
+ dcss_wrscl_exit(dcss->wrscl);
+ dcss_dpr_exit(dcss->dpr);
+ dcss_dtrc_exit(dcss->dtrc);
+ dcss_ss_exit(dcss->ss);
+ dcss_dtg_exit(dcss->dtg);
+ dcss_ctxld_exit(dcss->ctxld);
+ dcss_blkctl_exit(dcss->blkctl);
+ dcss_clocks_disable(dcss);
+}
+
+static int dcss_clks_init(struct dcss_dev *dcss)
+{
+ int i;
+ struct {
+ const char *id;
+ struct clk **clk;
+ bool required;
+ } clks[] = {
+ {"apb", &dcss->apb_clk, true},
+ {"axi", &dcss->axi_clk, true},
+ {"pix", &dcss->pix_clk, true},
+ {"rtrm", &dcss->rtrm_clk, true},
+ {"dtrc", &dcss->dtrc_clk, true},
+ {"pll_src", &dcss->pll_src_clk, dcss->hdmi_output},
+ {"pll_phy_ref", &dcss->pll_phy_ref_clk, dcss->hdmi_output},
+ };
+
+ 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) && clks[i].required) {
+ dev_err(dcss->dev, "failed to get %s clock\n",
+ clks[i].id);
+ return PTR_ERR(*clks[i].clk);
+ }
+ }
+
+ dcss->clks_on = false;
+
+ return 0;
+}
+
+static void dcss_clks_release(struct dcss_dev *dcss)
+{
+ devm_clk_put(dcss->dev, dcss->dtrc_clk);
+ devm_clk_put(dcss->dev, dcss->rtrm_clk);
+ devm_clk_put(dcss->dev, dcss->pix_clk);
+ devm_clk_put(dcss->dev, dcss->axi_clk);
+ devm_clk_put(dcss->dev, dcss->apb_clk);
+}
+
+struct dcss_dev *dcss_dev_create(struct device *dev, bool hdmi_output)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ int ret;
+ struct resource *res;
+ struct dcss_dev *dcss;
+ const struct dcss_type_data *devtype;
+
+ devtype = of_device_get_match_data(dev);
+ if (!devtype) {
+ dev_err(dev, "no device match found\n");
+ return ERR_PTR(-ENODEV);
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "cannot get memory resource\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ dcss = devm_kzalloc(dev, sizeof(struct dcss_dev), GFP_KERNEL);
+ if (!dcss)
+ return ERR_PTR(-ENOMEM);
+
+ dcss->dev = dev;
+ dcss->devtype = devtype;
+ dcss->hdmi_output = hdmi_output;
+
+ ret = dcss_clks_init(dcss);
+ if (ret) {
+ dev_err(dev, "clocks initialization failed\n");
+ goto err;
+ }
+
+ dcss->of_port = of_graph_get_port_by_id(dev->of_node, 0);
+ if (!dcss->of_port) {
+ dev_err(dev, "no port@0 node in %s\n", dev->of_node->full_name);
+ ret = -ENODEV;
+ goto clks_err;
+ }
+
+ dcss->start_addr = res->start;
+
+ ret = dcss_submodules_init(dcss);
+ if (ret) {
+ dev_err(dev, "submodules initialization failed\n");
+ goto clks_err;
+ }
+
+ pm_runtime_enable(dev);
+
+ return dcss;
+
+clks_err:
+ dcss_clks_release(dcss);
+
+err:
+ devm_kfree(dcss->dev, dcss);
+
+ return ERR_PTR(ret);
+}
+
+void dcss_dev_destroy(struct dcss_dev *dcss)
+{
+ pm_runtime_disable(dcss->dev);
+
+ dcss_submodules_stop(dcss);
+
+ dcss_clks_release(dcss);
+
+ devm_kfree(dcss->dev, dcss);
+}
+
+#ifdef CONFIG_PM_SLEEP
+int dcss_dev_suspend(struct device *dev)
+{
+ struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dev);
+ int ret;
+
+ drm_mode_config_helper_suspend(dcss_drv_dev_to_drm(dev));
+
+ if (pm_runtime_suspended(dev))
+ return 0;
+
+ ret = dcss_ctxld_suspend(dcss->ctxld);
+ if (ret)
+ return ret;
+
+ dcss_clocks_disable(dcss);
+
+ dcss_busfreq_disable(dcss);
+
+ return 0;
+}
+
+int dcss_dev_resume(struct device *dev)
+{
+ struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dev);
+
+ if (pm_runtime_suspended(dev)) {
+ drm_mode_config_helper_resume(dcss_drv_dev_to_drm(dev));
+ return 0;
+ }
+
+ dcss_busfreq_enable(dcss);
+
+ dcss_clocks_enable(dcss);
+
+ dcss_blkctl_cfg(dcss->blkctl);
+
+ dcss_ctxld_resume(dcss->ctxld);
+
+ drm_mode_config_helper_resume(dcss_drv_dev_to_drm(dev));
+
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM
+int dcss_dev_runtime_suspend(struct device *dev)
+{
+ struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dev);
+ int ret;
+
+ ret = dcss_ctxld_suspend(dcss->ctxld);
+ if (ret)
+ return ret;
+
+ dcss_clocks_disable(dcss);
+
+ dcss_busfreq_disable(dcss);
+
+ return 0;
+}
+
+int dcss_dev_runtime_resume(struct device *dev)
+{
+ struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dev);
+
+ dcss_busfreq_enable(dcss);
+
+ dcss_clocks_enable(dcss);
+
+ dcss_blkctl_cfg(dcss->blkctl);
+
+ dcss_ctxld_resume(dcss->ctxld);
+
+ return 0;
+}
+#endif /* CONFIG_PM */
diff --git a/drivers/gpu/drm/imx/dcss/dcss-dev.h b/drivers/gpu/drm/imx/dcss/dcss-dev.h
new file mode 100644
index 000000000000..591a4b7a474e
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/dcss-dev.h
@@ -0,0 +1,359 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2019 NXP.
+ */
+
+#ifndef __DCSS_PRV_H__
+#define __DCSS_PRV_H__
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_fourcc.h>
+#include <linux/io.h>
+#include <video/videomode.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)
+
+static inline void dcss_update(u32 v, u32 m, void __iomem *c)
+{
+ writel((readl(c) & ~(m)) | (v), (c));
+}
+
+#define DCSS_DBG_REG(reg) {.name = #reg, .ofs = reg}
+
+enum {
+ DCSS_IMX8MQ = 0,
+};
+
+struct dcss_type_data {
+ 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;
+};
+
+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_dev {
+ struct device *dev;
+ const struct dcss_type_data *devtype;
+ struct device_node *of_port;
+
+ u32 start_addr;
+
+ struct dcss_blkctl *blkctl;
+ struct dcss_ctxld *ctxld;
+ struct dcss_dpr *dpr;
+ struct dcss_dtg *dtg;
+ struct dcss_ss *ss;
+ struct dcss_hdr10 *hdr10;
+ struct dcss_scaler *scaler;
+ struct dcss_dtrc *dtrc;
+ struct dcss_dec400d *dec400d;
+ struct dcss_wrscl *wrscl;
+ struct dcss_rdsrc *rdsrc;
+
+ struct clk *apb_clk;
+ struct clk *axi_clk;
+ struct clk *pix_clk;
+ struct clk *rtrm_clk;
+ struct clk *dtrc_clk;
+ struct clk *pll_src_clk;
+ struct clk *pll_phy_ref_clk;
+
+ void (*dcss_disable_callback)(void *data);
+
+ bool clks_on;
+ bool bus_freq_on;
+ bool hdmi_output;
+};
+
+enum dcss_color_space {
+ DCSS_COLORSPACE_RGB,
+ DCSS_COLORSPACE_YUV,
+ DCSS_COLORSPACE_UNKNOWN,
+};
+
+struct dcss_dev *dcss_drv_dev_to_dcss(struct device *dev);
+struct drm_device *dcss_drv_dev_to_drm(struct device *dev);
+struct dcss_dev *dcss_dev_create(struct device *dev, bool mipi_output);
+void dcss_dev_destroy(struct dcss_dev *dcss);
+int dcss_dev_runtime_suspend(struct device *dev);
+int dcss_dev_runtime_resume(struct device *dev);
+int dcss_dev_suspend(struct device *dev);
+int dcss_dev_resume(struct device *dev);
+
+/* BLKCTL */
+int dcss_blkctl_init(struct dcss_dev *dcss, unsigned long blkctl_base);
+void dcss_blkctl_cfg(struct dcss_blkctl *blkctl);
+void dcss_blkctl_exit(struct dcss_blkctl *blkctl);
+
+/* CTXLD */
+int dcss_ctxld_init(struct dcss_dev *dcss, unsigned long ctxld_base);
+void dcss_ctxld_exit(struct dcss_ctxld *ctxld);
+void dcss_ctxld_write(struct dcss_ctxld *ctxld, u32 ctx_id,
+ u32 val, u32 reg_idx);
+int dcss_ctxld_resume(struct dcss_ctxld *dcss_ctxld);
+int dcss_ctxld_suspend(struct dcss_ctxld *dcss_ctxld);
+void dcss_ctxld_write_irqsafe(struct dcss_ctxld *ctlxd, u32 ctx_id, u32 val,
+ u32 reg_ofs);
+void dcss_ctxld_kick(struct dcss_ctxld *ctxld);
+bool dcss_ctxld_is_flushed(struct dcss_ctxld *ctxld);
+int dcss_ctxld_enable(struct dcss_ctxld *ctxld);
+void dcss_ctxld_register_dtg_disable_cb(struct dcss_ctxld *ctxld,
+ void (*cb)(void *),
+ void *data);
+void dcss_ctxld_register_dtrc_cb(struct dcss_ctxld *ctxld,
+ bool (*cb)(void *),
+ void *data);
+
+/* 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,
+};
+
+int dcss_dpr_init(struct dcss_dev *dcss, unsigned long dpr_base);
+void dcss_dpr_exit(struct dcss_dpr *dpr);
+void dcss_dpr_write_sysctrl(struct dcss_dpr *dpr);
+void dcss_dpr_set_res(struct dcss_dpr *dpr, int ch_num, u32 xres, u32 yres);
+void dcss_dpr_addr_set(struct dcss_dpr *dpr, int ch_num, u32 luma_base_addr,
+ u32 chroma_base_addr, u16 pitch);
+void dcss_dpr_enable(struct dcss_dpr *dpr, int ch_num, bool en);
+void dcss_dpr_format_set(struct dcss_dpr *dpr, int ch_num,
+ const struct drm_format_info *format, u64 modifier);
+void dcss_dpr_set_rotation(struct dcss_dpr *dpr, int ch_num, u32 rotation);
+
+/* DTG */
+int dcss_dtg_init(struct dcss_dev *dcss, unsigned long dtg_base);
+void dcss_dtg_exit(struct dcss_dtg *dtg);
+bool dcss_dtg_vblank_irq_valid(struct dcss_dtg *dtg);
+void dcss_dtg_vblank_irq_enable(struct dcss_dtg *dtg, bool en);
+void dcss_dtg_vblank_irq_clear(struct dcss_dtg *dtg);
+void dcss_dtg_sync_set(struct dcss_dtg *dtg, struct videomode *vm);
+void dcss_dtg_css_set(struct dcss_dtg *dtg, bool out_is_yuv);
+void dcss_dtg_enable(struct dcss_dtg *dtg, bool en,
+ struct completion *dis_completion);
+bool dcss_dtg_is_enabled(struct dcss_dtg *dtg);
+void dcss_dtg_ctxld_kick_irq_enable(struct dcss_dtg *dtg, bool en);
+bool dcss_dtg_global_alpha_changed(struct dcss_dtg *dtg, int ch_num, int alpha);
+void dcss_dtg_plane_alpha_set(struct dcss_dtg *dtg, int ch_num,
+ const struct drm_format_info *format, int alpha);
+void dcss_dtg_plane_pos_set(struct dcss_dtg *dtg, int ch_num,
+ int px, int py, int pw, int ph);
+void dcss_dtg_ch_enable(struct dcss_dtg *dtg, int ch_num, bool en);
+
+/* SUBSAM */
+int dcss_ss_init(struct dcss_dev *dcss, unsigned long subsam_base);
+void dcss_ss_exit(struct dcss_ss *ss);
+void dcss_ss_enable(struct dcss_ss *ss);
+void dcss_ss_disable(struct dcss_ss *ss);
+void dcss_ss_subsam_set(struct dcss_ss *ss, bool output_is_yuv);
+void dcss_ss_sync_set(struct dcss_ss *ss, struct videomode *vm,
+ bool phsync, bool pvsync);
+
+/* SCALER */
+int dcss_scaler_init(struct dcss_dev *dcss, unsigned long scaler_base);
+void dcss_scaler_exit(struct dcss_scaler *scl);
+void dcss_scaler_setup(struct dcss_scaler *scl, int ch_num,
+ const struct drm_format_info *format,
+ int src_xres, int src_yres, int dst_xres, int dst_yres,
+ u32 vrefresh_hz);
+void dcss_scaler_ch_enable(struct dcss_scaler *scl, int ch_num, bool en);
+int dcss_scaler_get_min_max_ratios(struct dcss_scaler *scl, int ch_num,
+ int *min, int *max);
+void dcss_scaler_write_sclctrl(struct dcss_scaler *scl);
+
+/* DEC400D */
+
+#define VIV_VIDMEM_METADATA_MAGIC fourcc_code('v', 'i', 'v', 'm')
+
+/* Compressed format now was defined same as dec400d, should be general. */
+typedef enum _VIV_COMPRESS_FMT
+{
+ _VIV_CFMT_ARGB8 = 0,
+ _VIV_CFMT_XRGB8,
+ _VIV_CFMT_AYUV,
+ _VIV_CFMT_UYVY,
+ _VIV_CFMT_YUY2,
+ _VIV_CFMT_YUV_ONLY,
+ _VIV_CFMT_UV_MIX,
+ _VIV_CFMT_ARGB4,
+ _VIV_CFMT_XRGB4,
+ _VIV_CFMT_A1R5G5B5,
+ _VIV_CFMT_X1R5G5B5,
+ _VIV_CFMT_R5G6B5,
+ _VIV_CFMT_Z24S8,
+ _VIV_CFMT_Z24,
+ _VIV_CFMT_Z16,
+ _VIV_CFMT_A2R10G10B10,
+ _VIV_CFMT_BAYER,
+ _VIV_CFMT_SIGNED_BAYER,
+ _VIV_CFMT_VAA16,
+ _VIV_CFMT_S8,
+
+ _VIV_CFMT_MAX,
+} _VIV_COMPRESS_FMT;
+
+/* Metadata for cross-device fd share with additional (ts) info. */
+typedef struct _VIV_VIDMEM_METADATA
+{
+ uint32_t magic;
+
+ int32_t ts_fd;
+ void * ts_dma_buf;
+
+ uint32_t fc_enabled;
+ uint32_t fc_value;
+ uint32_t fc_value_upper;
+
+ uint32_t compressed;
+ uint32_t compress_format;
+} _VIV_VIDMEM_METADATA;
+
+int dcss_dec400d_init(struct dcss_dev *dcss, unsigned long dec400d_base);
+void dcss_dec400d_exit(struct dcss_dec400d *dec400d);
+void dcss_dec400d_bypass(struct dcss_dec400d *dec400d);
+void dcss_dec400d_shadow_trig(struct dcss_dec400d *dec400d);
+void dcss_dec400d_enable(struct dcss_dec400d *dec400d);
+void dcss_dec400d_fast_clear_config(struct dcss_dec400d *dec400d,
+ u32 fc_value,
+ bool enable);
+void dcss_dec400d_read_config(struct dcss_dec400d *dec400d,
+ u32 read_id,
+ bool compress_en,
+ u32 compress_format);
+void dcss_dec400d_addr_set(struct dcss_dec400d *dec400d, u32 baddr, u32 caddr);
+
+/* HDR10 */
+enum dcss_hdr10_nonlinearity {
+ NL_REC2084,
+ NL_REC709,
+ NL_BT1886,
+ NL_2100HLG,
+ NL_SRGB,
+};
+
+enum dcss_hdr10_pixel_range {
+ PR_LIMITED,
+ PR_FULL,
+};
+
+enum dcss_hdr10_gamut {
+ G_REC2020,
+ G_REC709,
+ G_REC601_NTSC,
+ G_REC601_PAL,
+ G_ADOBE_ARGB,
+};
+
+struct dcss_hdr10_pipe_cfg {
+ bool is_yuv;
+ enum dcss_hdr10_nonlinearity nl;
+ enum dcss_hdr10_pixel_range pr;
+ enum dcss_hdr10_gamut g;
+};
+
+int dcss_hdr10_init(struct dcss_dev *dcss, unsigned long hdr10_base);
+void dcss_hdr10_exit(struct dcss_hdr10 *hdr10);
+void dcss_hdr10_setup(struct dcss_hdr10 *hdr10, int ch_num,
+ struct dcss_hdr10_pipe_cfg *ipipe_cfg,
+ struct dcss_hdr10_pipe_cfg *opipe_cfg);
+
+/* enums common to both WRSCL and RDSRC */
+enum dcss_wrscl_rdsrc_psize {
+ PSIZE_64,
+ PSIZE_128,
+ PSIZE_256,
+ PSIZE_512,
+ PSIZE_1024,
+ PSIZE_2048,
+ PSIZE_4096,
+};
+
+enum dcss_wrscl_rdsrc_tsize {
+ TSIZE_64,
+ TSIZE_128,
+ TSIZE_256,
+ TSIZE_512,
+};
+
+enum dcss_wrscl_rdsrc_fifo_size {
+ FIFO_512,
+ FIFO_1024,
+ FIFO_2048,
+ FIFO_4096,
+};
+
+enum dcss_wrscl_rdsrc_bpp {
+ BPP_38, /* 38 bit unpacked components */
+ BPP_32_UPCONVERT,
+ BPP_32_10BIT_OUTPUT,
+ BPP_20, /* 10-bit YUV422 */
+ BPP_16, /* 8-bit YUV422 */
+};
+
+/* WRSCL */
+int dcss_wrscl_init(struct dcss_dev *dcss, unsigned long wrscl_base);
+void dcss_wrscl_exit(struct dcss_wrscl *wrscl);
+u32 dcss_wrscl_setup(struct dcss_wrscl *wrscl, u32 pix_format, u32 pix_clk_hz,
+ u32 dst_xres, u32 dst_yres);
+void dcss_wrscl_enable(struct dcss_wrscl *wrscl);
+void dcss_wrscl_disable(struct dcss_wrscl *wrscl);
+
+/* RDSRC */
+int dcss_rdsrc_init(struct dcss_dev *dcss, unsigned long rdsrc_base);
+void dcss_rdsrc_exit(struct dcss_rdsrc *rdsrc);
+void dcss_rdsrc_setup(struct dcss_rdsrc *rdsrc, u32 pix_format, u32 dst_xres,
+ u32 dst_yres, u32 base_addr);
+void dcss_rdsrc_enable(struct dcss_rdsrc *rdsrc);
+void dcss_rdsrc_disable(struct dcss_rdsrc *rdsrc);
+
+/* DTRC */
+int dcss_dtrc_init(struct dcss_dev *dcss, unsigned long dtrc_base);
+void dcss_dtrc_exit(struct dcss_dtrc *dtrc);
+void dcss_dtrc_bypass(struct dcss_dtrc *dtrc, int ch_num);
+void dcss_dtrc_set_format_mod(struct dcss_dtrc *dtrc, int ch_num, u64 modifier);
+void dcss_dtrc_addr_set(struct dcss_dtrc *dtrc, int ch_num,
+ u32 p1_ba, u32 p2_ba, uint64_t dec_table_ofs);
+bool dcss_dtrc_ch_running(struct dcss_dtrc *dtrc, int ch_num);
+bool dcss_dtrc_is_running(struct dcss_dtrc *dtrc);
+void dcss_dtrc_enable(struct dcss_dtrc *dtrc, int ch_num, bool enable);
+void dcss_dtrc_set_res(struct dcss_dtrc *dtrc, int ch_num,
+ struct drm_plane_state *state, u32 *dtrc_w, u32 *dtrc_h);
+void dcss_dtrc_switch_banks(struct dcss_dtrc *dtrc);
+
+#endif /* __DCSS_PRV_H__ */
diff --git a/drivers/gpu/drm/imx/dcss/dcss-dpr.c b/drivers/gpu/drm/imx/dcss/dcss-dpr.c
new file mode 100644
index 000000000000..0feb0c66813b
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/dcss-dpr.c
@@ -0,0 +1,571 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/device.h>
+
+#include "dcss-dev.h"
+
+#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 {
+ struct dcss_dpr *dpr;
+ void __iomem *base_reg;
+ u32 base_ofs;
+
+ struct drm_format_info format;
+ 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;
+
+ bool sys_ctrl_chgd;
+
+ u32 pitch;
+
+ int ch_num;
+ int irq;
+
+ bool use_dtrc;
+};
+
+struct dcss_dpr {
+ struct device *dev;
+ struct dcss_dtrc *dtrc;
+ struct dcss_ctxld *ctxld;
+ u32 ctx_id;
+
+ struct dcss_dpr_ch ch[3];
+};
+
+static void dcss_dpr_write(struct dcss_dpr_ch *ch, u32 val, u32 ofs)
+{
+ struct dcss_dpr *dpr = ch->dpr;
+
+ dcss_ctxld_write(dpr->ctxld, dpr->ctx_id, val, ch->base_ofs + ofs);
+}
+
+static int dcss_dpr_ch_init_all(struct dcss_dpr *dpr, unsigned long dpr_base)
+{
+ struct dcss_dpr_ch *ch;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ ch = &dpr->ch[i];
+
+ ch->base_ofs = dpr_base + i * 0x1000;
+
+ ch->base_reg = devm_ioremap(dpr->dev, ch->base_ofs, SZ_4K);
+ if (!ch->base_reg) {
+ dev_err(dpr->dev, "dpr: unable to remap ch %d base\n",
+ i);
+ return -ENOMEM;
+ }
+
+ ch->dpr = dpr;
+ ch->ch_num = i;
+ }
+
+ return 0;
+}
+
+int dcss_dpr_init(struct dcss_dev *dcss, unsigned long dpr_base)
+{
+ struct dcss_dpr *dpr;
+
+ dpr = devm_kzalloc(dcss->dev, sizeof(struct dcss_dpr), GFP_KERNEL);
+ if (!dpr)
+ return -ENOMEM;
+
+ dcss->dpr = dpr;
+ dpr->dev = dcss->dev;
+ dpr->ctxld = dcss->ctxld;
+ dpr->ctx_id = CTX_SB_HP;
+ dpr->dtrc = dcss->dtrc;
+
+ if (dcss_dpr_ch_init_all(dpr, dpr_base)) {
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ if (dpr->ch[i].base_reg)
+ devm_iounmap(dpr->dev, dpr->ch[i].base_reg);
+ }
+
+ devm_kfree(dpr->dev, dpr);
+
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void dcss_dpr_exit(struct dcss_dpr *dpr)
+{
+ 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);
+
+ if (ch->base_reg)
+ devm_iounmap(dpr->dev, ch->base_reg);
+ }
+
+ devm_kfree(dpr->dev, dpr);
+}
+
+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];
+
+ if (pix_format == DRM_FORMAT_NV12_10LE40)
+ pix_wide = pix_wide * 10 / 8;
+
+ 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_dpr *dpr, int ch_num, u32 xres, u32 yres)
+{
+ struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
+ u32 pix_format = ch->format.format;
+ u32 gap = DCSS_DPR_FRAME_2P_BASE_ADDR - DCSS_DPR_FRAME_1P_BASE_ADDR;
+ int plane, max_planes = 1;
+ u32 pix_x_wide, pix_y_high;
+
+ if (pix_format == DRM_FORMAT_NV12 ||
+ pix_format == DRM_FORMAT_NV21 ||
+ pix_format == DRM_FORMAT_NV12_10LE40)
+ 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);
+
+ if (plane == 0)
+ ch->pitch = pix_x_wide;
+
+ dcss_dpr_write(ch, pix_x_wide,
+ DCSS_DPR_FRAME_1P_PIX_X_CTRL + plane * gap);
+ dcss_dpr_write(ch, pix_y_high,
+ DCSS_DPR_FRAME_1P_PIX_Y_CTRL + plane * gap);
+
+ dcss_dpr_write(ch, ch->use_dtrc ? 7 : 2,
+ DCSS_DPR_FRAME_1P_CTRL0 + plane * gap);
+ }
+}
+
+void dcss_dpr_addr_set(struct dcss_dpr *dpr, int ch_num, u32 luma_base_addr,
+ u32 chroma_base_addr, u16 pitch)
+{
+ struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
+
+ if (ch->use_dtrc) {
+ luma_base_addr = 0x0;
+ chroma_base_addr = 0x10000000;
+ }
+
+ if (!dcss_dtrc_ch_running(dpr->dtrc, ch_num)) {
+ dcss_dpr_write(ch, luma_base_addr, DCSS_DPR_FRAME_1P_BASE_ADDR);
+ dcss_dpr_write(ch, chroma_base_addr,
+ DCSS_DPR_FRAME_2P_BASE_ADDR);
+ }
+
+ if (ch->use_dtrc)
+ pitch = ch->pitch;
+
+ ch->frame_ctrl &= ~PITCH_MASK;
+ ch->frame_ctrl |= (((u32)pitch << PITCH_POS) & PITCH_MASK);
+}
+
+static void dcss_dpr_argb_comp_sel(struct dcss_dpr_ch *ch, int a_sel, int r_sel,
+ int g_sel, int b_sel)
+{
+ 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_dpr_ch *ch,
+ const struct drm_format_info *format)
+{
+ u32 val;
+
+ switch (format->format) {
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV21:
+ case DRM_FORMAT_NV12_10LE40:
+ val = 0;
+ break;
+
+ case DRM_FORMAT_UYVY:
+ case DRM_FORMAT_VYUY:
+ case DRM_FORMAT_YUYV:
+ case DRM_FORMAT_YVYU:
+ val = 1;
+ 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_dpr_ch *ch, bool swap)
+{
+ ch->mode_ctrl &= ~PIX_UV_SWAP;
+ ch->mode_ctrl |= (swap ? PIX_UV_SWAP : 0);
+}
+
+static void dcss_dpr_y_uv_swap(struct dcss_dpr_ch *ch, bool swap)
+{
+ ch->mode_ctrl &= ~PIX_LUMA_UV_SWAP;
+ ch->mode_ctrl |= (swap ? PIX_LUMA_UV_SWAP : 0);
+}
+
+static void dcss_dpr_2plane_en(struct dcss_dpr_ch *ch, bool en)
+{
+ ch->mode_ctrl &= ~COMP_2PLANE_EN;
+ ch->mode_ctrl |= (en ? COMP_2PLANE_EN : 0);
+}
+
+static void dcss_dpr_yuv_en(struct dcss_dpr_ch *ch, bool en)
+{
+ ch->mode_ctrl &= ~YUV_EN;
+ ch->mode_ctrl |= (en ? YUV_EN : 0);
+}
+
+void dcss_dpr_enable(struct dcss_dpr *dpr, int ch_num, bool en)
+{
+ struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
+ u32 sys_ctrl;
+
+ sys_ctrl = (en ? REPEAT_EN | RUN_EN : 0);
+
+ if (en) {
+ dcss_dpr_write(ch, ch->mode_ctrl, DCSS_DPR_MODE_CTRL0);
+ dcss_dpr_write(ch, ch->frame_ctrl, DCSS_DPR_FRAME_CTRL0);
+ dcss_dpr_write(ch, ch->rtram_ctrl, DCSS_DPR_RTRAM_CTRL0);
+ }
+
+ if (ch->sys_ctrl != sys_ctrl)
+ ch->sys_ctrl_chgd = true;
+
+ ch->sys_ctrl = sys_ctrl;
+}
+
+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_dpr_ch *ch, u32 pix_format)
+{
+ u32 val, mask;
+
+ switch (pix_format) {
+ case DRM_FORMAT_NV21:
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV12_10LE40:
+ ch->rtram_3buf_en = true;
+ ch->rtram_4line_en = false;
+ break;
+
+ default:
+ ch->rtram_3buf_en = true;
+ ch->rtram_4line_en = true;
+ 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);
+
+ val = (ch->rtram_4line_en ? 0 : NUM_ROWS_ACTIVE);
+ val |= (3 << THRES_LOW_POS) & THRES_LOW_MASK;
+ val |= (4 << THRES_HIGH_POS) & THRES_HIGH_MASK;
+ mask = THRES_LOW_MASK | THRES_HIGH_MASK | NUM_ROWS_ACTIVE;
+
+ ch->rtram_ctrl &= ~mask;
+ ch->rtram_ctrl |= (val & mask);
+}
+
+static void dcss_dpr_setup_components(struct dcss_dpr_ch *ch,
+ const struct drm_format_info *format)
+{
+ int a_sel, r_sel, g_sel, b_sel;
+ bool uv_swap, y_uv_swap;
+
+ switch (format->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(ch, uv_swap);
+
+ dcss_dpr_y_uv_swap(ch, y_uv_swap);
+
+ if (!format->is_yuv) {
+ if (!to_comp_sel(format->format, &a_sel, &r_sel,
+ &g_sel, &b_sel)) {
+ dcss_dpr_argb_comp_sel(ch, a_sel, r_sel, g_sel, b_sel);
+ } else {
+ dcss_dpr_argb_comp_sel(ch, 3, 2, 1, 0);
+ }
+ } else {
+ dcss_dpr_argb_comp_sel(ch, 0, 0, 0, 0);
+ }
+}
+
+static void dcss_dpr_tile_set(struct dcss_dpr_ch *ch, uint64_t modifier)
+{
+ switch (ch->ch_num) {
+ case 0:
+ switch (modifier) {
+ case DRM_FORMAT_MOD_LINEAR:
+ ch->tile = TILE_LINEAR;
+ break;
+ case DRM_FORMAT_MOD_VIVANTE_TILED:
+ ch->tile = TILE_GPU_STANDARD;
+ break;
+ case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
+ case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED_FC:
+ ch->tile = TILE_GPU_SUPER;
+ break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+ break;
+ case 1:
+ case 2:
+ ch->tile = TILE_LINEAR;
+ break;
+ default:
+ WARN_ON(1);
+ return;
+ }
+
+ ch->mode_ctrl &= ~TILE_TYPE_MASK;
+ ch->mode_ctrl |= ((ch->tile << TILE_TYPE_POS) & TILE_TYPE_MASK);
+}
+
+void dcss_dpr_format_set(struct dcss_dpr *dpr, int ch_num,
+ const struct drm_format_info *format, u64 modifier)
+{
+ struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
+
+ ch->format = *format;
+ ch->use_dtrc = ch_num && modifier != DRM_FORMAT_MOD_LINEAR;
+
+ dcss_dpr_yuv_en(ch, format->is_yuv);
+
+ dcss_dpr_pix_size_set(ch, format);
+
+ dcss_dpr_setup_components(ch, format);
+
+ dcss_dpr_2plane_en(ch, format->num_planes == 2);
+
+ dcss_dpr_rtram_set(ch, format->format);
+
+ dcss_dpr_tile_set(ch, modifier);
+}
+
+/* This function will be called from interrupt context. */
+void dcss_dpr_write_sysctrl(struct dcss_dpr *dpr)
+{
+ int chnum;
+
+ for (chnum = 0; chnum < 3; chnum++) {
+ struct dcss_dpr_ch *ch = &dpr->ch[chnum];
+
+ if (ch->sys_ctrl_chgd) {
+ dcss_ctxld_write_irqsafe(dpr->ctxld, dpr->ctx_id,
+ ch->sys_ctrl,
+ ch->base_ofs +
+ DCSS_DPR_SYSTEM_CTRL0);
+ ch->sys_ctrl_chgd = false;
+ }
+ }
+}
+
+void dcss_dpr_set_rotation(struct dcss_dpr *dpr, int ch_num, u32 rotation)
+{
+ struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
+
+ ch->frame_ctrl &= ~(HFLIP_EN | VFLIP_EN | ROT_ENC_MASK);
+
+ ch->frame_ctrl |= rotation & DRM_MODE_REFLECT_X ? HFLIP_EN : 0;
+ ch->frame_ctrl |= rotation & DRM_MODE_REFLECT_Y ? VFLIP_EN : 0;
+
+ if (rotation & DRM_MODE_ROTATE_90)
+ ch->frame_ctrl |= 1 << ROT_ENC_POS;
+ else if (rotation & DRM_MODE_ROTATE_180)
+ ch->frame_ctrl |= 2 << ROT_ENC_POS;
+ else if (rotation & DRM_MODE_ROTATE_270)
+ ch->frame_ctrl |= 3 << ROT_ENC_POS;
+}
diff --git a/drivers/gpu/drm/imx/dcss/dcss-drv.c b/drivers/gpu/drm/imx/dcss/dcss-drv.c
new file mode 100644
index 000000000000..4082e529f3f5
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/dcss-drv.c
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/component.h>
+#include <drm/drm_of.h>
+#include <drm/drmP.h>
+
+#include "dcss-dev.h"
+#include "dcss-kms.h"
+
+struct dcss_drv {
+ struct dcss_dev *dcss;
+ struct dcss_kms_dev *kms;
+
+ bool is_componentized;
+};
+
+struct dcss_dev *dcss_drv_dev_to_dcss(struct device *dev)
+{
+ struct dcss_drv *mdrv = dev_get_drvdata(dev);
+
+ return mdrv ? mdrv->dcss : NULL;
+}
+
+struct drm_device *dcss_drv_dev_to_drm(struct device *dev)
+{
+ struct dcss_drv *mdrv = dev_get_drvdata(dev);
+
+ return mdrv ? &mdrv->kms->base : NULL;
+}
+
+static int dcss_drv_init(struct device *dev, bool componentized)
+{
+ struct dcss_drv *mdrv;
+ int err = 0;
+
+ mdrv = devm_kzalloc(dev, sizeof(*mdrv), GFP_KERNEL);
+ if (!mdrv)
+ return -ENOMEM;
+
+ mdrv->is_componentized = componentized;
+
+ mdrv->dcss = dcss_dev_create(dev, componentized);
+ if (IS_ERR(mdrv->dcss)) {
+ err = PTR_ERR(mdrv->dcss);
+ goto err;
+ }
+
+ dev_set_drvdata(dev, mdrv);
+
+ mdrv->kms = dcss_kms_attach(mdrv->dcss, componentized);
+ if (IS_ERR(mdrv->kms)) {
+ err = PTR_ERR(mdrv->kms);
+ goto dcss_shutoff;
+ }
+
+ return 0;
+
+dcss_shutoff:
+ dcss_dev_destroy(mdrv->dcss);
+
+ dev_set_drvdata(dev, NULL);
+
+err:
+ devm_kfree(dev, mdrv);
+ return err;
+}
+
+static void dcss_drv_deinit(struct device *dev, bool componentized)
+{
+ struct dcss_drv *mdrv = dev_get_drvdata(dev);
+
+ if (!mdrv)
+ return;
+
+ dcss_kms_detach(mdrv->kms, componentized);
+ dcss_dev_destroy(mdrv->dcss);
+
+ dev_set_drvdata(dev, NULL);
+}
+
+static int dcss_drv_bind(struct device *dev)
+{
+ return dcss_drv_init(dev, true);
+}
+
+static void dcss_drv_unbind(struct device *dev)
+{
+ return dcss_drv_deinit(dev, true);
+}
+
+static const struct component_master_ops dcss_master_ops = {
+ .bind = dcss_drv_bind,
+ .unbind = dcss_drv_unbind,
+};
+
+static int compare_of(struct device *dev, void *data)
+{
+ return dev->of_node == data;
+}
+
+static int dcss_drv_platform_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct component_match *match = NULL;
+ struct device_node *remote;
+
+ if (!dev->of_node)
+ return -ENODEV;
+
+ remote = of_graph_get_remote_node(dev->of_node, 0, 0);
+ if (!remote)
+ return -ENODEV;
+
+ if (of_device_is_compatible(remote, "fsl,imx8mq-nwl-dsi")) {
+ of_node_put(remote);
+ return dcss_drv_init(dev, false);
+ }
+
+ drm_of_component_match_add(dev, &match, compare_of, remote);
+ of_node_put(remote);
+
+ return component_master_add_with_match(dev, &dcss_master_ops, match);
+}
+
+static int dcss_drv_platform_remove(struct platform_device *pdev)
+{
+ struct dcss_drv *mdrv = dev_get_drvdata(&pdev->dev);
+
+ if (mdrv->is_componentized)
+ component_master_del(&pdev->dev, &dcss_master_ops);
+ else
+ dcss_drv_deinit(&pdev->dev, false);
+
+ return 0;
+}
+
+static struct dcss_type_data dcss_types[] = {
+ [DCSS_IMX8MQ] = {
+ .name = "DCSS_IMX8MQ",
+ .blkctl_ofs = 0x2F000,
+ .ctxld_ofs = 0x23000,
+ .dtg_ofs = 0x20000,
+ .rdsrc_ofs = 0x22000,
+ .wrscl_ofs = 0x21000,
+ .scaler_ofs = 0x1C000,
+ .ss_ofs = 0x1B000,
+ .dpr_ofs = 0x18000,
+ .dec400d_ofs = 0x15000,
+ .hdr10_ofs = 0x00000,
+ .dtrc_ofs = 0x16000,
+ },
+};
+
+static const struct of_device_id dcss_of_match[] = {
+ { .compatible = "nxp,imx8mq-dcss", .data = &dcss_types[DCSS_IMX8MQ], },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, dcss_of_match);
+
+static const struct dev_pm_ops dcss_dev_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(dcss_dev_suspend, dcss_dev_resume)
+ SET_RUNTIME_PM_OPS(dcss_dev_runtime_suspend,
+ dcss_dev_runtime_resume, NULL)
+};
+
+static struct platform_driver dcss_platform_driver = {
+ .probe = dcss_drv_platform_probe,
+ .remove = dcss_drv_platform_remove,
+ .driver = {
+ .name = "imx-dcss",
+ .of_match_table = dcss_of_match,
+ .pm = &dcss_dev_pm,
+ },
+};
+
+module_platform_driver(dcss_platform_driver);
+
+MODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@nxp.com>");
+MODULE_DESCRIPTION("DCSS driver for i.MX8MQ");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/imx/dcss/dcss-dtg.c b/drivers/gpu/drm/imx/dcss/dcss-dtg.c
new file mode 100644
index 000000000000..44879db7e0a4
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/dcss-dtg.c
@@ -0,0 +1,454 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "dcss-dev.h"
+
+#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
+
+struct dcss_dtg {
+ struct device *dev;
+ struct dcss_ctxld *ctxld;
+ void __iomem *base_reg;
+ u32 base_ofs;
+
+ u32 ctx_id;
+
+ bool in_use;
+ bool hdmi_output;
+
+ u32 dis_ulc_x;
+ u32 dis_ulc_y;
+
+ u32 control_status;
+ u32 alpha;
+
+ int ctxld_kick_irq;
+ bool ctxld_kick_irq_en;
+
+ struct clk *pix_clk;
+ struct clk *pll_src_clk;
+ struct clk *pll_phy_ref_clk;
+
+ /*
+ * This will be passed on by DRM CRTC so that we can signal when DTG has
+ * been successfully stopped. Otherwise, any modesetting while DTG is
+ * still ON may result in unpredictable behavior.
+ */
+ struct completion *dis_completion;
+};
+
+static void dcss_dtg_write(struct dcss_dtg *dtg, u32 val, u32 ofs)
+{
+ if (!dtg->in_use)
+ dcss_writel(val, dtg->base_reg + ofs);
+
+ dcss_ctxld_write(dtg->ctxld, dtg->ctx_id, val, dtg->base_ofs + ofs);
+}
+
+static irqreturn_t dcss_dtg_irq_handler(int irq, void *data)
+{
+ struct dcss_dtg *dtg = data;
+ u32 status;
+
+ status = dcss_readl(dtg->base_reg + DCSS_DTG_INT_STATUS);
+
+ if (!(status & LINE0_IRQ))
+ return IRQ_HANDLED;
+
+ dcss_ctxld_kick(dtg->ctxld);
+
+ dcss_writel(status & LINE0_IRQ, dtg->base_reg + DCSS_DTG_INT_CONTROL);
+
+ return IRQ_HANDLED;
+}
+
+static int dcss_dtg_irq_config(struct dcss_dtg *dtg,
+ struct platform_device *pdev)
+{
+ int ret;
+
+ dtg->ctxld_kick_irq = platform_get_irq_byname(pdev, "ctxld_kick");
+ if (dtg->ctxld_kick_irq < 0) {
+ dev_err(dtg->dev, "dtg: can't get line2 irq number\n");
+ return dtg->ctxld_kick_irq;
+ }
+
+ ret = devm_request_irq(dtg->dev, dtg->ctxld_kick_irq,
+ dcss_dtg_irq_handler,
+ IRQF_TRIGGER_HIGH,
+ "dcss_ctxld_kick", dtg);
+ if (ret) {
+ dev_err(dtg->dev, "dtg: irq request failed.\n");
+ return ret;
+ }
+
+ disable_irq(dtg->ctxld_kick_irq);
+
+ dtg->ctxld_kick_irq_en = false;
+
+ dcss_update(LINE0_IRQ, LINE0_IRQ, dtg->base_reg + DCSS_DTG_INT_MASK);
+
+ return 0;
+}
+
+int dcss_dtg_init(struct dcss_dev *dcss, unsigned long dtg_base)
+{
+ int ret = 0;
+ struct dcss_dtg *dtg;
+
+ dtg = devm_kzalloc(dcss->dev, sizeof(*dtg), GFP_KERNEL);
+ if (!dtg)
+ return -ENOMEM;
+
+ dcss->dtg = dtg;
+ dtg->dev = dcss->dev;
+ dtg->ctxld = dcss->ctxld;
+ dtg->hdmi_output = dcss->hdmi_output;
+
+ 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");
+ ret = -ENOMEM;
+ goto err_ioremap;
+ }
+
+ dtg->base_ofs = dtg_base;
+ dtg->ctx_id = CTX_DB;
+
+ dtg->pix_clk = dcss->pix_clk;
+ dtg->pll_src_clk = dcss->pll_src_clk;
+ dtg->pll_phy_ref_clk = dcss->pll_phy_ref_clk;
+
+ dtg->alpha = 255;
+
+ dtg->control_status |= OVL_DATA_MODE | BLENDER_VIDEO_ALPHA_SEL |
+ ((dtg->alpha << DEFAULT_FG_ALPHA_POS) & DEFAULT_FG_ALPHA_MASK);
+
+ ret = dcss_dtg_irq_config(dtg, to_platform_device(dcss->dev));
+ if (ret)
+ goto err_irq;
+
+ return 0;
+
+err_irq:
+ devm_iounmap(dtg->dev, dtg->base_reg);
+
+err_ioremap:
+ devm_kfree(dtg->dev, dtg);
+
+ return ret;
+}
+
+void dcss_dtg_exit(struct dcss_dtg *dtg)
+{
+ /* stop DTG */
+ dcss_writel(DTG_START, dtg->base_reg + DCSS_DTG_TC_CONTROL_STATUS);
+
+ devm_free_irq(dtg->dev, dtg->ctxld_kick_irq, dtg);
+
+ if (dtg->base_reg)
+ devm_iounmap(dtg->dev, dtg->base_reg);
+
+ devm_kfree(dtg->dev, dtg);
+}
+
+void dcss_dtg_sync_set(struct dcss_dtg *dtg, struct videomode *vm)
+{
+ u16 dtg_lrc_x, dtg_lrc_y;
+ u16 dis_ulc_x, dis_ulc_y;
+ u16 dis_lrc_x, dis_lrc_y;
+ u32 sb_ctxld_trig, db_ctxld_trig;
+ u32 pixclock = vm->pixelclock;
+ u32 actual_clk;
+
+ 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;
+
+ clk_disable_unprepare(dtg->pix_clk);
+ if (dtg->hdmi_output) {
+ int err;
+
+ clk_disable_unprepare(dtg->pll_src_clk);
+ err = clk_set_parent(dtg->pll_src_clk, dtg->pll_phy_ref_clk);
+ if (err < 0)
+ dev_warn(dtg->dev, "clk_set_parent() returned %d", err);
+ clk_prepare_enable(dtg->pll_src_clk);
+ }
+ clk_set_rate(dtg->pix_clk, vm->pixelclock);
+ clk_prepare_enable(dtg->pix_clk);
+
+ actual_clk = clk_get_rate(dtg->pix_clk);
+ if (pixclock != actual_clk) {
+ dev_info(dtg->dev,
+ "Pixel clock set to %u kHz instead of %u kHz.\n",
+ (actual_clk / 1000), (pixclock / 1000));
+ }
+
+ msleep(50);
+
+ 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;
+
+ sb_ctxld_trig = ((0 * dis_lrc_y / 100) << TC_CTXLD_SB_Y_POS) &
+ TC_CTXLD_SB_Y_MASK;
+ db_ctxld_trig = ((99 * dis_lrc_y / 100) << TC_CTXLD_DB_Y_POS) &
+ TC_CTXLD_DB_Y_MASK;
+
+ dcss_dtg_write(dtg, sb_ctxld_trig | db_ctxld_trig, DCSS_DTG_TC_CTXLD);
+
+ /* vblank trigger */
+ dcss_dtg_write(dtg, 0, DCSS_DTG_LINE1_INT);
+
+ /* CTXLD trigger */
+ dcss_dtg_write(dtg, ((90 * dis_lrc_y) / 100) << 16, DCSS_DTG_LINE0_INT);
+}
+
+void dcss_dtg_plane_pos_set(struct dcss_dtg *dtg, int ch_num,
+ int px, int py, int pw, int ph)
+{
+ 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);
+ }
+}
+
+bool dcss_dtg_global_alpha_changed(struct dcss_dtg *dtg, int ch_num, int alpha)
+{
+ if (ch_num)
+ return false;
+
+ return alpha != dtg->alpha;
+}
+
+void dcss_dtg_plane_alpha_set(struct dcss_dtg *dtg, int ch_num,
+ const struct drm_format_info *format, int alpha)
+{
+ 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;
+
+ /*
+ * Use global alpha if pixel format does not have alpha channel or the
+ * user explicitly chose to use global alpha (i.e. alpha is not OPAQUE).
+ */
+ if (!format->has_alpha || alpha != 255) {
+ dtg->control_status &= ~(CH1_ALPHA_SEL | DEFAULT_FG_ALPHA_MASK);
+ dtg->control_status |= alpha_val;
+ } else { /* use per-pixel alpha otherwise */
+ dtg->control_status |= CH1_ALPHA_SEL;
+ }
+
+ dtg->alpha = alpha;
+}
+
+void dcss_dtg_css_set(struct dcss_dtg *dtg, bool out_is_yuv)
+{
+ dtg->control_status &= ~CSS_PIX_COMP_SWAP_MASK;
+
+ if (out_is_yuv)
+ return;
+
+ dtg->control_status |=
+ (0x5 << CSS_PIX_COMP_SWAP_POS) & CSS_PIX_COMP_SWAP_MASK;
+}
+
+static void dcss_dtg_disable_callback(void *data)
+{
+ struct dcss_dtg *dtg = data;
+
+ dtg->control_status &= ~DTG_START;
+
+ dcss_writel(dtg->control_status,
+ dtg->base_reg + DCSS_DTG_TC_CONTROL_STATUS);
+
+ dtg->in_use = false;
+
+ complete(dtg->dis_completion);
+}
+
+void dcss_dtg_enable(struct dcss_dtg *dtg, bool en,
+ struct completion *dis_completion)
+{
+ if (!en) {
+ dtg->dis_completion = dis_completion;
+ dcss_ctxld_register_dtg_disable_cb(dtg->ctxld,
+ dcss_dtg_disable_callback,
+ dtg);
+ return;
+ }
+
+ dtg->dis_completion = NULL;
+
+ dtg->control_status |= DTG_START;
+
+ dcss_dtg_write(dtg, dtg->control_status, DCSS_DTG_TC_CONTROL_STATUS);
+
+ dtg->in_use = true;
+}
+
+bool dcss_dtg_is_enabled(struct dcss_dtg *dtg)
+{
+ return dtg->in_use;
+}
+
+void dcss_dtg_ch_enable(struct dcss_dtg *dtg, int ch_num, bool en)
+{
+ u32 ch_en_map[] = {CH1_EN, CH2_EN, CH3_EN};
+ u32 control_status;
+
+ control_status = dtg->control_status & ~ch_en_map[ch_num];
+ control_status |= en ? ch_en_map[ch_num] : 0;
+
+ if (dtg->control_status != control_status)
+ dcss_dtg_write(dtg, control_status, DCSS_DTG_TC_CONTROL_STATUS);
+
+ dtg->control_status = control_status;
+}
+
+void dcss_dtg_vblank_irq_enable(struct dcss_dtg *dtg, bool en)
+{
+ u32 status;
+
+ dcss_update(LINE1_IRQ, LINE1_IRQ, dtg->base_reg + DCSS_DTG_INT_MASK);
+
+ if (en) {
+ status = dcss_readl(dtg->base_reg + DCSS_DTG_INT_STATUS);
+ dcss_writel(status & LINE1_IRQ,
+ dtg->base_reg + DCSS_DTG_INT_CONTROL);
+ }
+}
+
+void dcss_dtg_ctxld_kick_irq_enable(struct dcss_dtg *dtg, bool en)
+{
+ u32 status;
+
+ if (en) {
+ status = dcss_readl(dtg->base_reg + DCSS_DTG_INT_STATUS);
+
+ if (!dtg->ctxld_kick_irq_en) {
+ dcss_writel(status & LINE0_IRQ,
+ dtg->base_reg + DCSS_DTG_INT_CONTROL);
+ enable_irq(dtg->ctxld_kick_irq);
+ dtg->ctxld_kick_irq_en = true;
+ return;
+ }
+
+ return;
+ }
+
+ if (!dtg->ctxld_kick_irq_en)
+ return;
+
+ disable_irq_nosync(dtg->ctxld_kick_irq);
+ dtg->ctxld_kick_irq_en = false;
+}
+
+void dcss_dtg_vblank_irq_clear(struct dcss_dtg *dtg)
+{
+ dcss_update(LINE1_IRQ, LINE1_IRQ, dtg->base_reg + DCSS_DTG_INT_CONTROL);
+}
+
+bool dcss_dtg_vblank_irq_valid(struct dcss_dtg *dtg)
+{
+ return !!(dcss_readl(dtg->base_reg + DCSS_DTG_INT_STATUS) & LINE1_IRQ);
+}
+
diff --git a/drivers/gpu/drm/imx/dcss/dcss-dtrc.c b/drivers/gpu/drm/imx/dcss/dcss-dtrc.c
new file mode 100644
index 000000000000..1caa293651a0
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/dcss-dtrc.c
@@ -0,0 +1,514 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_rect.h>
+
+#include "dcss-dev.h"
+
+#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 CROP_HEIGHT_POS 16
+#define CROP_HEIGHT_MASK GENMASK(28, 16)
+#define CROP_WIDTH_POS 0
+#define CROP_WIDTH_MASK GENMASK(12, 0)
+#define DCSS_DTRC_DCTL 0x2C
+#define CROPPING_EN BIT(18)
+#define COMPRESSION_DIS BIT(17)
+#define PIX_DEPTH_8BIT_EN BIT(1)
+#define CONFIG_READY BIT(0)
+#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 ADDRESS_ID_ENABLE BIT(30)
+#define ENDIANNESS_10BIT BIT(29)
+#define MERGE_ARID_ENABLE BIT(28)
+#define NON_G1_2_SWAP_MODE_POS 24
+#define NON_G1_2_SWAP_MODE_MASK GENMASK(27, 24)
+#define TABLE_DATA_SWAP_POS 20
+#define TABLE_DATA_SWAP_MASK GENMASK(23, 20)
+#define TILED_SWAP_POS 16
+#define TILED_SWAP_MASK GENMASK(19, 16)
+#define RASTER_SWAP_POS 12
+#define RASTER_SWAP_MASK GENMASK(15, 12)
+#define BURST_LENGTH_POS 4
+#define BURST_LENGTH_MASK GENMASK(11, 4)
+#define G1_TILED_DATA_EN BIT(3)
+#define HOT_RESET BIT(2)
+#define ARIDR_MODE_DETILE 0
+#define ARIDR_MODE_BYPASS 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 {
+ struct dcss_dtrc *dtrc;
+
+ void __iomem *base_reg;
+ u32 base_ofs;
+
+ u32 xres;
+ u32 yres;
+ u32 pix_format;
+ u64 format_modifier;
+ u32 y_dec_ofs;
+ u32 uv_dec_ofs;
+
+ int curr_frame;
+
+ u32 dctl;
+
+ bool bypass;
+ bool running;
+
+ int irq;
+ int ch_num;
+};
+
+struct dcss_dtrc {
+ struct device *dev;
+
+ struct dcss_dtrc_ch ch[2];
+
+ u32 ctx_id;
+ struct dcss_ctxld *ctxld;
+};
+
+static irqreturn_t dcss_dtrc_irq_handler(int irq, void *data)
+{
+ struct dcss_dtrc_ch *ch = data;
+ u32 b0, b1, curr_bank;
+
+ b0 = dcss_readl(ch->base_reg + DCSS_DTRC_DCTL) & 0x1;
+ b1 = dcss_readl(ch->base_reg + DTRC_F1_OFS + DCSS_DTRC_DCTL) & 0x1;
+ curr_bank = dcss_readl(ch->base_reg + DCSS_DTRC_DTCTRL) >> 31;
+
+ dcss_update(1, 1, ch->base_reg + DCSS_DTRC_FDINTR);
+
+ return IRQ_HANDLED;
+}
+
+static int dcss_dtrc_irq_config(struct dcss_dtrc *dtrc, int ch_num)
+{
+ struct platform_device *pdev = to_platform_device(dtrc->dev);
+ struct dcss_dtrc_ch *ch = &dtrc->ch[ch_num];
+ char irq_name[20];
+ int ret;
+
+ sprintf(irq_name, "dtrc_ch%d", ch_num + 1);
+ irq_name[8] = 0;
+
+ ch->irq = platform_get_irq_byname(pdev, irq_name);
+ if (ch->irq < 0) {
+ dev_err(dtrc->dev, "dtrc: can't get DTRC irq\n");
+ return ch->irq;
+ }
+
+ ret = devm_request_irq(dtrc->dev, ch->irq,
+ dcss_dtrc_irq_handler,
+ IRQF_TRIGGER_HIGH,
+ "dcss-dtrc", ch);
+ if (ret) {
+ dev_err(dtrc->dev, "dtrc: irq request failed.\n");
+ return ret;
+ }
+
+ dcss_writel(1, ch->base_reg + DCSS_DTRC_INTEN);
+
+ return 0;
+}
+
+static int dcss_dtrc_ch_init_all(struct dcss_dtrc *dtrc, u32 dtrc_base)
+{
+ struct dcss_dtrc_ch *ch;
+ int i, ret;
+
+ for (i = 0; i < 2; i++) {
+ ch = &dtrc->ch[i];
+
+ ch->base_ofs = dtrc_base + i * 0x1000;
+
+ ch->base_reg = devm_ioremap(dtrc->dev, ch->base_ofs, SZ_4K);
+ if (!ch->base_reg) {
+ dev_err(dtrc->dev, "dtrc: unable to remap ch base\n");
+ return -ENOMEM;
+ }
+
+ ch->ch_num = i;
+ ch->dtrc = dtrc;
+
+ ret = dcss_dtrc_irq_config(dtrc, i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void dcss_dtrc_write(struct dcss_dtrc_ch *ch, u32 val, u32 ofs)
+{
+ dcss_ctxld_write(ch->dtrc->ctxld, ch->dtrc->ctx_id,
+ val, ch->base_ofs + ofs);
+}
+
+static void dcss_dtrc_write_irqsafe(struct dcss_dtrc_ch *ch, u32 val, u32 ofs)
+{
+ dcss_ctxld_write_irqsafe(ch->dtrc->ctxld, ch->dtrc->ctx_id,
+ val, ch->base_ofs + ofs);
+}
+
+int dcss_dtrc_init(struct dcss_dev *dcss, unsigned long dtrc_base)
+{
+ struct dcss_dtrc *dtrc;
+
+ dtrc = devm_kzalloc(dcss->dev, sizeof(*dtrc), GFP_KERNEL);
+ if (!dtrc)
+ return -ENOMEM;
+
+ dcss->dtrc = dtrc;
+ dtrc->dev = dcss->dev;
+ dtrc->ctxld = dcss->ctxld;
+ dtrc->ctx_id = CTX_SB_HP;
+
+ if (dcss_dtrc_ch_init_all(dtrc, dtrc_base)) {
+ struct dcss_dtrc_ch *ch;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ ch = &dtrc->ch[i];
+
+ if (ch->irq)
+ devm_free_irq(dtrc->dev, ch->irq, ch);
+
+ if (ch->base_reg)
+ devm_iounmap(dtrc->dev, ch->base_reg);
+ }
+
+ devm_kfree(dtrc->dev, dtrc);
+
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void dcss_dtrc_exit(struct dcss_dtrc *dtrc)
+{
+ int ch_no;
+
+ for (ch_no = 0; ch_no < 2; ch_no++) {
+ struct dcss_dtrc_ch *ch = &dtrc->ch[ch_no];
+
+ if (ch->base_reg) {
+ /* reset the module to default */
+ dcss_writel(HOT_RESET,
+ ch->base_reg + DCSS_DTRC_DTCTRL);
+ devm_iounmap(dtrc->dev, ch->base_reg);
+ }
+ }
+
+ devm_kfree(dtrc->dev, dtrc);
+}
+
+void dcss_dtrc_bypass(struct dcss_dtrc *dtrc, int ch_num)
+{
+ struct dcss_dtrc_ch *ch;
+
+ if (ch_num == 0)
+ return;
+
+ ch = &dtrc->ch[ch_num - 1];
+
+ if (ch->bypass)
+ return;
+
+ dcss_dtrc_write(ch, ARIDR_MODE_BYPASS, DCSS_DTRC_DTCTRL);
+ dcss_dtrc_write(ch, 0, DCSS_DTRC_DYTSADDR);
+ dcss_dtrc_write(ch, 0, DCSS_DTRC_DCTSADDR);
+ dcss_dtrc_write(ch, 0x0f0e0100, DCSS_DTRC_ARIDR);
+ dcss_dtrc_write(ch, 0x0f0e, DCSS_DTRC_DTID2DDR);
+
+ ch->bypass = true;
+}
+
+void dcss_dtrc_addr_set(struct dcss_dtrc *dtrc, int ch_num,
+ u32 p1_ba, u32 p2_ba, uint64_t dec_table_ofs)
+{
+ struct dcss_dtrc_ch *ch;
+
+ if (ch_num == 0)
+ return;
+
+ ch = &dtrc->ch[ch_num - 1];
+
+ dcss_dtrc_write(ch, p1_ba, DCSS_DTRC_DYDSADDR);
+ dcss_dtrc_write(ch, p2_ba, DCSS_DTRC_DCDSADDR);
+
+ dcss_dtrc_write(ch, p1_ba, DTRC_F1_OFS + DCSS_DTRC_DYDSADDR);
+ dcss_dtrc_write(ch, p2_ba, DTRC_F1_OFS + DCSS_DTRC_DCDSADDR);
+
+ if (ch->format_modifier == DRM_FORMAT_MOD_VSI_G2_TILED_COMPRESSED) {
+ ch->y_dec_ofs = dec_table_ofs & 0xFFFFFFFF;
+ ch->uv_dec_ofs = dec_table_ofs >> 32;
+
+ dcss_dtrc_write(ch, p1_ba + ch->y_dec_ofs,
+ DCSS_DTRC_DYTSADDR);
+ dcss_dtrc_write(ch, p1_ba + ch->uv_dec_ofs,
+ DCSS_DTRC_DCTSADDR);
+ dcss_dtrc_write(ch, p1_ba + ch->y_dec_ofs,
+ DTRC_F1_OFS + DCSS_DTRC_DYTSADDR);
+ dcss_dtrc_write(ch, p1_ba + ch->uv_dec_ofs,
+ DTRC_F1_OFS + DCSS_DTRC_DCTSADDR);
+ }
+
+ ch->bypass = false;
+}
+
+void dcss_dtrc_set_res(struct dcss_dtrc *dtrc, int ch_num,
+ struct drm_plane_state *state, u32 *dtrc_w, u32 *dtrc_h)
+{
+ struct drm_framebuffer *fb = state->fb;
+ u32 pixel_format = fb->format->format;
+ struct dcss_dtrc_ch *ch;
+ u32 frame_height, frame_width;
+ u32 crop_w, crop_h, crop_orig_w, crop_orig_h;
+ int bank;
+ u32 old_xres, old_yres, xres, yres;
+ u32 x1, y1, x2, y2;
+ u32 pix_depth;
+ u16 width_align = 0;
+
+ if (ch_num == 0)
+ return;
+
+ ch = &dtrc->ch[ch_num - 1];
+
+ bank = dcss_readl(ch->base_reg + DCSS_DTRC_DTCTRL) >> 31;
+
+ ch->pix_format = pixel_format;
+ ch->format_modifier = fb->modifier;
+
+ pix_depth = ch->pix_format == DRM_FORMAT_NV12_10LE40 ? 10 : 8;
+
+ old_xres = state->src_w >> 16;
+ old_yres = state->src_h >> 16;
+
+ x1 = (state->src.x1 >> 16) & ~1;
+ y1 = (state->src.y1 >> 16) & ~1;
+ x2 = state->src.x2 >> 16;
+ y2 = state->src.y2 >> 16;
+
+ xres = x2 - x1;
+ yres = y2 - y1;
+
+ frame_height = ((old_yres >> 3) << FRAME_HEIGHT_POS) & FRAME_HEIGHT_MASK;
+ frame_width = ((old_xres >> 3) << FRAME_WIDTH_POS) & FRAME_WIDTH_MASK;
+
+ dcss_dtrc_write(ch, frame_height | frame_width,
+ DTRC_F1_OFS * bank + DCSS_DTRC_SIZE);
+
+ dcss_dtrc_write(ch, frame_height | frame_width,
+ DTRC_F1_OFS * (bank ^ 1) + DCSS_DTRC_SIZE);
+
+ /*
+ * Image original size is aligned:
+ * - 128 pixels for width (8-bit) or 256 (10-bit);
+ * - 8 lines for height;
+ */
+ width_align = ch->pix_format == DRM_FORMAT_NV12_10LE40 ? 0xff : 0x7f;
+
+ if (xres == old_xres && !(xres & width_align) &&
+ yres == old_yres && !(yres & 0xf)) {
+ ch->dctl &= ~CROPPING_EN;
+ goto exit;
+ }
+
+ /* align the image size: down align for compressed formats */
+ if (ch->format_modifier == DRM_FORMAT_MOD_VSI_G2_TILED_COMPRESSED && x1)
+ xres = xres & ~width_align;
+ else
+ xres = (xres + width_align) & ~width_align;
+
+ if (ch->format_modifier == DRM_FORMAT_MOD_VSI_G2_TILED_COMPRESSED && y1)
+ yres = yres & ~0xf;
+ else
+ yres = (yres + 0xf) & ~0xf;
+
+ crop_orig_w = (x1 << CROP_WIDTH_POS) & CROP_WIDTH_MASK;
+ crop_orig_h = (y1 << CROP_HEIGHT_POS) & CROP_HEIGHT_MASK;
+
+ dcss_dtrc_write(ch, crop_orig_w | crop_orig_h,
+ DCSS_DTRC_CROPORIG);
+ dcss_dtrc_write(ch, crop_orig_w | crop_orig_h,
+ DTRC_F1_OFS + DCSS_DTRC_CROPORIG);
+
+ crop_w = (xres << CROP_WIDTH_POS) & CROP_WIDTH_MASK;
+ crop_h = (yres << CROP_HEIGHT_POS) & CROP_HEIGHT_MASK;
+
+ dcss_dtrc_write(ch, crop_w | crop_h,
+ DTRC_F1_OFS * bank + DCSS_DTRC_CROPSIZE);
+ dcss_dtrc_write(ch, crop_w | crop_h,
+ DTRC_F1_OFS * (bank ^ 1) + DCSS_DTRC_CROPSIZE);
+
+ ch->dctl |= CROPPING_EN;
+
+exit:
+ dcss_dtrc_write(ch, xres * yres * pix_depth / 8,
+ DCSS_DTRC_SYSEA);
+ dcss_dtrc_write(ch, xres * yres * pix_depth / 8,
+ DTRC_F1_OFS + DCSS_DTRC_SYSEA);
+
+ dcss_dtrc_write(ch, 0x10000000 + xres * yres * pix_depth / 8 / 2,
+ DCSS_DTRC_SUVSEA);
+ dcss_dtrc_write(ch, 0x10000000 + xres * yres * pix_depth / 8 / 2,
+ DTRC_F1_OFS + DCSS_DTRC_SUVSEA);
+
+ *dtrc_w = xres;
+ *dtrc_h = yres;
+
+ if (ch->running)
+ return;
+
+ dcss_dtrc_write(ch, 0x0, DCSS_DTRC_SYSSA);
+ dcss_dtrc_write(ch, 0x0, DTRC_F1_OFS + DCSS_DTRC_SYSSA);
+
+ dcss_dtrc_write(ch, 0x10000000, DCSS_DTRC_SUVSSA);
+ dcss_dtrc_write(ch, 0x10000000, DTRC_F1_OFS + DCSS_DTRC_SUVSSA);
+}
+
+void dcss_dtrc_enable(struct dcss_dtrc *dtrc, int ch_num, bool enable)
+{
+ struct dcss_dtrc_ch *ch;
+ int curr_frame;
+ u32 fdctl, dtctrl;
+
+ if (ch_num == 0)
+ return;
+
+ ch = &dtrc->ch[ch_num - 1];
+
+ if (ch->bypass)
+ return;
+
+ if (!enable) {
+ ch->running = false;
+ return;
+ }
+
+ if (ch->running)
+ return;
+
+ dcss_update(HOT_RESET, HOT_RESET, ch->base_reg + DCSS_DTRC_DTCTRL);
+ while (dcss_readl(ch->base_reg + DCSS_DTRC_DTCTRL) & HOT_RESET)
+ usleep_range(100, 200);
+
+ dcss_dtrc_write(ch, 0x0f0e0100,
+ DCSS_DTRC_ARIDR);
+ dcss_dtrc_write(ch, 0x0f0e,
+ DCSS_DTRC_DTID2DDR);
+
+ dtctrl = ADDRESS_ID_ENABLE | MERGE_ARID_ENABLE |
+ ((0xF << TABLE_DATA_SWAP_POS) & TABLE_DATA_SWAP_MASK) |
+ ((0x10 << BURST_LENGTH_POS) & BURST_LENGTH_MASK);
+
+ if (ch->format_modifier == DRM_FORMAT_MOD_VSI_G1_TILED)
+ dtctrl |= G1_TILED_DATA_EN;
+
+ dcss_dtrc_write(ch, dtctrl, DCSS_DTRC_DTCTRL);
+
+ curr_frame = dcss_readl(ch->base_reg + DCSS_DTRC_DTCTRL) >> 31;
+
+ fdctl = ch->dctl & ~(PIX_DEPTH_8BIT_EN | COMPRESSION_DIS);
+
+ fdctl |= ch->pix_format == DRM_FORMAT_NV12_10LE40 ? 0 : PIX_DEPTH_8BIT_EN;
+
+ if (ch->format_modifier != DRM_FORMAT_MOD_VSI_G2_TILED_COMPRESSED)
+ fdctl |= COMPRESSION_DIS;
+
+ dcss_dtrc_write(ch, fdctl,
+ (curr_frame ^ 1) * DTRC_F1_OFS + DCSS_DTRC_DCTL);
+ dcss_dtrc_write(ch, fdctl | CONFIG_READY,
+ curr_frame * DTRC_F1_OFS + DCSS_DTRC_DCTL);
+
+ ch->curr_frame = curr_frame;
+ ch->dctl = fdctl;
+ ch->running = true;
+}
+
+bool dcss_dtrc_ch_running(struct dcss_dtrc *dtrc, int ch_num)
+{
+ struct dcss_dtrc_ch *ch;
+
+ if (ch_num == 0)
+ return false;
+
+ ch = &dtrc->ch[ch_num - 1];
+
+ return ch->running;
+}
+
+bool dcss_dtrc_is_running(struct dcss_dtrc *dtrc)
+{
+ return dtrc->ch[0].running || dtrc->ch[1].running;
+}
+
+static void dcss_dtrc_ch_switch_banks(struct dcss_dtrc *dtrc, int dtrc_ch)
+{
+ struct dcss_dtrc_ch *ch = &dtrc->ch[dtrc_ch];
+ u32 b0, b1;
+
+ if (!ch->running)
+ return;
+
+ b0 = dcss_readl(ch->base_reg + DCSS_DTRC_DCTL) & 0x1;
+ b1 = dcss_readl(ch->base_reg + DTRC_F1_OFS + DCSS_DTRC_DCTL) & 0x1;
+
+ ch->curr_frame = dcss_readl(ch->base_reg + DCSS_DTRC_DTCTRL) >> 31;
+
+ dcss_dtrc_write_irqsafe(ch, ch->dctl | CONFIG_READY,
+ (ch->curr_frame ^ 1) * DTRC_F1_OFS + DCSS_DTRC_DCTL);
+}
+
+void dcss_dtrc_switch_banks(struct dcss_dtrc *dtrc)
+{
+ dcss_dtrc_ch_switch_banks(dtrc, 0);
+ dcss_dtrc_ch_switch_banks(dtrc, 1);
+}
diff --git a/drivers/gpu/drm/imx/dcss/dcss-hdr10-tables.h b/drivers/gpu/drm/imx/dcss/dcss-hdr10-tables.h
new file mode 100644
index 000000000000..a8f3e1d42926
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/dcss-hdr10-tables.h
@@ -0,0 +1,1311 @@
+/*
+ * Copyright (C) 2018 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_HDR10_TABLES_H__
+#define __DCSS_HDR10_TABLES_H__
+
+/*
+ * Table descriptor (64 bit) contains flags with identify to which
+ * input/output configurations' combinations the table is applied. Choosing the
+ * right CSC depends on both output/input pipe configuration.
+ *
+ * Bit 0-2: Table type
+ * * LUT - bit 0
+ * * CSCA - bit 1 (CSC for output pipe)
+ * * CSCB - bit 2 (not used for output pipe)
+ * Bit 3: Pipe type
+ * * Input - unset
+ * * Output - set
+ * Bit 4-5: Input pipe bits-per-component
+ * * 8 bpc - bit 4
+ * * 10 bpc - bit 5
+ * Bit 6-7: Input pipe colorspace
+ * * RGB - bit 6
+ * * YUV - bit 7
+ * Bit 8-12: Input pipe nonlinearity
+ * * REC2084 - bit 8
+ * * REC709 - bit 9
+ * * BT1886 - bit 10
+ * * REC2100HLG - bit 11
+ * * SRGB - bit 12
+ * Bit 13-14: Input pipe pixel range
+ * * Limited - bit 13
+ * * Full - bit 14
+ * Bit 15-19: Input pipe gamut
+ * * REC2020 - bit 15
+ * * REC709 - bit 16
+ * * REC601_NTSC - bit 17
+ * * REC601_PAL - bit 18
+ * * ADOBE_RGB - bit 19
+ * Bit 20-21: Output pipe bits-per-component (see above)
+ * Bit 22-23: Output pipe colorspace (see above)
+ * Bit 24-28: Output pipe nonlinearity (see above)
+ * Bit 29-30: Ouptut pipe pixel range (see above)
+ * Bit 31-35: Output pipe gamut (see above)
+ */
+
+static u32 dcss_hdr10_tables[] = {
+ /* table descriptor */
+ 0x68effbe9, 0xf,
+ /* table length */
+ 0x400,
+ /* table data */
+ 0x552, 0x153, 0x10ef, 0x54, 0x2fd, 0x92d, 0x208d, 0x14, 0xbe, 0x213, 0x412,
+ 0x6ea, 0xc62, 0x1764, 0x2d8d, 0x5, 0x2f, 0x83, 0x103, 0x1ad, 0x282, 0x382,
+ 0x4ad, 0x60c, 0x7f2, 0xaa4, 0xe76, 0x13e1, 0x1b92, 0x267c, 0x35f8, 0x1,
+ 0xb, 0x20, 0x40, 0x6a, 0x9f, 0xdf, 0x12a, 0x17f, 0x1df, 0x249, 0x2be,
+ 0x33e, 0x3c9, 0x45e, 0x4fe, 0x5ab, 0x676, 0x768, 0x889, 0x9e0, 0xb79,
+ 0xd60, 0xfa4, 0x1258, 0x158f, 0x1964, 0x1df4, 0x2364, 0x29dd, 0x3193,
+ 0x3ac3, 0x0, 0x2, 0x7, 0xf, 0x1a, 0x27, 0x37, 0x49, 0x5f, 0x76, 0x91, 0xae,
+ 0xce, 0xf1, 0x116, 0x13e, 0x168, 0x196, 0x1c6, 0x1f8, 0x22d, 0x265, 0x2a0,
+ 0x2dd, 0x31d, 0x360, 0x3a5, 0x3ed, 0x438, 0x485, 0x4d5, 0x528, 0x57e,
+ 0x5db, 0x640, 0x6af, 0x728, 0x7ac, 0x83c, 0x8d9, 0x984, 0xa40, 0xb0c,
+ 0xbeb, 0xcde, 0xde8, 0xf0a, 0x1046, 0x119f, 0x1318, 0x14b4, 0x1674, 0x185e,
+ 0x1a75, 0x1cbd, 0x1f39, 0x21f1, 0x24e7, 0x2823, 0x2bab, 0x2f85, 0x33b9,
+ 0x3850, 0x3d52, 0x0, 0x0, 0x1, 0x3, 0x6, 0x9, 0xd, 0x12, 0x17, 0x1d, 0x23,
+ 0x2b, 0x33, 0x3b, 0x45, 0x4e, 0x59, 0x64, 0x70, 0x7d, 0x8a, 0x98, 0xa7,
+ 0xb6, 0xc6, 0xd7, 0xe8, 0xfa, 0x10c, 0x120, 0x134, 0x148, 0x15e, 0x174,
+ 0x18a, 0x1a1, 0x1b9, 0x1d2, 0x1eb, 0x205, 0x220, 0x23b, 0x257, 0x274,
+ 0x291, 0x2af, 0x2ce, 0x2ed, 0x30d, 0x32e, 0x34f, 0x371, 0x394, 0x3b7,
+ 0x3db, 0x400, 0x425, 0x44b, 0x472, 0x499, 0x4c1, 0x4ea, 0x513, 0x53d,
+ 0x568, 0x594, 0x5c3, 0x5f3, 0x626, 0x65b, 0x692, 0x6cc, 0x709, 0x748,
+ 0x78a, 0x7cf, 0x817, 0x862, 0x8b0, 0x902, 0x958, 0x9b2, 0xa0f, 0xa71,
+ 0xad7, 0xb42, 0xbb1, 0xc26, 0xc9f, 0xd1e, 0xda3, 0xe2e, 0xebf, 0xf56,
+ 0xff4, 0x109a, 0x1146, 0x11fb, 0x12b7, 0x137c, 0x1449, 0x1520, 0x1600,
+ 0x16eb, 0x17e0, 0x18e0, 0x19eb, 0x1b02, 0x1c26, 0x1d57, 0x1e95, 0x1fe2,
+ 0x213d, 0x22a8, 0x2423, 0x25af, 0x274d, 0x28fe, 0x2ac1, 0x2c99, 0x2e86,
+ 0x3089, 0x32a3, 0x34d5, 0x3721, 0x3986, 0x3c07, 0x3ea5, 0x0, 0x0, 0x0, 0x0,
+ 0x1, 0x2, 0x3, 0x4, 0x5, 0x7, 0x8, 0xa, 0xc, 0xe, 0x10, 0x13, 0x16, 0x18,
+ 0x1b, 0x1e, 0x22, 0x25, 0x29, 0x2d, 0x31, 0x35, 0x39, 0x3d, 0x42, 0x47,
+ 0x4c, 0x51, 0x56, 0x5c, 0x61, 0x67, 0x6d, 0x73, 0x7a, 0x80, 0x87, 0x8e,
+ 0x95, 0x9c, 0xa3, 0xaa, 0xb2, 0xba, 0xc2, 0xca, 0xd2, 0xdb, 0xe3, 0xec,
+ 0xf5, 0xfe, 0x108, 0x111, 0x11b, 0x125, 0x12f, 0x139, 0x143, 0x14e, 0x158,
+ 0x163, 0x16e, 0x179, 0x184, 0x190, 0x19c, 0x1a7, 0x1b3, 0x1bf, 0x1cc,
+ 0x1d8, 0x1e5, 0x1f2, 0x1ff, 0x20c, 0x219, 0x227, 0x234, 0x242, 0x250,
+ 0x25e, 0x26d, 0x27b, 0x28a, 0x299, 0x2a8, 0x2b7, 0x2c6, 0x2d6, 0x2e5,
+ 0x2f5, 0x305, 0x315, 0x325, 0x336, 0x347, 0x357, 0x368, 0x37a, 0x38b,
+ 0x39c, 0x3ae, 0x3c0, 0x3d2, 0x3e4, 0x3f6, 0x409, 0x41b, 0x42e, 0x441,
+ 0x454, 0x468, 0x47b, 0x48f, 0x4a3, 0x4b7, 0x4cb, 0x4df, 0x4f4, 0x508,
+ 0x51d, 0x532, 0x547, 0x55d, 0x573, 0x589, 0x5a0, 0x5b7, 0x5cf, 0x5e7,
+ 0x600, 0x619, 0x633, 0x64d, 0x669, 0x684, 0x6a0, 0x6bd, 0x6db, 0x6f9,
+ 0x718, 0x738, 0x758, 0x779, 0x79b, 0x7bd, 0x7e0, 0x804, 0x829, 0x84f,
+ 0x875, 0x89c, 0x8c4, 0x8ed, 0x917, 0x942, 0x96e, 0x99b, 0x9c9, 0x9f7,
+ 0xa27, 0xa58, 0xa8a, 0xabd, 0xaf1, 0xb27, 0xb5d, 0xb95, 0xbce, 0xc08,
+ 0xc44, 0xc80, 0xcbf, 0xcfe, 0xd3f, 0xd82, 0xdc5, 0xe0b, 0xe52, 0xe9a,
+ 0xee4, 0xf30, 0xf7d, 0xfcc, 0x101d, 0x1070, 0x10c4, 0x111a, 0x1173, 0x11cd,
+ 0x1229, 0x1287, 0x12e7, 0x134a, 0x13ae, 0x1415, 0x147e, 0x14ea, 0x1557,
+ 0x15c7, 0x163a, 0x16af, 0x1727, 0x17a2, 0x181f, 0x189f, 0x1921, 0x19a7,
+ 0x1a30, 0x1abb, 0x1b4a, 0x1bdc, 0x1c71, 0x1d09, 0x1da5, 0x1e44, 0x1ee7,
+ 0x1f8d, 0x2037, 0x20e5, 0x2196, 0x224c, 0x2305, 0x23c3, 0x2485, 0x254b,
+ 0x2615, 0x26e4, 0x27b8, 0x2890, 0x296d, 0x2a4f, 0x2b35, 0x2c21, 0x2d13,
+ 0x2e09, 0x2f05, 0x3006, 0x310e, 0x321b, 0x332e, 0x3447, 0x3566, 0x368b,
+ 0x37b8, 0x38ea, 0x3a24, 0x3b64, 0x3cac, 0x3dfa, 0x3f51, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x2, 0x2, 0x3, 0x3, 0x4, 0x4, 0x5, 0x6, 0x6,
+ 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x14, 0x15,
+ 0x16, 0x18, 0x19, 0x1b, 0x1c, 0x1e, 0x1f, 0x21, 0x23, 0x24, 0x26, 0x28,
+ 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3f, 0x41,
+ 0x43, 0x46, 0x48, 0x4b, 0x4d, 0x50, 0x52, 0x55, 0x58, 0x5a, 0x5d, 0x60,
+ 0x63, 0x66, 0x69, 0x6c, 0x6f, 0x72, 0x75, 0x78, 0x7b, 0x7e, 0x82, 0x85,
+ 0x88, 0x8c, 0x8f, 0x93, 0x96, 0x9a, 0x9d, 0xa1, 0xa5, 0xa9, 0xac, 0xb0,
+ 0xb4, 0xb8, 0xbc, 0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4, 0xd9, 0xdd, 0xe1,
+ 0xe6, 0xea, 0xee, 0xf3, 0xf7, 0xfc, 0x101, 0x105, 0x10a, 0x10f, 0x114,
+ 0x118, 0x11d, 0x122, 0x127, 0x12c, 0x131, 0x136, 0x13b, 0x140, 0x146,
+ 0x14b, 0x150, 0x155, 0x15b, 0x160, 0x166, 0x16b, 0x171, 0x176, 0x17c,
+ 0x182, 0x187, 0x18d, 0x193, 0x199, 0x19e, 0x1a4, 0x1aa, 0x1b0, 0x1b6,
+ 0x1bc, 0x1c3, 0x1c9, 0x1cf, 0x1d5, 0x1db, 0x1e2, 0x1e8, 0x1ef, 0x1f5,
+ 0x1fb, 0x202, 0x209, 0x20f, 0x216, 0x21d, 0x223, 0x22a, 0x231, 0x238,
+ 0x23f, 0x246, 0x24d, 0x254, 0x25b, 0x262, 0x269, 0x270, 0x277, 0x27f,
+ 0x286, 0x28d, 0x295, 0x29c, 0x2a4, 0x2ab, 0x2b3, 0x2bb, 0x2c2, 0x2ca,
+ 0x2d2, 0x2d9, 0x2e1, 0x2e9, 0x2f1, 0x2f9, 0x301, 0x309, 0x311, 0x319,
+ 0x321, 0x32a, 0x332, 0x33a, 0x342, 0x34b, 0x353, 0x35c, 0x364, 0x36d,
+ 0x375, 0x37e, 0x387, 0x38f, 0x398, 0x3a1, 0x3aa, 0x3b2, 0x3bb, 0x3c4,
+ 0x3cd, 0x3d6, 0x3df, 0x3e9, 0x3f2, 0x3fb, 0x404, 0x40d, 0x417, 0x420,
+ 0x42a, 0x433, 0x43d, 0x446, 0x450, 0x459, 0x463, 0x46d, 0x476, 0x480,
+ 0x48a, 0x494, 0x49e, 0x4a8, 0x4b2, 0x4bc, 0x4c6, 0x4d0, 0x4da, 0x4e4,
+ 0x4ef, 0x4f9, 0x503, 0x50e, 0x518, 0x523, 0x52d, 0x538, 0x542, 0x54d,
+ 0x557, 0x562, 0x56d, 0x578, 0x583, 0x58e, 0x59a, 0x5a5, 0x5b1, 0x5bd,
+ 0x5c9, 0x5d5, 0x5e1, 0x5ed, 0x5f9, 0x606, 0x613, 0x61f, 0x62c, 0x639,
+ 0x647, 0x654, 0x662, 0x66f, 0x67d, 0x68b, 0x699, 0x6a8, 0x6b6, 0x6c5,
+ 0x6d4, 0x6e2, 0x6f2, 0x701, 0x710, 0x720, 0x730, 0x740, 0x750, 0x760,
+ 0x771, 0x781, 0x792, 0x7a3, 0x7b4, 0x7c6, 0x7d7, 0x7e9, 0x7fb, 0x80d,
+ 0x820, 0x832, 0x845, 0x858, 0x86b, 0x87f, 0x892, 0x8a6, 0x8ba, 0x8cf,
+ 0x8e3, 0x8f8, 0x90d, 0x922, 0x937, 0x94d, 0x963, 0x979, 0x990, 0x9a6,
+ 0x9bd, 0x9d4, 0x9ec, 0xa03, 0xa1b, 0xa33, 0xa4c, 0xa65, 0xa7e, 0xa97,
+ 0xab0, 0xaca, 0xae4, 0xaff, 0xb19, 0xb34, 0xb50, 0xb6b, 0xb87, 0xba3,
+ 0xbc0, 0xbdc, 0xbf9, 0xc17, 0xc35, 0xc53, 0xc71, 0xc90, 0xcaf, 0xcce,
+ 0xcee, 0xd0e, 0xd2f, 0xd50, 0xd71, 0xd92, 0xdb4, 0xdd7, 0xdf9, 0xe1c,
+ 0xe40, 0xe64, 0xe88, 0xeac, 0xed1, 0xef7, 0xf1d, 0xf43, 0xf6a, 0xf91,
+ 0xfb8, 0xfe0, 0x1009, 0x1032, 0x105b, 0x1085, 0x10af, 0x10d9, 0x1105,
+ 0x1130, 0x115c, 0x1189, 0x11b6, 0x11e4, 0x1212, 0x1240, 0x126f, 0x129f,
+ 0x12cf, 0x1300, 0x1331, 0x1363, 0x1395, 0x13c8, 0x13fb, 0x142f, 0x1464,
+ 0x1499, 0x14ce, 0x1505, 0x153c, 0x1573, 0x15ab, 0x15e4, 0x161d, 0x1657,
+ 0x1692, 0x16cd, 0x1709, 0x1745, 0x1783, 0x17c1, 0x17ff, 0x183e, 0x187e,
+ 0x18bf, 0x1900, 0x1943, 0x1985, 0x19c9, 0x1a0d, 0x1a52, 0x1a98, 0x1adf,
+ 0x1b26, 0x1b6e, 0x1bb7, 0x1c01, 0x1c4b, 0x1c97, 0x1ce3, 0x1d30, 0x1d7e,
+ 0x1dcc, 0x1e1c, 0x1e6c, 0x1ebe, 0x1f10, 0x1f63, 0x1fb7, 0x200c, 0x2062,
+ 0x20b9, 0x2111, 0x216a, 0x21c3, 0x221e, 0x227a, 0x22d7, 0x2334, 0x2393,
+ 0x23f3, 0x2454, 0x24b6, 0x2519, 0x257d, 0x25e2, 0x2649, 0x26b0, 0x2719,
+ 0x2782, 0x27ed, 0x2859, 0x28c7, 0x2935, 0x29a5, 0x2a16, 0x2a88, 0x2afb,
+ 0x2b70, 0x2be6, 0x2c5d, 0x2cd6, 0x2d50, 0x2dcb, 0x2e47, 0x2ec5, 0x2f45,
+ 0x2fc6, 0x3048, 0x30cb, 0x3150, 0x31d7, 0x325f, 0x32e8, 0x3373, 0x3400,
+ 0x348e, 0x351d, 0x35af, 0x3641, 0x36d6, 0x376c, 0x3804, 0x389d, 0x3938,
+ 0x39d5, 0x3a73, 0x3b13, 0x3bb5, 0x3c59, 0x3cff, 0x3da6, 0x3e4f, 0x3efa,
+ 0x3fa7, 0x6,
+ /* table descriptor */
+ 0xe8effbe9, 0x0,
+ /* table length */
+ 0x400,
+ /* table data */
+ 0x32a8, 0x2ea6, 0x361d, 0x2aa0, 0x30fc, 0x344a, 0x3808, 0x2696, 0x2cf8,
+ 0x3012, 0x3208, 0x3374, 0x3517, 0x36eb, 0x38d8, 0x2281, 0x28f0, 0x2c0f,
+ 0x2e06, 0x2f5a, 0x3082, 0x3181, 0x3256, 0x3305, 0x33f8, 0x34a8, 0x359c,
+ 0x367b, 0x3771, 0x3867, 0x395e, 0x1e58, 0x24e1, 0x2808, 0x2a01, 0x2b54,
+ 0x2c7e, 0x2d7d, 0x2e53, 0x2efd, 0x2fbd, 0x3049, 0x30be, 0x313d, 0x31c8,
+ 0x322e, 0x327e, 0x32d5, 0x333a, 0x33b3, 0x3421, 0x3477, 0x34dd, 0x3557,
+ 0x35e8, 0x364a, 0x36b1, 0x372b, 0x37bd, 0x3835, 0x389d, 0x3918, 0x39ab,
+ 0x1a0b, 0x20c2, 0x23f6, 0x25f1, 0x2748, 0x2877, 0x2974, 0x2a4e, 0x2af8,
+ 0x2bb6, 0x2c45, 0x2cba, 0x2d39, 0x2dc3, 0x2e2c, 0x2e7c, 0x2ed1, 0x2f2b,
+ 0x2f8b, 0x2ff0, 0x302d, 0x3065, 0x309f, 0x30dd, 0x311d, 0x315f, 0x31a4,
+ 0x31ec, 0x321b, 0x3242, 0x326a, 0x3293, 0x32be, 0x32ec, 0x331f, 0x3356,
+ 0x3393, 0x33d5, 0x340e, 0x3435, 0x3460, 0x348f, 0x34c2, 0x34fa, 0x3536,
+ 0x3579, 0x35c1, 0x3608, 0x3633, 0x3662, 0x3695, 0x36cd, 0x370b, 0x374d,
+ 0x3796, 0x37e6, 0x381e, 0x384d, 0x3881, 0x38ba, 0x38f7, 0x393a, 0x3984,
+ 0x39d4, 0x1500, 0x1c85, 0x1fc3, 0x21cc, 0x2331, 0x2468, 0x2563, 0x2644,
+ 0x26ec, 0x27aa, 0x283e, 0x28b2, 0x2931, 0x29bb, 0x2a27, 0x2a76, 0x2acb,
+ 0x2b25, 0x2b85, 0x2bea, 0x2c2a, 0x2c61, 0x2c9c, 0x2cd9, 0x2d18, 0x2d5b,
+ 0x2da0, 0x2de8, 0x2e19, 0x2e3f, 0x2e67, 0x2e90, 0x2ebb, 0x2ee7, 0x2f14,
+ 0x2f43, 0x2f72, 0x2fa4, 0x2fd6, 0x3005, 0x301f, 0x303b, 0x3057, 0x3073,
+ 0x3091, 0x30ae, 0x30cd, 0x30ec, 0x310c, 0x312d, 0x314e, 0x3170, 0x3193,
+ 0x31b6, 0x31da, 0x31ff, 0x3212, 0x3225, 0x3238, 0x324c, 0x3260, 0x3274,
+ 0x3289, 0x329e, 0x32b3, 0x32c9, 0x32e0, 0x32f9, 0x3312, 0x332c, 0x3348,
+ 0x3365, 0x3383, 0x33a3, 0x33c4, 0x33e6, 0x3405, 0x3418, 0x342b, 0x3440,
+ 0x3455, 0x346b, 0x3483, 0x349b, 0x34b5, 0x34cf, 0x34eb, 0x3508, 0x3527,
+ 0x3546, 0x3568, 0x358a, 0x35ae, 0x35d4, 0x35fc, 0x3612, 0x3628, 0x363e,
+ 0x3656, 0x366e, 0x3688, 0x36a3, 0x36bf, 0x36dc, 0x36fb, 0x371b, 0x373c,
+ 0x375f, 0x3783, 0x37aa, 0x37d1, 0x37fb, 0x3813, 0x382a, 0x3841, 0x385a,
+ 0x3874, 0x388f, 0x38ab, 0x38c8, 0x38e7, 0x3907, 0x3929, 0x394c, 0x3971,
+ 0x3997, 0x39bf, 0x39e9, 0xea8, 0x1815, 0x1b60, 0x1d86, 0x1f03, 0x204c,
+ 0x2142, 0x2231, 0x22d6, 0x2391, 0x2430, 0x24a3, 0x2521, 0x25a9, 0x261e,
+ 0x266c, 0x26c0, 0x271a, 0x2779, 0x27dd, 0x2823, 0x285a, 0x2894, 0x28d1,
+ 0x2910, 0x2952, 0x2997, 0x29df, 0x2a14, 0x2a3a, 0x2a62, 0x2a8b, 0x2ab6,
+ 0x2ae1, 0x2b0e, 0x2b3d, 0x2b6c, 0x2b9d, 0x2bd0, 0x2c02, 0x2c1c, 0x2c37,
+ 0x2c53, 0x2c70, 0x2c8d, 0x2cab, 0x2cc9, 0x2ce8, 0x2d08, 0x2d29, 0x2d4a,
+ 0x2d6c, 0x2d8e, 0x2db2, 0x2dd5, 0x2dfa, 0x2e0f, 0x2e22, 0x2e36, 0x2e49,
+ 0x2e5d, 0x2e71, 0x2e86, 0x2e9b, 0x2eb0, 0x2ec6, 0x2edc, 0x2ef2, 0x2f09,
+ 0x2f20, 0x2f37, 0x2f4e, 0x2f66, 0x2f7f, 0x2f97, 0x2fb0, 0x2fc9, 0x2fe3,
+ 0x2ffd, 0x300b, 0x3019, 0x3026, 0x3034, 0x3042, 0x3050, 0x305e, 0x306c,
+ 0x307b, 0x3089, 0x3098, 0x30a7, 0x30b6, 0x30c5, 0x30d5, 0x30e4, 0x30f4,
+ 0x3104, 0x3114, 0x3125, 0x3135, 0x3146, 0x3157, 0x3168, 0x3179, 0x318a,
+ 0x319c, 0x31ad, 0x31bf, 0x31d1, 0x31e3, 0x31f5, 0x3204, 0x320d, 0x3216,
+ 0x3220, 0x3229, 0x3233, 0x323d, 0x3247, 0x3251, 0x325b, 0x3265, 0x326f,
+ 0x3279, 0x3283, 0x328e, 0x3298, 0x32a3, 0x32ae, 0x32b8, 0x32c4, 0x32cf,
+ 0x32da, 0x32e6, 0x32f2, 0x32ff, 0x330c, 0x3318, 0x3326, 0x3333, 0x3341,
+ 0x334f, 0x335e, 0x336c, 0x337c, 0x338b, 0x339b, 0x33ab, 0x33bb, 0x33cc,
+ 0x33dd, 0x33ef, 0x3400, 0x3409, 0x3413, 0x341c, 0x3426, 0x3430, 0x343a,
+ 0x3445, 0x3450, 0x345b, 0x3466, 0x3471, 0x347d, 0x3489, 0x3495, 0x34a2,
+ 0x34ae, 0x34bb, 0x34c9, 0x34d6, 0x34e4, 0x34f2, 0x3501, 0x3510, 0x351f,
+ 0x352f, 0x353e, 0x354f, 0x355f, 0x3570, 0x3581, 0x3593, 0x35a5, 0x35b8,
+ 0x35cb, 0x35de, 0x35f2, 0x3603, 0x360d, 0x3618, 0x3622, 0x362d, 0x3639,
+ 0x3644, 0x3650, 0x365c, 0x3668, 0x3675, 0x3682, 0x368f, 0x369c, 0x36aa,
+ 0x36b8, 0x36c6, 0x36d5, 0x36e4, 0x36f3, 0x3703, 0x3713, 0x3723, 0x3734,
+ 0x3745, 0x3756, 0x3768, 0x377a, 0x378d, 0x37a0, 0x37b3, 0x37c7, 0x37dc,
+ 0x37f0, 0x3802, 0x380d, 0x3818, 0x3824, 0x382f, 0x383b, 0x3847, 0x3854,
+ 0x3860, 0x386d, 0x387a, 0x3888, 0x3896, 0x38a4, 0x38b2, 0x38c1, 0x38d0,
+ 0x38df, 0x38ef, 0x38ff, 0x3910, 0x3920, 0x3932, 0x3943, 0x3955, 0x3967,
+ 0x397a, 0x398d, 0x39a1, 0x39b5, 0x39c9, 0x39de, 0x39f4, 0x0, 0x12aa,
+ 0x16ab, 0x1900, 0x1aab, 0x1c15, 0x1d00, 0x1e0b, 0x1eab, 0x1f60, 0x2015,
+ 0x2085, 0x2100, 0x2186, 0x220b, 0x2258, 0x22ab, 0x2303, 0x2360, 0x23c3,
+ 0x2415, 0x244c, 0x2485, 0x24c2, 0x2500, 0x2542, 0x2586, 0x25cc, 0x260b,
+ 0x2631, 0x2658, 0x2681, 0x26ab, 0x26d6, 0x2703, 0x2731, 0x2760, 0x2791,
+ 0x27c3, 0x27f6, 0x2815, 0x2830, 0x284c, 0x2868, 0x2885, 0x28a3, 0x28c2,
+ 0x28e1, 0x2900, 0x2921, 0x2942, 0x2963, 0x2986, 0x29a9, 0x29cc, 0x29f1,
+ 0x2a0b, 0x2a1e, 0x2a31, 0x2a44, 0x2a58, 0x2a6c, 0x2a81, 0x2a96, 0x2aab,
+ 0x2ac0, 0x2ad6, 0x2aec, 0x2b03, 0x2b1a, 0x2b31, 0x2b48, 0x2b60, 0x2b79,
+ 0x2b91, 0x2baa, 0x2bc3, 0x2bdd, 0x2bf6, 0x2c08, 0x2c15, 0x2c23, 0x2c30,
+ 0x2c3e, 0x2c4c, 0x2c5a, 0x2c68, 0x2c77, 0x2c85, 0x2c94, 0x2ca3, 0x2cb2,
+ 0x2cc2, 0x2cd1, 0x2ce1, 0x2cf0, 0x2d00, 0x2d10, 0x2d21, 0x2d31, 0x2d42,
+ 0x2d52, 0x2d63, 0x2d74, 0x2d86, 0x2d97, 0x2da9, 0x2dbb, 0x2dcc, 0x2ddf,
+ 0x2df1, 0x2e01, 0x2e0b, 0x2e14, 0x2e1e, 0x2e27, 0x2e31, 0x2e3a, 0x2e44,
+ 0x2e4e, 0x2e58, 0x2e62, 0x2e6c, 0x2e76, 0x2e81, 0x2e8b, 0x2e96, 0x2ea0,
+ 0x2eab, 0x2eb6, 0x2ec0, 0x2ecb, 0x2ed6, 0x2ee1, 0x2eec, 0x2ef8, 0x2f03,
+ 0x2f0e, 0x2f1a, 0x2f25, 0x2f31, 0x2f3d, 0x2f48, 0x2f54, 0x2f60, 0x2f6c,
+ 0x2f79, 0x2f85, 0x2f91, 0x2f9d, 0x2faa, 0x2fb6, 0x2fc3, 0x2fd0, 0x2fdd,
+ 0x2fea, 0x2ff6, 0x3002, 0x3008, 0x300f, 0x3015, 0x301c, 0x3023, 0x302a,
+ 0x3030, 0x3037, 0x303e, 0x3045, 0x304c, 0x3053, 0x305a, 0x3061, 0x3068,
+ 0x3070, 0x3077, 0x307e, 0x3085, 0x308d, 0x3094, 0x309c, 0x30a3, 0x30ab,
+ 0x30b2, 0x30ba, 0x30c2, 0x30c9, 0x30d1, 0x30d9, 0x30e1, 0x30e8, 0x30f0,
+ 0x30f8, 0x3100, 0x3108, 0x3110, 0x3118, 0x3121, 0x3129, 0x3131, 0x3139,
+ 0x3142, 0x314a, 0x3152, 0x315b, 0x3163, 0x316c, 0x3174, 0x317d, 0x3186,
+ 0x318e, 0x3197, 0x31a0, 0x31a9, 0x31b2, 0x31bb, 0x31c3, 0x31cc, 0x31d5,
+ 0x31df, 0x31e8, 0x31f1, 0x31fa, 0x3201, 0x3206, 0x320b, 0x320f, 0x3214,
+ 0x3219, 0x321e, 0x3222, 0x3227, 0x322c, 0x3231, 0x3236, 0x323a, 0x323f,
+ 0x3244, 0x3249, 0x324e, 0x3253, 0x3258, 0x325d, 0x3262, 0x3267, 0x326c,
+ 0x3271, 0x3276, 0x327c, 0x3281, 0x3286, 0x328b, 0x3290, 0x3296, 0x329b,
+ 0x32a0, 0x32a6, 0x32ab, 0x32b0, 0x32b6, 0x32bb, 0x32c1, 0x32c6, 0x32cc,
+ 0x32d2, 0x32d8, 0x32dd, 0x32e3, 0x32e9, 0x32ef, 0x32f6, 0x32fc, 0x3302,
+ 0x3308, 0x330f, 0x3315, 0x331c, 0x3322, 0x3329, 0x3330, 0x3337, 0x333e,
+ 0x3345, 0x334c, 0x3353, 0x335a, 0x3361, 0x3369, 0x3370, 0x3378, 0x337f,
+ 0x3387, 0x338f, 0x3397, 0x339f, 0x33a7, 0x33af, 0x33b7, 0x33bf, 0x33c8,
+ 0x33d0, 0x33d9, 0x33e2, 0x33eb, 0x33f3, 0x33fc, 0x3402, 0x3407, 0x340c,
+ 0x3410, 0x3415, 0x341a, 0x341f, 0x3424, 0x3429, 0x342e, 0x3433, 0x3438,
+ 0x343d, 0x3442, 0x3448, 0x344d, 0x3452, 0x3458, 0x345d, 0x3463, 0x3469,
+ 0x346e, 0x3474, 0x347a, 0x3480, 0x3486, 0x348c, 0x3492, 0x3498, 0x349e,
+ 0x34a5, 0x34ab, 0x34b2, 0x34b8, 0x34bf, 0x34c5, 0x34cc, 0x34d3, 0x34da,
+ 0x34e1, 0x34e8, 0x34ef, 0x34f6, 0x34fd, 0x3505, 0x350c, 0x3514, 0x351b,
+ 0x3523, 0x352b, 0x3532, 0x353a, 0x3542, 0x354b, 0x3553, 0x355b, 0x3563,
+ 0x356c, 0x3574, 0x357d, 0x3586, 0x358f, 0x3598, 0x35a1, 0x35aa, 0x35b3,
+ 0x35bc, 0x35c6, 0x35cf, 0x35d9, 0x35e3, 0x35ed, 0x35f7, 0x3600, 0x3605,
+ 0x360a, 0x3610, 0x3615, 0x361a, 0x3620, 0x3625, 0x362b, 0x3630, 0x3636,
+ 0x363b, 0x3641, 0x3647, 0x364d, 0x3653, 0x3659, 0x365f, 0x3665, 0x366b,
+ 0x3672, 0x3678, 0x367e, 0x3685, 0x368b, 0x3692, 0x3699, 0x36a0, 0x36a6,
+ 0x36ad, 0x36b4, 0x36bb, 0x36c3, 0x36ca, 0x36d1, 0x36d9, 0x36e0, 0x36e8,
+ 0x36ef, 0x36f7, 0x36ff, 0x3707, 0x370f, 0x3717, 0x371f, 0x3727, 0x372f,
+ 0x3738, 0x3740, 0x3749, 0x3752, 0x375b, 0x3764, 0x376d, 0x3776, 0x377f,
+ 0x3788, 0x3792, 0x379b, 0x37a5, 0x37ae, 0x37b8, 0x37c2, 0x37cc, 0x37d6,
+ 0x37e1, 0x37eb, 0x37f6, 0x3800, 0x3805, 0x380b, 0x3810, 0x3816, 0x381b,
+ 0x3821, 0x3827, 0x382c, 0x3832, 0x3838, 0x383e, 0x3844, 0x384a, 0x3851,
+ 0x3857, 0x385d, 0x3864, 0x386a, 0x3870, 0x3877, 0x387e, 0x3885, 0x388b,
+ 0x3892, 0x3899, 0x38a0, 0x38a7, 0x38af, 0x38b6, 0x38bd, 0x38c5, 0x38cc,
+ 0x38d4, 0x38dc, 0x38e3, 0x38eb, 0x38f3, 0x38fb, 0x3903, 0x390c, 0x3914,
+ 0x391c, 0x3925, 0x392d, 0x3936, 0x393f, 0x3948, 0x3951, 0x395a, 0x3963,
+ 0x396c, 0x3975, 0x397f, 0x3989, 0x3992, 0x399c, 0x39a6, 0x39b0, 0x39ba,
+ 0x39c4, 0x39cf, 0x39d9, 0x39e4, 0x39ee, 0x39f9, 0xc,
+ /* table descriptor */
+ 0xe1effbe9, 0x0,
+ /* table length */
+ 0x400,
+ /* table data */
+ 0x2c59, 0x2416, 0x3322, 0x1dd0, 0x287e, 0x2ff0, 0x3679, 0x188b, 0x2131,
+ 0x2661, 0x2a78, 0x2e2b, 0x3186, 0x34c8, 0x3836, 0x141d, 0x1b81, 0x1fa3,
+ 0x22a3, 0x2531, 0x277a, 0x2988, 0x2b6b, 0x2d33, 0x2eed, 0x30a3, 0x325a,
+ 0x3416, 0x35b5, 0x374e, 0x38f8, 0xff8, 0x1698, 0x1a32, 0x1ca3, 0x1eab,
+ 0x206e, 0x2210, 0x2355, 0x2497, 0x25e9, 0x26e2, 0x2816, 0x28f9, 0x2a17,
+ 0x2ae8, 0x2c01, 0x2cbe, 0x2dbb, 0x2e85, 0x2f65, 0x3047, 0x310d, 0x3209,
+ 0x32b7, 0x339e, 0x3469, 0x3536, 0x3624, 0x36db, 0x37d2, 0x388f, 0x3971,
+ 0xbe0, 0x124a, 0x1572, 0x17b5, 0x1962, 0x1acc, 0x1c29, 0x1d30, 0x1e43,
+ 0x1f20, 0x201b, 0x20ca, 0x21a2, 0x2256, 0x22f8, 0x23bc, 0x2454, 0x24e1,
+ 0x2589, 0x2629, 0x269f, 0x272b, 0x27d0, 0x2848, 0x28b9, 0x293d, 0x29d8,
+ 0x2a45, 0x2aae, 0x2b27, 0x2bb4, 0x2c2b, 0x2c89, 0x2cf6, 0x2d74, 0x2e03,
+ 0x2e57, 0x2eb8, 0x2f27, 0x2fa8, 0x301e, 0x3073, 0x30d6, 0x3147, 0x31ca,
+ 0x3230, 0x3287, 0x32eb, 0x335e, 0x33e3, 0x343e, 0x3497, 0x34fd, 0x3573,
+ 0x35fc, 0x364d, 0x36a8, 0x3712, 0x378d, 0x380e, 0x3861, 0x38c1, 0x3932,
+ 0x39b5, 0x700, 0xe30, 0x1120, 0x132c, 0x14bb, 0x1621, 0x171f, 0x182e,
+ 0x18f2, 0x19de, 0x1a7c, 0x1b23, 0x1be6, 0x1c64, 0x1ce7, 0x1d7d, 0x1e14,
+ 0x1e75, 0x1ee3, 0x1f60, 0x1feb, 0x2043, 0x209b, 0x20fc, 0x2168, 0x21e0,
+ 0x2232, 0x227b, 0x22cc, 0x2325, 0x2387, 0x23f3, 0x2434, 0x2475, 0x24bb,
+ 0x2508, 0x255d, 0x25b8, 0x260e, 0x2644, 0x2680, 0x26c0, 0x2706, 0x2752,
+ 0x27a4, 0x27fd, 0x282f, 0x2863, 0x289b, 0x28d8, 0x291a, 0x2962, 0x29af,
+ 0x2a01, 0x2a2e, 0x2a5e, 0x2a92, 0x2aca, 0x2b07, 0x2b48, 0x2b8f, 0x2bda,
+ 0x2c16, 0x2c41, 0x2c70, 0x2ca3, 0x2cda, 0x2d14, 0x2d53, 0x2d97, 0x2de0,
+ 0x2e17, 0x2e41, 0x2e6e, 0x2e9e, 0x2ed2, 0x2f0a, 0x2f46, 0x2f86, 0x2fcb,
+ 0x300a, 0x3032, 0x305d, 0x308b, 0x30bc, 0x30f1, 0x3129, 0x3166, 0x31a8,
+ 0x31ee, 0x321c, 0x3245, 0x3270, 0x329f, 0x32d1, 0x3306, 0x3340, 0x337e,
+ 0x33c0, 0x3404, 0x342a, 0x3453, 0x347f, 0x34af, 0x34e2, 0x3519, 0x3554,
+ 0x3593, 0x35d8, 0x3610, 0x3638, 0x3662, 0x3690, 0x36c1, 0x36f6, 0x372f,
+ 0x376d, 0x37af, 0x37f7, 0x3821, 0x384b, 0x3878, 0x38a8, 0x38dc, 0x3914,
+ 0x3951, 0x3992, 0x39d9, 0x200, 0xa20, 0xd00, 0xf00, 0x1084, 0x11d0, 0x12b6,
+ 0x13ae, 0x1469, 0x1513, 0x15d7, 0x165b, 0x16da, 0x1768, 0x1803, 0x185b,
+ 0x18bd, 0x1929, 0x199f, 0x1a10, 0x1a56, 0x1aa3, 0x1af6, 0x1b51, 0x1bb2,
+ 0x1c0e, 0x1c46, 0x1c83, 0x1cc5, 0x1d0b, 0x1d56, 0x1da6, 0x1dfc, 0x1e2b,
+ 0x1e5c, 0x1e90, 0x1ec7, 0x1f01, 0x1f3f, 0x1f81, 0x1fc7, 0x2008, 0x202f,
+ 0x2058, 0x2084, 0x20b2, 0x20e3, 0x2116, 0x214c, 0x2185, 0x21c1, 0x2200,
+ 0x2221, 0x2244, 0x2268, 0x228f, 0x22b7, 0x22e2, 0x230e, 0x233d, 0x236e,
+ 0x23a1, 0x23d7, 0x2407, 0x2425, 0x2444, 0x2464, 0x2486, 0x24a9, 0x24ce,
+ 0x24f4, 0x251d, 0x2547, 0x2573, 0x25a1, 0x25d1, 0x2601, 0x261b, 0x2636,
+ 0x2653, 0x2670, 0x268f, 0x26af, 0x26d1, 0x26f4, 0x2718, 0x273e, 0x2766,
+ 0x278f, 0x27b9, 0x27e6, 0x280a, 0x2822, 0x283b, 0x2855, 0x2870, 0x288d,
+ 0x28aa, 0x28c9, 0x28e8, 0x2909, 0x292c, 0x294f, 0x2975, 0x299b, 0x29c3,
+ 0x29ed, 0x2a0c, 0x2a22, 0x2a39, 0x2a52, 0x2a6b, 0x2a85, 0x2aa0, 0x2abc,
+ 0x2ad9, 0x2af7, 0x2b17, 0x2b38, 0x2b59, 0x2b7d, 0x2ba1, 0x2bc7, 0x2bee,
+ 0x2c0b, 0x2c20, 0x2c36, 0x2c4d, 0x2c64, 0x2c7d, 0x2c96, 0x2cb0, 0x2ccc,
+ 0x2ce8, 0x2d05, 0x2d24, 0x2d43, 0x2d64, 0x2d85, 0x2da9, 0x2dcd, 0x2df3,
+ 0x2e0d, 0x2e21, 0x2e36, 0x2e4c, 0x2e62, 0x2e79, 0x2e92, 0x2eab, 0x2ec5,
+ 0x2ee0, 0x2efb, 0x2f18, 0x2f36, 0x2f55, 0x2f76, 0x2f97, 0x2fb9, 0x2fdd,
+ 0x3001, 0x3014, 0x3028, 0x303d, 0x3052, 0x3068, 0x307f, 0x3097, 0x30af,
+ 0x30c9, 0x30e3, 0x30ff, 0x311b, 0x3138, 0x3157, 0x3176, 0x3197, 0x31b9,
+ 0x31dc, 0x3200, 0x3213, 0x3226, 0x323a, 0x324f, 0x3265, 0x327b, 0x3293,
+ 0x32ab, 0x32c4, 0x32de, 0x32f8, 0x3314, 0x3331, 0x334f, 0x336e, 0x338e,
+ 0x33af, 0x33d2, 0x33f5, 0x340d, 0x3420, 0x3434, 0x3448, 0x345e, 0x3474,
+ 0x348b, 0x34a3, 0x34bb, 0x34d5, 0x34ef, 0x350b, 0x3527, 0x3545, 0x3563,
+ 0x3583, 0x35a4, 0x35c6, 0x35ea, 0x3607, 0x361a, 0x362e, 0x3642, 0x3657,
+ 0x366d, 0x3684, 0x369c, 0x36b5, 0x36ce, 0x36e9, 0x3704, 0x3721, 0x373e,
+ 0x375d, 0x377d, 0x379e, 0x37c1, 0x37e4, 0x3804, 0x3818, 0x382c, 0x3840,
+ 0x3856, 0x386c, 0x3883, 0x389b, 0x38b5, 0x38cf, 0x38ea, 0x3906, 0x3923,
+ 0x3941, 0x3961, 0x3981, 0x39a3, 0x39c7, 0x39ec, 0x0, 0x500, 0x8c0, 0xae0,
+ 0xc70, 0xdb0, 0xe98, 0xf78, 0x103c, 0x10d0, 0x1178, 0x1218, 0x127e, 0x12f0,
+ 0x136c, 0x13f2, 0x1442, 0x1491, 0x14e6, 0x1542, 0x15a4, 0x1606, 0x163e,
+ 0x1679, 0x16b9, 0x16fc, 0x1743, 0x178e, 0x17dd, 0x1818, 0x1844, 0x1873,
+ 0x18a4, 0x18d7, 0x190d, 0x1945, 0x1980, 0x19be, 0x19ff, 0x1a21, 0x1a44,
+ 0x1a69, 0x1a8f, 0x1ab7, 0x1ae1, 0x1b0c, 0x1b39, 0x1b68, 0x1b99, 0x1bcc,
+ 0x1c00, 0x1c1b, 0x1c38, 0x1c55, 0x1c74, 0x1c93, 0x1cb4, 0x1cd6, 0x1cf9,
+ 0x1d1d, 0x1d42, 0x1d69, 0x1d91, 0x1dbb, 0x1de6, 0x1e09, 0x1e20, 0x1e37,
+ 0x1e4f, 0x1e69, 0x1e82, 0x1e9d, 0x1eb9, 0x1ed5, 0x1ef2, 0x1f10, 0x1f2f,
+ 0x1f4f, 0x1f70, 0x1f92, 0x1fb5, 0x1fd9, 0x1ffe, 0x2012, 0x2025, 0x2039,
+ 0x204e, 0x2063, 0x2079, 0x208f, 0x20a6, 0x20be, 0x20d6, 0x20ef, 0x2109,
+ 0x2123, 0x213e, 0x215a, 0x2176, 0x2194, 0x21b2, 0x21d0, 0x21f0, 0x2208,
+ 0x2218, 0x2229, 0x223b, 0x224d, 0x225f, 0x2272, 0x2285, 0x2299, 0x22ad,
+ 0x22c2, 0x22d7, 0x22ed, 0x2303, 0x231a, 0x2331, 0x2349, 0x2361, 0x237a,
+ 0x2394, 0x23ae, 0x23c9, 0x23e5, 0x2400, 0x240f, 0x241d, 0x242c, 0x243c,
+ 0x244c, 0x245c, 0x246c, 0x247d, 0x248e, 0x24a0, 0x24b2, 0x24c4, 0x24d7,
+ 0x24eb, 0x24fe, 0x2512, 0x2527, 0x253c, 0x2552, 0x2568, 0x257e, 0x2595,
+ 0x25ac, 0x25c4, 0x25dd, 0x25f6, 0x2607, 0x2614, 0x2622, 0x262f, 0x263d,
+ 0x264c, 0x265a, 0x2669, 0x2678, 0x2687, 0x2697, 0x26a7, 0x26b8, 0x26c8,
+ 0x26d9, 0x26eb, 0x26fd, 0x270f, 0x2722, 0x2734, 0x2748, 0x275c, 0x2770,
+ 0x2784, 0x2799, 0x27af, 0x27c4, 0x27db, 0x27f1, 0x2804, 0x2810, 0x281c,
+ 0x2828, 0x2835, 0x2842, 0x284f, 0x285c, 0x286a, 0x2877, 0x2886, 0x2894,
+ 0x28a3, 0x28b2, 0x28c1, 0x28d0, 0x28e0, 0x28f1, 0x2901, 0x2912, 0x2923,
+ 0x2935, 0x2946, 0x2959, 0x296b, 0x297e, 0x2991, 0x29a5, 0x29b9, 0x29cd,
+ 0x29e2, 0x29f7, 0x2a06, 0x2a11, 0x2a1c, 0x2a28, 0x2a33, 0x2a3f, 0x2a4b,
+ 0x2a58, 0x2a64, 0x2a71, 0x2a7e, 0x2a8b, 0x2a99, 0x2aa7, 0x2ab5, 0x2ac3,
+ 0x2ad2, 0x2ae1, 0x2af0, 0x2aff, 0x2b0f, 0x2b1f, 0x2b2f, 0x2b40, 0x2b51,
+ 0x2b62, 0x2b74, 0x2b86, 0x2b98, 0x2baa, 0x2bbd, 0x2bd0, 0x2be4, 0x2bf8,
+ 0x2c06, 0x2c10, 0x2c1b, 0x2c26, 0x2c31, 0x2c3c, 0x2c47, 0x2c53, 0x2c5e,
+ 0x2c6a, 0x2c77, 0x2c83, 0x2c90, 0x2c9d, 0x2caa, 0x2cb7, 0x2cc5, 0x2cd3,
+ 0x2ce1, 0x2cef, 0x2cfe, 0x2d0d, 0x2d1c, 0x2d2b, 0x2d3b, 0x2d4b, 0x2d5b,
+ 0x2d6c, 0x2d7d, 0x2d8e, 0x2da0, 0x2db2, 0x2dc4, 0x2dd6, 0x2de9, 0x2dfc,
+ 0x2e08, 0x2e12, 0x2e1c, 0x2e26, 0x2e30, 0x2e3b, 0x2e46, 0x2e51, 0x2e5c,
+ 0x2e68, 0x2e73, 0x2e7f, 0x2e8b, 0x2e98, 0x2ea4, 0x2eb1, 0x2ebe, 0x2ecb,
+ 0x2ed9, 0x2ee6, 0x2ef4, 0x2f03, 0x2f11, 0x2f20, 0x2f2f, 0x2f3e, 0x2f4e,
+ 0x2f5d, 0x2f6d, 0x2f7e, 0x2f8e, 0x2f9f, 0x2fb1, 0x2fc2, 0x2fd4, 0x2fe6,
+ 0x2ff9, 0x3006, 0x300f, 0x3019, 0x3023, 0x302d, 0x3037, 0x3042, 0x304d,
+ 0x3057, 0x3062, 0x306e, 0x3079, 0x3085, 0x3091, 0x309d, 0x30a9, 0x30b6,
+ 0x30c2, 0x30cf, 0x30dd, 0x30ea, 0x30f8, 0x3106, 0x3114, 0x3122, 0x3131,
+ 0x3140, 0x314f, 0x315e, 0x316e, 0x317e, 0x318f, 0x319f, 0x31b0, 0x31c1,
+ 0x31d3, 0x31e5, 0x31f7, 0x3204, 0x320e, 0x3217, 0x3221, 0x322b, 0x3235,
+ 0x323f, 0x324a, 0x3255, 0x325f, 0x326a, 0x3276, 0x3281, 0x328d, 0x3299,
+ 0x32a5, 0x32b1, 0x32bd, 0x32ca, 0x32d7, 0x32e4, 0x32f2, 0x32ff, 0x330d,
+ 0x331b, 0x332a, 0x3338, 0x3347, 0x3357, 0x3366, 0x3376, 0x3386, 0x3396,
+ 0x33a7, 0x33b8, 0x33c9, 0x33da, 0x33ec, 0x33fe, 0x3408, 0x3412, 0x341b,
+ 0x3425, 0x342f, 0x3439, 0x3443, 0x344e, 0x3458, 0x3463, 0x346e, 0x347a,
+ 0x3485, 0x3491, 0x349d, 0x34a9, 0x34b5, 0x34c2, 0x34ce, 0x34db, 0x34e9,
+ 0x34f6, 0x3504, 0x3512, 0x3520, 0x352f, 0x353d, 0x354c, 0x355c, 0x356b,
+ 0x357b, 0x358b, 0x359c, 0x35ad, 0x35be, 0x35cf, 0x35e1, 0x35f3, 0x3602,
+ 0x360c, 0x3615, 0x361f, 0x3629, 0x3633, 0x363d, 0x3647, 0x3652, 0x365d,
+ 0x3668, 0x3673, 0x367f, 0x368a, 0x3696, 0x36a2, 0x36ae, 0x36bb, 0x36c8,
+ 0x36d5, 0x36e2, 0x36f0, 0x36fd, 0x370b, 0x371a, 0x3728, 0x3737, 0x3746,
+ 0x3755, 0x3765, 0x3775, 0x3785, 0x3796, 0x37a7, 0x37b8, 0x37c9, 0x37db,
+ 0x37ed, 0x3800, 0x3809, 0x3813, 0x381d, 0x3826, 0x3831, 0x383b, 0x3846,
+ 0x3850, 0x385b, 0x3866, 0x3872, 0x387d, 0x3889, 0x3895, 0x38a2, 0x38ae,
+ 0x38bb, 0x38c8, 0x38d5, 0x38e3, 0x38f1, 0x38ff, 0x390d, 0x391b, 0x392a,
+ 0x3939, 0x3949, 0x3959, 0x3969, 0x3979, 0x398a, 0x399b, 0x39ac, 0x39be,
+ 0x39d0, 0x39e2, 0x39f5, 0xc,
+ /* table descriptor */
+ 0xe2effbe9, 0xf,
+ /* table length */
+ 0x400,
+ /* table data */
+ 0x1095, 0x4fa, 0x240a, 0x1d9, 0x9d8, 0x1949, 0x30eb, 0xe0, 0x334, 0x72f,
+ 0xcf9, 0x14ae, 0x1e66, 0x2a35, 0x382e, 0x6e, 0x152, 0x27a, 0x409, 0x606,
+ 0x875, 0xb5a, 0xeb7, 0x1291, 0x16eb, 0x1bc7, 0x2127, 0x270e, 0x2d7f,
+ 0x347b, 0x3c04, 0x35, 0xa7, 0x119, 0x193, 0x226, 0x2d4, 0x39b, 0x47e,
+ 0x57d, 0x697, 0x7cf, 0x923, 0xa95, 0xc25, 0xdd4, 0xfa2, 0x118f, 0x139c,
+ 0x15c9, 0x1816, 0x1a84, 0x1d12, 0x1fc2, 0x2294, 0x2588, 0x289e, 0x2bd6,
+ 0x2f31, 0x32af, 0x3650, 0x3a15, 0x3dfd, 0x18, 0x51, 0x8a, 0xc3, 0xfc,
+ 0x134, 0x172, 0x1b5, 0x1ff, 0x24f, 0x2a6, 0x303, 0x367, 0x3d2, 0x443,
+ 0x4bb, 0x53a, 0x5c1, 0x64e, 0x6e2, 0x77e, 0x821, 0x8cb, 0x97d, 0xa36,
+ 0xaf6, 0xbbf, 0xc8e, 0xd66, 0xe45, 0xf2c, 0x101a, 0x1111, 0x120f, 0x1316,
+ 0x1424, 0x153a, 0x1659, 0x177f, 0x18ae, 0x19e5, 0x1b24, 0x1c6c, 0x1dbb,
+ 0x1f13, 0x2074, 0x21dd, 0x234e, 0x24c8, 0x264a, 0x27d5, 0x2968, 0x2b05,
+ 0x2ca9, 0x2e57, 0x300d, 0x31cc, 0x3394, 0x3564, 0x373e, 0x3920, 0x3b0b,
+ 0x3cff, 0x3efd, 0xa, 0x27, 0x43, 0x60, 0x7c, 0x99, 0xb5, 0xd1, 0xee, 0x10a,
+ 0x126, 0x143, 0x162, 0x182, 0x1a4, 0x1c7, 0x1ec, 0x213, 0x23b, 0x264,
+ 0x290, 0x2bd, 0x2eb, 0x31c, 0x34d, 0x381, 0x3b6, 0x3ed, 0x426, 0x460,
+ 0x49c, 0x4da, 0x51a, 0x55b, 0x59e, 0x5e3, 0x62a, 0x672, 0x6bd, 0x709,
+ 0x756, 0x7a6, 0x7f7, 0x84b, 0x8a0, 0x8f7, 0x950, 0x9aa, 0xa07, 0xa65,
+ 0xac6, 0xb28, 0xb8c, 0xbf2, 0xc5a, 0xcc3, 0xd2f, 0xd9d, 0xe0c, 0xe7e,
+ 0xef1, 0xf67, 0xfde, 0x1057, 0x10d3, 0x1150, 0x11cf, 0x1250, 0x12d3,
+ 0x1359, 0x13e0, 0x1469, 0x14f4, 0x1581, 0x1610, 0x16a2, 0x1735, 0x17ca,
+ 0x1862, 0x18fb, 0x1996, 0x1a34, 0x1ad4, 0x1b75, 0x1c19, 0x1cbf, 0x1d67,
+ 0x1e10, 0x1ebd, 0x1f6b, 0x201b, 0x20cd, 0x2182, 0x2238, 0x22f1, 0x23ac,
+ 0x2469, 0x2528, 0x25e9, 0x26ac, 0x2771, 0x2839, 0x2903, 0x29cf, 0x2a9d,
+ 0x2b6d, 0x2c3f, 0x2d14, 0x2deb, 0x2ec4, 0x2f9f, 0x307c, 0x315b, 0x323d,
+ 0x3321, 0x3407, 0x34ef, 0x35da, 0x36c7, 0x37b6, 0x38a7, 0x399a, 0x3a90,
+ 0x3b87, 0x3c82, 0x3d7e, 0x3e7c, 0x3f7d, 0x3, 0x11, 0x20, 0x2e, 0x3c, 0x4a,
+ 0x58, 0x67, 0x75, 0x83, 0x91, 0xa0, 0xae, 0xbc, 0xca, 0xd9, 0xe7, 0xf5,
+ 0x103, 0x112, 0x120, 0x12d, 0x13c, 0x14b, 0x15a, 0x16a, 0x17a, 0x18a,
+ 0x19b, 0x1ad, 0x1be, 0x1d0, 0x1e3, 0x1f6, 0x209, 0x21c, 0x230, 0x245,
+ 0x25a, 0x26f, 0x285, 0x29b, 0x2b1, 0x2c8, 0x2df, 0x2f7, 0x30f, 0x328,
+ 0x341, 0x35a, 0x374, 0x38e, 0x3a9, 0x3c4, 0x3df, 0x3fb, 0x418, 0x434,
+ 0x452, 0x46f, 0x48d, 0x4ac, 0x4cb, 0x4ea, 0x50a, 0x52a, 0x54b, 0x56c,
+ 0x58d, 0x5af, 0x5d2, 0x5f5, 0x618, 0x63c, 0x660, 0x685, 0x6aa, 0x6cf,
+ 0x6f5, 0x71c, 0x743, 0x76a, 0x792, 0x7ba, 0x7e3, 0x80c, 0x836, 0x860,
+ 0x88a, 0x8b5, 0x8e1, 0x90d, 0x939, 0x966, 0x993, 0x9c1, 0x9f0, 0xa1e,
+ 0xa4e, 0xa7d, 0xaad, 0xade, 0xb0f, 0xb41, 0xb73, 0xba5, 0xbd8, 0xc0c,
+ 0xc40, 0xc74, 0xca9, 0xcde, 0xd14, 0xd4a, 0xd81, 0xdb8, 0xdf0, 0xe29,
+ 0xe61, 0xe9a, 0xed4, 0xf0e, 0xf49, 0xf84, 0xfc0, 0xffc, 0x1039, 0x1076,
+ 0x10b4, 0x10f2, 0x1130, 0x116f, 0x11af, 0x11ef, 0x1230, 0x1271, 0x12b2,
+ 0x12f4, 0x1337, 0x137a, 0x13be, 0x1402, 0x1446, 0x148b, 0x14d1, 0x1517,
+ 0x155e, 0x15a5, 0x15ec, 0x1635, 0x167d, 0x16c6, 0x1710, 0x175a, 0x17a5,
+ 0x17f0, 0x183c, 0x1888, 0x18d5, 0x1922, 0x196f, 0x19be, 0x1a0c, 0x1a5c,
+ 0x1aab, 0x1afc, 0x1b4d, 0x1b9e, 0x1bf0, 0x1c42, 0x1c95, 0x1ce8, 0x1d3c,
+ 0x1d91, 0x1de6, 0x1e3b, 0x1e91, 0x1ee8, 0x1f3f, 0x1f96, 0x1fef, 0x2047,
+ 0x20a0, 0x20fa, 0x2154, 0x21af, 0x220a, 0x2266, 0x22c2, 0x231f, 0x237d,
+ 0x23db, 0x2439, 0x2498, 0x24f8, 0x2558, 0x25b8, 0x2619, 0x267b, 0x26dd,
+ 0x2740, 0x27a3, 0x2807, 0x286b, 0x28d0, 0x2936, 0x299c, 0x2a02, 0x2a69,
+ 0x2ad1, 0x2b39, 0x2ba1, 0x2c0b, 0x2c74, 0x2cdf, 0x2d49, 0x2db5, 0x2e21,
+ 0x2e8d, 0x2efa, 0x2f68, 0x2fd6, 0x3044, 0x30b4, 0x3123, 0x3194, 0x3205,
+ 0x3276, 0x32e8, 0x335a, 0x33cd, 0x3441, 0x34b5, 0x352a, 0x359f, 0x3615,
+ 0x368b, 0x3702, 0x377a, 0x37f2, 0x386a, 0x38e3, 0x395d, 0x39d7, 0x3a52,
+ 0x3acd, 0x3b49, 0x3bc6, 0x3c43, 0x3cc0, 0x3d3f, 0x3dbd, 0x3e3d, 0x3ebc,
+ 0x3f3d, 0x3fbe, 0x0, 0x7, 0xe, 0x15, 0x1c, 0x23, 0x2a, 0x31, 0x38, 0x40,
+ 0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x80, 0x87, 0x8e, 0x95,
+ 0x9c, 0xa3, 0xaa, 0xb1, 0xb9, 0xc0, 0xc7, 0xce, 0xd5, 0xdc, 0xe3, 0xea,
+ 0xf1, 0xf9, 0x100, 0x107, 0x10e, 0x115, 0x11c, 0x123, 0x12a, 0x131, 0x138,
+ 0x13f, 0x147, 0x14e, 0x156, 0x15e, 0x166, 0x16e, 0x176, 0x17e, 0x186,
+ 0x18f, 0x197, 0x1a0, 0x1a8, 0x1b1, 0x1ba, 0x1c3, 0x1cc, 0x1d5, 0x1de,
+ 0x1e7, 0x1f1, 0x1fa, 0x204, 0x20e, 0x217, 0x221, 0x22b, 0x236, 0x240,
+ 0x24a, 0x255, 0x25f, 0x26a, 0x274, 0x27f, 0x28a, 0x295, 0x2a0, 0x2ac,
+ 0x2b7, 0x2c2, 0x2ce, 0x2da, 0x2e5, 0x2f1, 0x2fd, 0x309, 0x315, 0x322,
+ 0x32e, 0x33b, 0x347, 0x354, 0x361, 0x36d, 0x37a, 0x388, 0x395, 0x3a2,
+ 0x3b0, 0x3bd, 0x3cb, 0x3d8, 0x3e6, 0x3f4, 0x402, 0x411, 0x41f, 0x42d,
+ 0x43c, 0x44a, 0x459, 0x468, 0x477, 0x486, 0x495, 0x4a4, 0x4b3, 0x4c3,
+ 0x4d3, 0x4e2, 0x4f2, 0x502, 0x512, 0x522, 0x532, 0x543, 0x553, 0x564,
+ 0x574, 0x585, 0x596, 0x5a7, 0x5b8, 0x5c9, 0x5db, 0x5ec, 0x5fe, 0x60f,
+ 0x621, 0x633, 0x645, 0x657, 0x669, 0x67b, 0x68e, 0x6a0, 0x6b3, 0x6c6,
+ 0x6d9, 0x6ec, 0x6ff, 0x712, 0x726, 0x739, 0x74d, 0x760, 0x774, 0x788,
+ 0x79c, 0x7b0, 0x7c4, 0x7d9, 0x7ed, 0x802, 0x816, 0x82b, 0x840, 0x855,
+ 0x86a, 0x880, 0x895, 0x8ab, 0x8c0, 0x8d6, 0x8ec, 0x902, 0x918, 0x92e,
+ 0x944, 0x95b, 0x971, 0x988, 0x99f, 0x9b6, 0x9cd, 0x9e4, 0x9fb, 0xa13,
+ 0xa2a, 0xa42, 0xa59, 0xa71, 0xa89, 0xaa1, 0xab9, 0xad2, 0xaea, 0xb03,
+ 0xb1b, 0xb34, 0xb4d, 0xb66, 0xb7f, 0xb98, 0xbb2, 0xbcb, 0xbe5, 0xbff,
+ 0xc19, 0xc32, 0xc4d, 0xc67, 0xc81, 0xc9c, 0xcb6, 0xcd1, 0xcec, 0xd07,
+ 0xd22, 0xd3d, 0xd58, 0xd73, 0xd8f, 0xdab, 0xdc6, 0xde2, 0xdfe, 0xe1a,
+ 0xe37, 0xe53, 0xe70, 0xe8c, 0xea9, 0xec6, 0xee3, 0xf00, 0xf1d, 0xf3a,
+ 0xf58, 0xf75, 0xf93, 0xfb1, 0xfcf, 0xfed, 0x100b, 0x102a, 0x1048, 0x1067,
+ 0x1085, 0x10a4, 0x10c3, 0x10e2, 0x1101, 0x1121, 0x1140, 0x1160, 0x117f,
+ 0x119f, 0x11bf, 0x11df, 0x11ff, 0x121f, 0x1240, 0x1260, 0x1281, 0x12a2,
+ 0x12c3, 0x12e4, 0x1305, 0x1326, 0x1348, 0x1369, 0x138b, 0x13ad, 0x13cf,
+ 0x13f1, 0x1413, 0x1435, 0x1458, 0x147a, 0x149d, 0x14c0, 0x14e3, 0x1506,
+ 0x1529, 0x154c, 0x156f, 0x1593, 0x15b7, 0x15db, 0x15fe, 0x1623, 0x1647,
+ 0x166b, 0x168f, 0x16b4, 0x16d9, 0x16fe, 0x1722, 0x1748, 0x176d, 0x1792,
+ 0x17b8, 0x17dd, 0x1803, 0x1829, 0x184f, 0x1875, 0x189b, 0x18c1, 0x18e8,
+ 0x190e, 0x1935, 0x195c, 0x1983, 0x19aa, 0x19d1, 0x19f9, 0x1a20, 0x1a48,
+ 0x1a70, 0x1a97, 0x1ac0, 0x1ae8, 0x1b10, 0x1b38, 0x1b61, 0x1b8a, 0x1bb2,
+ 0x1bdb, 0x1c04, 0x1c2e, 0x1c57, 0x1c80, 0x1caa, 0x1cd4, 0x1cfd, 0x1d27,
+ 0x1d51, 0x1d7c, 0x1da6, 0x1dd1, 0x1dfb, 0x1e26, 0x1e51, 0x1e7c, 0x1ea7,
+ 0x1ed2, 0x1efe, 0x1f29, 0x1f55, 0x1f81, 0x1fac, 0x1fd9, 0x2005, 0x2031,
+ 0x205d, 0x208a, 0x20b7, 0x20e4, 0x2111, 0x213e, 0x216b, 0x2198, 0x21c6,
+ 0x21f3, 0x2221, 0x224f, 0x227d, 0x22ab, 0x22da, 0x2308, 0x2337, 0x2365,
+ 0x2394, 0x23c3, 0x23f2, 0x2421, 0x2451, 0x2480, 0x24b0, 0x24e0, 0x2510,
+ 0x2540, 0x2570, 0x25a0, 0x25d0, 0x2601, 0x2632, 0x2663, 0x2693, 0x26c5,
+ 0x26f6, 0x2727, 0x2759, 0x278a, 0x27bc, 0x27ee, 0x2820, 0x2852, 0x2884,
+ 0x28b7, 0x28e9, 0x291c, 0x294f, 0x2982, 0x29b5, 0x29e8, 0x2a1c, 0x2a4f,
+ 0x2a83, 0x2ab7, 0x2aeb, 0x2b1f, 0x2b53, 0x2b87, 0x2bbc, 0x2bf0, 0x2c25,
+ 0x2c5a, 0x2c8f, 0x2cc4, 0x2cf9, 0x2d2f, 0x2d64, 0x2d9a, 0x2dd0, 0x2e06,
+ 0x2e3c, 0x2e72, 0x2ea8, 0x2edf, 0x2f16, 0x2f4c, 0x2f83, 0x2fba, 0x2ff1,
+ 0x3029, 0x3060, 0x3098, 0x30d0, 0x3107, 0x313f, 0x3178, 0x31b0, 0x31e8,
+ 0x3221, 0x325a, 0x3292, 0x32cb, 0x3304, 0x333e, 0x3377, 0x33b1, 0x33ea,
+ 0x3424, 0x345e, 0x3498, 0x34d2, 0x350d, 0x3547, 0x3582, 0x35bc, 0x35f7,
+ 0x3632, 0x366e, 0x36a9, 0x36e4, 0x3720, 0x375c, 0x3798, 0x37d4, 0x3810,
+ 0x384c, 0x3888, 0x38c5, 0x3902, 0x393f, 0x397c, 0x39b9, 0x39f6, 0x3a33,
+ 0x3a71, 0x3aaf, 0x3aec, 0x3b2a, 0x3b68, 0x3ba7, 0x3be5, 0x3c24, 0x3c62,
+ 0x3ca1, 0x3ce0, 0x3d1f, 0x3d5e, 0x3d9e, 0x3ddd, 0x3e1d, 0x3e5d, 0x3e9c,
+ 0x3edc, 0x3f1d, 0x3f5d, 0x3f9e, 0x3fde, 0x6,
+ /* table descriptor */
+ 0x61effbe9, 0xf,
+ /* table length */
+ 0x400,
+ /* table data */
+ 0x96, 0x8, 0x647, 0x0, 0x27, 0x1f8, 0x13cf, 0x0, 0x3, 0x13, 0x4f, 0x116,
+ 0x387, 0xb24, 0x236d, 0x0, 0x0, 0x1, 0x5, 0xc, 0x1b, 0x38, 0x6d, 0xcd,
+ 0x177, 0x2a4, 0x4b5, 0x85d, 0xed9, 0x1a77, 0x2f8b, 0x0, 0x0, 0x0, 0x0, 0x1,
+ 0x2, 0x4, 0x6, 0xa, 0xf, 0x17, 0x21, 0x2f, 0x42, 0x5d, 0x80, 0xaf, 0xee,
+ 0x143, 0x1b3, 0x248, 0x30d, 0x414, 0x570, 0x73f, 0x9a7, 0xcdc, 0x1126,
+ 0x16e4, 0x1e9c, 0x2906, 0x3723, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x1, 0x1, 0x2, 0x2, 0x3, 0x4, 0x5, 0x7, 0x9, 0xb, 0xe, 0x11, 0x15, 0x19,
+ 0x1e, 0x24, 0x2b, 0x33, 0x3d, 0x48, 0x55, 0x65, 0x76, 0x8b, 0xa2, 0xbd,
+ 0xdd, 0x101, 0x12b, 0x15c, 0x194, 0x1d4, 0x21e, 0x274, 0x2d7, 0x348, 0x3cb,
+ 0x462, 0x50f, 0x5d8, 0x6be, 0x7c9, 0x8fc, 0xa5f, 0xbf8, 0xdd1, 0xff5,
+ 0x126e, 0x154b, 0x189c, 0x1c76, 0x20ed, 0x261f, 0x2c29, 0x3331, 0x3b65,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x3, 0x3, 0x4, 0x4, 0x5, 0x6,
+ 0x7, 0x7, 0x8, 0x9, 0xa, 0xc, 0xd, 0xe, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a,
+ 0x1d, 0x1f, 0x22, 0x26, 0x29, 0x2d, 0x31, 0x36, 0x3b, 0x40, 0x45, 0x4b,
+ 0x52, 0x59, 0x61, 0x69, 0x71, 0x7b, 0x85, 0x90, 0x9c, 0xa9, 0xb6, 0xc5,
+ 0xd5, 0xe6, 0xf8, 0x10b, 0x120, 0x137, 0x14f, 0x169, 0x185, 0x1a3, 0x1c3,
+ 0x1e6, 0x20b, 0x233, 0x25d, 0x28b, 0x2bd, 0x2f1, 0x32a, 0x367, 0x3a8,
+ 0x3ef, 0x43a, 0x48b, 0x4e2, 0x53f, 0x5a3, 0x60e, 0x682, 0x6fe, 0x783,
+ 0x811, 0x8ab, 0x950, 0xa01, 0xabf, 0xb8c, 0xc68, 0xd55, 0xe53, 0xf64,
+ 0x108a, 0x11c7, 0x131b, 0x1489, 0x1613, 0x17bc, 0x1985, 0x1b71, 0x1d84,
+ 0x1fbf, 0x2227, 0x24bf, 0x278b, 0x2a90, 0x2dd1, 0x3155, 0x3520, 0x3939,
+ 0x3da6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2,
+ 0x2, 0x2, 0x2, 0x2, 0x3, 0x3, 0x3, 0x3, 0x4, 0x4, 0x4, 0x4, 0x5, 0x5, 0x5,
+ 0x6, 0x6, 0x6, 0x7, 0x7, 0x8, 0x8, 0x9, 0x9, 0xa, 0xa, 0xb, 0xb, 0xc, 0xd,
+ 0xd, 0xe, 0xf, 0x10, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19, 0x1b, 0x1c, 0x1d, 0x1f, 0x20, 0x22, 0x23, 0x25, 0x27, 0x28, 0x2a,
+ 0x2c, 0x2e, 0x30, 0x32, 0x35, 0x37, 0x39, 0x3c, 0x3e, 0x41, 0x44, 0x47,
+ 0x4a, 0x4d, 0x50, 0x54, 0x57, 0x5b, 0x5f, 0x63, 0x67, 0x6b, 0x6f, 0x74,
+ 0x79, 0x7d, 0x83, 0x88, 0x8d, 0x93, 0x99, 0x9f, 0xa5, 0xac, 0xb3, 0xba,
+ 0xc1, 0xc9, 0xd1, 0xd9, 0xe1, 0xea, 0xf3, 0xfc, 0x106, 0x110, 0x11b, 0x126,
+ 0x131, 0x13d, 0x149, 0x155, 0x162, 0x170, 0x17e, 0x18c, 0x19b, 0x1ab,
+ 0x1bb, 0x1cc, 0x1dd, 0x1ef, 0x201, 0x215, 0x228, 0x23d, 0x252, 0x269,
+ 0x280, 0x297, 0x2b0, 0x2c9, 0x2e4, 0x2ff, 0x31c, 0x339, 0x357, 0x377,
+ 0x398, 0x3ba, 0x3dd, 0x401, 0x427, 0x44e, 0x476, 0x4a0, 0x4cb, 0x4f8,
+ 0x527, 0x557, 0x589, 0x5bd, 0x5f3, 0x62a, 0x664, 0x6a0, 0x6de, 0x71e,
+ 0x760, 0x7a5, 0x7ed, 0x837, 0x884, 0x8d3, 0x926, 0x97b, 0x9d4, 0xa2f,
+ 0xa8f, 0xaf1, 0xb58, 0xbc2, 0xc30, 0xca2, 0xd18, 0xd92, 0xe11, 0xe95,
+ 0xf1e, 0xfac, 0x103f, 0x10d7, 0x1175, 0x1219, 0x12c3, 0x1374, 0x142b,
+ 0x14e9, 0x15ae, 0x167b, 0x174f, 0x182b, 0x1910, 0x19fd, 0x1af3, 0x1bf2,
+ 0x1cfb, 0x1e0f, 0x1f2c, 0x2055, 0x2189, 0x22c9, 0x2415, 0x256d, 0x26d3,
+ 0x2847, 0x29c9, 0x2b5a, 0x2cfb, 0x2eac, 0x306e, 0x3241, 0x3426, 0x361f,
+ 0x382b, 0x3a4c, 0x3c83, 0x3ecf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1,
+ 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
+ 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x3, 0x3, 0x3, 0x3,
+ 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x5, 0x5, 0x5,
+ 0x5, 0x5, 0x5, 0x6, 0x6, 0x6, 0x6, 0x6, 0x6, 0x7, 0x7, 0x7, 0x7, 0x8, 0x8,
+ 0x8, 0x8, 0x8, 0x9, 0x9, 0x9, 0x9, 0xa, 0xa, 0xa, 0xb, 0xb, 0xb, 0xb, 0xc,
+ 0xc, 0xc, 0xd, 0xd, 0xd, 0xe, 0xe, 0xf, 0xf, 0xf, 0x10, 0x10, 0x11, 0x11,
+ 0x11, 0x12, 0x12, 0x13, 0x13, 0x14, 0x14, 0x15, 0x15, 0x16, 0x16, 0x17,
+ 0x17, 0x18, 0x19, 0x19, 0x1a, 0x1a, 0x1b, 0x1c, 0x1c, 0x1d, 0x1e, 0x1e,
+ 0x1f, 0x20, 0x21, 0x21, 0x22, 0x23, 0x24, 0x24, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34,
+ 0x35, 0x36, 0x37, 0x39, 0x3a, 0x3b, 0x3c, 0x3e, 0x3f, 0x40, 0x42, 0x43,
+ 0x45, 0x46, 0x48, 0x49, 0x4b, 0x4c, 0x4e, 0x4f, 0x51, 0x53, 0x54, 0x56,
+ 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e,
+ 0x70, 0x73, 0x75, 0x77, 0x7a, 0x7c, 0x7f, 0x81, 0x84, 0x86, 0x89, 0x8c,
+ 0x8f, 0x92, 0x94, 0x97, 0x9a, 0x9d, 0xa1, 0xa4, 0xa7, 0xaa, 0xae, 0xb1,
+ 0xb4, 0xb8, 0xbc, 0xbf, 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7, 0xdb, 0xdf,
+ 0xe3, 0xe8, 0xec, 0xf1, 0xf5, 0xfa, 0xff, 0x104, 0x109, 0x10e, 0x113,
+ 0x118, 0x11e, 0x123, 0x129, 0x12e, 0x134, 0x13a, 0x140, 0x146, 0x14c,
+ 0x152, 0x159, 0x15f, 0x166, 0x16c, 0x173, 0x17a, 0x181, 0x189, 0x190,
+ 0x197, 0x19f, 0x1a7, 0x1af, 0x1b7, 0x1bf, 0x1c7, 0x1d0, 0x1d8, 0x1e1,
+ 0x1ea, 0x1f3, 0x1fd, 0x206, 0x210, 0x219, 0x223, 0x22e, 0x238, 0x242,
+ 0x24d, 0x258, 0x263, 0x26e, 0x27a, 0x285, 0x291, 0x29d, 0x2aa, 0x2b6,
+ 0x2c3, 0x2d0, 0x2dd, 0x2eb, 0x2f8, 0x306, 0x314, 0x323, 0x332, 0x341,
+ 0x350, 0x35f, 0x36f, 0x37f, 0x38f, 0x3a0, 0x3b1, 0x3c2, 0x3d4, 0x3e6,
+ 0x3f8, 0x40a, 0x41d, 0x430, 0x444, 0x458, 0x46c, 0x480, 0x495, 0x4ab,
+ 0x4c0, 0x4d6, 0x4ed, 0x504, 0x51b, 0x533, 0x54b, 0x564, 0x57d, 0x596,
+ 0x5b0, 0x5ca, 0x5e5, 0x600, 0x61c, 0x639, 0x655, 0x673, 0x691, 0x6af,
+ 0x6ce, 0x6ee, 0x70e, 0x72e, 0x750, 0x771, 0x794, 0x7b7, 0x7db, 0x7ff,
+ 0x824, 0x84a, 0x870, 0x897, 0x8bf, 0x8e7, 0x911, 0x93b, 0x965, 0x991,
+ 0x9bd, 0x9ea, 0xa18, 0xa47, 0xa76, 0xaa7, 0xad8, 0xb0a, 0xb3e, 0xb72,
+ 0xba7, 0xbdd, 0xc14, 0xc4c, 0xc85, 0xcbf, 0xcfa, 0xd36, 0xd73, 0xdb2,
+ 0xdf1, 0xe32, 0xe74, 0xeb7, 0xefb, 0xf41, 0xf88, 0xfd0, 0x1019, 0x1064,
+ 0x10b1, 0x10fe, 0x114d, 0x119e, 0x11f0, 0x1243, 0x1298, 0x12ef, 0x1347,
+ 0x13a1, 0x13fd, 0x145a, 0x14b9, 0x151a, 0x157c, 0x15e1, 0x1647, 0x16af,
+ 0x1719, 0x1785, 0x17f3, 0x1863, 0x18d6, 0x194a, 0x19c1, 0x1a39, 0x1ab4,
+ 0x1b32, 0x1bb1, 0x1c34, 0x1cb8, 0x1d3f, 0x1dc9, 0x1e55, 0x1ee4, 0x1f75,
+ 0x200a, 0x20a1, 0x213b, 0x21d8, 0x2277, 0x231a, 0x23c0, 0x2469, 0x2516,
+ 0x25c6, 0x2679, 0x272f, 0x27e9, 0x28a6, 0x2967, 0x2a2c, 0x2af5, 0x2bc1,
+ 0x2c91, 0x2d66, 0x2e3e, 0x2f1b, 0x2ffc, 0x30e1, 0x31ca, 0x32b9, 0x33ab,
+ 0x34a3, 0x359f, 0x36a0, 0x37a6, 0x38b2, 0x39c2, 0x3ad8, 0x3bf3, 0x3d14,
+ 0x3e3a, 0x3f66, 0x6,
+ /* table descriptor */
+ 0xf0effbe9, 0xf,
+ /* table length */
+ 0x400,
+ /* table data */
+ 0xdab, 0x33c, 0x216a, 0xe8, 0x766, 0x1646, 0x2f44, 0x52, 0x1dc, 0x512,
+ 0xa41, 0x11aa, 0x1b84, 0x27fd, 0x3743, 0x26, 0x92, 0x155, 0x27e, 0x418,
+ 0x62b, 0x8c2, 0xbe4, 0xf97, 0x13e4, 0x18d0, 0x1e61, 0x249e, 0x2b8a, 0x332c,
+ 0x3b89, 0x12, 0x3a, 0x70, 0xba, 0x11c, 0x196, 0x22a, 0x2da, 0x3a6, 0x491,
+ 0x59a, 0x6c4, 0x810, 0x97d, 0xb0e, 0xcc3, 0xe9c, 0x109c, 0x12c2, 0x1510,
+ 0x1786, 0x1a25, 0x1ced, 0x1fe0, 0x22fe, 0x2648, 0x29be, 0x2d61, 0x3132,
+ 0x3532, 0x3960, 0x3dbe, 0x8, 0x1c, 0x30, 0x46, 0x60, 0x80, 0xa5, 0xd0,
+ 0x101, 0x138, 0x175, 0x1b8, 0x202, 0x253, 0x2ab, 0x30a, 0x370, 0x3de,
+ 0x453, 0x4d0, 0x555, 0x5e2, 0x677, 0x714, 0x7ba, 0x868, 0x91e, 0x9de,
+ 0xaa6, 0xb77, 0xc52, 0xd35, 0xe22, 0xf19, 0x1018, 0x1122, 0x1235, 0x1352,
+ 0x1479, 0x15aa, 0x16e4, 0x182a, 0x1979, 0x1ad3, 0x1c37, 0x1da6, 0x1f1f,
+ 0x20a4, 0x2233, 0x23cc, 0x2571, 0x2721, 0x28dc, 0x2aa3, 0x2c74, 0x2e51,
+ 0x303a, 0x322e, 0x342e, 0x3639, 0x3850, 0x3a73, 0x3ca2, 0x3edd, 0x3, 0xd,
+ 0x17, 0x21, 0x2b, 0x35, 0x40, 0x4c, 0x59, 0x68, 0x78, 0x89, 0x9c, 0xb0,
+ 0xc5, 0xdc, 0xf4, 0x10e, 0x12a, 0x146, 0x165, 0x185, 0x1a7, 0x1ca, 0x1ef,
+ 0x216, 0x23e, 0x269, 0x294, 0x2c2, 0x2f2, 0x323, 0x356, 0x38b, 0x3c2,
+ 0x3fb, 0x435, 0x472, 0x4b0, 0x4f1, 0x533, 0x577, 0x5be, 0x606, 0x651,
+ 0x69d, 0x6ec, 0x73d, 0x78f, 0x7e4, 0x83b, 0x895, 0x8f0, 0x94d, 0x9ad,
+ 0xa0f, 0xa73, 0xada, 0xb42, 0xbad, 0xc1a, 0xc8a, 0xcfc, 0xd70, 0xde6,
+ 0xe5f, 0xeda, 0xf58, 0xfd8, 0x105a, 0x10df, 0x1166, 0x11ef, 0x127b, 0x130a,
+ 0x139b, 0x142e, 0x14c4, 0x155c, 0x15f7, 0x1695, 0x1735, 0x17d7, 0x187d,
+ 0x1924, 0x19cf, 0x1a7b, 0x1b2b, 0x1bdd, 0x1c92, 0x1d49, 0x1e03, 0x1ec0,
+ 0x1f7f, 0x2042, 0x2106, 0x21ce, 0x2298, 0x2365, 0x2435, 0x2507, 0x25dc,
+ 0x26b4, 0x278f, 0x286d, 0x294d, 0x2a30, 0x2b16, 0x2bff, 0x2ceb, 0x2dd9,
+ 0x2eca, 0x2fbf, 0x30b6, 0x31b0, 0x32ad, 0x33ac, 0x34af, 0x35b5, 0x36bd,
+ 0x37c9, 0x38d8, 0x39e9, 0x3afd, 0x3c15, 0x3d2f, 0x3e4d, 0x3f6d, 0x1, 0x6,
+ 0xb, 0x10, 0x15, 0x1a, 0x1e, 0x23, 0x28, 0x2d, 0x32, 0x37, 0x3d, 0x43,
+ 0x49, 0x4f, 0x56, 0x5d, 0x64, 0x6c, 0x74, 0x7c, 0x85, 0x8e, 0x97, 0xa0,
+ 0xaa, 0xb5, 0xc0, 0xcb, 0xd6, 0xe2, 0xee, 0xfb, 0x108, 0x115, 0x123, 0x131,
+ 0x13f, 0x14e, 0x15d, 0x16d, 0x17d, 0x18d, 0x19e, 0x1af, 0x1c1, 0x1d3,
+ 0x1e6, 0x1f9, 0x20c, 0x220, 0x234, 0x249, 0x25e, 0x273, 0x289, 0x2a0,
+ 0x2b7, 0x2ce, 0x2e6, 0x2fe, 0x316, 0x32f, 0x349, 0x363, 0x37e, 0x398,
+ 0x3b4, 0x3d0, 0x3ec, 0x409, 0x426, 0x444, 0x462, 0x481, 0x4a0, 0x4c0,
+ 0x4e0, 0x501, 0x522, 0x544, 0x566, 0x589, 0x5ac, 0x5d0, 0x5f4, 0x619,
+ 0x63e, 0x664, 0x68a, 0x6b1, 0x6d8, 0x700, 0x728, 0x751, 0x77a, 0x7a4,
+ 0x7cf, 0x7fa, 0x825, 0x851, 0x87e, 0x8ab, 0x8d9, 0x907, 0x936, 0x965,
+ 0x995, 0x9c5, 0x9f6, 0xa28, 0xa5a, 0xa8d, 0xac0, 0xaf4, 0xb28, 0xb5d,
+ 0xb92, 0xbc8, 0xbff, 0xc36, 0xc6e, 0xca6, 0xcdf, 0xd19, 0xd53, 0xd8d,
+ 0xdc8, 0xe04, 0xe41, 0xe7e, 0xebb, 0xef9, 0xf38, 0xf77, 0xfb7, 0xff8,
+ 0x1039, 0x107b, 0x10bd, 0x1100, 0x1144, 0x1188, 0x11cd, 0x1212, 0x1258,
+ 0x129f, 0x12e6, 0x132e, 0x1376, 0x13bf, 0x1409, 0x1453, 0x149e, 0x14ea,
+ 0x1536, 0x1583, 0x15d0, 0x161e, 0x166d, 0x16bd, 0x170d, 0x175d, 0x17af,
+ 0x1800, 0x1853, 0x18a6, 0x18fa, 0x194f, 0x19a4, 0x19fa, 0x1a50, 0x1aa7,
+ 0x1aff, 0x1b57, 0x1bb0, 0x1c0a, 0x1c64, 0x1cbf, 0x1d1b, 0x1d78, 0x1dd5,
+ 0x1e32, 0x1e91, 0x1ef0, 0x1f4f, 0x1fb0, 0x2011, 0x2072, 0x20d5, 0x2138,
+ 0x219c, 0x2200, 0x2265, 0x22cb, 0x2331, 0x2399, 0x2401, 0x2469, 0x24d2,
+ 0x253c, 0x25a7, 0x2612, 0x267e, 0x26eb, 0x2758, 0x27c6, 0x2835, 0x28a4,
+ 0x2915, 0x2985, 0x29f7, 0x2a69, 0x2adc, 0x2b50, 0x2bc4, 0x2c3a, 0x2caf,
+ 0x2d26, 0x2d9d, 0x2e15, 0x2e8e, 0x2f07, 0x2f81, 0x2ffc, 0x3078, 0x30f4,
+ 0x3171, 0x31ef, 0x326d, 0x32ec, 0x336c, 0x33ed, 0x346e, 0x34f0, 0x3573,
+ 0x35f7, 0x367b, 0x3700, 0x3786, 0x380c, 0x3894, 0x391c, 0x39a4, 0x3a2e,
+ 0x3ab8, 0x3b43, 0x3bcf, 0x3c5b, 0x3ce8, 0x3d76, 0x3e05, 0x3e95, 0x3f25,
+ 0x3fb6, 0x0, 0x2, 0x4, 0x7, 0x9, 0xc, 0xe, 0x11, 0x13, 0x16, 0x18, 0x1b,
+ 0x1d, 0x20, 0x22, 0x25, 0x27, 0x2a, 0x2c, 0x2f, 0x31, 0x34, 0x36, 0x39,
+ 0x3c, 0x3e, 0x41, 0x44, 0x47, 0x4a, 0x4d, 0x51, 0x54, 0x57, 0x5b, 0x5f,
+ 0x62, 0x66, 0x6a, 0x6e, 0x72, 0x76, 0x7a, 0x7e, 0x82, 0x87, 0x8b, 0x90,
+ 0x94, 0x99, 0x9e, 0xa3, 0xa8, 0xad, 0xb2, 0xb7, 0xbd, 0xc2, 0xc8, 0xcd,
+ 0xd3, 0xd9, 0xdf, 0xe5, 0xeb, 0xf1, 0xf7, 0xfe, 0x104, 0x10b, 0x111, 0x118,
+ 0x11f, 0x126, 0x12d, 0x134, 0x13b, 0x143, 0x14a, 0x152, 0x159, 0x161,
+ 0x169, 0x171, 0x179, 0x181, 0x189, 0x192, 0x19a, 0x1a2, 0x1ab, 0x1b4,
+ 0x1bd, 0x1c6, 0x1cf, 0x1d8, 0x1e1, 0x1ea, 0x1f4, 0x1fe, 0x207, 0x211,
+ 0x21b, 0x225, 0x22f, 0x239, 0x244, 0x24e, 0x258, 0x263, 0x26e, 0x279,
+ 0x284, 0x28f, 0x29a, 0x2a5, 0x2b1, 0x2bc, 0x2c8, 0x2d4, 0x2e0, 0x2ec,
+ 0x2f8, 0x304, 0x310, 0x31d, 0x329, 0x336, 0x343, 0x350, 0x35d, 0x36a,
+ 0x377, 0x384, 0x392, 0x39f, 0x3ad, 0x3bb, 0x3c9, 0x3d7, 0x3e5, 0x3f3,
+ 0x402, 0x410, 0x41f, 0x42e, 0x43d, 0x44c, 0x45b, 0x46a, 0x479, 0x489,
+ 0x499, 0x4a8, 0x4b8, 0x4c8, 0x4d8, 0x4e8, 0x4f9, 0x509, 0x51a, 0x52b,
+ 0x53b, 0x54c, 0x55e, 0x56f, 0x580, 0x592, 0x5a3, 0x5b5, 0x5c7, 0x5d9,
+ 0x5eb, 0x5fd, 0x60f, 0x622, 0x635, 0x647, 0x65a, 0x66d, 0x680, 0x694,
+ 0x6a7, 0x6bb, 0x6ce, 0x6e2, 0x6f6, 0x70a, 0x71e, 0x732, 0x747, 0x75b,
+ 0x770, 0x785, 0x79a, 0x7af, 0x7c4, 0x7da, 0x7ef, 0x805, 0x81a, 0x830,
+ 0x846, 0x85d, 0x873, 0x889, 0x8a0, 0x8b7, 0x8cd, 0x8e4, 0x8fb, 0x913,
+ 0x92a, 0x942, 0x959, 0x971, 0x989, 0x9a1, 0x9b9, 0x9d2, 0x9ea, 0xa03,
+ 0xa1c, 0xa34, 0xa4d, 0xa67, 0xa80, 0xa99, 0xab3, 0xacd, 0xae7, 0xb01,
+ 0xb1b, 0xb35, 0xb50, 0xb6a, 0xb85, 0xba0, 0xbbb, 0xbd6, 0xbf1, 0xc0d,
+ 0xc28, 0xc44, 0xc60, 0xc7c, 0xc98, 0xcb4, 0xcd1, 0xced, 0xd0a, 0xd27,
+ 0xd44, 0xd61, 0xd7e, 0xd9c, 0xdba, 0xdd7, 0xdf5, 0xe13, 0xe31, 0xe50,
+ 0xe6e, 0xe8d, 0xeac, 0xecb, 0xeea, 0xf09, 0xf28, 0xf48, 0xf68, 0xf87,
+ 0xfa7, 0xfc7, 0xfe8, 0x1008, 0x1029, 0x1049, 0x106a, 0x108b, 0x10ad,
+ 0x10ce, 0x10ef, 0x1111, 0x1133, 0x1155, 0x1177, 0x1199, 0x11bb, 0x11de,
+ 0x1201, 0x1223, 0x1246, 0x126a, 0x128d, 0x12b0, 0x12d4, 0x12f8, 0x131c,
+ 0x1340, 0x1364, 0x1388, 0x13ad, 0x13d2, 0x13f6, 0x141c, 0x1441, 0x1466,
+ 0x148b, 0x14b1, 0x14d7, 0x14fd, 0x1523, 0x1549, 0x1570, 0x1596, 0x15bd,
+ 0x15e4, 0x160b, 0x1632, 0x1659, 0x1681, 0x16a9, 0x16d1, 0x16f9, 0x1721,
+ 0x1749, 0x1771, 0x179a, 0x17c3, 0x17ec, 0x1815, 0x183e, 0x1868, 0x1891,
+ 0x18bb, 0x18e5, 0x190f, 0x1939, 0x1964, 0x198e, 0x19b9, 0x19e4, 0x1a0f,
+ 0x1a3a, 0x1a66, 0x1a91, 0x1abd, 0x1ae9, 0x1b15, 0x1b41, 0x1b6d, 0x1b9a,
+ 0x1bc7, 0x1bf4, 0x1c21, 0x1c4e, 0x1c7b, 0x1ca9, 0x1cd6, 0x1d04, 0x1d32,
+ 0x1d60, 0x1d8f, 0x1dbd, 0x1dec, 0x1e1b, 0x1e4a, 0x1e79, 0x1ea8, 0x1ed8,
+ 0x1f07, 0x1f37, 0x1f67, 0x1f98, 0x1fc8, 0x1ff8, 0x2029, 0x205a, 0x208b,
+ 0x20bc, 0x20ee, 0x211f, 0x2151, 0x2183, 0x21b5, 0x21e7, 0x2219, 0x224c,
+ 0x227f, 0x22b2, 0x22e5, 0x2318, 0x234b, 0x237f, 0x23b3, 0x23e6, 0x241b,
+ 0x244f, 0x2483, 0x24b8, 0x24ed, 0x2522, 0x2557, 0x258c, 0x25c2, 0x25f7,
+ 0x262d, 0x2663, 0x2699, 0x26cf, 0x2706, 0x273d, 0x2774, 0x27ab, 0x27e2,
+ 0x2819, 0x2851, 0x2888, 0x28c0, 0x28f8, 0x2931, 0x2969, 0x29a2, 0x29db,
+ 0x2a14, 0x2a4d, 0x2a86, 0x2ac0, 0x2af9, 0x2b33, 0x2b6d, 0x2ba7, 0x2be2,
+ 0x2c1c, 0x2c57, 0x2c92, 0x2ccd, 0x2d08, 0x2d44, 0x2d7f, 0x2dbb, 0x2df7,
+ 0x2e33, 0x2e70, 0x2eac, 0x2ee9, 0x2f26, 0x2f63, 0x2fa0, 0x2fdd, 0x301b,
+ 0x3059, 0x3097, 0x30d5, 0x3113, 0x3152, 0x3190, 0x31cf, 0x320e, 0x324e,
+ 0x328d, 0x32cd, 0x330c, 0x334c, 0x338c, 0x33cd, 0x340d, 0x344e, 0x348f,
+ 0x34d0, 0x3511, 0x3552, 0x3594, 0x35d6, 0x3618, 0x365a, 0x369c, 0x36df,
+ 0x3721, 0x3764, 0x37a7, 0x37eb, 0x382e, 0x3872, 0x38b6, 0x38fa, 0x393e,
+ 0x3982, 0x39c7, 0x3a0b, 0x3a50, 0x3a95, 0x3adb, 0x3b20, 0x3b66, 0x3bac,
+ 0x3bf2, 0x3c38, 0x3c7e, 0x3cc5, 0x3d0c, 0x3d53, 0x3d9a, 0x3de1, 0x3e29,
+ 0x3e71, 0x3eb9, 0x3f01, 0x3f49, 0x3f91, 0x3fda, 0x6,
+ /* table descriptor */
+ 0x7baffbea, 0x6,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x2646, 0x4b23, 0xe98, 0xffffea68, 0xffffd59b, 0x4000, 0x4000,
+ 0xffffca6a, 0xfffff599, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+ 0xf, 0x0, 0x200, 0x200, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+ /* table descriptor */
+ 0x7baffbea, 0x8,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x4000, 0x0, 0x0, 0x0, 0x4000, 0x0, 0x0, 0x0, 0x4000, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff, 0xe, 0x0, 0x200, 0x200, 0x0, 0x0, 0x0,
+ 0x3ff, 0x3ff, 0x3ff,
+ /* table descriptor */
+ 0xfbaffbea, 0x0,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x21a1, 0x56c9, 0x798, 0xffffee22, 0xffffd1e1, 0x4000, 0x4000,
+ 0xffffc527, 0xfffffadc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+ 0xf, 0x0, 0x200, 0x200, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+ /* table descriptor */
+ 0x7baffbea, 0x1,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x1b37, 0x5b8c, 0x93e, 0xfffff157, 0xffffceac, 0x4000, 0x4000,
+ 0xffffc5e0, 0xfffffa23, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+ 0xf, 0x0, 0x200, 0x200, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+ /* table descriptor */
+ 0xfb6ffbea, 0xf,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x8000, 0x4000, 0x0, 0x0, 0x0, 0x4000, 0x0, 0x0, 0x0, 0x4000, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff, 0xe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x3ff, 0x3ff, 0x3ff,
+ /* table descriptor */
+ 0xfbefe8e1, 0xf,
+ /* table length */
+ 0x402,
+ /* table data */
+ 0x3, 0x0, 0xea8, 0x12aa, 0x1500, 0x16ab, 0x1815, 0x1900, 0x1a0b, 0x1aab,
+ 0x1b60, 0x1c15, 0x1c85, 0x1d00, 0x1d86, 0x1e0b, 0x1e58, 0x1eab, 0x1f03,
+ 0x1f60, 0x1fc3, 0x2015, 0x204c, 0x2085, 0x20c2, 0x2100, 0x2142, 0x2186,
+ 0x21cc, 0x220b, 0x2231, 0x2258, 0x2281, 0x22ab, 0x22d6, 0x2303, 0x2331,
+ 0x2360, 0x2391, 0x23c3, 0x23f6, 0x2415, 0x2430, 0x244c, 0x2468, 0x2485,
+ 0x24a3, 0x24c2, 0x24e1, 0x2500, 0x2521, 0x2542, 0x2563, 0x2586, 0x25a9,
+ 0x25cc, 0x25f1, 0x260b, 0x261e, 0x2631, 0x2644, 0x2658, 0x266c, 0x2681,
+ 0x2696, 0x26ab, 0x26c0, 0x26d6, 0x26ec, 0x2703, 0x271a, 0x2731, 0x2748,
+ 0x2760, 0x2779, 0x2791, 0x27aa, 0x27c3, 0x27dd, 0x27f6, 0x2808, 0x2815,
+ 0x2823, 0x2830, 0x283e, 0x284c, 0x285a, 0x2868, 0x2877, 0x2885, 0x2894,
+ 0x28a3, 0x28b2, 0x28c2, 0x28d1, 0x28e1, 0x28f0, 0x2900, 0x2910, 0x2921,
+ 0x2931, 0x2942, 0x2952, 0x2963, 0x2974, 0x2986, 0x2997, 0x29a9, 0x29bb,
+ 0x29cc, 0x29df, 0x29f1, 0x2a01, 0x2a0b, 0x2a14, 0x2a1e, 0x2a27, 0x2a31,
+ 0x2a3a, 0x2a44, 0x2a4e, 0x2a58, 0x2a62, 0x2a6c, 0x2a76, 0x2a81, 0x2a8b,
+ 0x2a96, 0x2aa0, 0x2aab, 0x2ab6, 0x2ac0, 0x2acb, 0x2ad6, 0x2ae1, 0x2aec,
+ 0x2af8, 0x2b03, 0x2b0e, 0x2b1a, 0x2b25, 0x2b31, 0x2b3d, 0x2b48, 0x2b54,
+ 0x2b60, 0x2b6c, 0x2b79, 0x2b85, 0x2b91, 0x2b9d, 0x2baa, 0x2bb6, 0x2bc3,
+ 0x2bd0, 0x2bdd, 0x2bea, 0x2bf6, 0x2c02, 0x2c08, 0x2c0f, 0x2c15, 0x2c1c,
+ 0x2c23, 0x2c2a, 0x2c30, 0x2c37, 0x2c3e, 0x2c45, 0x2c4c, 0x2c53, 0x2c5a,
+ 0x2c61, 0x2c68, 0x2c70, 0x2c77, 0x2c7e, 0x2c85, 0x2c8d, 0x2c94, 0x2c9c,
+ 0x2ca3, 0x2cab, 0x2cb2, 0x2cba, 0x2cc2, 0x2cc9, 0x2cd1, 0x2cd9, 0x2ce1,
+ 0x2ce8, 0x2cf0, 0x2cf8, 0x2d00, 0x2d08, 0x2d10, 0x2d18, 0x2d21, 0x2d29,
+ 0x2d31, 0x2d39, 0x2d42, 0x2d4a, 0x2d52, 0x2d5b, 0x2d63, 0x2d6c, 0x2d74,
+ 0x2d7d, 0x2d86, 0x2d8e, 0x2d97, 0x2da0, 0x2da9, 0x2db2, 0x2dbb, 0x2dc3,
+ 0x2dcc, 0x2dd5, 0x2ddf, 0x2de8, 0x2df1, 0x2dfa, 0x2e01, 0x2e06, 0x2e0b,
+ 0x2e0f, 0x2e14, 0x2e19, 0x2e1e, 0x2e22, 0x2e27, 0x2e2c, 0x2e31, 0x2e36,
+ 0x2e3a, 0x2e3f, 0x2e44, 0x2e49, 0x2e4e, 0x2e53, 0x2e58, 0x2e5d, 0x2e62,
+ 0x2e67, 0x2e6c, 0x2e71, 0x2e76, 0x2e7c, 0x2e81, 0x2e86, 0x2e8b, 0x2e90,
+ 0x2e96, 0x2e9b, 0x2ea0, 0x2ea6, 0x2eab, 0x2eb0, 0x2eb6, 0x2ebb, 0x2ec0,
+ 0x2ec6, 0x2ecb, 0x2ed1, 0x2ed6, 0x2edc, 0x2ee1, 0x2ee7, 0x2eec, 0x2ef2,
+ 0x2ef8, 0x2efd, 0x2f03, 0x2f09, 0x2f0e, 0x2f14, 0x2f1a, 0x2f20, 0x2f25,
+ 0x2f2b, 0x2f31, 0x2f37, 0x2f3d, 0x2f43, 0x2f48, 0x2f4e, 0x2f54, 0x2f5a,
+ 0x2f60, 0x2f66, 0x2f6c, 0x2f72, 0x2f79, 0x2f7f, 0x2f85, 0x2f8b, 0x2f91,
+ 0x2f97, 0x2f9d, 0x2fa4, 0x2faa, 0x2fb0, 0x2fb6, 0x2fbd, 0x2fc3, 0x2fc9,
+ 0x2fd0, 0x2fd6, 0x2fdd, 0x2fe3, 0x2fea, 0x2ff0, 0x2ff6, 0x2ffd, 0x3002,
+ 0x3005, 0x3008, 0x300b, 0x300f, 0x3012, 0x3015, 0x3019, 0x301c, 0x301f,
+ 0x3023, 0x3026, 0x302a, 0x302d, 0x3030, 0x3034, 0x3037, 0x303b, 0x303e,
+ 0x3042, 0x3045, 0x3049, 0x304c, 0x3050, 0x3053, 0x3057, 0x305a, 0x305e,
+ 0x3061, 0x3065, 0x3068, 0x306c, 0x3070, 0x3073, 0x3077, 0x307b, 0x307e,
+ 0x3082, 0x3085, 0x3089, 0x308d, 0x3091, 0x3094, 0x3098, 0x309c, 0x309f,
+ 0x30a3, 0x30a7, 0x30ab, 0x30ae, 0x30b2, 0x30b6, 0x30ba, 0x30be, 0x30c2,
+ 0x30c5, 0x30c9, 0x30cd, 0x30d1, 0x30d5, 0x30d9, 0x30dd, 0x30e1, 0x30e4,
+ 0x30e8, 0x30ec, 0x30f0, 0x30f4, 0x30f8, 0x30fc, 0x3100, 0x3104, 0x3108,
+ 0x310c, 0x3110, 0x3114, 0x3118, 0x311d, 0x3121, 0x3125, 0x3129, 0x312d,
+ 0x3131, 0x3135, 0x3139, 0x313d, 0x3142, 0x3146, 0x314a, 0x314e, 0x3152,
+ 0x3157, 0x315b, 0x315f, 0x3163, 0x3168, 0x316c, 0x3170, 0x3174, 0x3179,
+ 0x317d, 0x3181, 0x3186, 0x318a, 0x318e, 0x3193, 0x3197, 0x319c, 0x31a0,
+ 0x31a4, 0x31a9, 0x31ad, 0x31b2, 0x31b6, 0x31bb, 0x31bf, 0x31c3, 0x31c8,
+ 0x31cc, 0x31d1, 0x31d5, 0x31da, 0x31df, 0x31e3, 0x31e8, 0x31ec, 0x31f1,
+ 0x31f5, 0x31fa, 0x31ff, 0x3201, 0x3204, 0x3206, 0x3208, 0x320b, 0x320d,
+ 0x320f, 0x3212, 0x3214, 0x3216, 0x3219, 0x321b, 0x321e, 0x3220, 0x3222,
+ 0x3225, 0x3227, 0x3229, 0x322c, 0x322e, 0x3231, 0x3233, 0x3236, 0x3238,
+ 0x323a, 0x323d, 0x323f, 0x3242, 0x3244, 0x3247, 0x3249, 0x324c, 0x324e,
+ 0x3251, 0x3253, 0x3256, 0x3258, 0x325b, 0x325d, 0x3260, 0x3262, 0x3265,
+ 0x3267, 0x326a, 0x326c, 0x326f, 0x3271, 0x3274, 0x3276, 0x3279, 0x327c,
+ 0x327e, 0x3281, 0x3283, 0x3286, 0x3289, 0x328b, 0x328e, 0x3290, 0x3293,
+ 0x3296, 0x3298, 0x329b, 0x329e, 0x32a0, 0x32a3, 0x32a6, 0x32a8, 0x32ab,
+ 0x32ae, 0x32b0, 0x32b3, 0x32b6, 0x32b8, 0x32bb, 0x32be, 0x32c1, 0x32c4,
+ 0x32c6, 0x32c9, 0x32cc, 0x32cf, 0x32d2, 0x32d5, 0x32d8, 0x32da, 0x32dd,
+ 0x32e0, 0x32e3, 0x32e6, 0x32e9, 0x32ec, 0x32ef, 0x32f2, 0x32f6, 0x32f9,
+ 0x32fc, 0x32ff, 0x3302, 0x3305, 0x3308, 0x330c, 0x330f, 0x3312, 0x3315,
+ 0x3318, 0x331c, 0x331f, 0x3322, 0x3326, 0x3329, 0x332c, 0x3330, 0x3333,
+ 0x3337, 0x333a, 0x333e, 0x3341, 0x3345, 0x3348, 0x334c, 0x334f, 0x3353,
+ 0x3356, 0x335a, 0x335e, 0x3361, 0x3365, 0x3369, 0x336c, 0x3370, 0x3374,
+ 0x3378, 0x337c, 0x337f, 0x3383, 0x3387, 0x338b, 0x338f, 0x3393, 0x3397,
+ 0x339b, 0x339f, 0x33a3, 0x33a7, 0x33ab, 0x33af, 0x33b3, 0x33b7, 0x33bb,
+ 0x33bf, 0x33c4, 0x33c8, 0x33cc, 0x33d0, 0x33d5, 0x33d9, 0x33dd, 0x33e2,
+ 0x33e6, 0x33eb, 0x33ef, 0x33f3, 0x33f8, 0x33fc, 0x3400, 0x3402, 0x3405,
+ 0x3407, 0x3409, 0x340c, 0x340e, 0x3410, 0x3413, 0x3415, 0x3418, 0x341a,
+ 0x341c, 0x341f, 0x3421, 0x3424, 0x3426, 0x3429, 0x342b, 0x342e, 0x3430,
+ 0x3433, 0x3435, 0x3438, 0x343a, 0x343d, 0x3440, 0x3442, 0x3445, 0x3448,
+ 0x344a, 0x344d, 0x3450, 0x3452, 0x3455, 0x3458, 0x345b, 0x345d, 0x3460,
+ 0x3463, 0x3466, 0x3469, 0x346b, 0x346e, 0x3471, 0x3474, 0x3477, 0x347a,
+ 0x347d, 0x3480, 0x3483, 0x3486, 0x3489, 0x348c, 0x348f, 0x3492, 0x3495,
+ 0x3498, 0x349b, 0x349e, 0x34a2, 0x34a5, 0x34a8, 0x34ab, 0x34ae, 0x34b2,
+ 0x34b5, 0x34b8, 0x34bb, 0x34bf, 0x34c2, 0x34c5, 0x34c9, 0x34cc, 0x34cf,
+ 0x34d3, 0x34d6, 0x34da, 0x34dd, 0x34e1, 0x34e4, 0x34e8, 0x34eb, 0x34ef,
+ 0x34f2, 0x34f6, 0x34fa, 0x34fd, 0x3501, 0x3505, 0x3508, 0x350c, 0x3510,
+ 0x3514, 0x3517, 0x351b, 0x351f, 0x3523, 0x3527, 0x352b, 0x352f, 0x3532,
+ 0x3536, 0x353a, 0x353e, 0x3542, 0x3546, 0x354b, 0x354f, 0x3553, 0x3557,
+ 0x355b, 0x355f, 0x3563, 0x3568, 0x356c, 0x3570, 0x3574, 0x3579, 0x357d,
+ 0x3581, 0x3586, 0x358a, 0x358f, 0x3593, 0x3598, 0x359c, 0x35a1, 0x35a5,
+ 0x35aa, 0x35ae, 0x35b3, 0x35b8, 0x35bc, 0x35c1, 0x35c6, 0x35cb, 0x35cf,
+ 0x35d4, 0x35d9, 0x35de, 0x35e3, 0x35e8, 0x35ed, 0x35f2, 0x35f7, 0x35fc,
+ 0x3600, 0x3603, 0x3605, 0x3608, 0x360a, 0x360d, 0x3610, 0x3612, 0x3615,
+ 0x3618, 0x361a, 0x361d, 0x3620, 0x3622, 0x3625, 0x3628, 0x362b, 0x362d,
+ 0x3630, 0x3633, 0x3636, 0x3639, 0x363b, 0x363e, 0x3641, 0x3644, 0x3647,
+ 0x364a, 0x364d, 0x3650, 0x3653, 0x3656, 0x3659, 0x365c, 0x365f, 0x3662,
+ 0x3665, 0x3668, 0x366b, 0x366e, 0x3672, 0x3675, 0x3678, 0x367b, 0x367e,
+ 0x3682, 0x3685, 0x3688, 0x368b, 0x368f, 0x3692, 0x3695, 0x3699, 0x369c,
+ 0x36a0, 0x36a3, 0x36a6, 0x36aa, 0x36ad, 0x36b1, 0x36b4, 0x36b8, 0x36bb,
+ 0x36bf, 0x36c3, 0x36c6, 0x36ca, 0x36cd, 0x36d1, 0x36d5, 0x36d9, 0x36dc,
+ 0x36e0, 0x36e4, 0x36e8, 0x36eb, 0x36ef, 0x36f3, 0x36f7, 0x36fb, 0x36ff,
+ 0x3703, 0x3707, 0x370b, 0x370f, 0x3713, 0x3717, 0x371b, 0x371f, 0x3723,
+ 0x3727, 0x372b, 0x372f, 0x3734, 0x3738, 0x373c, 0x3740, 0x3745, 0x3749,
+ 0x374d, 0x3752, 0x3756, 0x375b, 0x375f, 0x3764, 0x3768, 0x376d, 0x3771,
+ 0x3776, 0x377a, 0x377f, 0x3783, 0x3788, 0x378d, 0x3792, 0x3796, 0x379b,
+ 0x37a0, 0x37a5, 0x37aa, 0x37ae, 0x37b3, 0x37b8, 0x37bd, 0x37c2, 0x37c7,
+ 0x37cc, 0x37d1, 0x37d6, 0x37dc, 0x37e1, 0x37e6, 0x37eb, 0x37f0, 0x37f6,
+ 0x37fb, 0x3800, 0x3802, 0x3805, 0x3808, 0x380b, 0x380d, 0x3810, 0x3813,
+ 0x3816, 0x3818, 0x381b, 0x381e, 0x3821, 0x3824, 0x3827, 0x382a, 0x382c,
+ 0x382f, 0x3832, 0x3835, 0x3838, 0x383b, 0x383e, 0x3841, 0x3844, 0x3847,
+ 0x384a, 0x384d, 0x3851, 0x3854, 0x3857, 0x385a, 0x385d, 0x3860, 0x3864,
+ 0x3867, 0x386a, 0x386d, 0x3870, 0x3874, 0x3877, 0x387a, 0x387e, 0x3881,
+ 0x3885, 0x3888, 0x388b, 0x388f, 0x3892, 0x3896, 0x3899, 0x389d, 0x38a0,
+ 0x38a4, 0x38a7, 0x38ab, 0x38af, 0x38b2, 0x38b6, 0x38ba, 0x38bd, 0x38c1,
+ 0x38c5, 0x38c8, 0x38cc, 0x38d0, 0x38d4, 0x38d8, 0x38dc, 0x38df, 0x38e3,
+ 0x38e7, 0x38eb, 0x38ef, 0x38f3, 0x38f7, 0x38fb, 0x38ff, 0x3903, 0x3907,
+ 0x390c, 0x3910, 0x3914, 0x3918, 0x391c, 0x3920, 0x3925, 0x3929, 0x392d,
+ 0x3932, 0x3936, 0x393a, 0x393f, 0x3943, 0x3948, 0x394c, 0x3951, 0x3955,
+ 0x395a, 0x395e, 0x3963, 0x3967, 0x396c, 0x3971, 0x3975, 0x397a, 0x397f,
+ 0x3984, 0x3989, 0x398d, 0x3992, 0x3997, 0x399c, 0x39a1, 0x39a6, 0x39ab,
+ 0x39b0, 0x39b5, 0x39ba, 0x39bf, 0x39c4, 0x39c9, 0x39cf, 0x39d4, 0x39d9,
+ 0x39de, 0x39e4, 0x39e9, 0x39ee, 0x39f4, 0x39f9, 0x39ff, 0x3,
+ /* table descriptor */
+ 0xfbeff0e1, 0xf,
+ /* table length */
+ 0x402,
+ /* table data */
+ 0x3, 0x0, 0x1, 0x2, 0x3, 0x4, 0x6, 0x7, 0x8, 0x9, 0xb, 0xc, 0xd, 0xe, 0x10,
+ 0x11, 0x12, 0x13, 0x15, 0x16, 0x17, 0x18, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
+ 0x20, 0x21, 0x22, 0x23, 0x25, 0x26, 0x27, 0x28, 0x2a, 0x2b, 0x2c, 0x2d,
+ 0x2f, 0x30, 0x31, 0x32, 0x34, 0x35, 0x36, 0x37, 0x39, 0x3a, 0x3c, 0x3d,
+ 0x3e, 0x40, 0x41, 0x43, 0x44, 0x46, 0x47, 0x49, 0x4a, 0x4c, 0x4d, 0x4f,
+ 0x51, 0x52, 0x54, 0x56, 0x57, 0x59, 0x5b, 0x5d, 0x5f, 0x60, 0x62, 0x64,
+ 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c,
+ 0x7e, 0x80, 0x82, 0x85, 0x87, 0x89, 0x8b, 0x8e, 0x90, 0x92, 0x94, 0x97,
+ 0x99, 0x9c, 0x9e, 0xa0, 0xa3, 0xa5, 0xa8, 0xaa, 0xad, 0xb0, 0xb2, 0xb5,
+ 0xb7, 0xba, 0xbd, 0xc0, 0xc2, 0xc5, 0xc8, 0xcb, 0xcd, 0xd0, 0xd3, 0xd6,
+ 0xd9, 0xdc, 0xdf, 0xe2, 0xe5, 0xe8, 0xeb, 0xee, 0xf1, 0xf4, 0xf7, 0xfb,
+ 0xfe, 0x101, 0x104, 0x108, 0x10b, 0x10e, 0x111, 0x115, 0x118, 0x11c, 0x11f,
+ 0x123, 0x126, 0x12a, 0x12d, 0x131, 0x134, 0x138, 0x13b, 0x13f, 0x143,
+ 0x146, 0x14a, 0x14e, 0x152, 0x155, 0x159, 0x15d, 0x161, 0x165, 0x169,
+ 0x16d, 0x171, 0x175, 0x179, 0x17d, 0x181, 0x185, 0x189, 0x18d, 0x192,
+ 0x196, 0x19a, 0x19e, 0x1a2, 0x1a7, 0x1ab, 0x1af, 0x1b4, 0x1b8, 0x1bd,
+ 0x1c1, 0x1c6, 0x1ca, 0x1cf, 0x1d3, 0x1d8, 0x1dc, 0x1e1, 0x1e6, 0x1ea,
+ 0x1ef, 0x1f4, 0x1f9, 0x1fe, 0x202, 0x207, 0x20c, 0x211, 0x216, 0x21b,
+ 0x220, 0x225, 0x22a, 0x22f, 0x234, 0x239, 0x23e, 0x244, 0x249, 0x24e,
+ 0x253, 0x258, 0x25e, 0x263, 0x269, 0x26e, 0x273, 0x279, 0x27e, 0x284,
+ 0x289, 0x28f, 0x294, 0x29a, 0x2a0, 0x2a5, 0x2ab, 0x2b1, 0x2b7, 0x2bc,
+ 0x2c2, 0x2c8, 0x2ce, 0x2d4, 0x2da, 0x2e0, 0x2e6, 0x2ec, 0x2f2, 0x2f8,
+ 0x2fe, 0x304, 0x30a, 0x310, 0x316, 0x31d, 0x323, 0x329, 0x32f, 0x336,
+ 0x33c, 0x343, 0x349, 0x350, 0x356, 0x35d, 0x363, 0x36a, 0x370, 0x377,
+ 0x37e, 0x384, 0x38b, 0x392, 0x398, 0x39f, 0x3a6, 0x3ad, 0x3b4, 0x3bb,
+ 0x3c2, 0x3c9, 0x3d0, 0x3d7, 0x3de, 0x3e5, 0x3ec, 0x3f3, 0x3fb, 0x402,
+ 0x409, 0x410, 0x418, 0x41f, 0x426, 0x42e, 0x435, 0x43d, 0x444, 0x44c,
+ 0x453, 0x45b, 0x462, 0x46a, 0x472, 0x479, 0x481, 0x489, 0x491, 0x499,
+ 0x4a0, 0x4a8, 0x4b0, 0x4b8, 0x4c0, 0x4c8, 0x4d0, 0x4d8, 0x4e0, 0x4e8,
+ 0x4f1, 0x4f9, 0x501, 0x509, 0x512, 0x51a, 0x522, 0x52b, 0x533, 0x53b,
+ 0x544, 0x54c, 0x555, 0x55e, 0x566, 0x56f, 0x577, 0x580, 0x589, 0x592,
+ 0x59a, 0x5a3, 0x5ac, 0x5b5, 0x5be, 0x5c7, 0x5d0, 0x5d9, 0x5e2, 0x5eb,
+ 0x5f4, 0x5fd, 0x606, 0x60f, 0x619, 0x622, 0x62b, 0x635, 0x63e, 0x647,
+ 0x651, 0x65a, 0x664, 0x66d, 0x677, 0x680, 0x68a, 0x694, 0x69d, 0x6a7,
+ 0x6b1, 0x6bb, 0x6c4, 0x6ce, 0x6d8, 0x6e2, 0x6ec, 0x6f6, 0x700, 0x70a,
+ 0x714, 0x71e, 0x728, 0x732, 0x73d, 0x747, 0x751, 0x75b, 0x766, 0x770,
+ 0x77a, 0x785, 0x78f, 0x79a, 0x7a4, 0x7af, 0x7ba, 0x7c4, 0x7cf, 0x7da,
+ 0x7e4, 0x7ef, 0x7fa, 0x805, 0x810, 0x81a, 0x825, 0x830, 0x83b, 0x846,
+ 0x851, 0x85d, 0x868, 0x873, 0x87e, 0x889, 0x895, 0x8a0, 0x8ab, 0x8b7,
+ 0x8c2, 0x8cd, 0x8d9, 0x8e4, 0x8f0, 0x8fb, 0x907, 0x913, 0x91e, 0x92a,
+ 0x936, 0x942, 0x94d, 0x959, 0x965, 0x971, 0x97d, 0x989, 0x995, 0x9a1,
+ 0x9ad, 0x9b9, 0x9c5, 0x9d2, 0x9de, 0x9ea, 0x9f6, 0xa03, 0xa0f, 0xa1c,
+ 0xa28, 0xa34, 0xa41, 0xa4d, 0xa5a, 0xa67, 0xa73, 0xa80, 0xa8d, 0xa99,
+ 0xaa6, 0xab3, 0xac0, 0xacd, 0xada, 0xae7, 0xaf4, 0xb01, 0xb0e, 0xb1b,
+ 0xb28, 0xb35, 0xb42, 0xb50, 0xb5d, 0xb6a, 0xb77, 0xb85, 0xb92, 0xba0,
+ 0xbad, 0xbbb, 0xbc8, 0xbd6, 0xbe4, 0xbf1, 0xbff, 0xc0d, 0xc1a, 0xc28,
+ 0xc36, 0xc44, 0xc52, 0xc60, 0xc6e, 0xc7c, 0xc8a, 0xc98, 0xca6, 0xcb4,
+ 0xcc3, 0xcd1, 0xcdf, 0xced, 0xcfc, 0xd0a, 0xd19, 0xd27, 0xd35, 0xd44,
+ 0xd53, 0xd61, 0xd70, 0xd7e, 0xd8d, 0xd9c, 0xdab, 0xdba, 0xdc8, 0xdd7,
+ 0xde6, 0xdf5, 0xe04, 0xe13, 0xe22, 0xe31, 0xe41, 0xe50, 0xe5f, 0xe6e,
+ 0xe7e, 0xe8d, 0xe9c, 0xeac, 0xebb, 0xecb, 0xeda, 0xeea, 0xef9, 0xf09,
+ 0xf19, 0xf28, 0xf38, 0xf48, 0xf58, 0xf68, 0xf77, 0xf87, 0xf97, 0xfa7,
+ 0xfb7, 0xfc7, 0xfd8, 0xfe8, 0xff8, 0x1008, 0x1018, 0x1029, 0x1039, 0x1049,
+ 0x105a, 0x106a, 0x107b, 0x108b, 0x109c, 0x10ad, 0x10bd, 0x10ce, 0x10df,
+ 0x10ef, 0x1100, 0x1111, 0x1122, 0x1133, 0x1144, 0x1155, 0x1166, 0x1177,
+ 0x1188, 0x1199, 0x11aa, 0x11bb, 0x11cd, 0x11de, 0x11ef, 0x1201, 0x1212,
+ 0x1223, 0x1235, 0x1246, 0x1258, 0x126a, 0x127b, 0x128d, 0x129f, 0x12b0,
+ 0x12c2, 0x12d4, 0x12e6, 0x12f8, 0x130a, 0x131c, 0x132e, 0x1340, 0x1352,
+ 0x1364, 0x1376, 0x1388, 0x139b, 0x13ad, 0x13bf, 0x13d2, 0x13e4, 0x13f6,
+ 0x1409, 0x141c, 0x142e, 0x1441, 0x1453, 0x1466, 0x1479, 0x148b, 0x149e,
+ 0x14b1, 0x14c4, 0x14d7, 0x14ea, 0x14fd, 0x1510, 0x1523, 0x1536, 0x1549,
+ 0x155c, 0x1570, 0x1583, 0x1596, 0x15aa, 0x15bd, 0x15d0, 0x15e4, 0x15f7,
+ 0x160b, 0x161e, 0x1632, 0x1646, 0x1659, 0x166d, 0x1681, 0x1695, 0x16a9,
+ 0x16bd, 0x16d1, 0x16e4, 0x16f9, 0x170d, 0x1721, 0x1735, 0x1749, 0x175d,
+ 0x1771, 0x1786, 0x179a, 0x17af, 0x17c3, 0x17d7, 0x17ec, 0x1800, 0x1815,
+ 0x182a, 0x183e, 0x1853, 0x1868, 0x187d, 0x1891, 0x18a6, 0x18bb, 0x18d0,
+ 0x18e5, 0x18fa, 0x190f, 0x1924, 0x1939, 0x194f, 0x1964, 0x1979, 0x198e,
+ 0x19a4, 0x19b9, 0x19cf, 0x19e4, 0x19fa, 0x1a0f, 0x1a25, 0x1a3a, 0x1a50,
+ 0x1a66, 0x1a7b, 0x1a91, 0x1aa7, 0x1abd, 0x1ad3, 0x1ae9, 0x1aff, 0x1b15,
+ 0x1b2b, 0x1b41, 0x1b57, 0x1b6d, 0x1b84, 0x1b9a, 0x1bb0, 0x1bc7, 0x1bdd,
+ 0x1bf4, 0x1c0a, 0x1c21, 0x1c37, 0x1c4e, 0x1c64, 0x1c7b, 0x1c92, 0x1ca9,
+ 0x1cbf, 0x1cd6, 0x1ced, 0x1d04, 0x1d1b, 0x1d32, 0x1d49, 0x1d60, 0x1d78,
+ 0x1d8f, 0x1da6, 0x1dbd, 0x1dd5, 0x1dec, 0x1e03, 0x1e1b, 0x1e32, 0x1e4a,
+ 0x1e61, 0x1e79, 0x1e91, 0x1ea8, 0x1ec0, 0x1ed8, 0x1ef0, 0x1f07, 0x1f1f,
+ 0x1f37, 0x1f4f, 0x1f67, 0x1f7f, 0x1f98, 0x1fb0, 0x1fc8, 0x1fe0, 0x1ff8,
+ 0x2011, 0x2029, 0x2042, 0x205a, 0x2072, 0x208b, 0x20a4, 0x20bc, 0x20d5,
+ 0x20ee, 0x2106, 0x211f, 0x2138, 0x2151, 0x216a, 0x2183, 0x219c, 0x21b5,
+ 0x21ce, 0x21e7, 0x2200, 0x2219, 0x2233, 0x224c, 0x2265, 0x227f, 0x2298,
+ 0x22b2, 0x22cb, 0x22e5, 0x22fe, 0x2318, 0x2331, 0x234b, 0x2365, 0x237f,
+ 0x2399, 0x23b3, 0x23cc, 0x23e6, 0x2401, 0x241b, 0x2435, 0x244f, 0x2469,
+ 0x2483, 0x249e, 0x24b8, 0x24d2, 0x24ed, 0x2507, 0x2522, 0x253c, 0x2557,
+ 0x2571, 0x258c, 0x25a7, 0x25c2, 0x25dc, 0x25f7, 0x2612, 0x262d, 0x2648,
+ 0x2663, 0x267e, 0x2699, 0x26b4, 0x26cf, 0x26eb, 0x2706, 0x2721, 0x273d,
+ 0x2758, 0x2774, 0x278f, 0x27ab, 0x27c6, 0x27e2, 0x27fd, 0x2819, 0x2835,
+ 0x2851, 0x286d, 0x2888, 0x28a4, 0x28c0, 0x28dc, 0x28f8, 0x2915, 0x2931,
+ 0x294d, 0x2969, 0x2985, 0x29a2, 0x29be, 0x29db, 0x29f7, 0x2a14, 0x2a30,
+ 0x2a4d, 0x2a69, 0x2a86, 0x2aa3, 0x2ac0, 0x2adc, 0x2af9, 0x2b16, 0x2b33,
+ 0x2b50, 0x2b6d, 0x2b8a, 0x2ba7, 0x2bc4, 0x2be2, 0x2bff, 0x2c1c, 0x2c3a,
+ 0x2c57, 0x2c74, 0x2c92, 0x2caf, 0x2ccd, 0x2ceb, 0x2d08, 0x2d26, 0x2d44,
+ 0x2d61, 0x2d7f, 0x2d9d, 0x2dbb, 0x2dd9, 0x2df7, 0x2e15, 0x2e33, 0x2e51,
+ 0x2e70, 0x2e8e, 0x2eac, 0x2eca, 0x2ee9, 0x2f07, 0x2f26, 0x2f44, 0x2f63,
+ 0x2f81, 0x2fa0, 0x2fbf, 0x2fdd, 0x2ffc, 0x301b, 0x303a, 0x3059, 0x3078,
+ 0x3097, 0x30b6, 0x30d5, 0x30f4, 0x3113, 0x3132, 0x3152, 0x3171, 0x3190,
+ 0x31b0, 0x31cf, 0x31ef, 0x320e, 0x322e, 0x324e, 0x326d, 0x328d, 0x32ad,
+ 0x32cd, 0x32ec, 0x330c, 0x332c, 0x334c, 0x336c, 0x338c, 0x33ac, 0x33cd,
+ 0x33ed, 0x340d, 0x342e, 0x344e, 0x346e, 0x348f, 0x34af, 0x34d0, 0x34f0,
+ 0x3511, 0x3532, 0x3552, 0x3573, 0x3594, 0x35b5, 0x35d6, 0x35f7, 0x3618,
+ 0x3639, 0x365a, 0x367b, 0x369c, 0x36bd, 0x36df, 0x3700, 0x3721, 0x3743,
+ 0x3764, 0x3786, 0x37a7, 0x37c9, 0x37eb, 0x380c, 0x382e, 0x3850, 0x3872,
+ 0x3894, 0x38b6, 0x38d8, 0x38fa, 0x391c, 0x393e, 0x3960, 0x3982, 0x39a4,
+ 0x39c7, 0x39e9, 0x3a0b, 0x3a2e, 0x3a50, 0x3a73, 0x3a95, 0x3ab8, 0x3adb,
+ 0x3afd, 0x3b20, 0x3b43, 0x3b66, 0x3b89, 0x3bac, 0x3bcf, 0x3bf2, 0x3c15,
+ 0x3c38, 0x3c5b, 0x3c7e, 0x3ca2, 0x3cc5, 0x3ce8, 0x3d0c, 0x3d2f, 0x3d53,
+ 0x3d76, 0x3d9a, 0x3dbe, 0x3de1, 0x3e05, 0x3e29, 0x3e4d, 0x3e71, 0x3e95,
+ 0x3eb9, 0x3edd, 0x3f01, 0x3f25, 0x3f49, 0x3f6d, 0x3f91, 0x3fb6, 0x3fda,
+ 0x3fff, 0x0,
+ /* table descriptor */
+ 0xfbefe1e1, 0xf,
+ /* table length */
+ 0x402,
+ /* table data */
+ 0x3, 0x0, 0x200, 0x500, 0x700, 0x8c0, 0xa20, 0xae0, 0xbe0, 0xc70, 0xd00,
+ 0xdb0, 0xe30, 0xe98, 0xf00, 0xf78, 0xff8, 0x103c, 0x1084, 0x10d0, 0x1120,
+ 0x1178, 0x11d0, 0x1218, 0x124a, 0x127e, 0x12b6, 0x12f0, 0x132c, 0x136c,
+ 0x13ae, 0x13f2, 0x141d, 0x1442, 0x1469, 0x1491, 0x14bb, 0x14e6, 0x1513,
+ 0x1542, 0x1572, 0x15a4, 0x15d7, 0x1606, 0x1621, 0x163e, 0x165b, 0x1679,
+ 0x1698, 0x16b9, 0x16da, 0x16fc, 0x171f, 0x1743, 0x1768, 0x178e, 0x17b5,
+ 0x17dd, 0x1803, 0x1818, 0x182e, 0x1844, 0x185b, 0x1873, 0x188b, 0x18a4,
+ 0x18bd, 0x18d7, 0x18f2, 0x190d, 0x1929, 0x1945, 0x1962, 0x1980, 0x199f,
+ 0x19be, 0x19de, 0x19ff, 0x1a10, 0x1a21, 0x1a32, 0x1a44, 0x1a56, 0x1a69,
+ 0x1a7c, 0x1a8f, 0x1aa3, 0x1ab7, 0x1acc, 0x1ae1, 0x1af6, 0x1b0c, 0x1b23,
+ 0x1b39, 0x1b51, 0x1b68, 0x1b81, 0x1b99, 0x1bb2, 0x1bcc, 0x1be6, 0x1c00,
+ 0x1c0e, 0x1c1b, 0x1c29, 0x1c38, 0x1c46, 0x1c55, 0x1c64, 0x1c74, 0x1c83,
+ 0x1c93, 0x1ca3, 0x1cb4, 0x1cc5, 0x1cd6, 0x1ce7, 0x1cf9, 0x1d0b, 0x1d1d,
+ 0x1d30, 0x1d42, 0x1d56, 0x1d69, 0x1d7d, 0x1d91, 0x1da6, 0x1dbb, 0x1dd0,
+ 0x1de6, 0x1dfc, 0x1e09, 0x1e14, 0x1e20, 0x1e2b, 0x1e37, 0x1e43, 0x1e4f,
+ 0x1e5c, 0x1e69, 0x1e75, 0x1e82, 0x1e90, 0x1e9d, 0x1eab, 0x1eb9, 0x1ec7,
+ 0x1ed5, 0x1ee3, 0x1ef2, 0x1f01, 0x1f10, 0x1f20, 0x1f2f, 0x1f3f, 0x1f4f,
+ 0x1f60, 0x1f70, 0x1f81, 0x1f92, 0x1fa3, 0x1fb5, 0x1fc7, 0x1fd9, 0x1feb,
+ 0x1ffe, 0x2008, 0x2012, 0x201b, 0x2025, 0x202f, 0x2039, 0x2043, 0x204e,
+ 0x2058, 0x2063, 0x206e, 0x2079, 0x2084, 0x208f, 0x209b, 0x20a6, 0x20b2,
+ 0x20be, 0x20ca, 0x20d6, 0x20e3, 0x20ef, 0x20fc, 0x2109, 0x2116, 0x2123,
+ 0x2131, 0x213e, 0x214c, 0x215a, 0x2168, 0x2176, 0x2185, 0x2194, 0x21a2,
+ 0x21b2, 0x21c1, 0x21d0, 0x21e0, 0x21f0, 0x2200, 0x2208, 0x2210, 0x2218,
+ 0x2221, 0x2229, 0x2232, 0x223b, 0x2244, 0x224d, 0x2256, 0x225f, 0x2268,
+ 0x2272, 0x227b, 0x2285, 0x228f, 0x2299, 0x22a3, 0x22ad, 0x22b7, 0x22c2,
+ 0x22cc, 0x22d7, 0x22e2, 0x22ed, 0x22f8, 0x2303, 0x230e, 0x231a, 0x2325,
+ 0x2331, 0x233d, 0x2349, 0x2355, 0x2361, 0x236e, 0x237a, 0x2387, 0x2394,
+ 0x23a1, 0x23ae, 0x23bc, 0x23c9, 0x23d7, 0x23e5, 0x23f3, 0x2400, 0x2407,
+ 0x240f, 0x2416, 0x241d, 0x2425, 0x242c, 0x2434, 0x243c, 0x2444, 0x244c,
+ 0x2454, 0x245c, 0x2464, 0x246c, 0x2475, 0x247d, 0x2486, 0x248e, 0x2497,
+ 0x24a0, 0x24a9, 0x24b2, 0x24bb, 0x24c4, 0x24ce, 0x24d7, 0x24e1, 0x24eb,
+ 0x24f4, 0x24fe, 0x2508, 0x2512, 0x251d, 0x2527, 0x2531, 0x253c, 0x2547,
+ 0x2552, 0x255d, 0x2568, 0x2573, 0x257e, 0x2589, 0x2595, 0x25a1, 0x25ac,
+ 0x25b8, 0x25c4, 0x25d1, 0x25dd, 0x25e9, 0x25f6, 0x2601, 0x2607, 0x260e,
+ 0x2614, 0x261b, 0x2622, 0x2629, 0x262f, 0x2636, 0x263d, 0x2644, 0x264c,
+ 0x2653, 0x265a, 0x2661, 0x2669, 0x2670, 0x2678, 0x2680, 0x2687, 0x268f,
+ 0x2697, 0x269f, 0x26a7, 0x26af, 0x26b8, 0x26c0, 0x26c8, 0x26d1, 0x26d9,
+ 0x26e2, 0x26eb, 0x26f4, 0x26fd, 0x2706, 0x270f, 0x2718, 0x2722, 0x272b,
+ 0x2734, 0x273e, 0x2748, 0x2752, 0x275c, 0x2766, 0x2770, 0x277a, 0x2784,
+ 0x278f, 0x2799, 0x27a4, 0x27af, 0x27b9, 0x27c4, 0x27d0, 0x27db, 0x27e6,
+ 0x27f1, 0x27fd, 0x2804, 0x280a, 0x2810, 0x2816, 0x281c, 0x2822, 0x2828,
+ 0x282f, 0x2835, 0x283b, 0x2842, 0x2848, 0x284f, 0x2855, 0x285c, 0x2863,
+ 0x286a, 0x2870, 0x2877, 0x287e, 0x2886, 0x288d, 0x2894, 0x289b, 0x28a3,
+ 0x28aa, 0x28b2, 0x28b9, 0x28c1, 0x28c9, 0x28d0, 0x28d8, 0x28e0, 0x28e8,
+ 0x28f1, 0x28f9, 0x2901, 0x2909, 0x2912, 0x291a, 0x2923, 0x292c, 0x2935,
+ 0x293d, 0x2946, 0x294f, 0x2959, 0x2962, 0x296b, 0x2975, 0x297e, 0x2988,
+ 0x2991, 0x299b, 0x29a5, 0x29af, 0x29b9, 0x29c3, 0x29cd, 0x29d8, 0x29e2,
+ 0x29ed, 0x29f7, 0x2a01, 0x2a06, 0x2a0c, 0x2a11, 0x2a17, 0x2a1c, 0x2a22,
+ 0x2a28, 0x2a2e, 0x2a33, 0x2a39, 0x2a3f, 0x2a45, 0x2a4b, 0x2a52, 0x2a58,
+ 0x2a5e, 0x2a64, 0x2a6b, 0x2a71, 0x2a78, 0x2a7e, 0x2a85, 0x2a8b, 0x2a92,
+ 0x2a99, 0x2aa0, 0x2aa7, 0x2aae, 0x2ab5, 0x2abc, 0x2ac3, 0x2aca, 0x2ad2,
+ 0x2ad9, 0x2ae1, 0x2ae8, 0x2af0, 0x2af7, 0x2aff, 0x2b07, 0x2b0f, 0x2b17,
+ 0x2b1f, 0x2b27, 0x2b2f, 0x2b38, 0x2b40, 0x2b48, 0x2b51, 0x2b59, 0x2b62,
+ 0x2b6b, 0x2b74, 0x2b7d, 0x2b86, 0x2b8f, 0x2b98, 0x2ba1, 0x2baa, 0x2bb4,
+ 0x2bbd, 0x2bc7, 0x2bd0, 0x2bda, 0x2be4, 0x2bee, 0x2bf8, 0x2c01, 0x2c06,
+ 0x2c0b, 0x2c10, 0x2c16, 0x2c1b, 0x2c20, 0x2c26, 0x2c2b, 0x2c31, 0x2c36,
+ 0x2c3c, 0x2c41, 0x2c47, 0x2c4d, 0x2c53, 0x2c59, 0x2c5e, 0x2c64, 0x2c6a,
+ 0x2c70, 0x2c77, 0x2c7d, 0x2c83, 0x2c89, 0x2c90, 0x2c96, 0x2c9d, 0x2ca3,
+ 0x2caa, 0x2cb0, 0x2cb7, 0x2cbe, 0x2cc5, 0x2ccc, 0x2cd3, 0x2cda, 0x2ce1,
+ 0x2ce8, 0x2cef, 0x2cf6, 0x2cfe, 0x2d05, 0x2d0d, 0x2d14, 0x2d1c, 0x2d24,
+ 0x2d2b, 0x2d33, 0x2d3b, 0x2d43, 0x2d4b, 0x2d53, 0x2d5b, 0x2d64, 0x2d6c,
+ 0x2d74, 0x2d7d, 0x2d85, 0x2d8e, 0x2d97, 0x2da0, 0x2da9, 0x2db2, 0x2dbb,
+ 0x2dc4, 0x2dcd, 0x2dd6, 0x2de0, 0x2de9, 0x2df3, 0x2dfc, 0x2e03, 0x2e08,
+ 0x2e0d, 0x2e12, 0x2e17, 0x2e1c, 0x2e21, 0x2e26, 0x2e2b, 0x2e30, 0x2e36,
+ 0x2e3b, 0x2e41, 0x2e46, 0x2e4c, 0x2e51, 0x2e57, 0x2e5c, 0x2e62, 0x2e68,
+ 0x2e6e, 0x2e73, 0x2e79, 0x2e7f, 0x2e85, 0x2e8b, 0x2e92, 0x2e98, 0x2e9e,
+ 0x2ea4, 0x2eab, 0x2eb1, 0x2eb8, 0x2ebe, 0x2ec5, 0x2ecb, 0x2ed2, 0x2ed9,
+ 0x2ee0, 0x2ee6, 0x2eed, 0x2ef4, 0x2efb, 0x2f03, 0x2f0a, 0x2f11, 0x2f18,
+ 0x2f20, 0x2f27, 0x2f2f, 0x2f36, 0x2f3e, 0x2f46, 0x2f4e, 0x2f55, 0x2f5d,
+ 0x2f65, 0x2f6d, 0x2f76, 0x2f7e, 0x2f86, 0x2f8e, 0x2f97, 0x2f9f, 0x2fa8,
+ 0x2fb1, 0x2fb9, 0x2fc2, 0x2fcb, 0x2fd4, 0x2fdd, 0x2fe6, 0x2ff0, 0x2ff9,
+ 0x3001, 0x3006, 0x300a, 0x300f, 0x3014, 0x3019, 0x301e, 0x3023, 0x3028,
+ 0x302d, 0x3032, 0x3037, 0x303d, 0x3042, 0x3047, 0x304d, 0x3052, 0x3057,
+ 0x305d, 0x3062, 0x3068, 0x306e, 0x3073, 0x3079, 0x307f, 0x3085, 0x308b,
+ 0x3091, 0x3097, 0x309d, 0x30a3, 0x30a9, 0x30af, 0x30b6, 0x30bc, 0x30c2,
+ 0x30c9, 0x30cf, 0x30d6, 0x30dd, 0x30e3, 0x30ea, 0x30f1, 0x30f8, 0x30ff,
+ 0x3106, 0x310d, 0x3114, 0x311b, 0x3122, 0x3129, 0x3131, 0x3138, 0x3140,
+ 0x3147, 0x314f, 0x3157, 0x315e, 0x3166, 0x316e, 0x3176, 0x317e, 0x3186,
+ 0x318f, 0x3197, 0x319f, 0x31a8, 0x31b0, 0x31b9, 0x31c1, 0x31ca, 0x31d3,
+ 0x31dc, 0x31e5, 0x31ee, 0x31f7, 0x3200, 0x3204, 0x3209, 0x320e, 0x3213,
+ 0x3217, 0x321c, 0x3221, 0x3226, 0x322b, 0x3230, 0x3235, 0x323a, 0x323f,
+ 0x3245, 0x324a, 0x324f, 0x3255, 0x325a, 0x325f, 0x3265, 0x326a, 0x3270,
+ 0x3276, 0x327b, 0x3281, 0x3287, 0x328d, 0x3293, 0x3299, 0x329f, 0x32a5,
+ 0x32ab, 0x32b1, 0x32b7, 0x32bd, 0x32c4, 0x32ca, 0x32d1, 0x32d7, 0x32de,
+ 0x32e4, 0x32eb, 0x32f2, 0x32f8, 0x32ff, 0x3306, 0x330d, 0x3314, 0x331b,
+ 0x3322, 0x332a, 0x3331, 0x3338, 0x3340, 0x3347, 0x334f, 0x3357, 0x335e,
+ 0x3366, 0x336e, 0x3376, 0x337e, 0x3386, 0x338e, 0x3396, 0x339e, 0x33a7,
+ 0x33af, 0x33b8, 0x33c0, 0x33c9, 0x33d2, 0x33da, 0x33e3, 0x33ec, 0x33f5,
+ 0x33fe, 0x3404, 0x3408, 0x340d, 0x3412, 0x3416, 0x341b, 0x3420, 0x3425,
+ 0x342a, 0x342f, 0x3434, 0x3439, 0x343e, 0x3443, 0x3448, 0x344e, 0x3453,
+ 0x3458, 0x345e, 0x3463, 0x3469, 0x346e, 0x3474, 0x347a, 0x347f, 0x3485,
+ 0x348b, 0x3491, 0x3497, 0x349d, 0x34a3, 0x34a9, 0x34af, 0x34b5, 0x34bb,
+ 0x34c2, 0x34c8, 0x34ce, 0x34d5, 0x34db, 0x34e2, 0x34e9, 0x34ef, 0x34f6,
+ 0x34fd, 0x3504, 0x350b, 0x3512, 0x3519, 0x3520, 0x3527, 0x352f, 0x3536,
+ 0x353d, 0x3545, 0x354c, 0x3554, 0x355c, 0x3563, 0x356b, 0x3573, 0x357b,
+ 0x3583, 0x358b, 0x3593, 0x359c, 0x35a4, 0x35ad, 0x35b5, 0x35be, 0x35c6,
+ 0x35cf, 0x35d8, 0x35e1, 0x35ea, 0x35f3, 0x35fc, 0x3602, 0x3607, 0x360c,
+ 0x3610, 0x3615, 0x361a, 0x361f, 0x3624, 0x3629, 0x362e, 0x3633, 0x3638,
+ 0x363d, 0x3642, 0x3647, 0x364d, 0x3652, 0x3657, 0x365d, 0x3662, 0x3668,
+ 0x366d, 0x3673, 0x3679, 0x367f, 0x3684, 0x368a, 0x3690, 0x3696, 0x369c,
+ 0x36a2, 0x36a8, 0x36ae, 0x36b5, 0x36bb, 0x36c1, 0x36c8, 0x36ce, 0x36d5,
+ 0x36db, 0x36e2, 0x36e9, 0x36f0, 0x36f6, 0x36fd, 0x3704, 0x370b, 0x3712,
+ 0x371a, 0x3721, 0x3728, 0x372f, 0x3737, 0x373e, 0x3746, 0x374e, 0x3755,
+ 0x375d, 0x3765, 0x376d, 0x3775, 0x377d, 0x3785, 0x378d, 0x3796, 0x379e,
+ 0x37a7, 0x37af, 0x37b8, 0x37c1, 0x37c9, 0x37d2, 0x37db, 0x37e4, 0x37ed,
+ 0x37f7, 0x3800, 0x3804, 0x3809, 0x380e, 0x3813, 0x3818, 0x381d, 0x3821,
+ 0x3826, 0x382c, 0x3831, 0x3836, 0x383b, 0x3840, 0x3846, 0x384b, 0x3850,
+ 0x3856, 0x385b, 0x3861, 0x3866, 0x386c, 0x3872, 0x3878, 0x387d, 0x3883,
+ 0x3889, 0x388f, 0x3895, 0x389b, 0x38a2, 0x38a8, 0x38ae, 0x38b5, 0x38bb,
+ 0x38c1, 0x38c8, 0x38cf, 0x38d5, 0x38dc, 0x38e3, 0x38ea, 0x38f1, 0x38f8,
+ 0x38ff, 0x3906, 0x390d, 0x3914, 0x391b, 0x3923, 0x392a, 0x3932, 0x3939,
+ 0x3941, 0x3949, 0x3951, 0x3959, 0x3961, 0x3969, 0x3971, 0x3979, 0x3981,
+ 0x398a, 0x3992, 0x399b, 0x39a3, 0x39ac, 0x39b5, 0x39be, 0x39c7, 0x39d0,
+ 0x39d9, 0x39e2, 0x39ec, 0x39f5, 0x39ff, 0x3,
+ /* table descriptor */
+ 0xfbefe2e1, 0xf,
+ /* table length */
+ 0x402,
+ /* table data */
+ 0x3, 0x0, 0x3, 0x7, 0xa, 0xe, 0x11, 0x15, 0x18, 0x1c, 0x20, 0x23, 0x27,
+ 0x2a, 0x2e, 0x31, 0x35, 0x38, 0x3c, 0x40, 0x43, 0x47, 0x4a, 0x4e, 0x51,
+ 0x55, 0x58, 0x5c, 0x60, 0x63, 0x67, 0x6a, 0x6e, 0x71, 0x75, 0x78, 0x7c,
+ 0x80, 0x83, 0x87, 0x8a, 0x8e, 0x91, 0x95, 0x99, 0x9c, 0xa0, 0xa3, 0xa7,
+ 0xaa, 0xae, 0xb1, 0xb5, 0xb9, 0xbc, 0xc0, 0xc3, 0xc7, 0xca, 0xce, 0xd1,
+ 0xd5, 0xd9, 0xdc, 0xe0, 0xe3, 0xe7, 0xea, 0xee, 0xf1, 0xf5, 0xf9, 0xfc,
+ 0x100, 0x103, 0x107, 0x10a, 0x10e, 0x112, 0x115, 0x119, 0x11c, 0x120,
+ 0x123, 0x126, 0x12a, 0x12d, 0x131, 0x134, 0x138, 0x13c, 0x13f, 0x143,
+ 0x147, 0x14b, 0x14e, 0x152, 0x156, 0x15a, 0x15e, 0x162, 0x166, 0x16a,
+ 0x16e, 0x172, 0x176, 0x17a, 0x17e, 0x182, 0x186, 0x18a, 0x18f, 0x193,
+ 0x197, 0x19b, 0x1a0, 0x1a4, 0x1a8, 0x1ad, 0x1b1, 0x1b5, 0x1ba, 0x1be,
+ 0x1c3, 0x1c7, 0x1cc, 0x1d0, 0x1d5, 0x1d9, 0x1de, 0x1e3, 0x1e7, 0x1ec,
+ 0x1f1, 0x1f6, 0x1fa, 0x1ff, 0x204, 0x209, 0x20e, 0x213, 0x217, 0x21c,
+ 0x221, 0x226, 0x22b, 0x230, 0x236, 0x23b, 0x240, 0x245, 0x24a, 0x24f,
+ 0x255, 0x25a, 0x25f, 0x264, 0x26a, 0x26f, 0x274, 0x27a, 0x27f, 0x285,
+ 0x28a, 0x290, 0x295, 0x29b, 0x2a0, 0x2a6, 0x2ac, 0x2b1, 0x2b7, 0x2bd,
+ 0x2c2, 0x2c8, 0x2ce, 0x2d4, 0x2da, 0x2df, 0x2e5, 0x2eb, 0x2f1, 0x2f7,
+ 0x2fd, 0x303, 0x309, 0x30f, 0x315, 0x31c, 0x322, 0x328, 0x32e, 0x334,
+ 0x33b, 0x341, 0x347, 0x34d, 0x354, 0x35a, 0x361, 0x367, 0x36d, 0x374,
+ 0x37a, 0x381, 0x388, 0x38e, 0x395, 0x39b, 0x3a2, 0x3a9, 0x3b0, 0x3b6,
+ 0x3bd, 0x3c4, 0x3cb, 0x3d2, 0x3d8, 0x3df, 0x3e6, 0x3ed, 0x3f4, 0x3fb,
+ 0x402, 0x409, 0x411, 0x418, 0x41f, 0x426, 0x42d, 0x434, 0x43c, 0x443,
+ 0x44a, 0x452, 0x459, 0x460, 0x468, 0x46f, 0x477, 0x47e, 0x486, 0x48d,
+ 0x495, 0x49c, 0x4a4, 0x4ac, 0x4b3, 0x4bb, 0x4c3, 0x4cb, 0x4d3, 0x4da,
+ 0x4e2, 0x4ea, 0x4f2, 0x4fa, 0x502, 0x50a, 0x512, 0x51a, 0x522, 0x52a,
+ 0x532, 0x53a, 0x543, 0x54b, 0x553, 0x55b, 0x564, 0x56c, 0x574, 0x57d,
+ 0x585, 0x58d, 0x596, 0x59e, 0x5a7, 0x5af, 0x5b8, 0x5c1, 0x5c9, 0x5d2,
+ 0x5db, 0x5e3, 0x5ec, 0x5f5, 0x5fe, 0x606, 0x60f, 0x618, 0x621, 0x62a,
+ 0x633, 0x63c, 0x645, 0x64e, 0x657, 0x660, 0x669, 0x672, 0x67b, 0x685,
+ 0x68e, 0x697, 0x6a0, 0x6aa, 0x6b3, 0x6bd, 0x6c6, 0x6cf, 0x6d9, 0x6e2,
+ 0x6ec, 0x6f5, 0x6ff, 0x709, 0x712, 0x71c, 0x726, 0x72f, 0x739, 0x743,
+ 0x74d, 0x756, 0x760, 0x76a, 0x774, 0x77e, 0x788, 0x792, 0x79c, 0x7a6,
+ 0x7b0, 0x7ba, 0x7c4, 0x7cf, 0x7d9, 0x7e3, 0x7ed, 0x7f7, 0x802, 0x80c,
+ 0x816, 0x821, 0x82b, 0x836, 0x840, 0x84b, 0x855, 0x860, 0x86a, 0x875,
+ 0x880, 0x88a, 0x895, 0x8a0, 0x8ab, 0x8b5, 0x8c0, 0x8cb, 0x8d6, 0x8e1,
+ 0x8ec, 0x8f7, 0x902, 0x90d, 0x918, 0x923, 0x92e, 0x939, 0x944, 0x950,
+ 0x95b, 0x966, 0x971, 0x97d, 0x988, 0x993, 0x99f, 0x9aa, 0x9b6, 0x9c1,
+ 0x9cd, 0x9d8, 0x9e4, 0x9f0, 0x9fb, 0xa07, 0xa13, 0xa1e, 0xa2a, 0xa36,
+ 0xa42, 0xa4e, 0xa59, 0xa65, 0xa71, 0xa7d, 0xa89, 0xa95, 0xaa1, 0xaad,
+ 0xab9, 0xac6, 0xad2, 0xade, 0xaea, 0xaf6, 0xb03, 0xb0f, 0xb1b, 0xb28,
+ 0xb34, 0xb41, 0xb4d, 0xb5a, 0xb66, 0xb73, 0xb7f, 0xb8c, 0xb98, 0xba5,
+ 0xbb2, 0xbbf, 0xbcb, 0xbd8, 0xbe5, 0xbf2, 0xbff, 0xc0c, 0xc19, 0xc25,
+ 0xc32, 0xc40, 0xc4d, 0xc5a, 0xc67, 0xc74, 0xc81, 0xc8e, 0xc9c, 0xca9,
+ 0xcb6, 0xcc3, 0xcd1, 0xcde, 0xcec, 0xcf9, 0xd07, 0xd14, 0xd22, 0xd2f,
+ 0xd3d, 0xd4a, 0xd58, 0xd66, 0xd73, 0xd81, 0xd8f, 0xd9d, 0xdab, 0xdb8,
+ 0xdc6, 0xdd4, 0xde2, 0xdf0, 0xdfe, 0xe0c, 0xe1a, 0xe29, 0xe37, 0xe45,
+ 0xe53, 0xe61, 0xe70, 0xe7e, 0xe8c, 0xe9a, 0xea9, 0xeb7, 0xec6, 0xed4,
+ 0xee3, 0xef1, 0xf00, 0xf0e, 0xf1d, 0xf2c, 0xf3a, 0xf49, 0xf58, 0xf67,
+ 0xf75, 0xf84, 0xf93, 0xfa2, 0xfb1, 0xfc0, 0xfcf, 0xfde, 0xfed, 0xffc,
+ 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,
+ 0x0,
+ /* table descriptor */
+ 0xfbe83ba2, 0xf,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x4031, 0x0, 0x0, 0x0, 0x4031, 0x0, 0x0, 0x0, 0x4031, 0x0, 0xffffff80,
+ 0xffffff80, 0x0, 0xffffff80, 0xffffff80, 0xff, 0x7f, 0x7f, 0xc, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+ /* table descriptor */
+ 0xfbe65ba2, 0xf,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x4000, 0x0, 0x59bb, 0x4000, 0xffffe9fb, 0xffffd24d, 0x4000, 0x7169,
+ 0x0, 0x0, 0xfffffe00, 0xfffffe00, 0x0, 0xfffffe00, 0xfffffe00, 0x3ff,
+ 0x1ff, 0x1ff, 0xe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+ /* table descriptor */
+ 0xfbefbb62, 0xf,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x1, 0x4031, 0x0, 0x0, 0x0, 0x4031, 0x0, 0x0, 0x0, 0x4031, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff,
+ 0x3ff, 0x3ff,
+ /* table descriptor */
+ 0xfbefdb62, 0xf,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x8000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ /* table descriptor */
+ 0xfbe0bba2, 0xf,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x4031, 0x0, 0x5ea7, 0x4031, 0xfffff571, 0xffffdb55, 0x4031, 0x78c4,
+ 0x0, 0x0, 0xffffff80, 0xffffff80, 0x0, 0xffffff80, 0xffffff80, 0xff, 0x7f,
+ 0x7f, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+ /* table descriptor */
+ 0xfbe63ba2, 0xf,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x4031, 0x0, 0x59fe, 0x4031, 0xffffe9ea, 0xffffd22b, 0x4031, 0x71be,
+ 0x0, 0x0, 0xffffff80, 0xffffff80, 0x0, 0xffffff80, 0xffffff80, 0xff, 0x7f,
+ 0x7f, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+ /* table descriptor */
+ 0xfbe15ba2, 0xf,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x4000, 0x0, 0x64ca, 0x4000, 0xfffff404, 0xffffe20c, 0x4000, 0x76c3,
+ 0x0, 0x0, 0xfffffe00, 0xfffffe00, 0x0, 0xfffffe00, 0xfffffe00, 0x3ff,
+ 0x1ff, 0x1ff, 0xe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+ /* table descriptor */
+ 0xfbe13ba2, 0xf,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x4031, 0x0, 0x6516, 0x4031, 0xfffff3fb, 0xffffe1f5, 0x4031, 0x771c,
+ 0x0, 0x0, 0xffffff80, 0xffffff80, 0x0, 0xffffff80, 0xffffff80, 0xff, 0x7f,
+ 0x7f, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+ /* table descriptor */
+ 0xfbe0dba2, 0xf,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x4000, 0x0, 0x5e60, 0x4000, 0xfffff579, 0xffffdb70, 0x4000, 0x7869,
+ 0x0, 0x0, 0xfffffe00, 0xfffffe00, 0x0, 0xfffffe00, 0xfffffe00, 0x3ff,
+ 0x1ff, 0x1ff, 0xe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+ /* table descriptor */
+ 0xfbe85ba2, 0xf,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x3, 0x4000, 0x0, 0x0, 0x0, 0x4000, 0x0, 0x0, 0x0, 0x4000, 0x0, 0xfffffe00,
+ 0xfffffe00, 0x0, 0xfffffe00, 0xfffffe00, 0x3ff, 0x1ff, 0x1ff, 0xe, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x3ff, 0x3ff, 0x3ff,
+ /* table descriptor */
+ 0xfbeffbe4, 0xf,
+ /* table length */
+ 0x1d,
+ /* table data */
+ 0x8000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+};
+
+#endif /* __DCSS_HDR10_TABLES_H__ */
diff --git a/drivers/gpu/drm/imx/dcss/dcss-hdr10.c b/drivers/gpu/drm/imx/dcss/dcss-hdr10.c
new file mode 100644
index 000000000000..0c8e2478d2f4
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/dcss-hdr10.c
@@ -0,0 +1,585 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/device.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/seq_file.h>
+#include <linux/firmware.h>
+#include <drm/drm_fourcc.h>
+
+#include "dcss-dev.h"
+
+#define USE_TBL_HEADER
+
+#ifdef USE_TBL_HEADER
+#include "dcss-hdr10-tables.h"
+#endif
+
+#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 LUT_BYPASS BIT(15)
+#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_IPIPE_LUT_MAX_ENTRIES 1024
+#define HDR10_OPIPE_LUT_MAX_ENTRIES 1023
+#define HDR10_CSC_MAX_REGS 29
+
+#define OPIPE_CH_NO 3
+
+/* Pipe config descriptor */
+
+/* bits per component */
+#define HDR10_BPC_POS 0
+#define HDR10_BPC_MASK GENMASK(1, 0)
+/* colorspace */
+#define HDR10_CS_POS 2
+#define HDR10_CS_MASK GENMASK(3, 2)
+/* nonlinearity type */
+#define HDR10_NL_POS 4
+#define HDR10_NL_MASK GENMASK(8, 4)
+/* pixel range */
+#define HDR10_PR_POS 9
+#define HDR10_PR_MASK GENMASK(10, 9)
+/* gamut type */
+#define HDR10_G_POS 11
+#define HDR10_G_MASK GENMASK(15, 11)
+
+/* FW Table Type Descriptor */
+#define HDR10_TT_LUT BIT(0)
+#define HDR10_TT_CSCA BIT(1)
+#define HDR10_TT_CSCB BIT(2)
+/* Pipe type */
+#define HDR10_PT_OUTPUT BIT(3)
+/* Output pipe config descriptor */
+#define HDR10_IPIPE_DESC_POS 4
+#define HDR10_IPIPE_DESC_MASK GENMASK(19, 4)
+/* Input pipe config descriptor */
+#define HDR10_OPIPE_DESC_POS 20
+#define HDR10_OPIPE_DESC_MASK GENMASK(35, 20)
+
+/* config invalid */
+#define HDR10_DESC_INVALID BIT(63)
+
+enum dcss_hdr10_csc {
+ HDR10_CSCA,
+ HDR10_CSCB,
+};
+
+struct dcss_hdr10_tbl_node {
+ struct list_head node;
+
+ u64 tbl_descriptor;
+ u32 *tbl_data;
+};
+
+struct dcss_hdr10_opipe_tbls {
+ struct list_head lut;
+ struct list_head csc;
+};
+
+struct dcss_hdr10_ipipe_tbls {
+ struct list_head lut;
+ struct list_head csca;
+ struct list_head cscb;
+};
+
+struct dcss_hdr10_ch {
+ struct dcss_hdr10 *hdr10;
+ void __iomem *base_reg;
+ u32 base_ofs;
+
+ u64 old_cfg_desc;
+
+ u32 id;
+};
+
+struct dcss_hdr10 {
+ struct device *dev;
+ struct dcss_ctxld *ctxld;
+
+ u32 ctx_id;
+
+ struct dcss_hdr10_ch ch[4]; /* 4th channel is, actually, OPIPE */
+
+ struct dcss_hdr10_ipipe_tbls *ipipe_tbls;
+ struct dcss_hdr10_opipe_tbls *opipe_tbls;
+
+ u8 *fw_data;
+ u32 fw_size;
+};
+
+static void dcss_hdr10_write(struct dcss_hdr10_ch *ch, u32 val, u32 ofs)
+{
+ struct dcss_hdr10 *hdr10 = ch->hdr10;
+
+ dcss_ctxld_write(hdr10->ctxld, hdr10->ctx_id, val, ch->base_ofs + ofs);
+}
+
+static void dcss_hdr10_csc_fill(struct dcss_hdr10_ch *ch,
+ enum dcss_hdr10_csc csc_to_use,
+ u32 *map)
+{
+ int i;
+ u32 csc_base_ofs[] = {
+ DCSS_HDR10_CSCA_BASE + DCSS_HDR10_CSC_CONTROL,
+ DCSS_HDR10_CSCB_BASE + DCSS_HDR10_CSC_CONTROL,
+ };
+
+ for (i = 0; i < HDR10_CSC_MAX_REGS; i++) {
+ u32 reg_ofs = csc_base_ofs[csc_to_use] + i * sizeof(u32);
+
+ dcss_hdr10_write(ch, map[i], reg_ofs);
+ }
+}
+
+static void dcss_hdr10_lut_fill(struct dcss_hdr10_ch *ch, u32 *map)
+{
+ int i, comp;
+ u32 lut_base_ofs, ctrl_ofs, lut_entries;
+
+ if (ch->id == OPIPE_CH_NO) {
+ ctrl_ofs = DCSS_HDR10_LTNL;
+ lut_entries = HDR10_OPIPE_LUT_MAX_ENTRIES;
+ } else {
+ ctrl_ofs = DCSS_HDR10_LUT_CONTROL;
+ lut_entries = HDR10_IPIPE_LUT_MAX_ENTRIES;
+ }
+
+ if (ch->id != OPIPE_CH_NO)
+ dcss_hdr10_write(ch, *map++, ctrl_ofs);
+
+ for (comp = 0; comp < 3; comp++) {
+ lut_base_ofs = DCSS_HDR10_A0_LUT + comp * 0x1000;
+
+ if (ch->id == OPIPE_CH_NO) {
+ dcss_hdr10_write(ch, map[0], lut_base_ofs);
+ lut_base_ofs += 4;
+ }
+
+ for (i = 0; i < lut_entries; i++) {
+ u32 reg_ofs = lut_base_ofs + i * sizeof(u32);
+
+ dcss_hdr10_write(ch, map[i], reg_ofs);
+ }
+ }
+
+ map += lut_entries;
+
+ if (ch->id != OPIPE_CH_NO)
+ dcss_hdr10_write(ch, *map, DCSS_HDR10_FL2FX);
+ else
+ dcss_hdr10_write(ch, *map, ctrl_ofs);
+}
+
+static int dcss_hdr10_ch_init_all(struct dcss_hdr10 *hdr10,
+ unsigned long hdr10_base)
+{
+ struct dcss_hdr10_ch *ch;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ ch = &hdr10->ch[i];
+
+ ch->base_ofs = hdr10_base + i * 0x4000;
+
+ ch->base_reg = devm_ioremap(hdr10->dev, ch->base_ofs, SZ_16K);
+ if (!ch->base_reg) {
+ dev_err(hdr10->dev, "hdr10: unable to remap ch base\n");
+ return -ENOMEM;
+ }
+
+ ch->old_cfg_desc = HDR10_DESC_INVALID;
+
+ ch->id = i;
+ ch->hdr10 = hdr10;
+ }
+
+ return 0;
+}
+
+static u32 *dcss_hdr10_find_tbl(u64 desc, struct list_head *head)
+{
+ struct list_head *node;
+ struct dcss_hdr10_tbl_node *tbl_node;
+
+ list_for_each(node, head) {
+ tbl_node = container_of(node, struct dcss_hdr10_tbl_node, node);
+
+ if ((tbl_node->tbl_descriptor & desc) == desc)
+ return tbl_node->tbl_data;
+ }
+
+ return NULL;
+}
+
+static int dcss_hdr10_get_tbls(struct dcss_hdr10 *hdr10, bool input,
+ u64 desc, u32 **lut, u32 **csca, u32 **cscb)
+{
+ struct list_head *lut_list, *csca_list, *cscb_list;
+
+ lut_list = input ? &hdr10->ipipe_tbls->lut : &hdr10->opipe_tbls->lut;
+ csca_list = input ? &hdr10->ipipe_tbls->csca : &hdr10->opipe_tbls->csc;
+ cscb_list = input ? &hdr10->ipipe_tbls->cscb : NULL;
+
+ *lut = dcss_hdr10_find_tbl(desc, lut_list);
+ *csca = dcss_hdr10_find_tbl(desc, csca_list);
+
+ *cscb = NULL;
+ if (cscb_list)
+ *cscb = dcss_hdr10_find_tbl(desc, cscb_list);
+
+ return 0;
+}
+
+static void dcss_hdr10_write_pipe_tbls(struct dcss_hdr10_ch *ch,
+ u32 *lut, u32 *csca, u32 *cscb)
+{
+ if (csca)
+ dcss_hdr10_csc_fill(ch, HDR10_CSCA, csca);
+
+ if (ch->id != OPIPE_CH_NO && cscb)
+ dcss_hdr10_csc_fill(ch, HDR10_CSCB, cscb);
+
+ if (lut)
+ dcss_hdr10_lut_fill(ch, lut);
+}
+
+static int dcss_hdr10_tbl_add(struct dcss_hdr10 *hdr10, u64 desc, u32 sz,
+ u32 *data)
+{
+ struct device *dev = hdr10->dev;
+ struct dcss_hdr10_tbl_node *node;
+
+ node = devm_kzalloc(dev, sizeof(*node), GFP_KERNEL);
+ if (!node)
+ return -ENOMEM;
+
+ /* we don't need to store the table type and pipe type */
+ node->tbl_descriptor = desc >> 4;
+ node->tbl_data = data;
+
+ if (!(desc & HDR10_PT_OUTPUT)) {
+ if (desc & HDR10_TT_LUT)
+ list_add(&node->node, &hdr10->ipipe_tbls->lut);
+ else if (desc & HDR10_TT_CSCA)
+ list_add(&node->node, &hdr10->ipipe_tbls->csca);
+ else if (desc & HDR10_TT_CSCB)
+ list_add(&node->node, &hdr10->ipipe_tbls->cscb);
+
+ return 0;
+ }
+
+ if (desc & HDR10_TT_LUT)
+ list_add(&node->node, &hdr10->opipe_tbls->lut);
+ else if (desc & HDR10_TT_CSCA)
+ list_add(&node->node, &hdr10->opipe_tbls->csc);
+
+ return 0;
+}
+
+static int dcss_hdr10_parse_fw_data(struct dcss_hdr10 *hdr10)
+{
+ u32 *data = (u32 *)hdr10->fw_data;
+ u32 remaining = hdr10->fw_size / sizeof(u32);
+ u64 tbl_desc;
+ u32 tbl_size;
+ int ret;
+
+ while (remaining) {
+ tbl_desc = *((u64 *)data);
+ data += 2;
+ tbl_size = *data++;
+
+ ret = dcss_hdr10_tbl_add(hdr10, tbl_desc, tbl_size, data);
+ if (ret)
+ return ret;
+
+ data += tbl_size;
+ remaining -= tbl_size + 3;
+ }
+
+ return 0;
+}
+
+static void dcss_hdr10_cleanup_tbls(struct dcss_hdr10 *hdr10)
+{
+ int i;
+ struct dcss_hdr10_tbl_node *tbl_node, *next;
+ struct list_head *tbls[] = {
+ &hdr10->ipipe_tbls->lut,
+ &hdr10->ipipe_tbls->csca,
+ &hdr10->ipipe_tbls->cscb,
+ &hdr10->opipe_tbls->lut,
+ &hdr10->opipe_tbls->csc,
+ };
+
+ for (i = 0; i < 5; i++) {
+ list_for_each_entry_safe(tbl_node, next, tbls[i], node) {
+ list_del(&tbl_node->node);
+ devm_kfree(hdr10->dev, tbl_node);
+ }
+ }
+
+ devm_kfree(hdr10->dev, hdr10->opipe_tbls);
+ devm_kfree(hdr10->dev, hdr10->ipipe_tbls);
+}
+
+#ifndef USE_TBL_HEADER
+static void dcss_hdr10_fw_handler(const struct firmware *fw, void *context)
+{
+ struct dcss_hdr10 *hdr10 = context;
+ int i;
+
+ if (!fw) {
+ dev_err(hdr10->dev, "hdr10: DCSS FW load failed.\n");
+ return;
+ }
+
+ /* we need to keep the tables for the entire life of the driver */
+ hdr10->fw_data = devm_kzalloc(hdr10->dev, fw->size, GFP_KERNEL);
+ if (!hdr10->fw_data)
+ return;
+
+ memcpy(hdr10->fw_data, fw->data, fw->size);
+ hdr10->fw_size = fw->size;
+
+ release_firmware(fw);
+
+ if (dcss_hdr10_parse_fw_data(hdr10)) {
+ dcss_hdr10_cleanup_tbls(hdr10);
+ return;
+ }
+
+ for (i = 0; i < 4; i++) {
+ u32 *lut, *csca, *cscb;
+ struct dcss_hdr10_ch *ch = &hdr10->ch[i];
+ bool is_input_pipe = i != OPIPE_CH_NO ? true : false;
+
+ if (ch->old_cfg_desc != HDR10_DESC_INVALID) {
+ dcss_hdr10_get_tbls(hdr10, is_input_pipe,
+ ch->old_cfg_desc, &lut,
+ &csca, &cscb);
+ dcss_hdr10_write_pipe_tbls(ch, lut, csca, cscb);
+ }
+ }
+
+ dev_info(hdr10->dev, "hdr10: DCSS FW loaded successfully\n");
+}
+#endif
+
+static int dcss_hdr10_tbls_init(struct dcss_hdr10 *hdr10)
+{
+ struct device *dev = hdr10->dev;
+
+ hdr10->ipipe_tbls = devm_kzalloc(dev, sizeof(*hdr10->ipipe_tbls),
+ GFP_KERNEL);
+ if (!hdr10->ipipe_tbls)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&hdr10->ipipe_tbls->lut);
+ INIT_LIST_HEAD(&hdr10->ipipe_tbls->csca);
+ INIT_LIST_HEAD(&hdr10->ipipe_tbls->cscb);
+
+ hdr10->opipe_tbls = devm_kzalloc(dev, sizeof(*hdr10->opipe_tbls),
+ GFP_KERNEL);
+ if (!hdr10->opipe_tbls) {
+ devm_kfree(dev, hdr10->ipipe_tbls);
+ return -ENOMEM;
+ }
+
+ INIT_LIST_HEAD(&hdr10->opipe_tbls->lut);
+ INIT_LIST_HEAD(&hdr10->opipe_tbls->csc);
+
+ return 0;
+}
+
+int dcss_hdr10_init(struct dcss_dev *dcss, unsigned long hdr10_base)
+{
+ int ret;
+ struct dcss_hdr10 *hdr10;
+
+ hdr10 = devm_kzalloc(dcss->dev, sizeof(*hdr10), GFP_KERNEL);
+ if (!hdr10)
+ return -ENOMEM;
+
+ dcss->hdr10 = hdr10;
+ hdr10->dev = dcss->dev;
+ hdr10->ctx_id = CTX_SB_HP;
+ hdr10->ctxld = dcss->ctxld;
+
+ ret = dcss_hdr10_tbls_init(hdr10);
+ if (ret < 0) {
+ dev_err(dcss->dev, "hdr10: Cannot init table lists.\n");
+ goto cleanup;
+ }
+
+#ifndef USE_TBL_HEADER
+ ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, "dcss.fw",
+ dcss->dev, GFP_KERNEL, hdr10,
+ dcss_hdr10_fw_handler);
+ if (ret < 0) {
+ dev_err(dcss->dev, "hdr10: Cannot async load DCSS FW.\n");
+ goto cleanup_tbls;
+ }
+#else
+ hdr10->fw_data = (u8 *)dcss_hdr10_tables;
+ hdr10->fw_size = sizeof(dcss_hdr10_tables);
+
+ ret = dcss_hdr10_parse_fw_data(hdr10);
+ if (ret)
+ goto cleanup_tbls;
+#endif
+
+ ret = dcss_hdr10_ch_init_all(hdr10, hdr10_base);
+ if (ret) {
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ if (hdr10->ch[i].base_reg)
+ devm_iounmap(hdr10->dev, hdr10->ch[i].base_reg);
+ }
+
+ goto cleanup_tbls;
+ }
+
+ return 0;
+
+cleanup_tbls:
+ dcss_hdr10_cleanup_tbls(hdr10);
+
+cleanup:
+ devm_kfree(hdr10->dev, hdr10);
+
+ return ret;
+}
+
+void dcss_hdr10_exit(struct dcss_hdr10 *hdr10)
+{
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ if (hdr10->ch[i].base_reg)
+ devm_iounmap(hdr10->dev, hdr10->ch[i].base_reg);
+ }
+
+ dcss_hdr10_cleanup_tbls(hdr10);
+
+ devm_kfree(hdr10->dev, hdr10);
+}
+
+static u32 dcss_hdr10_pipe_desc(struct dcss_hdr10_pipe_cfg *pipe_cfg)
+{
+ u32 desc;
+
+ desc = 2 << HDR10_BPC_POS;
+ desc |= pipe_cfg->is_yuv ? 2 << HDR10_CS_POS : 1 << HDR10_CS_POS;
+ desc |= ((1 << pipe_cfg->nl) << HDR10_NL_POS) & HDR10_NL_MASK;
+ desc |= ((1 << pipe_cfg->pr) << HDR10_PR_POS) & HDR10_PR_MASK;
+ desc |= ((1 << pipe_cfg->g) << HDR10_G_POS) & HDR10_G_MASK;
+
+ return desc;
+}
+
+static u64 dcss_hdr10_get_desc(struct dcss_hdr10_pipe_cfg *ipipe_cfg,
+ struct dcss_hdr10_pipe_cfg *opipe_cfg)
+{
+ u32 ipipe_desc, opipe_desc;
+
+ ipipe_desc = dcss_hdr10_pipe_desc(ipipe_cfg);
+ opipe_desc = dcss_hdr10_pipe_desc(opipe_cfg);
+
+ return (ipipe_desc & 0xFFFF) | ((opipe_desc & 0xFFFF) << 16);
+}
+
+static void dcss_hdr10_pipe_setup(struct dcss_hdr10_ch *ch, u64 desc)
+{
+ bool pipe_cfg_chgd;
+ u32 *csca, *cscb, *lut;
+
+ pipe_cfg_chgd = ch->old_cfg_desc != desc;
+
+ if (!pipe_cfg_chgd)
+ return;
+
+ dcss_hdr10_get_tbls(ch->hdr10, ch->id != OPIPE_CH_NO,
+ desc, &lut, &csca, &cscb);
+ dcss_hdr10_write_pipe_tbls(ch, lut, csca, cscb);
+
+ ch->old_cfg_desc = desc;
+}
+
+void dcss_hdr10_setup(struct dcss_hdr10 *hdr10, int ch_num,
+ struct dcss_hdr10_pipe_cfg *ipipe_cfg,
+ struct dcss_hdr10_pipe_cfg *opipe_cfg)
+{
+ u64 desc = dcss_hdr10_get_desc(ipipe_cfg, opipe_cfg);
+
+ dcss_hdr10_pipe_setup(&hdr10->ch[ch_num], desc);
+
+ /*
+ * Input pipe configuration doesn't matter for configuring the output
+ * pipe. So, will just mask off the input part of the descriptor.
+ */
+ dcss_hdr10_pipe_setup(&hdr10->ch[OPIPE_CH_NO], desc & ~0xffff);
+}
diff --git a/drivers/gpu/drm/imx/dcss/dcss-kms.c b/drivers/gpu/drm/imx/dcss/dcss-kms.c
new file mode 100644
index 000000000000..6e5c5ad13304
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/dcss-kms.c
@@ -0,0 +1,429 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drmP.h>
+#include <linux/component.h>
+
+#include "dcss-dev.h"
+#include "dcss-kms.h"
+
+DEFINE_DRM_GEM_CMA_FOPS(dcss_cma_fops);
+
+struct dcss_drm_commit {
+ struct work_struct work;
+ struct drm_device *drm;
+ struct drm_atomic_state *state;
+};
+
+static void dcss_kms_setup_opipe_gamut(u32 colorspace,
+ const struct drm_display_mode *mode,
+ enum dcss_hdr10_gamut *g,
+ enum dcss_hdr10_nonlinearity *nl)
+{
+ u8 vic;
+
+ switch (colorspace) {
+ case DRM_MODE_COLORIMETRY_BT709_YCC:
+ case DRM_MODE_COLORIMETRY_XVYCC_709:
+ *g = G_REC709;
+ *nl = NL_REC709;
+ return;
+ case DRM_MODE_COLORIMETRY_SMPTE_170M_YCC:
+ case DRM_MODE_COLORIMETRY_XVYCC_601:
+ case DRM_MODE_COLORIMETRY_SYCC_601:
+ case DRM_MODE_COLORIMETRY_OPYCC_601:
+ *g = G_REC601_NTSC;
+ *nl = NL_REC709;
+ return;
+ case DRM_MODE_COLORIMETRY_BT2020_CYCC:
+ case DRM_MODE_COLORIMETRY_BT2020_RGB:
+ case DRM_MODE_COLORIMETRY_BT2020_YCC:
+ *g = G_REC2020;
+ *nl = NL_REC2084;
+ return;
+ case DRM_MODE_COLORIMETRY_OPRGB:
+ *g = G_ADOBE_ARGB;
+ *nl = NL_SRGB;
+ return;
+ default:
+ break;
+ }
+
+ /*
+ * If we reached this point, it means the default colorimetry is used.
+ */
+
+ /* non-CEA mode, sRGB is used */
+ vic = drm_match_cea_mode(mode);
+ if (vic == 0) {
+ *g = G_ADOBE_ARGB;
+ *nl = NL_SRGB;
+ return;
+ }
+
+ if (mode->vdisplay == 480 || mode->vdisplay == 576 ||
+ mode->vdisplay == 240 || mode->vdisplay == 288) {
+ *g = G_REC601_NTSC;
+ *nl = NL_REC709;
+ return;
+ }
+
+ /* 2160p, 1080p, 720p */
+ *g = G_REC709;
+ *nl = NL_REC709;
+}
+
+#define YUV_MODE BIT(0)
+
+void dcss_kms_setup_opipe(struct drm_connector_state *conn_state)
+{
+ struct drm_crtc *crtc = conn_state->crtc;
+ struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
+ base);
+ int mode_flags = crtc->state->adjusted_mode.private_flags;
+ enum hdmi_quantization_range qr;
+
+ qr = drm_default_rgb_quant_range(&crtc->state->adjusted_mode);
+
+ dcss_kms_setup_opipe_gamut(conn_state->colorspace,
+ &crtc->state->adjusted_mode,
+ &dcss_crtc->opipe_g,
+ &dcss_crtc->opipe_nl);
+
+ dcss_crtc->opipe_pr = qr == HDMI_QUANTIZATION_RANGE_FULL ? PR_FULL :
+ PR_LIMITED;
+
+ dcss_crtc->output_is_yuv = !!(mode_flags & YUV_MODE);
+}
+
+static void dcss_kms_setup_output_pipe(struct drm_atomic_state *state)
+{
+ struct drm_crtc *crtc;
+ struct drm_connector *connector;
+ struct drm_connector_state *conn_state;
+ struct drm_display_info *di;
+ int i;
+
+ for_each_new_connector_in_state(state, connector, conn_state, i) {
+ if (!conn_state->best_encoder)
+ continue;
+
+ if (!conn_state->crtc->state->active ||
+ !drm_atomic_crtc_needs_modeset(conn_state->crtc->state))
+ continue;
+
+ crtc = connector->state->crtc;
+ di = &connector->display_info;
+
+ dcss_kms_setup_opipe(conn_state);
+ }
+}
+
+static void dcss_drm_atomic_commit_tail(struct dcss_drm_commit *commit)
+{
+ struct drm_atomic_state *state = commit->state;
+ struct drm_device *drm = commit->drm;
+ struct dcss_kms_dev *kms = container_of(drm, struct dcss_kms_dev, base);
+
+ drm_atomic_helper_wait_for_fences(drm, state, false);
+
+ drm_atomic_helper_wait_for_dependencies(state);
+
+ drm_atomic_helper_commit_modeset_disables(drm, state);
+
+ dcss_kms_setup_output_pipe(state);
+
+ drm_atomic_helper_commit_modeset_enables(drm, state);
+
+ drm_atomic_helper_commit_planes(drm, state,
+ DRM_PLANE_COMMIT_ACTIVE_ONLY);
+
+ drm_atomic_helper_commit_hw_done(state);
+
+ drm_atomic_helper_wait_for_vblanks(drm, state);
+
+ drm_atomic_helper_cleanup_planes(drm, state);
+
+ drm_atomic_helper_commit_cleanup_done(state);
+
+ drm_atomic_state_put(state);
+
+ spin_lock(&kms->commit.wait.lock);
+ kms->commit.pending = false;
+ wake_up_all_locked(&kms->commit.wait);
+ spin_unlock(&kms->commit.wait.lock);
+
+ kfree(commit);
+}
+
+static void dcss_commit_work(struct work_struct *work)
+{
+ struct dcss_drm_commit *commit = container_of(work,
+ struct dcss_drm_commit,
+ work);
+
+ dcss_drm_atomic_commit_tail(commit);
+}
+
+static int dcss_drm_atomic_commit(struct drm_device *drm,
+ struct drm_atomic_state *state,
+ bool nonblock)
+{
+ int ret;
+ struct dcss_kms_dev *kms = container_of(drm, struct dcss_kms_dev, base);
+ struct dcss_drm_commit *commit;
+
+ if (state->async_update) {
+ ret = drm_atomic_helper_prepare_planes(drm, state);
+ if (ret)
+ return ret;
+
+ drm_atomic_helper_async_commit(drm, state);
+ drm_atomic_helper_cleanup_planes(drm, state);
+
+ return 0;
+ }
+
+ commit = kzalloc(sizeof(*commit), GFP_KERNEL);
+ if (!commit)
+ return -ENOMEM;
+
+ commit->drm = drm;
+ commit->state = state;
+
+ ret = drm_atomic_helper_setup_commit(state, nonblock);
+ if (ret)
+ goto err_free;
+
+ INIT_WORK(&commit->work, dcss_commit_work);
+
+ ret = drm_atomic_helper_prepare_planes(drm, state);
+ if (ret)
+ goto err_free;
+
+ if (!nonblock) {
+ ret = drm_atomic_helper_wait_for_fences(drm, state, true);
+ if (ret)
+ goto err;
+ }
+
+ spin_lock(&kms->commit.wait.lock);
+ ret = wait_event_interruptible_locked(kms->commit.wait,
+ !kms->commit.pending);
+ if (ret == 0)
+ kms->commit.pending = true;
+ spin_unlock(&kms->commit.wait.lock);
+
+ if (ret)
+ goto err;
+
+ ret = drm_atomic_helper_swap_state(state, true);
+ if (ret)
+ goto err;
+
+ drm_atomic_state_get(state);
+ if (nonblock)
+ queue_work(kms->commit_wq, &commit->work);
+ else
+ dcss_drm_atomic_commit_tail(commit);
+
+ return 0;
+
+err:
+ drm_atomic_helper_cleanup_planes(drm, state);
+
+err_free:
+ kfree(commit);
+ return ret;
+}
+
+const struct drm_mode_config_funcs dcss_drm_mode_config_funcs = {
+ .fb_create = drm_gem_fb_create,
+ .output_poll_changed = drm_fb_helper_output_poll_changed,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = dcss_drm_atomic_commit,
+};
+
+static struct drm_driver dcss_kms_driver = {
+ .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
+ .gem_free_object_unlocked = drm_gem_cma_free_object,
+ .gem_vm_ops = &drm_gem_cma_vm_ops,
+ .dumb_create = drm_gem_cma_dumb_create,
+
+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+ .gem_prime_import = drm_gem_prime_import,
+ .gem_prime_export = drm_gem_prime_export,
+ .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
+ .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
+ .gem_prime_vmap = drm_gem_cma_prime_vmap,
+ .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
+ .gem_prime_mmap = drm_gem_cma_prime_mmap,
+ .fops = &dcss_cma_fops,
+ .name = "imx-dcss",
+ .desc = "i.MX8MQ Display Subsystem",
+ .date = "20190917",
+ .major = 1,
+ .minor = 0,
+ .patchlevel = 0,
+};
+
+static const struct drm_mode_config_helper_funcs dcss_mode_config_helpers = {
+ .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
+};
+
+static void dcss_kms_mode_config_init(struct dcss_kms_dev *kms)
+{
+ struct drm_mode_config *config = &kms->base.mode_config;
+
+ drm_mode_config_init(&kms->base);
+
+ config->min_width = 1;
+ config->min_height = 1;
+ config->max_width = 4096;
+ config->max_height = 4096;
+ config->allow_fb_modifiers = true;
+ config->normalize_zpos = true;
+
+ config->funcs = &dcss_drm_mode_config_funcs;
+ config->helper_private = &dcss_mode_config_helpers;
+}
+
+static const struct drm_encoder_funcs dcss_kms_simple_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+static int dcss_kms_setup_encoder(struct dcss_kms_dev *kms)
+{
+ struct drm_device *ddev = &kms->base;
+ struct drm_encoder *encoder = &kms->encoder;
+ struct drm_crtc *crtc = (struct drm_crtc *)&kms->crtc;
+ struct drm_panel *panel;
+ struct drm_bridge *bridge;
+ int ret;
+
+ ret = drm_of_find_panel_or_bridge(ddev->dev->of_node, 0, 0,
+ &panel, &bridge);
+ if (ret)
+ return ret;
+
+ if (!bridge) {
+ dev_err(ddev->dev, "No bridge found %d.\n", ret);
+ return -ENODEV;
+ }
+
+ encoder->possible_crtcs = drm_crtc_mask(crtc);
+
+ ret = drm_encoder_init(&kms->base, encoder,
+ &dcss_kms_simple_encoder_funcs,
+ DRM_MODE_ENCODER_NONE, NULL);
+ if (ret) {
+ dev_err(ddev->dev, "Failed initializing encoder %d.\n", ret);
+ return ret;
+ }
+
+ return drm_bridge_attach(encoder, bridge, NULL);
+}
+
+struct dcss_kms_dev *dcss_kms_attach(struct dcss_dev *dcss, bool componentized)
+{
+ struct dcss_kms_dev *kms = kzalloc(sizeof(*kms), GFP_KERNEL);
+ struct drm_device *drm;
+ struct dcss_crtc *crtc;
+ int ret;
+
+ if (!kms)
+ return ERR_PTR(-ENOMEM);
+
+ drm = &kms->base;
+ crtc = &kms->crtc;
+ ret = drm_dev_init(drm, &dcss_kms_driver, dcss->dev);
+ if (ret)
+ goto free_kms;
+
+ drm->dev_private = dcss;
+
+ dcss_kms_mode_config_init(kms);
+
+ ret = drm_vblank_init(drm, 1);
+ if (ret)
+ goto cleanup_mode_config;
+
+ drm->irq_enabled = true;
+
+ ret = dcss_crtc_init(crtc, drm);
+ if (ret)
+ goto cleanup_mode_config;
+
+ kms->commit_wq = alloc_ordered_workqueue("dcss_nonblock_commit_wq", 0);
+ if (!kms->commit_wq) {
+ ret = -ENOMEM;
+ goto cleanup_crtc;
+ }
+
+ init_waitqueue_head(&kms->commit.wait);
+
+ if (componentized)
+ ret = component_bind_all(dcss->dev, kms);
+ else
+ ret = dcss_kms_setup_encoder(kms);
+
+ if (ret)
+ goto cleanup_wq;
+
+ drm_mode_config_reset(drm);
+
+ dcss_crtc_attach_color_mgmt_properties(crtc);
+
+ drm_kms_helper_poll_init(drm);
+
+ ret = drm_dev_register(drm, 0);
+ if (ret)
+ goto cleanup_wq;
+
+ drm_fbdev_generic_setup(drm, 32);
+
+ return kms;
+
+cleanup_wq:
+ drm_kms_helper_poll_fini(drm);
+ destroy_workqueue(kms->commit_wq);
+
+cleanup_crtc:
+ dcss_crtc_deinit(crtc, drm);
+
+cleanup_mode_config:
+ drm_mode_config_cleanup(drm);
+
+free_kms:
+ kfree(kms);
+ return ERR_PTR(ret);
+}
+
+void dcss_kms_detach(struct dcss_kms_dev *kms, bool componentized)
+{
+ struct drm_device *drm = &kms->base;
+ struct dcss_dev *dcss = drm->dev_private;
+
+ drm_dev_unregister(drm);
+ drm_kms_helper_poll_fini(drm);
+ drm_atomic_helper_shutdown(drm);
+ drm_crtc_vblank_off(&kms->crtc.base);
+ drm->irq_enabled = false;
+ drm_mode_config_cleanup(drm);
+ destroy_workqueue(kms->commit_wq);
+ dcss_crtc_deinit(&kms->crtc, drm);
+ if (componentized)
+ component_unbind_all(dcss->dev, drm);
+ drm->dev_private = NULL;
+ drm_dev_put(drm);
+}
diff --git a/drivers/gpu/drm/imx/dcss/dcss-kms.h b/drivers/gpu/drm/imx/dcss/dcss-kms.h
new file mode 100644
index 000000000000..0c4c49ce2e99
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/dcss-kms.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2019 NXP.
+ */
+
+#ifndef _DCSS_KMS_H_
+#define _DCSS_KMS_H_
+
+#include <drm/drm_encoder.h>
+
+struct dcss_plane {
+ struct drm_plane base;
+
+ uint64_t dtrc_table_ofs_val;
+ struct drm_property *dtrc_table_ofs_prop;
+
+ int ch_num;
+
+ enum drm_plane_type type;
+ bool use_dtrc;
+};
+
+struct dcss_crtc {
+ struct drm_crtc base;
+ struct drm_crtc_state *state;
+
+ struct dcss_plane *plane[3];
+
+ int irq;
+ bool irq_enabled;
+
+ struct completion en_completion;
+ struct completion dis_completion;
+
+ bool output_is_yuv;
+ enum dcss_hdr10_nonlinearity opipe_nl;
+ enum dcss_hdr10_gamut opipe_g;
+ enum dcss_hdr10_pixel_range opipe_pr;
+};
+
+struct commit {
+ wait_queue_head_t wait;
+ bool pending;
+};
+
+struct dcss_kms_dev {
+ struct drm_device base;
+ struct dcss_crtc crtc;
+ struct drm_encoder encoder;
+ struct workqueue_struct *commit_wq;
+ struct commit commit;
+};
+
+struct dcss_kms_dev *dcss_kms_attach(struct dcss_dev *dcss, bool componentized);
+void dcss_kms_detach(struct dcss_kms_dev *kms, bool componentized);
+int dcss_crtc_init(struct dcss_crtc *crtc, struct drm_device *drm);
+void dcss_crtc_deinit(struct dcss_crtc *crtc, struct drm_device *drm);
+struct dcss_plane *dcss_plane_init(struct drm_device *drm,
+ unsigned int possible_crtcs,
+ enum drm_plane_type type,
+ unsigned int zpos);
+void dcss_crtc_attach_color_mgmt_properties(struct dcss_crtc *crtc);
+
+#endif
diff --git a/drivers/gpu/drm/imx/dcss/dcss-plane.c b/drivers/gpu/drm/imx/dcss/dcss-plane.c
new file mode 100644
index 000000000000..80e8f91c1d0c
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/dcss-plane.c
@@ -0,0 +1,673 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <linux/dma-buf.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+
+#include "dcss-dev.h"
+#include "dcss-kms.h"
+
+static const u32 dcss_graphics_formats[] = {
+ /* RGB */
+ DRM_FORMAT_ARGB8888,
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_ABGR8888,
+ DRM_FORMAT_XBGR8888,
+ DRM_FORMAT_RGBA8888,
+ DRM_FORMAT_RGBX8888,
+ DRM_FORMAT_BGRA8888,
+ DRM_FORMAT_BGRX8888,
+ DRM_FORMAT_XRGB2101010,
+ DRM_FORMAT_XBGR2101010,
+ DRM_FORMAT_RGBX1010102,
+ DRM_FORMAT_BGRX1010102,
+ DRM_FORMAT_ARGB2101010,
+ DRM_FORMAT_ABGR2101010,
+ DRM_FORMAT_RGBA1010102,
+ DRM_FORMAT_BGRA1010102,
+};
+
+static const u32 dcss_video_formats[] = {
+ /* YUV444 */
+ DRM_FORMAT_AYUV,
+
+ /* YUV422 */
+ DRM_FORMAT_UYVY,
+ DRM_FORMAT_VYUY,
+ DRM_FORMAT_YUYV,
+ DRM_FORMAT_YVYU,
+
+ /* YUV420 */
+ DRM_FORMAT_NV12,
+ DRM_FORMAT_NV21,
+ DRM_FORMAT_NV12_10LE40,
+};
+
+static const u64 dcss_video_format_modifiers[] = {
+ DRM_FORMAT_MOD_VSI_G1_TILED,
+ DRM_FORMAT_MOD_VSI_G2_TILED,
+ DRM_FORMAT_MOD_VSI_G2_TILED_COMPRESSED,
+ DRM_FORMAT_MOD_LINEAR,
+ DRM_FORMAT_MOD_INVALID,
+};
+
+static const u64 dcss_graphics_format_modifiers[] = {
+ DRM_FORMAT_MOD_VIVANTE_TILED,
+ DRM_FORMAT_MOD_VIVANTE_SUPER_TILED,
+ DRM_FORMAT_MOD_VIVANTE_SUPER_TILED_FC,
+ DRM_FORMAT_MOD_LINEAR,
+ DRM_FORMAT_MOD_INVALID,
+};
+
+static inline struct dcss_plane *to_dcss_plane(struct drm_plane *p)
+{
+ return container_of(p, struct dcss_plane, base);
+}
+
+static inline bool dcss_plane_fb_is_linear(const struct drm_framebuffer *fb)
+{
+ return ((fb->flags & DRM_MODE_FB_MODIFIERS) == 0) ||
+ ((fb->flags & DRM_MODE_FB_MODIFIERS) != 0 &&
+ fb->modifier == DRM_FORMAT_MOD_LINEAR);
+}
+
+static void dcss_plane_destroy(struct drm_plane *plane)
+{
+ struct dcss_plane *dcss_plane = container_of(plane, struct dcss_plane,
+ base);
+
+ drm_plane_cleanup(plane);
+ kfree(dcss_plane);
+}
+
+static int dcss_plane_atomic_set_property(struct drm_plane *plane,
+ struct drm_plane_state *state,
+ struct drm_property *property,
+ uint64_t val)
+{
+ struct dcss_plane *dcss_plane = to_dcss_plane(plane);
+
+ if (property == dcss_plane->dtrc_table_ofs_prop)
+ dcss_plane->dtrc_table_ofs_val = val;
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+static int dcss_plane_atomic_get_property(struct drm_plane *plane,
+ const struct drm_plane_state *state,
+ struct drm_property *property,
+ uint64_t *val)
+{
+ struct dcss_plane *dcss_plane = to_dcss_plane(plane);
+
+ if (property == dcss_plane->dtrc_table_ofs_prop)
+ *val = dcss_plane->dtrc_table_ofs_val;
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+static bool dcss_plane_format_mod_supported(struct drm_plane *plane,
+ u32 format,
+ u64 modifier)
+{
+ switch (plane->type) {
+ case DRM_PLANE_TYPE_PRIMARY:
+ switch (format) {
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_ARGB2101010:
+ return modifier == DRM_FORMAT_MOD_LINEAR ||
+ modifier == DRM_FORMAT_MOD_VIVANTE_TILED ||
+ modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED ||
+ modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED_FC;
+ default:
+ return modifier == DRM_FORMAT_MOD_LINEAR;
+ }
+ break;
+ case DRM_PLANE_TYPE_OVERLAY:
+ switch (format) {
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV21:
+ case DRM_FORMAT_NV12_10LE40:
+ return modifier == DRM_FORMAT_MOD_LINEAR ||
+ modifier == DRM_FORMAT_MOD_VSI_G1_TILED ||
+ modifier == DRM_FORMAT_MOD_VSI_G2_TILED ||
+ modifier == DRM_FORMAT_MOD_VSI_G2_TILED_COMPRESSED;
+ default:
+ return modifier == DRM_FORMAT_MOD_LINEAR;
+ }
+ break;
+ default:
+ return false;
+ }
+
+ return false;
+}
+
+static const struct drm_plane_funcs dcss_plane_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .destroy = dcss_plane_destroy,
+ .reset = drm_atomic_helper_plane_reset,
+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+ .atomic_set_property = dcss_plane_atomic_set_property,
+ .atomic_get_property = dcss_plane_atomic_get_property,
+ .format_mod_supported = dcss_plane_format_mod_supported,
+};
+
+static bool dcss_plane_can_rotate(const struct drm_format_info *format,
+ bool mod_present, u64 modifier,
+ unsigned int rotation)
+{
+ bool linear_format = !mod_present ||
+ (mod_present && modifier == DRM_FORMAT_MOD_LINEAR);
+ u32 supported_rotation = DRM_MODE_ROTATE_0;
+
+ if (!format->is_yuv && linear_format)
+ supported_rotation = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
+ DRM_MODE_REFLECT_MASK;
+ else if (!format->is_yuv &&
+ modifier == DRM_FORMAT_MOD_VIVANTE_TILED)
+ supported_rotation = DRM_MODE_ROTATE_MASK |
+ DRM_MODE_REFLECT_MASK;
+ else if (format->is_yuv && linear_format &&
+ (format->format == DRM_FORMAT_NV12 ||
+ format->format == DRM_FORMAT_NV21))
+ supported_rotation = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
+ DRM_MODE_REFLECT_MASK;
+ else if (format->is_yuv && linear_format &&
+ format->format == DRM_FORMAT_NV12_10LE40)
+ supported_rotation = DRM_MODE_ROTATE_0 | DRM_MODE_REFLECT_Y;
+
+ return !!(rotation & supported_rotation);
+}
+
+static bool dcss_plane_is_source_size_allowed(u16 src_w, u16 src_h, u32 pix_fmt)
+{
+ if (src_w < 64 &&
+ (pix_fmt == DRM_FORMAT_NV12 || pix_fmt == DRM_FORMAT_NV21 ||
+ pix_fmt == DRM_FORMAT_NV12_10LE40))
+ return false;
+ else if (src_w < 32 &&
+ (pix_fmt == DRM_FORMAT_UYVY || pix_fmt == DRM_FORMAT_VYUY ||
+ pix_fmt == DRM_FORMAT_YUYV || pix_fmt == DRM_FORMAT_YVYU))
+ return false;
+
+ return src_w >= 16 && src_h >= 8;
+}
+
+static inline bool dcss_plane_use_dtrc(struct drm_framebuffer *fb,
+ enum drm_plane_type type)
+{
+ u64 pix_format = fb->format->format;
+
+ return !dcss_plane_fb_is_linear(fb) &&
+ type == DRM_PLANE_TYPE_OVERLAY &&
+ (pix_format == DRM_FORMAT_NV12 ||
+ pix_format == DRM_FORMAT_NV21 ||
+ pix_format == DRM_FORMAT_NV12_10LE40);
+}
+
+static int dcss_plane_atomic_check(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ struct dcss_plane *dcss_plane = to_dcss_plane(plane);
+ struct dcss_dev *dcss = plane->dev->dev_private;
+ struct drm_framebuffer *fb = state->fb;
+ bool is_primary_plane = plane->type == DRM_PLANE_TYPE_PRIMARY;
+ struct drm_gem_cma_object *cma_obj;
+ struct drm_crtc_state *crtc_state;
+ int hdisplay, vdisplay;
+ int min, max;
+ int ret;
+
+ if (!fb || !state->crtc)
+ return 0;
+
+ cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+ WARN_ON(!cma_obj);
+
+ crtc_state = drm_atomic_get_existing_crtc_state(state->state,
+ state->crtc);
+
+ hdisplay = crtc_state->adjusted_mode.hdisplay;
+ vdisplay = crtc_state->adjusted_mode.vdisplay;
+
+ if (!dcss_plane_is_source_size_allowed(state->src_w >> 16,
+ state->src_h >> 16,
+ fb->format->format)) {
+ DRM_DEBUG_KMS("Source plane size is not allowed!\n");
+ return -EINVAL;
+ }
+
+ dcss_scaler_get_min_max_ratios(dcss->scaler, dcss_plane->ch_num,
+ &min, &max);
+
+ ret = drm_atomic_helper_check_plane_state(state, crtc_state,
+ min, max, !is_primary_plane,
+ false);
+ if (ret)
+ return ret;
+
+ if (!state->visible)
+ return 0;
+
+ if (!dcss_plane_can_rotate(fb->format,
+ !!(fb->flags & DRM_MODE_FB_MODIFIERS),
+ fb->modifier,
+ state->rotation)) {
+ DRM_DEBUG_KMS("requested rotation is not allowed!\n");
+ return -EINVAL;
+ }
+
+ if ((fb->flags & DRM_MODE_FB_MODIFIERS) &&
+ !plane->funcs->format_mod_supported(plane,
+ fb->format->format,
+ fb->modifier)) {
+ DRM_DEBUG_KMS("Invalid modifier: %llx", fb->modifier);
+ return -EINVAL;
+ }
+
+ dcss_plane->use_dtrc = dcss_plane_use_dtrc(fb, plane->type);
+
+ return 0;
+}
+
+static struct drm_gem_object *dcss_plane_gem_import(struct drm_device *dev,
+ struct dma_buf *dma_buf)
+{
+ struct drm_gem_object *obj;
+
+ if (IS_ERR(dma_buf))
+ return ERR_CAST(dma_buf);
+
+ mutex_lock(&dev->object_name_lock);
+
+ obj = dev->driver->gem_prime_import(dev, dma_buf);
+
+ mutex_unlock(&dev->object_name_lock);
+
+ return obj;
+}
+
+static void dcss_plane_set_primary_base(struct dcss_plane *dcss_plane,
+ u32 baddr)
+{
+ struct drm_plane *plane = &dcss_plane->base;
+ struct dcss_dev *dcss = plane->dev->dev_private;
+ struct drm_plane_state *state = plane->state;
+ struct drm_framebuffer *fb = state->fb;
+ struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+ struct dma_buf *dma_buf = cma_obj->base.dma_buf;
+ struct drm_gem_object *gem_obj;
+ dma_addr_t caddr;
+ bool compressed = true;
+ u32 compressed_format = _VIV_CFMT_ARGB8;
+ _VIV_VIDMEM_METADATA *mdata;
+
+ if (dcss_plane_fb_is_linear(fb) ||
+ ((fb->flags & DRM_MODE_FB_MODIFIERS) &&
+ (fb->modifier == DRM_FORMAT_MOD_VIVANTE_TILED ||
+ fb->modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED))) {
+ dcss_dec400d_bypass(dcss->dec400d);
+ return;
+ }
+
+ if (!dma_buf) {
+ caddr = cma_obj->paddr + ALIGN(fb->height, 64) * fb->pitches[0];
+ } else {
+ mdata = dma_buf->priv;
+ if (!mdata || mdata->magic != VIV_VIDMEM_METADATA_MAGIC)
+ return;
+
+ gem_obj = dcss_plane_gem_import(plane->dev, mdata->ts_dma_buf);
+ if (IS_ERR(gem_obj))
+ return;
+
+ caddr = to_drm_gem_cma_obj(gem_obj)->paddr;
+
+ /* release gem_obj */
+ drm_gem_object_put_unlocked(gem_obj);
+
+ dcss_dec400d_fast_clear_config(dcss->dec400d, mdata->fc_value,
+ mdata->fc_enabled);
+
+ compressed = !!mdata->compressed;
+ compressed_format = mdata->compress_format;
+ }
+
+ dcss_dec400d_read_config(dcss->dec400d, 0, compressed,
+ compressed_format);
+ dcss_dec400d_addr_set(dcss->dec400d, baddr, caddr);
+}
+
+static void dcss_plane_set_dtrc_base(struct dcss_plane *dcss_plane,
+ u32 p1_ba, u32 p2_ba)
+{
+ struct drm_plane *plane = &dcss_plane->base;
+ struct dcss_dev *dcss = plane->dev->dev_private;
+
+ if (!dcss_plane->use_dtrc) {
+ dcss_dtrc_bypass(dcss->dtrc, dcss_plane->ch_num);
+ return;
+ }
+
+ dcss_dtrc_addr_set(dcss->dtrc, dcss_plane->ch_num,
+ p1_ba, p2_ba, dcss_plane->dtrc_table_ofs_val);
+}
+
+static void dcss_plane_atomic_set_base(struct dcss_plane *dcss_plane)
+{
+ struct drm_plane *plane = &dcss_plane->base;
+ struct drm_plane_state *state = plane->state;
+ struct dcss_dev *dcss = plane->dev->dev_private;
+ struct drm_framebuffer *fb = state->fb;
+ const struct drm_format_info *format = fb->format;
+ struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+ unsigned long p1_ba = 0, p2_ba = 0;
+ u16 x1, y1;
+
+ x1 = state->src.x1 >> 16;
+ y1 = state->src.y1 >> 16;
+
+ if (!format->is_yuv ||
+ format->format == DRM_FORMAT_NV12 ||
+ format->format == DRM_FORMAT_NV21)
+ p1_ba = cma_obj->paddr + fb->offsets[0] +
+ fb->pitches[0] * y1 +
+ format->char_per_block[0] * x1;
+ else if (format->format == DRM_FORMAT_NV12_10LE40)
+ p1_ba = cma_obj->paddr + fb->offsets[0] +
+ fb->pitches[0] * y1 +
+ format->char_per_block[0] * (x1 >> 2);
+ else if (format->format == DRM_FORMAT_UYVY ||
+ format->format == DRM_FORMAT_VYUY ||
+ format->format == DRM_FORMAT_YUYV ||
+ format->format == DRM_FORMAT_YVYU)
+ p1_ba = cma_obj->paddr + fb->offsets[0] +
+ fb->pitches[0] * y1 +
+ 2 * format->char_per_block[0] * (x1 >> 1);
+
+ if (format->format == DRM_FORMAT_NV12 ||
+ format->format == DRM_FORMAT_NV21)
+ p2_ba = cma_obj->paddr + fb->offsets[1] +
+ (((fb->pitches[1] >> 1) * (y1 >> 1) +
+ (x1 >> 1)) << 1);
+ else if (format->format == DRM_FORMAT_NV12_10LE40)
+ p2_ba = cma_obj->paddr + fb->offsets[1] +
+ (((fb->pitches[1] >> 1) * (y1 >> 1)) << 1) +
+ format->char_per_block[1] * (x1 >> 2);
+
+ dcss_dpr_addr_set(dcss->dpr, dcss_plane->ch_num, p1_ba, p2_ba,
+ fb->pitches[0]);
+
+ if (plane->type == DRM_PLANE_TYPE_PRIMARY)
+ dcss_plane_set_primary_base(dcss_plane, p1_ba);
+ else
+ dcss_plane_set_dtrc_base(dcss_plane,
+ cma_obj->paddr + fb->offsets[0],
+ cma_obj->paddr + fb->offsets[1]);
+}
+
+static bool dcss_plane_needs_setup(struct drm_plane_state *state,
+ struct drm_plane_state *old_state)
+{
+ struct drm_framebuffer *fb = state->fb;
+ struct drm_framebuffer *old_fb = old_state->fb;
+
+ return state->crtc_x != old_state->crtc_x ||
+ state->crtc_y != old_state->crtc_y ||
+ state->crtc_w != old_state->crtc_w ||
+ state->crtc_h != old_state->crtc_h ||
+ state->src_x != old_state->src_x ||
+ state->src_y != old_state->src_y ||
+ state->src_w != old_state->src_w ||
+ state->src_h != old_state->src_h ||
+ fb->format->format != old_fb->format->format ||
+ fb->modifier != old_fb->modifier ||
+ state->rotation != old_state->rotation;
+}
+
+static void dcss_plane_setup_hdr10_pipes(struct drm_plane *plane)
+{
+ struct dcss_dev *dcss = plane->dev->dev_private;
+ struct dcss_plane *dcss_plane = to_dcss_plane(plane);
+ struct drm_plane_state *state = plane->state;
+ struct drm_crtc *crtc = state->crtc;
+ struct dcss_crtc *dcss_crtc = container_of(crtc, struct dcss_crtc,
+ base);
+ struct drm_framebuffer *fb = state->fb;
+ struct dcss_hdr10_pipe_cfg ipipe_cfg, opipe_cfg;
+
+ opipe_cfg.is_yuv = dcss_crtc->output_is_yuv;
+ opipe_cfg.g = dcss_crtc->opipe_g;
+ opipe_cfg.nl = dcss_crtc->opipe_nl;
+ opipe_cfg.pr = dcss_crtc->opipe_pr;
+
+ ipipe_cfg.is_yuv = fb->format->is_yuv;
+
+ if (!fb->format->is_yuv) {
+ ipipe_cfg.nl = NL_SRGB;
+ ipipe_cfg.pr = PR_FULL;
+ ipipe_cfg.g = G_ADOBE_ARGB;
+ goto setup;
+ }
+
+ switch (state->color_encoding) {
+ case DRM_COLOR_YCBCR_BT709:
+ ipipe_cfg.nl = NL_REC709;
+ ipipe_cfg.g = G_REC709;
+ break;
+
+ case DRM_COLOR_YCBCR_BT2020:
+ ipipe_cfg.nl = NL_REC2084;
+ ipipe_cfg.g = G_REC2020;
+ break;
+
+ default:
+ ipipe_cfg.nl = NL_REC709;
+ ipipe_cfg.g = G_REC601_PAL;
+ break;
+ }
+
+ ipipe_cfg.pr = state->color_range;
+
+setup:
+ dcss_hdr10_setup(dcss->hdr10, dcss_plane->ch_num,
+ &ipipe_cfg, &opipe_cfg);
+}
+
+static void dcss_plane_atomic_update(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+ struct drm_plane_state *state = plane->state;
+ struct dcss_plane *dcss_plane = to_dcss_plane(plane);
+ struct dcss_dev *dcss = plane->dev->dev_private;
+ struct drm_framebuffer *fb = state->fb;
+ u32 pixel_format;
+ struct drm_crtc_state *crtc_state;
+ bool modifiers_present;
+ u32 src_w, src_h, dst_w, dst_h;
+ struct drm_rect src, dst;
+ bool enable = true;
+
+ if (!fb || !state->crtc || !state->visible)
+ return;
+
+ pixel_format = fb->format->format;
+ crtc_state = state->crtc->state;
+ modifiers_present = !!(fb->flags & DRM_MODE_FB_MODIFIERS);
+
+ if (old_state->fb && !drm_atomic_crtc_needs_modeset(crtc_state) &&
+ !dcss_plane_needs_setup(state, old_state) &&
+ !dcss_dtg_global_alpha_changed(dcss->dtg, dcss_plane->ch_num,
+ state->alpha >> 8)) {
+ dcss_plane_atomic_set_base(dcss_plane);
+ if (plane->type == DRM_PLANE_TYPE_PRIMARY)
+ dcss_dec400d_shadow_trig(dcss->dec400d);
+ return;
+ }
+
+ src = plane->state->src;
+ dst = plane->state->dst;
+
+ /*
+ * The width and height after clipping.
+ */
+ src_w = drm_rect_width(&src) >> 16;
+ src_h = drm_rect_height(&src) >> 16;
+ dst_w = drm_rect_width(&dst);
+ dst_h = drm_rect_height(&dst);
+
+ dcss_dpr_format_set(dcss->dpr, dcss_plane->ch_num, state->fb->format,
+ modifiers_present ? fb->modifier :
+ DRM_FORMAT_MOD_LINEAR);
+
+ if (dcss_plane->use_dtrc) {
+ u32 dtrc_w, dtrc_h;
+
+ dcss_dtrc_set_res(dcss->dtrc, dcss_plane->ch_num, state,
+ &dtrc_w, &dtrc_h);
+ dcss_dpr_set_res(dcss->dpr, dcss_plane->ch_num, dtrc_w, dtrc_h);
+ } else {
+ dcss_dpr_set_res(dcss->dpr, dcss_plane->ch_num, src_w, src_h);
+ }
+
+ dcss_dpr_set_rotation(dcss->dpr, dcss_plane->ch_num,
+ state->rotation);
+
+ dcss_plane_atomic_set_base(dcss_plane);
+
+ dcss_scaler_setup(dcss->scaler, dcss_plane->ch_num,
+ state->fb->format, src_w, src_h,
+ dst_w, dst_h,
+ drm_mode_vrefresh(&crtc_state->mode));
+
+ dcss_plane_setup_hdr10_pipes(plane);
+
+ dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num,
+ dst.x1, dst.y1, dst_w, dst_h);
+ dcss_dtg_plane_alpha_set(dcss->dtg, dcss_plane->ch_num,
+ fb->format, state->alpha >> 8);
+
+ if (plane->type == DRM_PLANE_TYPE_PRIMARY)
+ dcss_dec400d_enable(dcss->dec400d);
+ else if (dcss_plane->use_dtrc)
+ dcss_dtrc_enable(dcss->dtrc, dcss_plane->ch_num, true);
+
+ if (!dcss_plane->ch_num && (state->alpha >> 8) == 0)
+ enable = false;
+
+ dcss_dpr_enable(dcss->dpr, dcss_plane->ch_num, enable);
+ dcss_scaler_ch_enable(dcss->scaler, dcss_plane->ch_num, enable);
+
+ if (!enable)
+ dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num,
+ 0, 0, 0, 0);
+
+ dcss_dtg_ch_enable(dcss->dtg, dcss_plane->ch_num, enable);
+}
+
+static void dcss_plane_atomic_disable(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+ struct dcss_plane *dcss_plane = to_dcss_plane(plane);
+ struct dcss_dev *dcss = plane->dev->dev_private;
+
+ if (dcss_plane->use_dtrc)
+ dcss_dtrc_enable(dcss->dtrc, dcss_plane->ch_num, false);
+ dcss_dpr_enable(dcss->dpr, dcss_plane->ch_num, false);
+ dcss_scaler_ch_enable(dcss->scaler, dcss_plane->ch_num, false);
+ dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num, 0, 0, 0, 0);
+ dcss_dtg_ch_enable(dcss->dtg, dcss_plane->ch_num, false);
+}
+
+static const struct drm_plane_helper_funcs dcss_plane_helper_funcs = {
+ .prepare_fb = drm_gem_fb_prepare_fb,
+ .atomic_check = dcss_plane_atomic_check,
+ .atomic_update = dcss_plane_atomic_update,
+ .atomic_disable = dcss_plane_atomic_disable,
+};
+
+struct dcss_plane *dcss_plane_init(struct drm_device *drm,
+ unsigned int possible_crtcs,
+ enum drm_plane_type type,
+ unsigned int zpos)
+{
+ struct dcss_plane *dcss_plane;
+ const u64 *format_modifiers = dcss_video_format_modifiers;
+ const u32 *formats = dcss_video_formats;
+ u32 formats_size = ARRAY_SIZE(dcss_video_formats);
+ struct drm_property *prop;
+ int ret;
+
+ if (zpos > 2)
+ return ERR_PTR(-EINVAL);
+
+ dcss_plane = kzalloc(sizeof(*dcss_plane), GFP_KERNEL);
+ if (!dcss_plane) {
+ DRM_ERROR("failed to allocate plane\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ if (type == DRM_PLANE_TYPE_PRIMARY) {
+ formats = dcss_graphics_formats;
+ formats_size = ARRAY_SIZE(dcss_graphics_formats);
+ format_modifiers = dcss_graphics_format_modifiers;
+ }
+
+ ret = drm_universal_plane_init(drm, &dcss_plane->base, possible_crtcs,
+ &dcss_plane_funcs, formats,
+ formats_size,
+ format_modifiers, type, NULL);
+ if (ret) {
+ DRM_ERROR("failed to initialize plane\n");
+ kfree(dcss_plane);
+ return ERR_PTR(ret);
+ }
+
+ drm_plane_helper_add(&dcss_plane->base, &dcss_plane_helper_funcs);
+
+ ret = drm_plane_create_zpos_immutable_property(&dcss_plane->base, zpos);
+ if (ret)
+ return ERR_PTR(ret);
+
+ drm_plane_create_rotation_property(&dcss_plane->base,
+ DRM_MODE_ROTATE_0,
+ DRM_MODE_ROTATE_0 |
+ DRM_MODE_ROTATE_90 |
+ DRM_MODE_ROTATE_180 |
+ DRM_MODE_ROTATE_270 |
+ DRM_MODE_REFLECT_X |
+ DRM_MODE_REFLECT_Y);
+
+ dcss_plane->ch_num = 2 - zpos;
+ dcss_plane->type = type;
+
+ if (type == DRM_PLANE_TYPE_PRIMARY)
+ return dcss_plane;
+
+ prop = drm_property_create_range(drm, 0, "dtrc_table_ofs",
+ 0, ULLONG_MAX);
+ if (!prop) {
+ DRM_ERROR("cannot create dtrc_table_ofs property\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ dcss_plane->dtrc_table_ofs_prop = prop;
+ drm_object_attach_property(&dcss_plane->base.base, prop, 0);
+
+ return dcss_plane;
+}
diff --git a/drivers/gpu/drm/imx/dcss/dcss-rdsrc.c b/drivers/gpu/drm/imx/dcss/dcss-rdsrc.c
new file mode 100644
index 000000000000..ef695e584acf
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/dcss-rdsrc.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/seq_file.h>
+
+#include "dcss-dev.h"
+
+#define DCSS_RDSRC_CTRL_STATUS 0x00
+#define RDSRC_RD_ERR BIT(31)
+#define RDSRC_FRAME_COMP BIT(30)
+#define RDSRC_FIFO_SIZE_POS 16
+#define RDSRC_FIFO_SIZE_MASK GENMASK(22, 16)
+#define RDSRC_RD_ERR_EN BIT(15)
+#define RDSRC_FRAME_COMP_EN BIT(14)
+#define RDSRC_P_SIZE_POS 7
+#define RDSRC_P_SIZE_MASK GENMASK(9, 7)
+#define RDSRC_T_SIZE_POS 5
+#define RDSRC_T_SIZE_MASK GENMASK(6, 5)
+#define RDSRC_BPP_POS 2
+#define RDSRC_BPP_MASK GENMASK(4, 2)
+#define RDSRC_ENABLE BIT(0)
+#define DCSS_RDSRC_BASE_ADDR 0x10
+#define DCSS_RDSRC_PITCH 0x14
+#define DCSS_RDSRC_WIDTH 0x18
+#define DCSS_RDSRC_HEIGHT 0x1C
+
+struct dcss_rdsrc {
+ struct device *dev;
+
+ void __iomem *base_reg;
+ u32 base_ofs;
+
+ struct dcss_ctxld *ctxld;
+ u32 ctx_id;
+
+ u32 buf_addr;
+
+ u32 ctrl_status;
+};
+
+static void dcss_rdsrc_write(struct dcss_rdsrc *rdsrc, u32 val, u32 ofs)
+{
+ dcss_ctxld_write(rdsrc->ctxld, rdsrc->ctx_id, val,
+ rdsrc->base_ofs + ofs);
+}
+
+int dcss_rdsrc_init(struct dcss_dev *dcss, unsigned long rdsrc_base)
+{
+ struct dcss_rdsrc *rdsrc;
+
+ rdsrc = devm_kzalloc(dcss->dev, sizeof(*rdsrc), GFP_KERNEL);
+ if (!rdsrc)
+ return -ENOMEM;
+
+ rdsrc->base_reg = devm_ioremap(dcss->dev, rdsrc_base, SZ_4K);
+ if (!rdsrc->base_reg) {
+ dev_err(dcss->dev, "rdsrc: unable to remap base\n");
+ devm_kfree(dcss->dev, rdsrc);
+ return -ENOMEM;
+ }
+
+ dcss->rdsrc = rdsrc;
+
+ rdsrc->dev = dcss->dev;
+ rdsrc->base_ofs = rdsrc_base;
+ rdsrc->ctxld = dcss->ctxld;
+ rdsrc->ctx_id = CTX_SB_HP;
+
+ return 0;
+}
+
+void dcss_rdsrc_exit(struct dcss_rdsrc *rdsrc)
+{
+ devm_iounmap(rdsrc->dev, rdsrc->base_reg);
+ devm_kfree(rdsrc->dev, rdsrc);
+}
+
+void dcss_rdsrc_setup(struct dcss_rdsrc *rdsrc, u32 pix_format, u32 dst_xres,
+ u32 dst_yres, u32 base_addr)
+{
+ u32 buf_size, pitch, bpp;
+
+ /* since the scaler output is YUV444, the RDSRC output has to match */
+ bpp = 4;
+
+ rdsrc->ctrl_status = FIFO_512 << RDSRC_FIFO_SIZE_POS;
+ rdsrc->ctrl_status |= PSIZE_256 << RDSRC_P_SIZE_POS;
+ rdsrc->ctrl_status |= TSIZE_256 << RDSRC_T_SIZE_POS;
+ rdsrc->ctrl_status |= BPP_32_10BIT_OUTPUT << RDSRC_BPP_POS;
+
+ buf_size = dst_xres * dst_yres * bpp;
+ pitch = dst_xres * bpp;
+
+ rdsrc->buf_addr = base_addr;
+
+ dcss_rdsrc_write(rdsrc, rdsrc->buf_addr, DCSS_RDSRC_BASE_ADDR);
+ dcss_rdsrc_write(rdsrc, pitch, DCSS_RDSRC_PITCH);
+ dcss_rdsrc_write(rdsrc, dst_xres, DCSS_RDSRC_WIDTH);
+ dcss_rdsrc_write(rdsrc, dst_yres, DCSS_RDSRC_HEIGHT);
+}
+
+void dcss_rdsrc_enable(struct dcss_rdsrc *rdsrc)
+{
+ dcss_rdsrc_write(rdsrc, rdsrc->ctrl_status, DCSS_RDSRC_CTRL_STATUS);
+}
+
+void dcss_rdsrc_disable(struct dcss_rdsrc *rdsrc)
+{
+ /* RDSRC is turned off by setting the width and height to 0 */
+ dcss_rdsrc_write(rdsrc, 0, DCSS_RDSRC_WIDTH);
+ dcss_rdsrc_write(rdsrc, 0, DCSS_RDSRC_HEIGHT);
+
+ dcss_rdsrc_write(rdsrc, rdsrc->ctrl_status, DCSS_RDSRC_CTRL_STATUS);
+}
diff --git a/drivers/gpu/drm/imx/dcss/dcss-scaler.c b/drivers/gpu/drm/imx/dcss/dcss-scaler.c
new file mode 100644
index 000000000000..d1ff5443c74d
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/dcss-scaler.c
@@ -0,0 +1,911 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ *
+ * Scaling algorithms were contributed by Dzung Hoang <dzung.hoang@nxp.com>
+ */
+
+#include <linux/device.h>
+
+#include "dcss-dev.h"
+
+#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
+
+struct dcss_scaler_ch {
+ void __iomem *base_reg;
+ u32 base_ofs;
+ struct dcss_scaler *scl;
+
+ u32 sdata_ctrl;
+ u32 scaler_ctrl;
+
+ bool scaler_ctrl_chgd;
+
+ u32 c_vstart;
+ u32 c_hstart;
+
+ int ch_num;
+};
+
+struct dcss_scaler {
+ struct device *dev;
+
+ struct dcss_ctxld *ctxld;
+ u32 ctx_id;
+
+ struct dcss_scaler_ch ch[3];
+
+ struct dcss_wrscl *wrscl;
+ struct dcss_rdsrc *rdsrc;
+ int ch_using_wrscl;
+};
+
+/* scaler coefficients generator */
+#define PSC_FRAC_BITS 30
+#define PSC_FRAC_SCALE BIT(PSC_FRAC_BITS)
+#define PSC_BITS_FOR_PHASE 4
+#define PSC_NUM_PHASES 16
+#define PSC_STORED_PHASES (PSC_NUM_PHASES / 2 + 1)
+#define PSC_NUM_TAPS 7
+#define PSC_NUM_TAPS_RGBA 5
+#define PSC_COEFF_PRECISION 10
+#define PSC_PHASE_FRACTION_BITS 13
+#define PSC_PHASE_MASK (PSC_NUM_PHASES - 1)
+#define PSC_Q_FRACTION 19
+#define PSC_Q_ROUND_OFFSET (1 << (PSC_Q_FRACTION - 1))
+
+/**
+ * mult_q() - Performs fixed-point multiplication.
+ * @A: multiplier
+ * @B: multiplicand
+ */
+static int mult_q(int A, int B)
+{
+ int result;
+ s64 temp;
+
+ temp = (int64_t)A * (int64_t)B;
+ temp += PSC_Q_ROUND_OFFSET;
+ result = (int)(temp >> PSC_Q_FRACTION);
+ return result;
+}
+
+/**
+ * div_q() - Performs fixed-point division.
+ * @A: dividend
+ * @B: divisor
+ */
+static int div_q(int A, int B)
+{
+ int result;
+ s64 temp;
+
+ temp = (int64_t)A << PSC_Q_FRACTION;
+ if ((temp >= 0 && B >= 0) || (temp < 0 && B < 0))
+ temp += B / 2;
+ else
+ temp -= B / 2;
+
+ result = (int)(temp / B);
+ return result;
+}
+
+/**
+ * exp_approx_q() - Compute approximation to exp(x) function using Taylor
+ * series.
+ * @x: fixed-point argument of exp function
+ */
+static int exp_approx_q(int x)
+{
+ int sum = 1 << PSC_Q_FRACTION;
+ int term = 1 << PSC_Q_FRACTION;
+
+ term = mult_q(term, div_q(x, 1 << PSC_Q_FRACTION));
+ sum += term;
+ term = mult_q(term, div_q(x, 2 << PSC_Q_FRACTION));
+ sum += term;
+ term = mult_q(term, div_q(x, 3 << PSC_Q_FRACTION));
+ sum += term;
+ term = mult_q(term, div_q(x, 4 << PSC_Q_FRACTION));
+ sum += term;
+
+ return sum;
+}
+
+/**
+ * dcss_scaler_gaussian_filter() - Generate gaussian prototype filter.
+ * @fc_q: fixed-point cutoff frequency normalized to range [0, 1]
+ * @use_5_taps: indicates whether to use 5 taps or 7 taps
+ * @coef: output filter coefficients
+ */
+static void dcss_scaler_gaussian_filter(int fc_q, bool use_5_taps,
+ bool phase0_identity,
+ int coef[][PSC_NUM_TAPS])
+{
+ int sigma_q, g0_q, g1_q, g2_q;
+ int tap_cnt1, tap_cnt2, tap_idx, phase_cnt;
+ int mid;
+ int phase;
+ int i;
+ int taps;
+
+ if (use_5_taps)
+ for (phase = 0; phase < PSC_STORED_PHASES; phase++) {
+ coef[phase][0] = 0;
+ coef[phase][PSC_NUM_TAPS - 1] = 0;
+ }
+
+ /* seed coefficient scanner */
+ taps = use_5_taps ? PSC_NUM_TAPS_RGBA : PSC_NUM_TAPS;
+ mid = (PSC_NUM_PHASES * taps) / 2 - 1;
+ phase_cnt = (PSC_NUM_PHASES * (PSC_NUM_TAPS + 1)) / 2;
+ tap_cnt1 = (PSC_NUM_PHASES * PSC_NUM_TAPS) / 2;
+ tap_cnt2 = (PSC_NUM_PHASES * PSC_NUM_TAPS) / 2;
+
+ /* seed gaussian filter generator */
+ sigma_q = div_q(PSC_Q_ROUND_OFFSET, fc_q);
+ g0_q = 1 << PSC_Q_FRACTION;
+ g1_q = exp_approx_q(div_q(-PSC_Q_ROUND_OFFSET,
+ mult_q(sigma_q, sigma_q)));
+ g2_q = mult_q(g1_q, g1_q);
+ coef[phase_cnt & PSC_PHASE_MASK][tap_cnt1 >> PSC_BITS_FOR_PHASE] = g0_q;
+
+ for (i = 0; i < mid; i++) {
+ phase_cnt++;
+ tap_cnt1--;
+ tap_cnt2++;
+
+ g0_q = mult_q(g0_q, g1_q);
+ g1_q = mult_q(g1_q, g2_q);
+
+ if ((phase_cnt & PSC_PHASE_MASK) <= 8) {
+ tap_idx = tap_cnt1 >> PSC_BITS_FOR_PHASE;
+ coef[phase_cnt & PSC_PHASE_MASK][tap_idx] = g0_q;
+ }
+ if (((-phase_cnt) & PSC_PHASE_MASK) <= 8) {
+ tap_idx = tap_cnt2 >> PSC_BITS_FOR_PHASE;
+ coef[(-phase_cnt) & PSC_PHASE_MASK][tap_idx] = g0_q;
+ }
+ }
+
+ phase_cnt++;
+ tap_cnt1--;
+ coef[phase_cnt & PSC_PHASE_MASK][tap_cnt1 >> PSC_BITS_FOR_PHASE] = 0;
+
+ /* override phase 0 with identity filter if specified */
+ if (phase0_identity)
+ for (i = 0; i < PSC_NUM_TAPS; i++)
+ coef[0][i] = i == (PSC_NUM_TAPS >> 1) ?
+ (1 << PSC_COEFF_PRECISION) : 0;
+
+ /* normalize coef */
+ for (phase = 0; phase < PSC_STORED_PHASES; phase++) {
+ int sum = 0;
+ s64 ll_temp;
+
+ for (i = 0; i < PSC_NUM_TAPS; i++)
+ sum += coef[phase][i];
+ for (i = 0; i < PSC_NUM_TAPS; i++) {
+ ll_temp = coef[phase][i];
+ ll_temp <<= PSC_COEFF_PRECISION;
+ ll_temp += sum >> 1;
+ ll_temp /= sum;
+ coef[phase][i] = (int)ll_temp;
+ }
+ }
+}
+
+/**
+ * dcss_scaler_filter_design() - Compute filter coefficients using
+ * Gaussian filter.
+ * @src_length: length of input
+ * @dst_length: length of output
+ * @use_5_taps: 0 for 7 taps per phase, 1 for 5 taps
+ * @coef: output coefficients
+ */
+static void dcss_scaler_filter_design(int src_length, int dst_length,
+ bool use_5_taps, bool phase0_identity,
+ int coef[][PSC_NUM_TAPS])
+{
+ int fc_q;
+
+ /* compute cutoff frequency */
+ if (dst_length >= src_length)
+ fc_q = div_q(1, PSC_NUM_PHASES);
+ else
+ fc_q = div_q(dst_length, src_length * PSC_NUM_PHASES);
+
+ /* compute gaussian filter coefficients */
+ dcss_scaler_gaussian_filter(fc_q, use_5_taps, phase0_identity, coef);
+}
+
+static void dcss_scaler_write(struct dcss_scaler_ch *ch, u32 val, u32 ofs)
+{
+ struct dcss_scaler *scl = ch->scl;
+
+ dcss_ctxld_write(scl->ctxld, scl->ctx_id, val, ch->base_ofs + ofs);
+}
+
+static int dcss_scaler_ch_init_all(struct dcss_scaler *scl,
+ unsigned long scaler_base)
+{
+ struct dcss_scaler_ch *ch;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ ch = &scl->ch[i];
+
+ ch->base_ofs = scaler_base + i * 0x400;
+
+ ch->base_reg = devm_ioremap(scl->dev, ch->base_ofs, SZ_4K);
+ if (!ch->base_reg) {
+ dev_err(scl->dev, "scaler: unable to remap ch base\n");
+ return -ENOMEM;
+ }
+
+ ch->scl = scl;
+ ch->ch_num = i;
+ }
+
+ return 0;
+}
+
+int dcss_scaler_init(struct dcss_dev *dcss, unsigned long scaler_base)
+{
+ struct dcss_scaler *scaler;
+
+ scaler = devm_kzalloc(dcss->dev, sizeof(*scaler), GFP_KERNEL);
+ if (!scaler)
+ return -ENOMEM;
+
+ dcss->scaler = scaler;
+ scaler->dev = dcss->dev;
+ scaler->ctxld = dcss->ctxld;
+ scaler->ctx_id = CTX_SB_HP;
+ scaler->wrscl = dcss->wrscl;
+ scaler->rdsrc = dcss->rdsrc;
+ scaler->ch_using_wrscl = -1;
+
+ if (dcss_scaler_ch_init_all(scaler, scaler_base)) {
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ if (scaler->ch[i].base_reg)
+ devm_iounmap(scaler->dev,
+ scaler->ch[i].base_reg);
+ }
+
+ devm_kfree(scaler->dev, scaler);
+
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void dcss_scaler_exit(struct dcss_scaler *scl)
+{
+ int ch_no;
+
+ for (ch_no = 0; ch_no < 3; ch_no++) {
+ struct dcss_scaler_ch *ch = &scl->ch[ch_no];
+
+ dcss_writel(0, ch->base_reg + DCSS_SCALER_CTRL);
+
+ if (ch->base_reg)
+ devm_iounmap(scl->dev, ch->base_reg);
+ }
+
+ devm_kfree(scl->dev, scl);
+}
+
+void dcss_scaler_ch_enable(struct dcss_scaler *scl, int ch_num, bool en)
+{
+ struct dcss_scaler_ch *ch = &scl->ch[ch_num];
+ u32 scaler_ctrl;
+
+ if (scl->ch_using_wrscl == ch_num) {
+ if (en) {
+ scaler_ctrl = SCALE2MEM_EN | MEM2OFIFO_EN | REPEAT_EN;
+ } else {
+ dcss_wrscl_disable(scl->wrscl);
+ dcss_rdsrc_disable(scl->rdsrc);
+
+ scl->ch_using_wrscl = -1;
+ scaler_ctrl = 0;
+ }
+ } else {
+ scaler_ctrl = en ? SCALER_EN | REPEAT_EN : 0;
+ }
+
+ if (en)
+ dcss_scaler_write(ch, ch->sdata_ctrl, DCSS_SCALER_SDATA_CTRL);
+
+ if (ch->scaler_ctrl != scaler_ctrl)
+ ch->scaler_ctrl_chgd = true;
+
+ ch->scaler_ctrl = scaler_ctrl;
+}
+
+static void dcss_scaler_yuv_enable(struct dcss_scaler_ch *ch, bool en)
+{
+ ch->sdata_ctrl &= ~YUV_EN;
+ ch->sdata_ctrl |= en ? YUV_EN : 0;
+}
+
+static void dcss_scaler_rtr_8lines_enable(struct dcss_scaler_ch *ch, bool en)
+{
+ ch->sdata_ctrl &= ~RTRAM_8LINES;
+ ch->sdata_ctrl |= en ? RTRAM_8LINES : 0;
+}
+
+static void dcss_scaler_bit_depth_set(struct dcss_scaler_ch *ch, int depth)
+{
+ u32 val;
+
+ val = depth == 30 ? 2 : 0;
+
+ dcss_scaler_write(ch,
+ ((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,
+};
+
+enum chroma_location {
+ PSC_LOC_HORZ_0_VERT_1_OVER_4 = 0,
+ PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_4 = 1,
+ PSC_LOC_HORZ_0_VERT_0 = 2,
+ PSC_LOC_HORZ_1_OVER_4_VERT_0 = 3,
+ PSC_LOC_HORZ_0_VERT_1_OVER_2 = 4,
+ PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_2 = 5
+};
+
+static void dcss_scaler_format_set(struct dcss_scaler_ch *ch,
+ enum buffer_format src_fmt,
+ enum buffer_format dst_fmt)
+{
+ dcss_scaler_write(ch, src_fmt, DCSS_SCALER_SRC_FORMAT);
+ dcss_scaler_write(ch, dst_fmt, DCSS_SCALER_DST_FORMAT);
+}
+
+static void dcss_scaler_res_set(struct dcss_scaler_ch *ch,
+ int src_xres, int src_yres,
+ int dst_xres, int dst_yres,
+ u32 pix_format, enum buffer_format dst_format)
+{
+ u32 lsrc_xres, lsrc_yres, csrc_xres, csrc_yres;
+ u32 ldst_xres, ldst_yres, cdst_xres, cdst_yres;
+ bool src_is_444 = true;
+
+ lsrc_xres = src_xres;
+ csrc_xres = src_xres;
+ lsrc_yres = src_yres;
+ csrc_yres = src_yres;
+ ldst_xres = dst_xres;
+ cdst_xres = dst_xres;
+ ldst_yres = dst_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;
+ src_is_444 = false;
+ } else if (pix_format == DRM_FORMAT_NV12 ||
+ pix_format == DRM_FORMAT_NV21 ||
+ pix_format == DRM_FORMAT_NV12_10LE40) {
+ csrc_xres >>= 1;
+ csrc_yres >>= 1;
+ src_is_444 = false;
+ }
+
+ if (dst_format == BUF_FMT_YUV422)
+ cdst_xres >>= 1;
+
+ /* for 4:4:4 to 4:2:2 conversion, source height should be 1 less */
+ if (src_is_444 && dst_format == BUF_FMT_YUV422) {
+ lsrc_yres--;
+ csrc_yres--;
+ }
+
+ dcss_scaler_write(ch, (((lsrc_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
+ (((lsrc_xres - 1) << WIDTH_POS) & WIDTH_MASK),
+ DCSS_SCALER_SRC_LUM_RES);
+ dcss_scaler_write(ch, (((csrc_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
+ (((csrc_xres - 1) << WIDTH_POS) & WIDTH_MASK),
+ DCSS_SCALER_SRC_CHR_RES);
+ dcss_scaler_write(ch, (((ldst_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
+ (((ldst_xres - 1) << WIDTH_POS) & WIDTH_MASK),
+ DCSS_SCALER_DST_LUM_RES);
+ dcss_scaler_write(ch, (((cdst_yres - 1) << HEIGHT_POS) & HEIGHT_MASK) |
+ (((cdst_xres - 1) << WIDTH_POS) & WIDTH_MASK),
+ DCSS_SCALER_DST_CHR_RES);
+}
+
+#define downscale_fp(factor, fp_pos) ((factor) << (fp_pos))
+#define upscale_fp(factor, fp_pos) ((1 << (fp_pos)) / (factor))
+
+struct dcss_scaler_factors {
+ int downscale;
+ int upscale;
+};
+
+static const struct dcss_scaler_factors dcss_scaler_factors[] = {
+ {3, 8}, {5, 8}, {5, 8},
+};
+
+static const struct dcss_scaler_factors dcss_scaler_wrscl_factors[] = {
+ {5, 8}, {7, 8}, {7, 8},
+};
+
+static bool dcss_scaler_fractions_set(struct dcss_scaler_ch *ch,
+ int src_xres, int src_yres,
+ int dst_xres, int dst_yres,
+ u32 src_format, u32 dst_format,
+ enum chroma_location src_chroma_loc)
+{
+ int src_c_xres, src_c_yres, dst_c_xres, dst_c_yres;
+ u32 l_vinc, l_hinc, c_vinc, c_hinc;
+ u32 c_vstart, c_hstart;
+ u8 upscale_factor, downscale_factor;
+
+ src_c_xres = src_xres;
+ src_c_yres = src_yres;
+ dst_c_xres = dst_xres;
+ dst_c_yres = dst_yres;
+
+ c_vstart = 0;
+ c_hstart = 0;
+
+ /* adjustments for source chroma location */
+ if (src_format == BUF_FMT_YUV420) {
+ /* vertical input chroma position adjustment */
+ switch (src_chroma_loc) {
+ case PSC_LOC_HORZ_0_VERT_1_OVER_4:
+ case PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_4:
+ /*
+ * move chroma up to first luma line
+ * (1/4 chroma input line spacing)
+ */
+ c_vstart -= (1 << (PSC_PHASE_FRACTION_BITS - 2));
+ break;
+ case PSC_LOC_HORZ_0_VERT_1_OVER_2:
+ case PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_2:
+ /*
+ * move chroma up to first luma line
+ * (1/2 chroma input line spacing)
+ */
+ c_vstart -= (1 << (PSC_PHASE_FRACTION_BITS - 1));
+ break;
+ default:
+ break;
+ }
+ /* horizontal input chroma position adjustment */
+ switch (src_chroma_loc) {
+ case PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_4:
+ case PSC_LOC_HORZ_1_OVER_4_VERT_0:
+ case PSC_LOC_HORZ_1_OVER_4_VERT_1_OVER_2:
+ /* move chroma left 1/4 chroma input sample spacing */
+ c_hstart -= (1 << (PSC_PHASE_FRACTION_BITS - 2));
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* adjustments to chroma resolution */
+ if (src_format == BUF_FMT_YUV420) {
+ src_c_xres >>= 1;
+ src_c_yres >>= 1;
+ } else if (src_format == BUF_FMT_YUV422) {
+ src_c_xres >>= 1;
+ }
+
+ if (dst_format == BUF_FMT_YUV422)
+ dst_c_xres >>= 1;
+
+ l_vinc = ((src_yres << 13) + (dst_yres >> 1)) / dst_yres;
+ c_vinc = ((src_c_yres << 13) + (dst_c_yres >> 1)) / dst_c_yres;
+ l_hinc = ((src_xres << 13) + (dst_xres >> 1)) / dst_xres;
+ c_hinc = ((src_c_xres << 13) + (dst_c_xres >> 1)) / dst_c_xres;
+
+ /* save chroma start phase */
+ ch->c_vstart = c_vstart;
+ ch->c_hstart = c_hstart;
+
+ dcss_scaler_write(ch, 0, DCSS_SCALER_V_LUM_START);
+ dcss_scaler_write(ch, l_vinc, DCSS_SCALER_V_LUM_INC);
+
+ dcss_scaler_write(ch, 0, DCSS_SCALER_H_LUM_START);
+ dcss_scaler_write(ch, l_hinc, DCSS_SCALER_H_LUM_INC);
+
+ dcss_scaler_write(ch, c_vstart, DCSS_SCALER_V_CHR_START);
+ dcss_scaler_write(ch, c_vinc, DCSS_SCALER_V_CHR_INC);
+
+ dcss_scaler_write(ch, c_hstart, DCSS_SCALER_H_CHR_START);
+ dcss_scaler_write(ch, c_hinc, DCSS_SCALER_H_CHR_INC);
+
+ downscale_factor = dcss_scaler_factors[ch->ch_num].downscale;
+ upscale_factor = dcss_scaler_factors[ch->ch_num].upscale;
+
+ /* return if WR_SCL/RD_SRC is needed to scale */
+ return l_vinc > downscale_fp(downscale_factor, 13) ||
+ l_vinc < upscale_fp(upscale_factor, 13) ||
+ l_hinc > downscale_fp(downscale_factor, 13) ||
+ l_hinc < upscale_fp(upscale_factor, 13);
+}
+
+int dcss_scaler_get_min_max_ratios(struct dcss_scaler *scl, int ch_num,
+ int *min, int *max)
+{
+ const struct dcss_scaler_factors *factors_map = dcss_scaler_factors;
+
+ if (scl->ch_using_wrscl == -1 || scl->ch_using_wrscl == ch_num)
+ factors_map = dcss_scaler_wrscl_factors;
+
+ *min = upscale_fp(factors_map[ch_num].upscale, 16);
+ *max = downscale_fp(factors_map[ch_num].downscale, 16);
+
+ return 0;
+}
+
+static void dcss_scaler_program_5_coef_set(struct dcss_scaler_ch *ch,
+ int base_addr,
+ int coef[][PSC_NUM_TAPS])
+{
+ int i, phase;
+
+ for (i = 0; i < PSC_STORED_PHASES; i++) {
+ dcss_scaler_write(ch, ((coef[i][1] & 0xfff) << 16 |
+ (coef[i][2] & 0xfff) << 4 |
+ (coef[i][3] & 0xf00) >> 8),
+ base_addr + i * sizeof(u32));
+ dcss_scaler_write(ch, ((coef[i][3] & 0x0ff) << 20 |
+ (coef[i][4] & 0xfff) << 8 |
+ (coef[i][5] & 0xff0) >> 4),
+ base_addr + 0x40 + i * sizeof(u32));
+ dcss_scaler_write(ch, ((coef[i][5] & 0x00f) << 24),
+ base_addr + 0x80 + i * sizeof(u32));
+ }
+
+ /* reverse both phase and tap orderings */
+ for (phase = (PSC_NUM_PHASES >> 1) - 1;
+ i < PSC_NUM_PHASES; i++, phase--) {
+ dcss_scaler_write(ch, ((coef[phase][5] & 0xfff) << 16 |
+ (coef[phase][4] & 0xfff) << 4 |
+ (coef[phase][3] & 0xf00) >> 8),
+ base_addr + i * sizeof(u32));
+ dcss_scaler_write(ch, ((coef[phase][3] & 0x0ff) << 20 |
+ (coef[phase][2] & 0xfff) << 8 |
+ (coef[phase][1] & 0xff0) >> 4),
+ base_addr + 0x40 + i * sizeof(u32));
+ dcss_scaler_write(ch, ((coef[phase][1] & 0x00f) << 24),
+ base_addr + 0x80 + i * sizeof(u32));
+ }
+}
+
+static void dcss_scaler_program_7_coef_set(struct dcss_scaler_ch *ch,
+ int base_addr,
+ int coef[][PSC_NUM_TAPS])
+{
+ int i, phase;
+
+ for (i = 0; i < PSC_STORED_PHASES; i++) {
+ dcss_scaler_write(ch, ((coef[i][0] & 0xfff) << 16 |
+ (coef[i][1] & 0xfff) << 4 |
+ (coef[i][2] & 0xf00) >> 8),
+ base_addr + i * sizeof(u32));
+ dcss_scaler_write(ch, ((coef[i][2] & 0x0ff) << 20 |
+ (coef[i][3] & 0xfff) << 8 |
+ (coef[i][4] & 0xff0) >> 4),
+ base_addr + 0x40 + i * sizeof(u32));
+ dcss_scaler_write(ch, ((coef[i][4] & 0x00f) << 24 |
+ (coef[i][5] & 0xfff) << 12 |
+ (coef[i][6] & 0xfff)),
+ base_addr + 0x80 + i * sizeof(u32));
+ }
+
+ /* reverse both phase and tap orderings */
+ for (phase = (PSC_NUM_PHASES >> 1) - 1;
+ i < PSC_NUM_PHASES; i++, phase--) {
+ dcss_scaler_write(ch, ((coef[phase][6] & 0xfff) << 16 |
+ (coef[phase][5] & 0xfff) << 4 |
+ (coef[phase][4] & 0xf00) >> 8),
+ base_addr + i * sizeof(u32));
+ dcss_scaler_write(ch, ((coef[phase][4] & 0x0ff) << 20 |
+ (coef[phase][3] & 0xfff) << 8 |
+ (coef[phase][2] & 0xff0) >> 4),
+ base_addr + 0x40 + i * sizeof(u32));
+ dcss_scaler_write(ch, ((coef[phase][2] & 0x00f) << 24 |
+ (coef[phase][1] & 0xfff) << 12 |
+ (coef[phase][0] & 0xfff)),
+ base_addr + 0x80 + i * sizeof(u32));
+ }
+}
+
+static void dcss_scaler_yuv_coef_set(struct dcss_scaler_ch *ch,
+ enum buffer_format src_format,
+ enum buffer_format dst_format,
+ bool use_5_taps,
+ int src_xres, int src_yres, int dst_xres,
+ int dst_yres)
+{
+ int coef[PSC_STORED_PHASES][PSC_NUM_TAPS];
+ bool program_5_taps = use_5_taps ||
+ (dst_format == BUF_FMT_YUV422 &&
+ src_format == BUF_FMT_ARGB8888_YUV444);
+
+ /* horizontal luma */
+ dcss_scaler_filter_design(src_xres, dst_xres, false,
+ src_xres == dst_xres, coef);
+ dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_HLUM, coef);
+
+ /* vertical luma */
+ dcss_scaler_filter_design(src_yres, dst_yres, program_5_taps,
+ src_yres == dst_yres, coef);
+
+ if (program_5_taps)
+ dcss_scaler_program_5_coef_set(ch, DCSS_SCALER_COEF_VLUM, coef);
+ else
+ dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_VLUM, coef);
+
+ /* adjust chroma resolution */
+ if (src_format != BUF_FMT_ARGB8888_YUV444)
+ src_xres >>= 1;
+ if (src_format == BUF_FMT_YUV420)
+ src_yres >>= 1;
+ if (dst_format != BUF_FMT_ARGB8888_YUV444)
+ dst_xres >>= 1;
+ if (dst_format == BUF_FMT_YUV420) /* should not happen */
+ dst_yres >>= 1;
+
+ /* horizontal chroma */
+ dcss_scaler_filter_design(src_xres, dst_xres, false,
+ (src_xres == dst_xres) && (ch->c_hstart == 0),
+ coef);
+
+ dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_HCHR, coef);
+
+ /* vertical chroma */
+ dcss_scaler_filter_design(src_yres, dst_yres, program_5_taps,
+ (src_yres == dst_yres) && (ch->c_vstart == 0),
+ coef);
+ if (program_5_taps)
+ dcss_scaler_program_5_coef_set(ch, DCSS_SCALER_COEF_VCHR, coef);
+ else
+ dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_VCHR, coef);
+}
+
+static void dcss_scaler_rgb_coef_set(struct dcss_scaler_ch *ch,
+ int src_xres, int src_yres, int dst_xres,
+ int dst_yres)
+{
+ int coef[PSC_STORED_PHASES][PSC_NUM_TAPS];
+
+ /* horizontal RGB */
+ dcss_scaler_filter_design(src_xres, dst_xres, false,
+ src_xres == dst_xres, coef);
+ dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_HLUM, coef);
+
+ /* vertical RGB */
+ dcss_scaler_filter_design(src_yres, dst_yres, false,
+ src_yres == dst_yres, coef);
+ dcss_scaler_program_7_coef_set(ch, DCSS_SCALER_COEF_VLUM, coef);
+}
+
+static void dcss_scaler_set_rgb10_order(struct dcss_scaler_ch *ch,
+ const struct drm_format_info *format)
+{
+ u32 a2r10g10b10_format;
+
+ if (format->is_yuv)
+ return;
+
+ ch->sdata_ctrl &= ~A2R10G10B10_FORMAT_MASK;
+
+ if (format->depth != 30)
+ return;
+
+ switch (format->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;
+}
+
+static void dcss_scaler_setup_path(struct dcss_scaler_ch *ch,
+ u32 pix_format, int dst_xres,
+ int dst_yres, u32 vrefresh_hz,
+ bool wrscl_needed)
+{
+ struct dcss_scaler *scl = ch->scl;
+ u32 base_addr;
+
+ /* nothing to do if WRSCL path is needed but it's already used */
+ if (wrscl_needed && scl->ch_using_wrscl != -1 &&
+ scl->ch_using_wrscl != ch->ch_num)
+ return;
+
+ if (!wrscl_needed) {
+ /* Channel has finished using WRSCL. Release WRSCL/RDSRC. */
+ if (scl->ch_using_wrscl == ch->ch_num) {
+ dcss_wrscl_disable(scl->wrscl);
+ dcss_rdsrc_disable(scl->rdsrc);
+
+ scl->ch_using_wrscl = -1;
+ }
+
+ return;
+ }
+
+ base_addr = dcss_wrscl_setup(scl->wrscl, pix_format, vrefresh_hz,
+ dst_xres, dst_yres);
+
+ dcss_rdsrc_setup(scl->rdsrc, pix_format, dst_xres, dst_yres,
+ base_addr);
+
+ dcss_wrscl_enable(scl->wrscl);
+ dcss_rdsrc_enable(scl->rdsrc);
+
+ scl->ch_using_wrscl = ch->ch_num;
+}
+
+void dcss_scaler_setup(struct dcss_scaler *scl, int ch_num,
+ const struct drm_format_info *format,
+ int src_xres, int src_yres, int dst_xres, int dst_yres,
+ u32 vrefresh_hz)
+{
+ struct dcss_scaler_ch *ch = &scl->ch[ch_num];
+ unsigned int pixel_depth = 0;
+ bool rtr_8line_en = false;
+ bool use_5_taps = false;
+ enum buffer_format src_format = BUF_FMT_ARGB8888_YUV444;
+ enum buffer_format dst_format = BUF_FMT_ARGB8888_YUV444;
+ u32 pix_format = format->format;
+ bool use_wrscl;
+
+ if (format->is_yuv) {
+ dcss_scaler_yuv_enable(ch, true);
+
+ if (pix_format == DRM_FORMAT_NV12 ||
+ pix_format == DRM_FORMAT_NV21 ||
+ pix_format == DRM_FORMAT_NV12_10LE40) {
+ 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;
+ }
+
+ use_5_taps = !rtr_8line_en;
+
+ if (pix_format == DRM_FORMAT_NV12_10LE40)
+ pixel_depth = 30;
+ } else {
+ dcss_scaler_yuv_enable(ch, false);
+
+ pixel_depth = format->depth;
+ }
+
+ use_wrscl = dcss_scaler_fractions_set(ch, src_xres, src_yres, dst_xres,
+ dst_yres, src_format, dst_format,
+ PSC_LOC_HORZ_0_VERT_1_OVER_4);
+
+ if (format->is_yuv)
+ dcss_scaler_yuv_coef_set(ch, src_format, dst_format,
+ use_5_taps, src_xres, src_yres,
+ dst_xres, dst_yres);
+ else
+ dcss_scaler_rgb_coef_set(ch, src_xres, src_yres,
+ dst_xres, dst_yres);
+
+ dcss_scaler_rtr_8lines_enable(ch, rtr_8line_en);
+ dcss_scaler_bit_depth_set(ch, pixel_depth);
+ dcss_scaler_set_rgb10_order(ch, format);
+ dcss_scaler_format_set(ch, src_format, dst_format);
+ dcss_scaler_res_set(ch, src_xres, src_yres, dst_xres, dst_yres,
+ pix_format, dst_format);
+
+ dcss_scaler_setup_path(ch, pix_format, dst_xres,
+ dst_yres, vrefresh_hz, use_wrscl);
+}
+
+/* This function will be called from interrupt context. */
+void dcss_scaler_write_sclctrl(struct dcss_scaler *scl)
+{
+ int chnum;
+
+ for (chnum = 0; chnum < 3; chnum++) {
+ struct dcss_scaler_ch *ch = &scl->ch[chnum];
+
+ if (ch->scaler_ctrl_chgd) {
+ dcss_ctxld_write_irqsafe(scl->ctxld, scl->ctx_id,
+ ch->scaler_ctrl,
+ ch->base_ofs +
+ DCSS_SCALER_CTRL);
+ ch->scaler_ctrl_chgd = false;
+ }
+ }
+}
diff --git a/drivers/gpu/drm/imx/dcss/dcss-ss.c b/drivers/gpu/drm/imx/dcss/dcss-ss.c
new file mode 100644
index 000000000000..39b27f0cde79
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/dcss-ss.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/device.h>
+
+#include "dcss-dev.h"
+
+#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)
+
+struct dcss_ss {
+ struct device *dev;
+ void __iomem *base_reg;
+ u32 base_ofs;
+
+ struct dcss_ctxld *ctxld;
+ u32 ctx_id;
+
+ bool in_use;
+};
+
+static void dcss_ss_write(struct dcss_ss *ss, u32 val, u32 ofs)
+{
+ if (!ss->in_use)
+ dcss_writel(val, ss->base_reg + ofs);
+
+ dcss_ctxld_write(ss->ctxld, ss->ctx_id, val,
+ ss->base_ofs + ofs);
+}
+
+int dcss_ss_init(struct dcss_dev *dcss, unsigned long ss_base)
+{
+ struct dcss_ss *ss;
+
+ ss = devm_kzalloc(dcss->dev, sizeof(*ss), GFP_KERNEL);
+ if (!ss)
+ return -ENOMEM;
+
+ dcss->ss = ss;
+ ss->dev = dcss->dev;
+ ss->ctxld = dcss->ctxld;
+
+ 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");
+ devm_kfree(ss->dev, ss);
+ return -ENOMEM;
+ }
+
+ ss->base_ofs = ss_base;
+ ss->ctx_id = CTX_SB_HP;
+
+ return 0;
+}
+
+void dcss_ss_exit(struct dcss_ss *ss)
+{
+ /* stop SS */
+ dcss_writel(0, ss->base_reg + DCSS_SS_SYS_CTRL);
+
+ if (ss->base_reg)
+ devm_iounmap(ss->dev, ss->base_reg);
+
+ devm_kfree(ss->dev, ss);
+}
+
+void dcss_ss_subsam_set(struct dcss_ss *ss, bool out_is_yuv)
+{
+ dcss_ss_write(ss, out_is_yuv ? 0x21612161 : 0x41614161, DCSS_SS_COEFF);
+ dcss_ss_write(ss, out_is_yuv ? 2 : 0, DCSS_SS_MODE);
+ dcss_ss_write(ss, 0x03ff0000, DCSS_SS_CLIP_CB);
+ dcss_ss_write(ss, 0x03ff0000, DCSS_SS_CLIP_CR);
+}
+
+void dcss_ss_sync_set(struct dcss_ss *ss, struct videomode *vm,
+ bool phsync, bool pvsync)
+{
+ 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) |
+ ((u32)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) |
+ ((u32)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 | ((u32)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);
+}
+
+void dcss_ss_enable(struct dcss_ss *ss)
+{
+ dcss_ss_write(ss, RUN_EN, DCSS_SS_SYS_CTRL);
+ ss->in_use = true;
+}
+
+void dcss_ss_disable(struct dcss_ss *ss)
+{
+ dcss_ss_write(ss, 0, DCSS_SS_SYS_CTRL);
+ ss->in_use = false;
+}
diff --git a/drivers/gpu/drm/imx/dcss/dcss-wrscl.c b/drivers/gpu/drm/imx/dcss/dcss-wrscl.c
new file mode 100644
index 000000000000..8228f8f46cae
--- /dev/null
+++ b/drivers/gpu/drm/imx/dcss/dcss-wrscl.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/seq_file.h>
+
+#include "dcss-dev.h"
+
+#define DCSS_WRSCL_CTRL_STATUS 0x00
+#define WRSCL_ERR BIT(31)
+#define WRSCL_ERR_EN BIT(30)
+#define WRSCL_FRAME_COMP BIT(29)
+#define WRSCL_FRAME_COMP_EN BIT(28)
+#define WRSCL_FIFO_SIZE_POS 18
+#define WRSCL_FIFO_SIZE_MASK GENMAK(24, 18)
+#define WRSCL_P_FREQ_POS 10
+#define WRSCL_P_FREQ_MASK GENMASK(17, 10)
+#define WRSCL_P_SIZE_POS 7
+#define WRSCL_P_SIZE_MASK GENMASK(9, 7)
+#define WRSCL_T_SIZE_POS 5
+#define WRSCL_T_SIZE_MASK GENMASK(6, 5)
+#define WRSCL_BPP_POS 2
+#define WRSCL_BPP_MASK GENMASK(4, 2)
+#define WRSCL_REPEAT BIT(1)
+#define WRSCL_ENABLE BIT(0)
+#define DCSS_WRSCL_BASE_ADDR 0x10
+#define DCSS_WRSCL_PITCH 0x14
+
+struct dcss_wrscl {
+ struct device *dev;
+
+ void __iomem *base_reg;
+ u32 base_ofs;
+
+ struct dcss_ctxld *ctxld;
+ u32 ctx_id;
+
+ u32 buf_size;
+ u32 buf_addr;
+ void *buf_vaddr;
+
+ struct clk *bclk;
+
+ u32 ctrl_status;
+};
+
+static void dcss_wrscl_write(struct dcss_wrscl *wrscl, u32 val, u32 ofs)
+{
+ dcss_ctxld_write(wrscl->ctxld, wrscl->ctx_id,
+ val, wrscl->base_ofs + ofs);
+}
+
+int dcss_wrscl_init(struct dcss_dev *dcss, unsigned long wrscl_base)
+{
+ struct dcss_wrscl *wrscl;
+
+ wrscl = devm_kzalloc(dcss->dev, sizeof(*wrscl), GFP_KERNEL);
+ if (!wrscl)
+ return -ENOMEM;
+
+ wrscl->base_reg = devm_ioremap(dcss->dev, wrscl_base, SZ_4K);
+ if (!wrscl->base_reg) {
+ dev_err(dcss->dev, "wrscl: unable to remap base\n");
+ devm_kfree(dcss->dev, wrscl);
+ return -ENOMEM;
+ }
+
+ dcss->wrscl = wrscl;
+
+ wrscl->dev = dcss->dev;
+ wrscl->base_ofs = wrscl_base;
+ wrscl->ctxld = dcss->ctxld;
+ wrscl->ctx_id = CTX_SB_HP;
+ wrscl->bclk = dcss->axi_clk;
+
+ return 0;
+}
+
+void dcss_wrscl_exit(struct dcss_wrscl *wrscl)
+{
+ devm_iounmap(wrscl->dev, wrscl->base_reg);
+ devm_kfree(wrscl->dev, wrscl);
+}
+
+static const u16 dcss_wrscl_psize_map[] = {64, 128, 256, 512, 1024, 2048, 4096};
+
+u32 dcss_wrscl_setup(struct dcss_wrscl *wrscl, u32 pix_format, u32 vrefresh_hz,
+ u32 dst_xres, u32 dst_yres)
+{
+ u32 pitch, p_size, p_freq, bpp;
+ dma_addr_t dma_handle;
+ u32 bclk_rate = clk_get_rate(wrscl->bclk);
+
+ /* we'd better release the old buffer */
+ if (wrscl->buf_addr)
+ dmam_free_coherent(wrscl->dev, wrscl->buf_size,
+ wrscl->buf_vaddr, wrscl->buf_addr);
+
+ p_size = PSIZE_256;
+
+ /* scaler output is YUV444 */
+ bpp = 4;
+
+ /* spread the load over the entire frame */
+ p_freq = ((u64)bclk_rate * dcss_wrscl_psize_map[p_size]) /
+ ((u64)dst_xres * dst_yres * vrefresh_hz * bpp * 8);
+
+ /* choose a slightly smaller p_freq */
+ p_freq = p_freq - 3 > 255 ? 255 : p_freq - 3;
+
+ wrscl->ctrl_status = FIFO_512 << WRSCL_FIFO_SIZE_POS;
+ wrscl->ctrl_status |= p_size << WRSCL_P_SIZE_POS;
+ wrscl->ctrl_status |= TSIZE_256 << WRSCL_T_SIZE_POS;
+ wrscl->ctrl_status |= BPP_32_10BIT_OUTPUT << WRSCL_BPP_POS;
+ wrscl->ctrl_status |= p_freq << WRSCL_P_FREQ_POS;
+
+ wrscl->buf_size = dst_xres * dst_yres * bpp;
+ pitch = dst_xres * bpp;
+
+ wrscl->buf_vaddr = dmam_alloc_coherent(wrscl->dev, wrscl->buf_size,
+ &dma_handle, GFP_KERNEL);
+ if (!wrscl->buf_vaddr) {
+ dev_err(wrscl->dev, "wrscl: cannot alloc buf mem\n");
+ return 0;
+ }
+
+ wrscl->buf_addr = dma_handle;
+
+ dcss_wrscl_write(wrscl, wrscl->buf_addr, DCSS_WRSCL_BASE_ADDR);
+ dcss_wrscl_write(wrscl, pitch, DCSS_WRSCL_PITCH);
+
+ return wrscl->buf_addr;
+}
+
+void dcss_wrscl_enable(struct dcss_wrscl *wrscl)
+{
+ wrscl->ctrl_status |= WRSCL_ENABLE | WRSCL_REPEAT;
+
+ dcss_wrscl_write(wrscl, wrscl->ctrl_status, DCSS_WRSCL_CTRL_STATUS);
+}
+
+void dcss_wrscl_disable(struct dcss_wrscl *wrscl)
+{
+ wrscl->ctrl_status &= ~(WRSCL_ENABLE | WRSCL_REPEAT);
+
+ dcss_wrscl_write(wrscl, wrscl->ctrl_status, DCSS_WRSCL_CTRL_STATUS);
+
+ if (wrscl->buf_addr) {
+ dmam_free_coherent(wrscl->dev, wrscl->buf_size,
+ wrscl->buf_vaddr, wrscl->buf_addr);
+ wrscl->buf_addr = 0;
+ }
+}
diff --git a/include/linux/busfreq-imx.h b/include/linux/busfreq-imx.h
new file mode 100644
index 000000000000..39c71a9f55eb
--- /dev/null
+++ b/include/linux/busfreq-imx.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2012-2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_MXC_BUSFREQ_H__
+#define __ASM_ARCH_MXC_BUSFREQ_H__
+
+#include <linux/notifier.h>
+#include <linux/regulator/consumer.h>
+
+/*
+ * This enumerates busfreq low power mode entry and exit.
+ */
+enum busfreq_event {
+ LOW_BUSFREQ_ENTER,
+ LOW_BUSFREQ_EXIT,
+};
+
+/*
+ * This enumerates the system bus and ddr frequencies in various modes.
+ * BUS_FREQ_HIGH - DDR @ 528MHz, AHB @ 132MHz.
+ * BUS_FREQ_MED - DDR @ 400MHz, AHB @ 132MHz
+ * BUS_FREQ_AUDIO - DDR @ 50MHz/100MHz, AHB @ 24MHz.
+ * BUS_FREQ_LOW - DDR @ 24MHz, AHB @ 24MHz.
+ * BUS_FREQ_ULTRA_LOW - DDR @ 1MHz, AHB - 3MHz.
+ *
+ * Drivers need to request/release the bus/ddr frequencies based on
+ * their performance requirements. Drivers cannot request/release
+ * BUS_FREQ_ULTRA_LOW mode as this mode is automatically entered from
+ * either BUS_FREQ_AUDIO or BUS_FREQ_LOW
+ * modes.
+ */
+enum bus_freq_mode {
+ BUS_FREQ_HIGH,
+ BUS_FREQ_MED,
+ BUS_FREQ_AUDIO,
+ BUS_FREQ_LOW,
+ BUS_FREQ_ULTRA_LOW,
+};
+
+#if defined(CONFIG_HAVE_IMX_BUSFREQ) && !defined(CONFIG_ARM64)
+extern struct regulator *arm_reg;
+extern struct regulator *soc_reg;
+void request_bus_freq(enum bus_freq_mode mode);
+void release_bus_freq(enum bus_freq_mode mode);
+int register_busfreq_notifier(struct notifier_block *nb);
+int unregister_busfreq_notifier(struct notifier_block *nb);
+int get_bus_freq_mode(void);
+#elif defined(CONFIG_HAVE_IMX_BUSFREQ)
+void request_bus_freq(enum bus_freq_mode mode);
+void release_bus_freq(enum bus_freq_mode mode);
+int get_bus_freq_mode(void);
+#else
+static inline void request_bus_freq(enum bus_freq_mode mode)
+{
+}
+static inline void release_bus_freq(enum bus_freq_mode mode)
+{
+}
+static inline int register_busfreq_notifier(struct notifier_block *nb)
+{
+ return 0;
+}
+static inline int unregister_busfreq_notifier(struct notifier_block *nb)
+{
+ return 0;
+}
+static inline int get_bus_freq_mode(void)
+{
+ return BUS_FREQ_HIGH;
+}
+#endif
+#endif