This patch creates this driver itself and register all the sub-components
which is from DTS inode, this driver uses components framework mechanism
to bind all the sub-components.

This patch also introduces a memory manager for hisilison drm. As cma
framebuffer helpers can no more be used.

Signed-off-by: Xinliang Liu <xinliang.liu at linaro.org>
Signed-off-by: Xinwei Kong <kong.kongxinwei at hisilicon.com>
Signed-off-by: Andy Green <andy.green at linaro.org>
Signed-off-by: Jiwen Qi <qijiwen at hisilicon.com>
Signed-off-by: Yu Gong <gongyu at hisilicon.com>
---
 arch/arm64/configs/defconfig             |   5 +
 drivers/gpu/drm/Kconfig                  |   2 +
 drivers/gpu/drm/Makefile                 |   1 +
 drivers/gpu/drm/hisilicon/Kconfig        |   9 ++
 drivers/gpu/drm/hisilicon/Makefile       |   7 ++
 drivers/gpu/drm/hisilicon/hisi_ade.c     | 166 +++++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 206 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hisi_drm_dsi.c | 131 ++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hisi_drm_fb.c  | 156 +++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hisi_drm_fb.h  |  26 ++++
 10 files changed, 709 insertions(+)
 create mode 100644 drivers/gpu/drm/hisilicon/Kconfig
 create mode 100644 drivers/gpu/drm/hisilicon/Makefile
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_ade.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_drv.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_fb.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_fb.h

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 4e17e7e..c2ea280 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -146,6 +146,8 @@ CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_SYSCON=y
 CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+
+
 CONFIG_LEDS_TRIGGER_CPU=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_EFI=y
@@ -199,3 +201,6 @@ CONFIG_CRYPTO_GHASH_ARM64_CE=y
 CONFIG_CRYPTO_AES_ARM64_CE_CCM=y
 CONFIG_CRYPTO_AES_ARM64_CE_BLK=y
 CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y
+CONFIG_DRM=y
+CONFIG_DRM_HISI=y
+# CONFIG_DRM_HISI_FBDEV is not set
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index c46ca31..31ee120 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -240,3 +240,5 @@ source "drivers/gpu/drm/sti/Kconfig"
 source "drivers/gpu/drm/amd/amdkfd/Kconfig"

 source "drivers/gpu/drm/imx/Kconfig"
+
+source "drivers/gpu/drm/hisilicon/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 5713d05..47936d4 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_DRM_MSM) += msm/
 obj-$(CONFIG_DRM_TEGRA) += tegra/
 obj-$(CONFIG_DRM_STI) += sti/
 obj-$(CONFIG_DRM_IMX) += imx/
+obj-$(CONFIG_DRM_HISI) += hisilicon/
 obj-y                  += i2c/
 obj-y                  += panel/
 obj-y                  += bridge/
