summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLiu Ying <victor.liu@nxp.com>2017-07-03 11:35:52 +0800
committerLeonard Crestez <leonard.crestez@nxp.com>2018-08-24 12:41:33 +0300
commitc242e43f8874501d861bfa34810ddd9a6fd4beb6 (patch)
tree04e8090c82e3d18a945ba1fc6d1baaec01fea3ca
parentfd9ae9865ca1f4bfaceded890131fb5b602fe3f8 (diff)
MLK-15110-2 gpu: imx: Add i.MX8 PRG(Prefetch Resolve Gasket) support
The Pretch Resolve Gasket(PRG) is a digital core function as a gasket interface between RTRAM controller and DPU. The main function of PRG is to convert the AXI interface to RTRAM interface and remapping the ARADDR to a RTRAM address. This patch adds the base driver support for i.MX8qm/qxp PRG. Signed-off-by: Liu Ying <victor.liu@nxp.com>
-rw-r--r--Documentation/devicetree/bindings/display/imx/fsl-imx-drm.txt23
-rw-r--r--drivers/gpu/imx/Kconfig5
-rw-r--r--drivers/gpu/imx/Makefile2
-rw-r--r--drivers/gpu/imx/imx8_prg.c380
-rw-r--r--include/video/imx8-prefetch.h46
5 files changed, 456 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/display/imx/fsl-imx-drm.txt b/Documentation/devicetree/bindings/display/imx/fsl-imx-drm.txt
index 6a5c927ecbb6..da728cc81af4 100644
--- a/Documentation/devicetree/bindings/display/imx/fsl-imx-drm.txt
+++ b/Documentation/devicetree/bindings/display/imx/fsl-imx-drm.txt
@@ -190,6 +190,29 @@ dcss_drm: dcss@0x32e00000 {
};
};
+Freescale i.MX8 PRG (Prefetch Resolve Gasket)
+=============================================
+Required properties:
+- compatible: should be "fsl,<chip>-prg"
+- reg: should be register base and length as documented in the
+ datasheet
+- clocks: phandles to the PRG apb and rtram clocks, as described in
+ Documentation/devicetree/bindings/clock/clock-bindings.txt,
+ Documentation/devicetree/bindings/clock/imx8qm-clock.txt and
+ Documentation/devicetree/bindings/clock/imx8qxp-clock.txt
+- clock-names: should be "apb" and "rtram"
+- power-domains: phandle pointing to power domain
+
+example:
+
+prg@56040000 {
+ compatible = "fsl,imx8qm-prg";
+ reg = <0x0 0x56040000 0x0 0x10000>;
+ clocks = <&clk IMX8QM_DC0_PRG0_APB_CLK>,
+ <&clk IMX8QM_DC0_PRG0_RTRAM_CLK>;
+ clock-names = "apb", "rtram";
+ power-domains = <&pd_dc0>;
+};
Parallel display support
========================
diff --git a/drivers/gpu/imx/Kconfig b/drivers/gpu/imx/Kconfig
index 9b1e9502ecdd..a94160290d68 100644
--- a/drivers/gpu/imx/Kconfig
+++ b/drivers/gpu/imx/Kconfig
@@ -1,3 +1,8 @@
+config IMX8_PRG
+ tristate
+ default y if IMX_DPU_CORE=y
+ default m if IMX_DPU_CORE=m
+
source drivers/gpu/imx/ipu-v3/Kconfig
source drivers/gpu/imx/dpu/Kconfig
source drivers/gpu/imx/dpu-blit/Kconfig
diff --git a/drivers/gpu/imx/Makefile b/drivers/gpu/imx/Makefile
index d3062986cbdc..fd3cb4757cb8 100644
--- a/drivers/gpu/imx/Makefile
+++ b/drivers/gpu/imx/Makefile
@@ -1,3 +1,5 @@
+obj-$(CONFIG_IMX8_PRG) += imx8_prg.o
+
obj-$(CONFIG_IMX_IPUV3_CORE) += ipu-v3/
obj-$(CONFIG_IMX_DPU_CORE) += dpu/
obj-$(CONFIG_IMX_DPU_BLIT) += dpu-blit/
diff --git a/drivers/gpu/imx/imx8_prg.c b/drivers/gpu/imx/imx8_prg.c
new file mode 100644
index 000000000000..8f2c98cee030
--- /dev/null
+++ b/drivers/gpu/imx/imx8_prg.c
@@ -0,0 +1,380 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+#include <drm/drm_fourcc.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <video/imx8-prefetch.h>
+
+#define SET 0x4
+#define CLR 0x8
+#define TOG 0xc
+
+#define PRG_CTRL 0x00
+#define BYPASS BIT(0)
+#define SC_DATA_TYPE BIT(2)
+#define SC_DATA_TYPE_8BIT 0
+#define SC_DATA_TYPE_10BIT BIT(2)
+#define UV_EN BIT(3)
+#define HANDSHAKE_MODE BIT(4)
+#define HANDSHAKE_MODE_4LINES 0
+#define HANDSHAKE_MODE_8LINES BIT(4)
+#define SHADOW_LOAD_MODE BIT(5)
+#define DES_DATA_TYPE 0x30000
+enum {
+ DES_DATA_TYPE_32BPP = (0 << 16),
+ DES_DATA_TYPE_24BPP = (1 << 16),
+ DES_DATA_TYPE_16BPP = (2 << 16),
+ DES_DATA_TYPE_8BPP = (3 << 16),
+};
+#define SOFTRST BIT(30)
+#define SHADOW_EN BIT(31)
+
+#define PRG_STATUS 0x10
+#define BUFFER_VALID_B BIT(1)
+#define BUFFER_VALID_A BIT(0)
+
+#define PRG_REG_UPDATE 0x20
+#define REG_UPDATE BIT(0)
+
+#define PRG_STRIDE 0x30
+#define STRIDE(n) (((n) - 1) & 0xffff)
+
+#define PRG_HEIGHT 0x40
+#define HEIGHT(n) (((n) - 1) & 0xffff)
+
+#define PRG_BADDR 0x50
+
+#define PRG_OFFSET 0x60
+#define Y(n) (((n) & 0x7) << 16)
+#define X(n) ((n) & 0xffff)
+
+#define PRG_WIDTH 0x70
+#define WIDTH(n) (((n) - 1) & 0xffff)
+
+struct prg {
+ struct device *dev;
+ void __iomem *base;
+ struct list_head list;
+ struct clk *clk_apb;
+ struct clk *clk_rtram;
+ bool is_auxiliary;
+};
+
+static DEFINE_MUTEX(prg_list_mutex);
+static LIST_HEAD(prg_list);
+
+static inline u32 prg_read(struct prg *prg, unsigned int offset)
+{
+ return readl(prg->base + offset);
+}
+
+static inline void prg_write(struct prg *prg, u32 value, unsigned int offset)
+{
+ writel(value, prg->base + offset);
+}
+
+static void prg_reset(struct prg *prg)
+{
+ prg_write(prg, SOFTRST, PRG_CTRL + SET);
+ usleep_range(1000, 2000);
+ prg_write(prg, SOFTRST, PRG_CTRL + CLR);
+}
+
+void prg_enable(struct prg *prg)
+{
+ if (WARN_ON(!prg))
+ return;
+
+ prg_write(prg, BYPASS, PRG_CTRL + CLR);
+}
+EXPORT_SYMBOL_GPL(prg_enable);
+
+void prg_disable(struct prg *prg)
+{
+ if (WARN_ON(!prg))
+ return;
+
+ prg_write(prg, BYPASS, PRG_CTRL);
+}
+EXPORT_SYMBOL_GPL(prg_disable);
+
+void prg_configure(struct prg *prg, unsigned int width, unsigned int height,
+ unsigned int x_offset, unsigned int y_offset,
+ unsigned int stride, unsigned int bits_per_pixel,
+ unsigned long baddr, u32 format, u64 modifier,
+ bool start)
+{
+ unsigned int burst_size;
+ u32 val;
+
+ if (WARN_ON(!prg))
+ return;
+
+ if (start)
+ prg_reset(prg);
+
+ /*
+ * address TKT343664:
+ * fetch unit base address has to align to burst_size
+ */
+ burst_size = 1 << (ffs(baddr) - 1);
+ burst_size = min(burst_size, 128U);
+
+ /*
+ * address TKT339017:
+ * fixup for burst size vs stride mismatch
+ */
+ stride = round_up(stride, burst_size);
+
+ /*
+ * address TKT342628(part 1):
+ * when prg stride is less or equals to burst size,
+ * the auxiliary prg height needs to be a half
+ */
+ if (prg->is_auxiliary && stride <= burst_size)
+ height /= 2;
+
+ /* prg finer cropping into tile block - top/left start point */
+ switch (modifier) {
+ case DRM_FORMAT_MOD_NONE:
+ break;
+ case DRM_FORMAT_MOD_AMPHION_TILED:
+ x_offset %= AMPHION_STRIPE_WIDTH;
+ y_offset %= (prg->is_auxiliary ?
+ AMPHION_UV_STRIPE_HEIGHT : AMPHION_Y_STRIPE_HEIGHT);
+ break;
+ case DRM_FORMAT_MOD_VIVANTE_TILED:
+ x_offset %= VIVANTE_TILE_WIDTH;
+ y_offset %= VIVANTE_TILE_HEIGHT;
+ break;
+ case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
+ x_offset %= VIVANTE_SUPER_TILE_WIDTH;
+ y_offset %= VIVANTE_SUPER_TILE_HEIGHT;
+ break;
+ default:
+ dev_err(prg->dev, "unsupported modifier 0x%016llx\n",
+ modifier);
+ return;
+ }
+
+ if (y_offset >
+ ((format == DRM_FORMAT_NV21 || format == DRM_FORMAT_NV12) ?
+ (PRG_HANDSHAKE_8LINES - 1) : (PRG_HANDSHAKE_4LINES - 1))) {
+ dev_err(prg->dev,
+ "unsupported crop line %d for modifier 0x%016llx\n",
+ y_offset, modifier);
+ return;
+ }
+
+ prg_write(prg, STRIDE(stride), PRG_STRIDE);
+ prg_write(prg, WIDTH(width), PRG_WIDTH);
+ prg_write(prg, HEIGHT(height), PRG_HEIGHT);
+ prg_write(prg, X(x_offset) | Y(y_offset), PRG_OFFSET);
+ prg_write(prg, baddr, PRG_BADDR);
+
+ val = prg_read(prg, PRG_CTRL);
+ val &= ~SC_DATA_TYPE;
+ val |= SC_DATA_TYPE_8BIT;
+ val &= ~HANDSHAKE_MODE;
+ if (format == DRM_FORMAT_NV21 || format == DRM_FORMAT_NV12) {
+ val |= HANDSHAKE_MODE_8LINES;
+ /*
+ * address TKT342628(part 2):
+ * when prg stride is less or equals to burst size,
+ * we disable UV_EN bit for the auxiliary prg
+ */
+ if (prg->is_auxiliary && stride > burst_size)
+ val |= UV_EN;
+ else
+ val &= ~UV_EN;
+ } else {
+ val |= HANDSHAKE_MODE_4LINES;
+ val &= ~UV_EN;
+ }
+ val |= SHADOW_LOAD_MODE;
+ val &= ~DES_DATA_TYPE;
+ switch (bits_per_pixel) {
+ case 32:
+ val |= DES_DATA_TYPE_32BPP;
+ break;
+ case 24:
+ val |= DES_DATA_TYPE_24BPP;
+ break;
+ case 16:
+ val |= DES_DATA_TYPE_16BPP;
+ break;
+ case 8:
+ val |= DES_DATA_TYPE_8BPP;
+ break;
+ }
+ if (start)
+ /* no shadow for the first frame */
+ val &= ~SHADOW_EN;
+ else
+ val |= SHADOW_EN;
+ prg_write(prg, val, PRG_CTRL);
+
+ dev_dbg(prg->dev, "bits per pixel %u\n", bits_per_pixel);
+}
+EXPORT_SYMBOL_GPL(prg_configure);
+
+void prg_reg_update(struct prg *prg)
+{
+ if (WARN_ON(!prg))
+ return;
+
+ prg_write(prg, REG_UPDATE, PRG_REG_UPDATE);
+}
+EXPORT_SYMBOL_GPL(prg_reg_update);
+
+void prg_shadow_enable(struct prg *prg)
+{
+ if (WARN_ON(!prg))
+ return;
+
+ prg_write(prg, SHADOW_EN, PRG_CTRL + SET);
+}
+EXPORT_SYMBOL_GPL(prg_shadow_enable);
+
+bool prg_stride_supported(struct prg *prg, unsigned int stride)
+{
+ return stride < 0x10000;
+}
+EXPORT_SYMBOL_GPL(prg_stride_supported);
+
+bool prg_stride_double_check(struct prg *prg,
+ unsigned int stride, dma_addr_t baddr)
+{
+ unsigned int burst_size;
+
+ /*
+ * address TKT343664:
+ * fetch unit base address has to align to burst size
+ */
+ burst_size = 1 << (ffs(baddr) - 1);
+ burst_size = min(burst_size, 128U);
+
+ /*
+ * address TKT339017:
+ * fixup for burst size vs stride mismatch
+ */
+ stride = round_up(stride, burst_size);
+
+ return stride < 0x10000;
+}
+EXPORT_SYMBOL_GPL(prg_stride_double_check);
+
+void prg_set_auxiliary(struct prg *prg)
+{
+ if (WARN_ON(!prg))
+ return;
+
+ prg->is_auxiliary = true;
+}
+EXPORT_SYMBOL_GPL(prg_set_auxiliary);
+
+struct prg *
+prg_lookup_by_phandle(struct device *dev, const char *name, int index)
+{
+ struct device_node *prg_node = of_parse_phandle(dev->of_node,
+ name, index);
+ struct prg *prg;
+
+ mutex_lock(&prg_list_mutex);
+ list_for_each_entry(prg, &prg_list, list) {
+ if (prg_node == prg->dev->of_node) {
+ mutex_unlock(&prg_list_mutex);
+ device_link_add(dev, prg->dev, DL_FLAG_AUTOREMOVE);
+ return prg;
+ }
+ }
+ mutex_unlock(&prg_list_mutex);
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(prg_lookup_by_phandle);
+
+static int prg_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ struct prg *prg;
+
+ prg = devm_kzalloc(dev, sizeof(*prg), GFP_KERNEL);
+ if (!prg)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ prg->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(prg->base))
+ return PTR_ERR(prg->base);
+
+ prg->clk_apb = devm_clk_get(dev, "apb");
+ if (IS_ERR(prg->clk_apb))
+ return PTR_ERR(prg->clk_apb);
+ clk_prepare_enable(prg->clk_apb);
+
+ prg->clk_rtram = devm_clk_get(dev, "rtram");
+ if (IS_ERR(prg->clk_rtram))
+ return PTR_ERR(prg->clk_rtram);
+ clk_prepare_enable(prg->clk_rtram);
+
+ prg->dev = dev;
+ platform_set_drvdata(pdev, prg);
+ mutex_lock(&prg_list_mutex);
+ list_add(&prg->list, &prg_list);
+ mutex_unlock(&prg_list_mutex);
+
+ prg_reset(prg);
+
+ return 0;
+}
+
+static int prg_remove(struct platform_device *pdev)
+{
+ struct prg *prg = platform_get_drvdata(pdev);
+
+ mutex_lock(&prg_list_mutex);
+ list_del(&prg->list);
+ mutex_unlock(&prg_list_mutex);
+
+ clk_disable_unprepare(prg->clk_rtram);
+ clk_disable_unprepare(prg->clk_apb);
+
+ return 0;
+}
+
+static const struct of_device_id prg_dt_ids[] = {
+ { .compatible = "fsl,imx8qm-prg", },
+ { .compatible = "fsl,imx8qxp-prg", },
+ { /* sentinel */ },
+};
+
+struct platform_driver prg_drv = {
+ .probe = prg_probe,
+ .remove = prg_remove,
+ .driver = {
+ .name = "imx8-prg",
+ .of_match_table = prg_dt_ids,
+ },
+};
+module_platform_driver(prg_drv);
+
+MODULE_DESCRIPTION("i.MX8 PRG driver");
+MODULE_AUTHOR("NXP Semiconductor");
+MODULE_LICENSE("GPL");
diff --git a/include/video/imx8-prefetch.h b/include/video/imx8-prefetch.h
new file mode 100644
index 000000000000..52ab319b04ea
--- /dev/null
+++ b/include/video/imx8-prefetch.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef _IMX8_PREFETCH_H_
+#define _IMX8_PREFETCH_H_
+
+#define PRG_HANDSHAKE_8LINES 8
+#define PRG_HANDSHAKE_4LINES 4
+#define AMPHION_STRIPE_WIDTH 8
+#define AMPHION_STRIPE_HEIGHT 128
+#define AMPHION_UV_STRIPE_HEIGHT AMPHION_STRIPE_HEIGHT
+#define AMPHION_Y_STRIPE_HEIGHT (2 * AMPHION_STRIPE_HEIGHT)
+#define VIVANTE_TILE_WIDTH 4
+#define VIVANTE_TILE_HEIGHT 4
+#define VIVANTE_SUPER_TILE_WIDTH 64
+#define VIVANTE_SUPER_TILE_HEIGHT 64
+
+struct prg;
+struct prg *
+prg_lookup_by_phandle(struct device *dev, const char *name, int index);
+void prg_enable(struct prg *prg);
+void prg_disable(struct prg *prg);
+void prg_configure(struct prg *prg, unsigned int width, unsigned int height,
+ unsigned int x_offset, unsigned int y_offset,
+ unsigned int stride, unsigned int bits_per_pixel,
+ unsigned long baddr, u32 format, u64 modifier,
+ bool start);
+void prg_reg_update(struct prg *prg);
+void prg_shadow_enable(struct prg *prg);
+bool prg_stride_supported(struct prg *prg, unsigned int stride);
+bool prg_stride_double_check(struct prg *prg,
+ unsigned int stride, dma_addr_t baddr);
+void prg_set_auxiliary(struct prg *prg);
+
+#endif