[COMMON] g2d: add skeleton driver
authorhyesoo.yu <hyesoo.yu@samsung.com>
Wed, 5 Apr 2017 13:15:16 +0000 (22:15 +0900)
committerSeungchul Kim <sc377.kim@samsung.com>
Mon, 28 May 2018 05:27:10 +0000 (14:27 +0900)
FIMG2D driver is just probed with the following initializations:
- A character device node is created under /dev/g2d
- SFR base is remapped and the interrupt handler is registered
- Runtime PM is enabled
- H/W Version is read
- IOMMU is attached

Change-Id: I7af02ef7013bdc90ee8750e4da3d44e01517d1c9
Signed-off-by: hyesoo.yu <hyesoo.yu@samsung.com>
Signed-off-by: Cho KyongHo <pullip.cho@samsung.com>
drivers/gpu/Makefile
drivers/gpu/exynos/Kconfig [new file with mode: 0644]
drivers/gpu/exynos/Makefile [new file with mode: 0644]
drivers/gpu/exynos/g2d/Kconfig [new file with mode: 0644]
drivers/gpu/exynos/g2d/Makefile [new file with mode: 0644]
drivers/gpu/exynos/g2d/g2d.h [new file with mode: 0644]
drivers/gpu/exynos/g2d/g2d_drv.c [new file with mode: 0644]
drivers/gpu/exynos/g2d/g2d_regs.h [new file with mode: 0644]
drivers/video/Kconfig

index 8bde693e7ab9b299fa75557ac37ccfb285ab17e5..a4040057fc9b833cf676c94e91d61c2dc3f0c2a9 100644 (file)
@@ -2,5 +2,5 @@
 # taken to initialize them in the correct order. Link order is the only way
 # to ensure this currently.
 obj-$(CONFIG_TEGRA_HOST1X)     += host1x/
-obj-y                  += arm/ drm/ vga/
+obj-y                  += arm/ drm/ vga/ exynos/
 obj-$(CONFIG_IMX_IPUV3_CORE)   += ipu-v3/