diff --git a/drivers/gpu/drm/hisilicon/Kconfig 
b/drivers/gpu/drm/hisilicon/Kconfig
new file mode 100644
index 0000000..60b42e4
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/Kconfig
@@ -0,0 +1,9 @@
+config DRM_HISI
+       tristate "DRM Support for Hisilicon Terminal SoCs Platform"
+       depends on DRM
+       select DRM_KMS_HELPER
+       select DRM_GEM_CMA_HELPER
+       help
+         Choose this option if you have a hisilicon terminal chipset.
+         If M is selected the module will be called hisi-drm.
+
diff --git a/drivers/gpu/drm/hisilicon/Makefile 
b/drivers/gpu/drm/hisilicon/Makefile
new file mode 100644
index 0000000..3f042fd
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/Makefile
@@ -0,0 +1,7 @@
+hisi-drm-y := hisi_drm_drv.o \
+             hisi_ade.o \
+             hisi_drm_dsi.o \
+             hisi_drm_fb.o \
+
+obj-$(CONFIG_DRM_HISI) += hisi-drm.o
+
diff --git a/drivers/gpu/drm/hisilicon/hisi_ade.c 
b/drivers/gpu/drm/hisilicon/hisi_ade.c
new file mode 100644
index 0000000..9b58d20
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_ade.c
@@ -0,0 +1,166 @@
+/*
+ * Hisilicon Terminal SoCs drm driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author: Xinwei Kong <kong.kongxinwei at hisilicon.com> for hisilicon
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/component.h>
+
+#include <drm/drm_gem_cma_helper.h>
+
+struct ade_hardware_context {
+       void __iomem  *base;
+       void __iomem  *media_base;
+
+       int irq;
+       u32 ade_core_rate;
+       u32 media_noc_rate;
+
+       struct clk *ade_core_clk;
+       struct clk *media_noc_clk;
+       struct clk *ade_pix_clk;
+       bool power_on;
+};
+
+struct hisi_ade {
+       struct ade_hardware_context ctx;
+};
+
+static int ade_dts_parse(struct platform_device *pdev,
+                        struct ade_hardware_context *ctx)
+{
+       struct resource *res;
+       struct device *dev;
+       struct device_node *np;
+       int ret;
+
+       dev = &pdev->dev;
+       np  = dev->of_node;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ade_base");
+       ctx->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(ctx->base)) {
+               DRM_ERROR("failed to remap ade io base\n");
+               return  PTR_ERR(ctx->base);
+       }
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "media_base");
+       ctx->media_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(ctx->media_base)) {
+               DRM_ERROR("failed to remap media io base\n");
+               return PTR_ERR(ctx->media_base);
+       }
+
+       ctx->irq = platform_get_irq(pdev, 0);
+       if (ctx->irq < 0) {
+               DRM_ERROR("failed to parse the irq\n");
+               return -ENODEV;
+       }
+
+       ctx->ade_core_clk = devm_clk_get(&pdev->dev, "clk_ade_core");
+       if (!ctx->ade_core_clk) {
+               DRM_ERROR("failed to parse the ade core clock\n");
+               return -ENODEV;
+       }
+       ctx->media_noc_clk = devm_clk_get(&pdev->dev,
+                                       "aclk_codec_jpeg_src");
+       if (!ctx->media_noc_clk) {
+               DRM_ERROR("failed to parse the codec jpeg\n");
+           return -ENODEV;
+       }
+       ctx->ade_pix_clk = devm_clk_get(&pdev->dev, "clk_ade_pix");
+       if (!ctx->ade_pix_clk) {
+               DRM_ERROR("failed to parse the ade pixel src\n");
+           return -ENODEV;
+       }
+
+       ret = of_property_read_u32(np, "ade_core_clk_rate",
+                                  &ctx->ade_core_rate);
+       if (ret) {
+               DRM_ERROR("failed to parse the ade core clk rate\n");
+           return -ENODEV;
+       }
+       ret = of_property_read_u32(np, "media_noc_clk_rate",
+                                  &ctx->media_noc_rate);
+       if (ret) {
+               DRM_ERROR("failed to parse the media noc clk rate\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int ade_bind(struct device *dev, struct device *master, void *data)
+{
+       return 0;
+}
+
+static void ade_unbind(struct device *dev, struct device *master,
+                      void *data)
+{
+       /* do nothing */
+}
+
+static const struct component_ops ade_ops = {
+       .bind   = ade_bind,
+       .unbind = ade_unbind,
+};
+
+static int ade_probe(struct platform_device *pdev)
+{
+       struct hisi_ade *ade;
+       int ret;
+
+       ade = devm_kzalloc(&pdev->dev, sizeof(*ade), GFP_KERNEL);
+       if (!ade) {
+               DRM_ERROR("failed to alloc hisi_ade\n");
+               return -ENOMEM;
+       }
+
+       ret = ade_dts_parse(pdev, &ade->ctx);
+       if (ret) {
+               DRM_ERROR("failed to parse ade dts!\n");
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, ade);
+
+       return component_add(&pdev->dev, &ade_ops);
+}
+
+static int ade_remove(struct platform_device *pdev)
+{
+       component_del(&pdev->dev, &ade_ops);
+
+       return 0;
+}
+
+static const struct of_device_id ade_of_match[] = {
+       { .compatible = "hisilicon,hi6220-ade" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, ade_of_match);
+
+static struct platform_driver ade_driver = {
+       .probe = ade_probe,
+       .remove = ade_remove,
+       .driver = {
+                  .name = "hisi-ade",
+                  .owner = THIS_MODULE,
+                  .of_match_table = ade_of_match,
+       },
+};
+
+module_platform_driver(ade_driver);
+
+MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei at hisilicon.com>");
+MODULE_AUTHOR("Xinliang Liu <z.liuxinliang at huawei.com>");
+MODULE_DESCRIPTION("hisilicon SoC DRM driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c 
b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
new file mode 100644
index 0000000..0983ad7
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
@@ -0,0 +1,206 @@
+/*
+ * Hisilicon Terminal SoCs drm driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author: Xinwei Kong <kong.kongxinwei at hisilicon.com> for hisilicon
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/of_platform.h>
+#include <linux/component.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+
+#include "hisi_drm_fb.h"
+
+#define DRIVER_NAME    "hisi-drm"
+
+static int hisi_drm_unload(struct drm_device *dev)
+{
+       drm_vblank_cleanup(dev);
+       drm_mode_config_cleanup(dev);
+       dev->dev_private = NULL;
+
+       return 0;
+}
+
+static const struct drm_mode_config_funcs hisi_drm_mode_config_funcs = {
+       .fb_create = hisi_drm_fb_create,
+       .atomic_check = drm_atomic_helper_check,
+       .atomic_commit = drm_atomic_helper_commit,
+};
+
+static void hisi_drm_mode_config_init(struct drm_device *dev)
+{
+       dev->mode_config.min_width = 0;
+       dev->mode_config.min_height = 0;
+
+       dev->mode_config.max_width = 2048;
+       dev->mode_config.max_height = 2048;
+
+       dev->mode_config.funcs = &hisi_drm_mode_config_funcs;
+}
+
+static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
+{
+       int ret;
+
+       /* debug setting
+       drm_debug = DRM_UT_DRIVER|DRM_UT_KMS; */
+
+       /* dev->mode_config initialization */
+       drm_mode_config_init(dev);
+       hisi_drm_mode_config_init(dev);
+
+       /* only support one crtc now */
+       ret = drm_vblank_init(dev, 1);
+       if (ret)
+               goto out_err;
+
+       ret = component_bind_all(dev->dev, dev);
+       if (ret)
+               goto out_err;
+
+       return 0;
+
+out_err:
+       hisi_drm_unload(dev);
+       return ret;
+}
+
+static const struct file_operations hisi_drm_fops = {
+       .owner          = THIS_MODULE,
+       .open           = drm_open,
+       .release        = drm_release,
+       .unlocked_ioctl = drm_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = drm_compat_ioctl,
+#endif
+       .poll           = drm_poll,
+       .read           = drm_read,
+       .llseek         = no_llseek,
+       .mmap           = drm_gem_cma_mmap,
+};
+
+static struct dma_buf *hisi_drm_gem_prime_export(struct drm_device *dev,
+                                                struct drm_gem_object *obj,
+                                                int flags)
+{
+       /* we want to be able to write in mmapped buffer */
+       flags |= O_RDWR;
+       return drm_gem_prime_export(dev, obj, flags);
+}
+
+static struct drm_driver hisi_drm_driver = {
+       .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME
+                               | DRIVER_HAVE_IRQ,
+       .load                   = hisi_drm_load,
+       .unload                 = hisi_drm_unload,
+       .fops                   = &hisi_drm_fops,
+       .set_busid              = drm_platform_set_busid,
+
+       .gem_free_object        = drm_gem_cma_free_object,
+       .gem_vm_ops             = &drm_gem_cma_vm_ops,
+       .dumb_create            = drm_gem_cma_dumb_create,
+       .dumb_map_offset        = drm_gem_cma_dumb_map_offset,
+       .dumb_destroy           = drm_gem_dumb_destroy,
+
+       .prime_handle_to_fd     = drm_gem_prime_handle_to_fd,
+       .prime_fd_to_handle     = drm_gem_prime_fd_to_handle,
+       .gem_prime_export       = hisi_drm_gem_prime_export,
+       .gem_prime_import       = drm_gem_prime_import,
+       .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,
+
+       .name                   = "hisi",
+       .desc                   = "Hisilicon Terminal SoCs DRM Driver",
+       .date                   = "20150830",
+       .major                  = 1,
+       .minor                  = 0,
+};
+
+/* 
-----------------------------------------------------------------------------
+ * Platform driver
+ */
+
+static int compare_of(struct device *dev, void *data)
+{
+       return dev->of_node == data;
+}
+
+static int hisi_drm_bind(struct device *dev)
+{
+       dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
+       return drm_platform_init(&hisi_drm_driver, to_platform_device(dev));
+}
+
+static void hisi_drm_unbind(struct device *dev)
+{
+       drm_put_dev(dev_get_drvdata(dev));
+}
+
+static const struct component_master_ops hisi_drm_ops = {
+       .bind = hisi_drm_bind,
+       .unbind = hisi_drm_unbind,
+};
+
+static int hisi_drm_platform_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *node = dev->of_node;
+       struct device_node *child_np;
+       struct component_match *match = NULL;
+
+       of_platform_populate(node, NULL, NULL, dev);
+
+       child_np = of_get_next_available_child(node, NULL);
+       while (child_np) {
+               component_match_add(dev, &match, compare_of, child_np);
+               of_node_put(child_np);
+               child_np = of_get_next_available_child(node, child_np);
+       }
+
+       return component_master_add_with_match(dev, &hisi_drm_ops, match);
+
+       return 0;
+}
+
+static int hisi_drm_platform_remove(struct platform_device *pdev)
+{
+       component_master_del(&pdev->dev, &hisi_drm_ops);
+       of_platform_depopulate(&pdev->dev);
+
+       return 0;
+}
+
+static const struct of_device_id hisi_drm_dt_ids[] = {
+       { .compatible = "hisilicon,display-subsystem", },
+       { /* end node */ },
+};
+MODULE_DEVICE_TABLE(of, hisi_drm_dt_ids);
+
+static struct platform_driver hisi_drm_platform_driver = {
+       .probe = hisi_drm_platform_probe,
+       .remove = hisi_drm_platform_remove,
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = DRIVER_NAME,
+               .of_match_table = hisi_drm_dt_ids,
+       },
+};
+
+module_platform_driver(hisi_drm_platform_driver);
+
+MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei at hisilicon.com>");
+MODULE_AUTHOR("Xinliang Liu <z.liuxinliang at huawei.com>");
+MODULE_DESCRIPTION("hisilicon SoC DRM driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c 
b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
new file mode 100644
index 0000000..a8dbaad
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
@@ -0,0 +1,131 @@
+/*
+ * Hisilicon Terminal SoCs drm driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author: Xinwei Kong <kong.kongxinwei at hisilicon.com> for hisilicon
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/component.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_encoder_slave.h>
+
+#define DSI_24BITS_1               (5)
+
+struct hisi_dsi {
+       u32 lanes;
+       u32 format;
+       u32 date_enable_pol;
+       u32 mode_flags;
+       u8 color_mode;
+       void *ctx;
+};
+
+struct hisi_dsi_context {
+       struct hisi_dsi dsi;
+       struct clk *dsi_cfg_clk;
+       struct drm_device *dev;
+
+       void __iomem *base;
+       int nominal_pixel_clk_kHz;
+};
+
+static int hisi_dsi_bind(struct device *dev, struct device *master,
+                        void *data)
+{
+       int ret = 0;
+
+       return ret;
+}
+
+static void hisi_dsi_unbind(struct device *dev, struct device *master,
+                           void *data)
+{
+       /* do nothing */
+}
+
+static const struct component_ops hisi_dsi_ops = {
+       .bind   = hisi_dsi_bind,
+       .unbind = hisi_dsi_unbind,
+};
+
+static int hisi_dsi_probe(struct platform_device *pdev)
+{
+       struct hisi_dsi_context *ctx;
+       struct hisi_dsi *dsi;
+       struct resource *res;
+       struct device_node *slave_node;
+       struct device_node *np = pdev->dev.of_node;
+       int ret;
+
+       ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+       if (!ctx) {
+               DRM_ERROR("failed to allocate hisi dsi context.\n");
+               ret = -ENOMEM;
+       }
+
+       ctx->dsi_cfg_clk = devm_clk_get(&pdev->dev, "pclk_dsi");
+       if (IS_ERR(ctx->dsi_cfg_clk)) {
+               DRM_ERROR("failed to parse the dsi config clock\n");
+               ret = PTR_ERR(ctx->dsi_cfg_clk);
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       ctx->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(ctx->base)) {
+               DRM_ERROR("failed to remap dsi io region\n");
+               ret = PTR_ERR(ctx->base);
+       }
+
+       slave_node = of_parse_phandle(np, "encoder-slave", 0);
+       if (!slave_node) {
+               DRM_ERROR("failed to parse the slave encoder node\n");
+               return -EINVAL;
+       }
+
+       dsi = &ctx->dsi;
+       dsi->ctx = ctx;
+       dsi->lanes = 3;
+       dsi->date_enable_pol = 0;
+       dsi->color_mode = DSI_24BITS_1;
+       dsi->format = MIPI_DSI_FMT_RGB888;
+       dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+
+       return component_add(&pdev->dev, &hisi_dsi_ops);
+}
+
+static int hisi_dsi_remove(struct platform_device *pdev)
+{
+       component_del(&pdev->dev, &hisi_dsi_ops);
+
+       return 0;
+}
+
+static const struct of_device_id hisi_dsi_of_match[] = {
+       {.compatible = "hisilicon,hi6220-dsi"},
+       { }
+};
+MODULE_DEVICE_TABLE(of, hisi_dsi_of_match);
+
+static struct platform_driver hisi_dsi_driver = {
+       .probe = hisi_dsi_probe,
+       .remove = hisi_dsi_remove,
+       .driver = {
+               .name = "hisi-dsi",
+               .owner = THIS_MODULE,
+               .of_match_table = hisi_dsi_of_match,
+       },
+};
+
+module_platform_driver(hisi_dsi_driver);
+
+MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei at hisilicon.com>");
+MODULE_AUTHOR("Xinliang Liu <z.liuxinliang at huawei.com>");
+MODULE_DESCRIPTION("hisilicon SoC DRM driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_fb.c 
b/drivers/gpu/drm/hisilicon/hisi_drm_fb.c
new file mode 100644
index 0000000..5dace8b
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_fb.c
@@ -0,0 +1,156 @@
+/*
+ * Hisilicon Terminal SoCs drm fbdev driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author: z.liuxinliang at huawei.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "hisi_drm_fb.h"
+
+struct hisi_drm_fb *to_hisi_drm_fb(struct drm_framebuffer *fb)
+{
+       return container_of(fb, struct hisi_drm_fb, fb);
+}
+
+void hisi_drm_fb_destroy(struct drm_framebuffer *fb)
+{
+       struct hisi_drm_fb *hisi_fb = to_hisi_drm_fb(fb);
+       int i;
+
+       for (i = 0; i < 4; i++) {
+               if (hisi_fb->obj[i])
+                       drm_gem_object_unreference_unlocked
+                               (&hisi_fb->obj[i]->base);
+       }
+
+       drm_framebuffer_cleanup(fb);
+       kfree(hisi_fb);
+}
+
+static int hisi_drm_fb_create_handle(struct drm_framebuffer *fb,
+                                    struct drm_file *file_priv,
+                                    unsigned int *handle)
+{
+       struct hisi_drm_fb *hisi_fb = to_hisi_drm_fb(fb);
+
+       return drm_gem_handle_create(file_priv,
+                       &hisi_fb->obj[0]->base, handle);
+}
+
+static int hisi_drm_fb_dirty(struct drm_framebuffer *fb,
+                            struct drm_file *file_priv,
+                            unsigned flags,
+                            unsigned color,
+                            struct drm_clip_rect *clips,
+                            unsigned num_clips)
+{
+       /* TODO */
+       return 0;
+}
+
+static struct drm_framebuffer_funcs hisi_drm_fb_funcs = {
+       .destroy        = hisi_drm_fb_destroy,
+       .create_handle  = hisi_drm_fb_create_handle,
+       .dirty          = hisi_drm_fb_dirty,
+};
+
+struct hisi_drm_fb *hisi_drm_fb_alloc(struct drm_device *dev,
+                                     struct drm_mode_fb_cmd2 *mode_cmd,
+                                     struct drm_gem_cma_object **obj,
+                                     unsigned int num_planes, bool is_fbdev_fb)
+{
+       struct hisi_drm_fb *hisi_fb;
+       int ret;
+       int i;
+
+       hisi_fb = kzalloc(sizeof(*hisi_fb), GFP_KERNEL);
+       if (!hisi_fb)
+               return ERR_PTR(-ENOMEM);
+
+       hisi_fb->is_fbdev_fb = is_fbdev_fb;
+       drm_helper_mode_fill_fb_struct(&hisi_fb->fb, mode_cmd);
+
+       for (i = 0; i < num_planes; i++)
+               hisi_fb->obj[i] = obj[i];
+
+       ret = drm_framebuffer_init(dev, &hisi_fb->fb, &hisi_drm_fb_funcs);
+       if (ret) {
+               DRM_ERROR("Failed to initialize framebuffer: %d\n", ret);
+               kfree(hisi_fb);
+               return ERR_PTR(ret);
+       }
+
+       return hisi_fb;
+}
+
+/**
+ * hisi_drm_fb_create() - (struct drm_mode_config_funcs *)->fb_create callback
+ *function
+ * If your hardware has special alignment or pitch requirements these should be
+ * checked before calling this function.
+ */
+
+struct drm_framebuffer *hisi_drm_fb_create(struct drm_device *dev,
+                                          struct drm_file *file_priv,
+                                          struct drm_mode_fb_cmd2 *mode_cmd)
+{
+       struct hisi_drm_fb *hisi_fb;
+       struct drm_gem_cma_object *objs[4];
+       struct drm_gem_object *obj;
+       unsigned int hsub;
+       unsigned int vsub;
+       int ret;
+       int i;
+
+       /* TODO: Need to use ion heaps to create frame buffer?? */
+
+       hsub = drm_format_horz_chroma_subsampling(mode_cmd->pixel_format);
+       vsub = drm_format_vert_chroma_subsampling(mode_cmd->pixel_format);
+
+       for (i = 0; i < drm_format_num_planes(mode_cmd->pixel_format); i++) {
+               unsigned int width = mode_cmd->width / (i ? hsub : 1);
+               unsigned int height = mode_cmd->height / (i ? vsub : 1);
+               unsigned int min_size;
+
+               obj = drm_gem_object_lookup(dev, file_priv,
+                                           mode_cmd->handles[i]);
+               if (!obj) {
+                       DRM_ERROR("Failed to lookup GEM object\n");
+                       ret = -ENXIO;
+                       goto err_gem_object_unreference;
+               }
+
+               min_size = (height - 1) * mode_cmd->pitches[i]
+                    + width * drm_format_plane_cpp(mode_cmd->pixel_format, i)
+                    + mode_cmd->offsets[i];
+
+               if (obj->size < min_size) {
+                       drm_gem_object_unreference_unlocked(obj);
+                       ret = -EINVAL;
+                       goto err_gem_object_unreference;
+               }
+               objs[i] = to_drm_gem_cma_obj(obj);
+       }
+
+       hisi_fb = hisi_drm_fb_alloc(dev, mode_cmd, objs, i, false);
+       if (IS_ERR(hisi_fb)) {
+               ret = PTR_ERR(hisi_fb);
+               goto err_gem_object_unreference;
+       }
+
+       return &hisi_fb->fb;
+
+err_gem_object_unreference:
+       for (i--; i >= 0; i--)
+               drm_gem_object_unreference_unlocked(&objs[i]->base);
+       return ERR_PTR(ret);
+}
+
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_fb.h 
b/drivers/gpu/drm/hisilicon/hisi_drm_fb.h
new file mode 100644
index 0000000..1db1289
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_fb.h
@@ -0,0 +1,26 @@
+/*
+ * Hisilicon Terminal SoCs drm fbdev driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author: z.liuxinliang at huawei.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __HISI_DRM_FB_H__
+#define __HISI_DRM_FB_H__
+
+struct hisi_drm_fb {
+       struct drm_framebuffer          fb;
+       struct drm_gem_cma_object       *obj[4];
+       bool is_fbdev_fb;
+};
+
+struct drm_framebuffer *hisi_drm_fb_create(struct drm_device *dev,
+                                          struct drm_file *file_priv,
+                                          struct drm_mode_fb_cmd2 *mode_cmd);
+
+#endif /* __HISI_DRM_FB_H__ */
-- 
1.9.1


Reply via email to