diff --git a/drivers/gpu/exynos/Kconfig b/drivers/gpu/exynos/Kconfig
new file mode 100644 (file)
index 0000000..e9bf19f
--- /dev/null
@@ -0,0 +1,3 @@
+menu "Exynos Graphic Devices"
+source "drivers/gpu/exynos/g2d/Kconfig"
+endmenu
diff --git a/drivers/gpu/exynos/Makefile b/drivers/gpu/exynos/Makefile
new file mode 100644 (file)
index 0000000..a00af4e
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_EXYNOS_GRAPHICS_G2D) += g2d/
diff --git a/drivers/gpu/exynos/g2d/Kconfig b/drivers/gpu/exynos/g2d/Kconfig
new file mode 100644 (file)
index 0000000..6d61bef
--- /dev/null
@@ -0,0 +1,4 @@
+config EXYNOS_GRAPHICS_G2D
+       bool "FIMG2D support"
+       help
+         This enables FIMG2D driver of Exynos SoCs.
diff --git a/drivers/gpu/exynos/g2d/Makefile b/drivers/gpu/exynos/g2d/Makefile
new file mode 100644 (file)
index 0000000..6d7a44c
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_EXYNOS_GRAPHICS_G2D) += g2d_drv.o
diff --git a/drivers/gpu/exynos/g2d/g2d.h b/drivers/gpu/exynos/g2d/g2d.h
new file mode 100644 (file)
index 0000000..39acfd5
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * linux/drivers/gpu/exynos/g2d/g2d.h
+ *
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Samsung Graphics 2D driver
+ *
+ * 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 __EXYNOS_G2D_H__
+#define __EXYNOS_G2D_H__
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+
+struct g2d_device {
+       struct miscdevice       misc;
+       struct device           *dev;
+       struct clk              *clock;
+       void __iomem            *reg;
+};
+
+struct g2d_context {
+       struct g2d_device       *g2d_dev;
+};
+
+#endif /* __EXYNOS_G2D_H__ */
diff --git a/drivers/gpu/exynos/g2d/g2d_drv.c b/drivers/gpu/exynos/g2d/g2d_drv.c
new file mode 100644 (file)
index 0000000..ea5352c
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * linux/drivers/gpu/exynos/g2d/g2d_drv.c
+ *
+ * Copyright (C) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Contact: Hyesoo Yu <hyesoo.yu@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/exynos_iovmm.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "g2d.h"
+#include "g2d_regs.h"
+
+#define MODULE_NAME "exynos-g2d"
+
+static irqreturn_t g2d_irq_handler(int irq, void *priv)
+{
+       return IRQ_HANDLED;
+}
+
+static __u32 get_hw_version(struct g2d_device *g2d_dev, __u32 *version)
+{
+       int ret;
+
+       ret = pm_runtime_get_sync(g2d_dev->dev);
+       if (ret < 0) {
+               dev_err(g2d_dev->dev, "Failed to enable power (%d)\n", ret);
+               return ret;
+       }
+
+       ret = clk_prepare_enable(g2d_dev->clock);
+       if (ret < 0) {
+               dev_err(g2d_dev->dev, "Failed to enable clock (%d)\n", ret);
+       } else {
+               *version = readl_relaxed(g2d_dev->reg + G2D_VERSION_INFO_REG);
+               clk_disable_unprepare(g2d_dev->clock);
+       }
+
+       pm_runtime_put(g2d_dev->dev);
+
+       return ret;
+}
+
+static int g2d_open(struct inode *inode, struct file *filp)
+{
+       struct g2d_device *g2d_dev = container_of(filp->private_data,
+                                                 struct g2d_device, misc);
+       struct g2d_context *g2d_ctx;
+
+       g2d_ctx = kzalloc(sizeof(*g2d_ctx), GFP_KERNEL);
+       if (!g2d_ctx)
+               return -ENOMEM;
+
+       filp->private_data = g2d_ctx;
+
+       g2d_ctx->g2d_dev = g2d_dev;
+
+       return 0;
+}
+
+static int g2d_release(struct inode *inode, struct file *filp)
+{
+       struct g2d_context *g2d_ctx = filp->private_data;
+
+       kfree(g2d_ctx);
+
+       return 0;
+}
+
+static long g2d_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+       return 0;
+}
+
+static long g2d_compat_ioctl(struct file *filp,
+                            unsigned int cmd, unsigned long arg)
+{
+       return 0;
+}
+
+static const struct file_operations g2d_fops = {
+       .owner          = THIS_MODULE,
+       .open           = g2d_open,
+       .release        = g2d_release,
+       .unlocked_ioctl = g2d_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = g2d_compat_ioctl,
+#endif
+};
+
+static int g2d_probe(struct platform_device *pdev)
+{
+       struct g2d_device *g2d_dev;
+       struct resource *res;
+       __u32 version;
+       int ret;
+
+       g2d_dev = devm_kzalloc(&pdev->dev, sizeof(*g2d_dev), GFP_KERNEL);
+       if (!g2d_dev)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, g2d_dev);
+       g2d_dev->dev = &pdev->dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       g2d_dev->reg = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(g2d_dev->reg))
+               return PTR_ERR(g2d_dev->reg);
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "Failed to get IRQ resource");
+               return -ENOENT;
+       }
+
+       ret = devm_request_irq(&pdev->dev, res->start,
+                              g2d_irq_handler, 0, pdev->name, g2d_dev);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to install IRQ handler");
+               return ret;
+       }
+
+       g2d_dev->clock = devm_clk_get(&pdev->dev, "gate");
+       if (IS_ERR(g2d_dev->clock)) {
+               dev_err(&pdev->dev, "Failed to get clock (%ld)\n",
+                                       PTR_ERR(g2d_dev->clock));
+               return PTR_ERR(g2d_dev->clock);
+       }
+
+       ret = iovmm_activate(&pdev->dev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to activate iommu\n");
+               return ret;
+       }
+
+       /* prepare clock and enable runtime pm */
+       pm_runtime_enable(&pdev->dev);
+
+       ret = get_hw_version(g2d_dev, &version);
+       if (ret < 0)
+               goto err;
+
+       g2d_dev->misc.minor = MISC_DYNAMIC_MINOR;
+       g2d_dev->misc.name = "g2d";
+       g2d_dev->misc.fops = &g2d_fops;
+
+       /* misc register */
+       ret = misc_register(&g2d_dev->misc);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to register misc device");
+               goto err;
+       }
+
+       dev_info(&pdev->dev, "Probed FIMG2D version %#010x\n", version);
+
+       return 0;
+err:
+       pm_runtime_disable(&pdev->dev);
+       iovmm_deactivate(g2d_dev->dev);
+
+       dev_err(&pdev->dev, "Failed to probe FIMG2D\n");
+
+       return ret;
+}
+
+static int g2d_remove(struct platform_device *pdev)
+{
+       struct g2d_device *g2d_dev = platform_get_drvdata(pdev);
+
+       misc_deregister(&g2d_dev->misc);
+
+       pm_runtime_disable(&pdev->dev);
+
+       iovmm_deactivate(g2d_dev->dev);
+
+       return 0;
+}
+
+static const struct of_device_id of_g2d_match[] = {
+       {
+               .compatible = "samsung,exynos9810-g2d",
+       },
+       {},
+};
+
+static struct platform_driver g2d_driver = {
+       .probe          = g2d_probe,
+       .remove         = g2d_remove,
+       .driver = {
+               .name   = MODULE_NAME,
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(of_g2d_match),
+       }
+};
+
+module_platform_driver(g2d_driver);
diff --git a/drivers/gpu/exynos/g2d/g2d_regs.h b/drivers/gpu/exynos/g2d/g2d_regs.h
new file mode 100644 (file)
index 0000000..869f797
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * linux/drivers/gpu/exynos/g2d/g2d_regs.h
+ *
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Register Definitions for Samsung Graphics 2D Hardware
+ *
+ * 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 __G2D_REGS_H__
+#define __G2D_REGS_H__
+
+/* General Registers */
+#define G2D_SOFT_RESET_REG                     0x000
+#define G2D_INTEN_REG                          0x004
+#define G2D_INTC_PEND_REG                      0x00c
+#define G2D_FIFO_STAT_REG                      0x010
+#define G2D_VERSION_INFO_REG                   0x014
+#define G2D_AXI_MODE_REG                       0x01c
+#define G2D_COMP_DEBUG_ADDR_REG                        0x0f0
+#define G2D_COMP_DEBUG_DATA_REG                        0x0f4
+
+/* Job Manager Registers */
+#define G2D_JOB_INT_ID_REG                     0x09C
+#define G2D_JOB_HEADER_REG                     0x080
+#define G2D_JOB_BASEADDR_REG                   0x084
+#define G2D_JOB_SFRNUM_REG                     0x088
+#define G2D_JOB_PUSH_REG                       0x08C
+#define G2D_JOB_KILL_REG                       0x090
+#define G2D_JOB_PUSHKILL_STATE_REG             0x094
+#define G2D_JOB_EMPTYSLOT_NUM_REG              0x098
+#define G2D_JOB_ID_REG                         0x009
+#define G2D_JOB_ID0_STATE_REG                  0x0A0
+#define G2D_JOB_IDn_STATE_REG(n)       (G2D_JOB_ID0_STATE_REG + ((n) * 0x4))
+
+/* G2D command Registers */
+#define G2D_BITBLT_START_REG                   0x100
+#define G2D_BITBLT_COMMAND_REG                 0x104
+#define G2D_LAYER_UPDATE_REG                   0x108
+
+/* HWFC related Registers */
+#define G2D_HWFC_CAPTURE_IDX_REG               0x8000
+#define G2D_HWFC_ENCODING_IDX_REG              0x8004
+
+/* Fields of G2D_INTEN_REG */
+#define G2D_BLIT_INT_ENABLE                    ((1 << 0) | (7 << 16))
+#define G2D_ERR_INT_ENABLE                     (7 << 16)
+
+/* Fields of G2D_INTC_PEND_REG */
+#define G2D_BLIT_INT_FLAG                      ((1 << 0) | (7 << 16))
+#define G2D_ERR_INT_FLAG                       (7 << 16)
+
+/* Fields of G2D_BITBLT_START_REG */
+#define G2D_START_BITBLT                       (1 << 0)
+
+/* Fields of G2D_JOB_HEADER_REG */
+#define G2D_JOB_HEADER_DATA(p, id)     ((((p) & 0x3) << 4) | ((id) & 0xF))
+
+/* Fields of G2D_JOB_PUSH_REG */
+#define G2D_JOBPUSH_INT_ENABLE                 0x1
+
+/* Fields of G2D_JOB_IDn_STATE_REG */
+#define G2D_JOB_STATE_DONE                     0x0
+#define G2D_JOB_STATE_QUEUEING                 0x1
+#define G2D_JOB_STATE_SUSPENDING               0x2
+#define G2D_JOB_STATE_RUNNING                  0x3
+#define G2D_JOB_STATE_MASK                     0x3
+
+/* Fields of G2D_SOFT_RESET_REG */
+#define G2D_SFR_CLEAR                          (1 << 2)
+#define G2D_GLOBAL_RESET                       (1 << 1)
+#define G2D_SOFT_RESET                         (1 << 0)
+
+#endif /* __G2D_REGS_H__ */
index 4ee8298ad15d5f769c2ba27d3a792ca018b962d1..e09abbcc74da11576db629e38b5e9905b76b5e77 100644 (file)
@@ -22,6 +22,8 @@ source "drivers/gpu/ipu-v3/Kconfig"
 
 source "drivers/gpu/drm/Kconfig"
 
+source "drivers/gpu/exynos/Kconfig"
+
 menu "Frame buffer Devices"
 source "drivers/video/fbdev/Kconfig"
 endmenu