All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v7 0/7] Add DRM driver for Hisilicon Hibmc
@ 2016-11-16 13:43 ` Rongrong Zou
  0 siblings, 0 replies; 40+ messages in thread
From: Rongrong Zou @ 2016-11-16 13:43 UTC (permalink / raw)
  To: linux-arm-kernel

This patch set adds a new drm driver for Hisilicon Hibmc. Hibmc is a
BMC SoC with a display controller intergrated, usually it is used on
server for Out-of-band management purpose. In this patch set, we just
support basic function for Hibmc display subsystem. Hibmc display
subsystem is connected to host CPU by PCIe as blow:

+----------+       +----------+
|          | PCIe  |  Hibmc   |
|host CPU( |<----->| display  |
|arm64,x86)|       |subsystem |
+----------+       +----------+

Hardware Detail for Hibmc display subsystem
-----------

  The display subsystem of Hibmc is show as bellow:
  +----+      +----+      +----+     +--------+
  |    |      |    |      |    |     |        |
  | FB |----->| DE |----->|VDAC|---->|external|
  |    |      |    |      |    |     | VGA    |
  +----+      +----+      +----+     +--------+

  -DE(Display Engine) is the display controller.
  -VDAC(Video Digital-to-Analog converter) converts the RGB diaital data
  stream from DE to VGA analog signals.

Change History
------------
Changes in v7:
  -remove hibmc_drm_power.c/hibmc_drm_power.h, move the functions to
   hibmc_drm_drv.c.
  -remove hibmc_drm_de.h and move the struct defined in head file to
   hibmc_drm_de.c.
  -plane is initialized inside crtc, not in hibmc_kms_init().
  -connector is initialized inside encoder, not in hibmc_kms_init().
  -remove plane/crtc/encoder/connector from hibmc_drm_private struct.
  -call drm_atomic_helper_suspend/resume in hibmc_pm_suspend/resume.
  -remove these empty stubs because caller will do NULL check.
    hibmc_plane_atomic_disable
    hibmc_crtc_atomic_check
    hibmc_encoder_disable
    hibmc_encoder_enable
    hibmc_encoder_atomic_check
  -clean up in all error paths of creating driver-private framebuffer. 

Changes in v6:
  -remove the embedded framebuffer and use a pointer of hibmc_framebuffer
   instead.
  -remove the deprecated drm_framebuffer_unregister_private(),
   drm_framebuffer_unreference() will be called in hibmc_fbdev_destroy().
  -uninstall irq in hibmc_unload().

Changes in v5:
  -rebase on v4.9-rc2.
  -replace drm_fb_helper_set_suspend with drm_fb_helper_set_suspend_unlocked.
   and remove redundant console_lock and console_unlock.

Changes in v4:
  -remove unused include files, and include header file when it is needed.
  -remove unused FLAG in Kconfig: DRM_GEM_CMA_HELPER/DRM_KMS_CMA_HELPER.
  -remove drm_helper_disable_unused_functions, since we use DRIVER_ATOMIC.

Changes in v3:
  -enable KMS, in v2, only fbdev is enabled.
  -management video memory with ttm.
  -add vblank interrupt.
  -remove drm_connector_register_all() and drm_connector_unregister_all().
  -I have a basic test with igt.

Changes in v2:
  -Remove self-defined macros for bit operations.
  -Remove unused register.
  -Replace those deprecated functions with new version of them.
  -use drm_connector_register_all() to register connector after
   drm_dev_register().

The patch v2 is at
https://lists.freedesktop.org/archives/dri-devel/2016-May/108661.html

Rongrong Zou (7):
  drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
  drm/hisilicon/hibmc: Add video memory management
  drm/hisilicon/hibmc: Add support for frame buffer
  drm/hisilicon/hibmc: Add support for display engine
  drm/hisilicon/hibmc: Add support for VDAC
  drm/hisilicon/hibmc: Add support for vblank interrupt
  MAINTAINERS: Update HISILICON DRM entries

 MAINTAINERS                                       |   1 +
 drivers/gpu/drm/hisilicon/Kconfig                 |   1 +
 drivers/gpu/drm/hisilicon/Makefile                |   1 +
 drivers/gpu/drm/hisilicon/hibmc/Kconfig           |   9 +
 drivers/gpu/drm/hisilicon/hibmc/Makefile          |   4 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c    | 477 ++++++++++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   | 456 ++++++++++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   | 114 +++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 267 +++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h  | 196 ++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c  | 147 ++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       | 558 ++++++++++++++++++++++
 12 files changed, 2231 insertions(+)
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Kconfig
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Makefile
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c

-- 
1.9.1

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v7 0/7] Add DRM driver for Hisilicon Hibmc
@ 2016-11-16 13:43 ` Rongrong Zou
  0 siblings, 0 replies; 40+ messages in thread
From: Rongrong Zou @ 2016-11-16 13:43 UTC (permalink / raw)
  To: airlied, daniel, seanpaul, seanpaul, dri-devel, emil.l.velikov,
	tomeu.vizoso, benjamin.gaignard, robh, daniel, architt, corbet,
	mark.rutland, xinliang.liu
  Cc: linuxarm, kong.kongxinwei, james.xiong, shenhui, guohanjun,
	lijianhua, linux-arm-kernel

This patch set adds a new drm driver for Hisilicon Hibmc. Hibmc is a
BMC SoC with a display controller intergrated, usually it is used on
server for Out-of-band management purpose. In this patch set, we just
support basic function for Hibmc display subsystem. Hibmc display
subsystem is connected to host CPU by PCIe as blow:

+----------+       +----------+
|          | PCIe  |  Hibmc   |
|host CPU( |<----->| display  |
|arm64,x86)|       |subsystem |
+----------+       +----------+

Hardware Detail for Hibmc display subsystem
-----------

  The display subsystem of Hibmc is show as bellow:
  +----+      +----+      +----+     +--------+
  |    |      |    |      |    |     |        |
  | FB |----->| DE |----->|VDAC|---->|external|
  |    |      |    |      |    |     | VGA    |
  +----+      +----+      +----+     +--------+

  -DE(Display Engine) is the display controller.
  -VDAC(Video Digital-to-Analog converter) converts the RGB diaital data
  stream from DE to VGA analog signals.

Change History
------------
Changes in v7:
  -remove hibmc_drm_power.c/hibmc_drm_power.h, move the functions to
   hibmc_drm_drv.c.
  -remove hibmc_drm_de.h and move the struct defined in head file to
   hibmc_drm_de.c.
  -plane is initialized inside crtc, not in hibmc_kms_init().
  -connector is initialized inside encoder, not in hibmc_kms_init().
  -remove plane/crtc/encoder/connector from hibmc_drm_private struct.
  -call drm_atomic_helper_suspend/resume in hibmc_pm_suspend/resume.
  -remove these empty stubs because caller will do NULL check.
    hibmc_plane_atomic_disable
    hibmc_crtc_atomic_check
    hibmc_encoder_disable
    hibmc_encoder_enable
    hibmc_encoder_atomic_check
  -clean up in all error paths of creating driver-private framebuffer. 

Changes in v6:
  -remove the embedded framebuffer and use a pointer of hibmc_framebuffer
   instead.
  -remove the deprecated drm_framebuffer_unregister_private(),
   drm_framebuffer_unreference() will be called in hibmc_fbdev_destroy().
  -uninstall irq in hibmc_unload().

Changes in v5:
  -rebase on v4.9-rc2.
  -replace drm_fb_helper_set_suspend with drm_fb_helper_set_suspend_unlocked.
   and remove redundant console_lock and console_unlock.

Changes in v4:
  -remove unused include files, and include header file when it is needed.
  -remove unused FLAG in Kconfig: DRM_GEM_CMA_HELPER/DRM_KMS_CMA_HELPER.
  -remove drm_helper_disable_unused_functions, since we use DRIVER_ATOMIC.

Changes in v3:
  -enable KMS, in v2, only fbdev is enabled.
  -management video memory with ttm.
  -add vblank interrupt.
  -remove drm_connector_register_all() and drm_connector_unregister_all().
  -I have a basic test with igt.

Changes in v2:
  -Remove self-defined macros for bit operations.
  -Remove unused register.
  -Replace those deprecated functions with new version of them.
  -use drm_connector_register_all() to register connector after
   drm_dev_register().

The patch v2 is at
https://lists.freedesktop.org/archives/dri-devel/2016-May/108661.html

Rongrong Zou (7):
  drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
  drm/hisilicon/hibmc: Add video memory management
  drm/hisilicon/hibmc: Add support for frame buffer
  drm/hisilicon/hibmc: Add support for display engine
  drm/hisilicon/hibmc: Add support for VDAC
  drm/hisilicon/hibmc: Add support for vblank interrupt
  MAINTAINERS: Update HISILICON DRM entries

 MAINTAINERS                                       |   1 +
 drivers/gpu/drm/hisilicon/Kconfig                 |   1 +
 drivers/gpu/drm/hisilicon/Makefile                |   1 +
 drivers/gpu/drm/hisilicon/hibmc/Kconfig           |   9 +
 drivers/gpu/drm/hisilicon/hibmc/Makefile          |   4 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c    | 477 ++++++++++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   | 456 ++++++++++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   | 114 +++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 267 +++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h  | 196 ++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c  | 147 ++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       | 558 ++++++++++++++++++++++
 12 files changed, 2231 insertions(+)
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Kconfig
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Makefile
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c

-- 
1.9.1

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v7 1/7] drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
  2016-11-16 13:43 ` Rongrong Zou
@ 2016-11-16 13:43   ` Rongrong Zou
  -1 siblings, 0 replies; 40+ messages in thread
From: Rongrong Zou @ 2016-11-16 13:43 UTC (permalink / raw)
  To: linux-arm-kernel

Add DRM master driver for Hisilicon Hibmc SoC which used for
Out-of-band management. Blow is the general hardware connection,
both the Hibmc and the host CPU are on the same mother board.

+----------+       +----------+
|          | PCIe  |  Hibmc   |
|host CPU( |<----->| display  |
|arm64,x86)|       |subsystem |
+----------+       +----------+

Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
---
 drivers/gpu/drm/hisilicon/Kconfig                |   1 +
 drivers/gpu/drm/hisilicon/Makefile               |   1 +
 drivers/gpu/drm/hisilicon/hibmc/Kconfig          |   9 +
 drivers/gpu/drm/hisilicon/hibmc/Makefile         |   4 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c  | 308 +++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h  |  41 +++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h | 196 +++++++++++++++
 7 files changed, 560 insertions(+)
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Kconfig
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Makefile
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h

diff --git a/drivers/gpu/drm/hisilicon/Kconfig b/drivers/gpu/drm/hisilicon/Kconfig
index 558c61b..2fd2724 100644
--- a/drivers/gpu/drm/hisilicon/Kconfig
+++ b/drivers/gpu/drm/hisilicon/Kconfig
@@ -2,4 +2,5 @@
 # hisilicon drm device configuration.
 # Please keep this list sorted alphabetically
 
+source "drivers/gpu/drm/hisilicon/hibmc/Kconfig"
 source "drivers/gpu/drm/hisilicon/kirin/Kconfig"
diff --git a/drivers/gpu/drm/hisilicon/Makefile b/drivers/gpu/drm/hisilicon/Makefile
index e3f6d49..c8155bf 100644
--- a/drivers/gpu/drm/hisilicon/Makefile
+++ b/drivers/gpu/drm/hisilicon/Makefile
@@ -2,4 +2,5 @@
 # Makefile for hisilicon drm drivers.
 # Please keep this list sorted alphabetically
 
+obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc/
 obj-$(CONFIG_DRM_HISI_KIRIN) += kirin/
diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
new file mode 100644
index 0000000..380622a
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
@@ -0,0 +1,9 @@
+config DRM_HISI_HIBMC
+	tristate "DRM Support for Hisilicon Hibmc"
+	depends on DRM && PCI
+	select DRM_KMS_HELPER
+	select DRM_TTM
+
+	help
+	  Choose this option if you have a Hisilicon Hibmc soc chipset.
+	  If M is selected the module will be called hibmc-drm.
diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
new file mode 100644
index 0000000..47962a0
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
@@ -0,0 +1,4 @@
+ccflags-y := -Iinclude/drm
+hibmc-drm-y := hibmc_drm_drv.o
+
+obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
new file mode 100644
index 0000000..6d20580
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -0,0 +1,308 @@
+/* Hisilicon Hibmc SoC drm driver
+ *
+ * Based on the bochs drm driver.
+ *
+ * Copyright (c) 2016 Huawei Limited.
+ *
+ * Author:
+ *	Rongrong Zou <zourongrong@huawei.com>
+ *	Rongrong Zou <zourongrong@gmail.com>
+ *	Jianhua Li <lijianhua@huawei.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/console.h>
+#include <linux/module.h>
+
+#include "hibmc_drm_drv.h"
+#include "hibmc_drm_regs.h"
+
+static const struct file_operations hibmc_fops = {
+	.owner		= THIS_MODULE,
+	.open		= drm_open,
+	.release	= drm_release,
+	.unlocked_ioctl	= drm_ioctl,
+	.compat_ioctl	= drm_compat_ioctl,
+	.poll		= drm_poll,
+	.read		= drm_read,
+	.llseek		= no_llseek,
+};
+
+static int hibmc_enable_vblank(struct drm_device *dev, unsigned int pipe)
+{
+	return 0;
+}
+
+static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
+{
+}
+
+static struct drm_driver hibmc_driver = {
+	.fops			= &hibmc_fops,
+	.name			= "hibmc",
+	.date			= "20160828",
+	.desc			= "hibmc drm driver",
+	.major			= 1,
+	.minor			= 0,
+	.get_vblank_counter	= drm_vblank_no_hw_counter,
+	.enable_vblank		= hibmc_enable_vblank,
+	.disable_vblank		= hibmc_disable_vblank,
+};
+
+static int hibmc_pm_suspend(struct device *dev)
+{
+	return 0;
+}
+
+static int hibmc_pm_resume(struct device *dev)
+{
+	return 0;
+}
+
+static const struct dev_pm_ops hibmc_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(hibmc_pm_suspend,
+				hibmc_pm_resume)
+};
+
+/*
+ * It can operate in one of three modes: 0, 1 or Sleep.
+ */
+void hibmc_set_power_mode(struct hibmc_drm_private *priv,
+			  unsigned int power_mode)
+{
+	unsigned int control_value = 0;
+	void __iomem   *mmio = priv->mmio;
+	unsigned int input = 1;
+
+	if (power_mode > HIBMC_PW_MODE_CTL_MODE_SLEEP)
+		return;
+
+	if (power_mode == HIBMC_PW_MODE_CTL_MODE_SLEEP)
+		input = 0;
+
+	control_value = readl(mmio + HIBMC_POWER_MODE_CTRL);
+	control_value &= ~(HIBMC_PW_MODE_CTL_MODE_MASK |
+			   HIBMC_PW_MODE_CTL_OSC_INPUT_MASK);
+	control_value |= HIBMC_FIELD(HIBMC_PW_MODE_CTL_MODE, power_mode);
+	control_value |= HIBMC_FIELD(HIBMC_PW_MODE_CTL_OSC_INPUT, input);
+	writel(control_value, mmio + HIBMC_POWER_MODE_CTRL);
+}
+
+void hibmc_set_current_gate(struct hibmc_drm_private *priv, unsigned int gate)
+{
+	unsigned int gate_reg;
+	unsigned int mode;
+	void __iomem   *mmio = priv->mmio;
+
+	/* Get current power mode. */
+	mode = (readl(mmio + HIBMC_POWER_MODE_CTRL) &
+		HIBMC_PW_MODE_CTL_MODE_MASK) >> HIBMC_PW_MODE_CTL_MODE_SHIFT;
+
+	switch (mode) {
+	case HIBMC_PW_MODE_CTL_MODE_MODE0:
+		gate_reg = HIBMC_MODE0_GATE;
+		break;
+
+	case HIBMC_PW_MODE_CTL_MODE_MODE1:
+		gate_reg = HIBMC_MODE1_GATE;
+		break;
+
+	default:
+		gate_reg = HIBMC_MODE0_GATE;
+		break;
+	}
+	writel(gate, mmio + gate_reg);
+}
+
+static void hibmc_hw_config(struct hibmc_drm_private *priv)
+{
+	unsigned int reg;
+
+	/* On hardware reset, power mode 0 is default. */
+	hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_MODE0);
+
+	/* Enable display power gate & LOCALMEM power gate*/
+	reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
+	reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
+	reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
+	reg |= HIBMC_CURR_GATE_DISPLAY(1);
+	reg |= HIBMC_CURR_GATE_LOCALMEM(1);
+
+	hibmc_set_current_gate(priv, reg);
+
+	/*
+	 * Reset the memory controller. If the memory controller
+	 * is not reset in chip,the system might hang when sw accesses
+	 * the memory.The memory should be resetted after
+	 * changing the MXCLK.
+	 */
+	reg = readl(priv->mmio + HIBMC_MISC_CTRL);
+	reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
+	reg |= HIBMC_MSCCTL_LOCALMEM_RESET(0);
+	writel(reg, priv->mmio + HIBMC_MISC_CTRL);
+
+	reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
+	reg |= HIBMC_MSCCTL_LOCALMEM_RESET(1);
+
+	writel(reg, priv->mmio + HIBMC_MISC_CTRL);
+}
+
+static int hibmc_hw_map(struct hibmc_drm_private *priv)
+{
+	struct drm_device *dev = priv->dev;
+	struct pci_dev *pdev = dev->pdev;
+	resource_size_t addr, size, ioaddr, iosize;
+
+	ioaddr = pci_resource_start(pdev, 1);
+	iosize = pci_resource_len(pdev, 1);
+	priv->mmio = devm_ioremap_nocache(dev->dev, ioaddr, iosize);
+	if (!priv->mmio) {
+		DRM_ERROR("Cannot map mmio region\n");
+		return -ENOMEM;
+	}
+
+	addr = pci_resource_start(pdev, 0);
+	size = pci_resource_len(pdev, 0);
+	priv->fb_map = devm_ioremap(dev->dev, addr, size);
+	if (!priv->fb_map) {
+		DRM_ERROR("Cannot map framebuffer\n");
+		return -ENOMEM;
+	}
+	priv->fb_base = addr;
+	priv->fb_size = size;
+
+	return 0;
+}
+
+static int hibmc_hw_init(struct hibmc_drm_private *priv)
+{
+	int ret;
+
+	ret = hibmc_hw_map(priv);
+	if (ret)
+		return ret;
+
+	hibmc_hw_config(priv);
+
+	return 0;
+}
+
+static int hibmc_unload(struct drm_device *dev)
+{
+	return 0;
+}
+
+static int hibmc_load(struct drm_device *dev)
+{
+	struct hibmc_drm_private *priv;
+	int ret;
+
+	priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		DRM_ERROR("no memory to allocate for hibmc_drm_private\n");
+		return -ENOMEM;
+	}
+	dev->dev_private = priv;
+	priv->dev = dev;
+
+	ret = hibmc_hw_init(priv);
+	if (ret)
+		goto err;
+
+	return 0;
+
+err:
+	hibmc_unload(dev);
+	DRM_ERROR("failed to initialize drm driver: %d\n", ret);
+	return ret;
+}
+
+static int hibmc_pci_probe(struct pci_dev *pdev,
+			   const struct pci_device_id *ent)
+{
+	struct drm_device *dev;
+	int ret;
+
+	dev = drm_dev_alloc(&hibmc_driver, &pdev->dev);
+	if (!dev) {
+		DRM_ERROR("failed to allocate drm_device\n");
+		return -ENOMEM;
+	}
+
+	dev->pdev = pdev;
+	pci_set_drvdata(pdev, dev);
+
+	ret = pci_enable_device(pdev);
+	if (ret) {
+		DRM_ERROR("failed to enable pci device: %d\n", ret);
+		goto err_free;
+	}
+
+	ret = hibmc_load(dev);
+	if (ret) {
+		DRM_ERROR("failed to load hibmc: %d\n", ret);
+		goto err_disable;
+	}
+
+	ret = drm_dev_register(dev, 0);
+	if (ret) {
+		DRM_ERROR("failed to register drv for userspace access: %d\n",
+			  ret);
+		goto err_unload;
+	}
+	return 0;
+
+err_unload:
+	hibmc_unload(dev);
+err_disable:
+	pci_disable_device(pdev);
+err_free:
+	drm_dev_unref(dev);
+
+	return ret;
+}
+
+static void hibmc_pci_remove(struct pci_dev *pdev)
+{
+	struct drm_device *dev = pci_get_drvdata(pdev);
+
+	drm_dev_unregister(dev);
+	hibmc_unload(dev);
+	drm_dev_unref(dev);
+}
+
+static struct pci_device_id hibmc_pci_table[] = {
+	{0x19e5, 0x1711, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0,}
+};
+
+static struct pci_driver hibmc_pci_driver = {
+	.name =		"hibmc-drm",
+	.id_table =	hibmc_pci_table,
+	.probe =	hibmc_pci_probe,
+	.remove =	hibmc_pci_remove,
+	.driver.pm =    &hibmc_pm_ops,
+};
+
+static int __init hibmc_init(void)
+{
+	return pci_register_driver(&hibmc_pci_driver);
+}
+
+static void __exit hibmc_exit(void)
+{
+	return pci_unregister_driver(&hibmc_pci_driver);
+}
+
+module_init(hibmc_init);
+module_exit(hibmc_exit);
+
+MODULE_DEVICE_TABLE(pci, hibmc_pci_table);
+MODULE_AUTHOR("RongrongZou <zourongrong@huawei.com>");
+MODULE_DESCRIPTION("DRM Driver for Hisilicon Hibmc");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
new file mode 100644
index 0000000..840cd5a
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -0,0 +1,41 @@
+/* Hisilicon Hibmc SoC drm driver
+ *
+ * Based on the bochs drm driver.
+ *
+ * Copyright (c) 2016 Huawei Limited.
+ *
+ * Author:
+ *	Rongrong Zou <zourongrong@huawei.com>
+ *	Rongrong Zou <zourongrong@gmail.com>
+ *	Jianhua Li <lijianhua@huawei.com>
+ *
+ * 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.
+ *
+ */
+
+#ifndef HIBMC_DRM_DRV_H
+#define HIBMC_DRM_DRV_H
+
+#include <drm/drmP.h>
+
+struct hibmc_drm_private {
+	/* hw */
+	void __iomem   *mmio;
+	void __iomem   *fb_map;
+	unsigned long  fb_base;
+	unsigned long  fb_size;
+
+	/* drm */
+	struct drm_device  *dev;
+
+};
+
+void hibmc_set_power_mode(struct hibmc_drm_private *priv,
+			  unsigned int power_mode);
+void hibmc_set_current_gate(struct hibmc_drm_private *priv,
+			    unsigned int gate);
+
+#endif
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
new file mode 100644
index 0000000..f7035bf
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
@@ -0,0 +1,196 @@
+/* Hisilicon Hibmc SoC drm driver
+ *
+ * Based on the bochs drm driver.
+ *
+ * Copyright (c) 2016 Huawei Limited.
+ *
+ * Author:
+ *	Rongrong Zou <zourongrong@huawei.com>
+ *	Rongrong Zou <zourongrong@gmail.com>
+ *	Jianhua Li <lijianhua@huawei.com>
+ *
+ * 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.
+ *
+ */
+
+#ifndef HIBMC_DRM_HW_H
+#define HIBMC_DRM_HW_H
+
+/* register definition */
+#define HIBMC_MISC_CTRL				0x4
+
+#define HIBMC_MSCCTL_LOCALMEM_RESET(x)		((x) << 6)
+#define HIBMC_MSCCTL_LOCALMEM_RESET_MASK	0x40
+
+#define HIBMC_CURRENT_GATE			0x000040
+#define HIBMC_CURR_GATE_DISPLAY(x)		((x) << 2)
+#define HIBMC_CURR_GATE_DISPLAY_MASK		0x4
+
+#define HIBMC_CURR_GATE_LOCALMEM(x)		((x) << 1)
+#define HIBMC_CURR_GATE_LOCALMEM_MASK		0x2
+
+#define HIBMC_MODE0_GATE			0x000044
+#define HIBMC_MODE1_GATE			0x000048
+#define HIBMC_POWER_MODE_CTRL			0x00004C
+
+#define HIBMC_PW_MODE_CTL_OSC_INPUT(x)		((x) << 3)
+#define HIBMC_PW_MODE_CTL_OSC_INPUT_MASK	0x8
+
+#define HIBMC_PW_MODE_CTL_MODE(x)		((x) << 0)
+#define HIBMC_PW_MODE_CTL_MODE_MASK		0x03
+#define HIBMC_PW_MODE_CTL_MODE_SHIFT		0
+
+#define HIBMC_PW_MODE_CTL_MODE_MODE0		0
+#define HIBMC_PW_MODE_CTL_MODE_MODE1		1
+#define HIBMC_PW_MODE_CTL_MODE_SLEEP		2
+
+#define HIBMC_PANEL_PLL_CTRL			0x00005C
+#define HIBMC_CRT_PLL_CTRL			0x000060
+
+#define HIBMC_PLL_CTRL_BYPASS(x)		((x) << 18)
+#define HIBMC_PLL_CTRL_BYPASS_MASK		0x40000
+
+#define HIBMC_PLL_CTRL_POWER(x)			((x) << 17)
+#define HIBMC_PLL_CTRL_POWER_MASK		0x20000
+
+#define HIBMC_PLL_CTRL_INPUT(x)			((x) << 16)
+#define HIBMC_PLL_CTRL_INPUT_MASK		0x10000
+
+#define HIBMC_PLL_CTRL_POD(x)			((x) << 14)
+#define HIBMC_PLL_CTRL_POD_MASK			0xC000
+
+#define HIBMC_PLL_CTRL_OD(x)			((x) << 12)
+#define HIBMC_PLL_CTRL_OD_MASK			0x3000
+
+#define HIBMC_PLL_CTRL_N(x)			((x) << 8)
+#define HIBMC_PLL_CTRL_N_MASK			0xF00
+
+#define HIBMC_PLL_CTRL_M(x)			((x) << 0)
+#define HIBMC_PLL_CTRL_M_MASK			0xFF
+
+#define HIBMC_CRT_DISP_CTL			0x80200
+
+#define HIBMC_CRT_DISP_CTL_CRTSELECT(x)		((x) << 25)
+#define HIBMC_CRT_DISP_CTL_CRTSELECT_MASK	0x2000000
+
+#define HIBMC_CRTSELECT_CRT			1
+
+#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE(x)	((x) << 14)
+#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE_MASK	0x4000
+
+#define HIBMC_CRT_DISP_CTL_VSYNC_PHASE(x)	((x) << 13)
+#define HIBMC_CRT_DISP_CTL_VSYNC_PHASE_MASK	0x2000
+
+#define HIBMC_CRT_DISP_CTL_HSYNC_PHASE(x)	((x) << 12)
+#define HIBMC_CRT_DISP_CTL_HSYNC_PHASE_MASK	0x1000
+
+#define HIBMC_CRT_DISP_CTL_TIMING(x)		((x) << 8)
+#define HIBMC_CRT_DISP_CTL_TIMING_MASK		0x100
+
+#define HIBMC_CRT_DISP_CTL_PLANE(x)		((x) << 2)
+#define HIBMC_CRT_DISP_CTL_PLANE_MASK		4
+
+#define HIBMC_CRT_DISP_CTL_FORMAT(x)		((x) << 0)
+#define HIBMC_CRT_DISP_CTL_FORMAT_MASK		0x03
+
+#define HIBMC_CRT_FB_ADDRESS			0x080204
+
+#define HIBMC_CRT_FB_WIDTH			0x080208
+#define HIBMC_CRT_FB_WIDTH_WIDTH(x)		((x) << 16)
+#define HIBMC_CRT_FB_WIDTH_WIDTH_MASK		0x3FFF0000
+#define HIBMC_CRT_FB_WIDTH_OFFS(x)		((x) << 0)
+#define HIBMC_CRT_FB_WIDTH_OFFS_MASK		0x3FFF
+
+#define HIBMC_CRT_HORZ_TOTAL			0x08020C
+#define HIBMC_CRT_HORZ_TOTAL_TOTAL(x)		((x) << 16)
+#define HIBMC_CRT_HORZ_TOTAL_TOTAL_MASK		0xFFF0000
+
+#define HIBMC_CRT_HORZ_TOTAL_DISP_END(x)	((x) << 0)
+#define HIBMC_CRT_HORZ_TOTAL_DISP_END_MASK	0xFFF
+
+#define HIBMC_CRT_HORZ_SYNC			0x080210
+#define HIBMC_CRT_HORZ_SYNC_WIDTH(x)		((x) << 16)
+#define HIBMC_CRT_HORZ_SYNC_WIDTH_MASK		0xFF0000
+
+#define HIBMC_CRT_HORZ_SYNC_START(x)		((x) << 0)
+#define HIBMC_CRT_HORZ_SYNC_START_MASK		0xFFF
+
+#define HIBMC_CRT_VERT_TOTAL			0x080214
+#define HIBMC_CRT_VERT_TOTAL_TOTAL(x)		((x) << 16)
+#define HIBMC_CRT_VERT_TOTAL_TOTAL_MASK		0x7FFF0000
+
+#define HIBMC_CRT_VERT_TOTAL_DISP_END(x)	((x) << 0)
+#define HIBMC_CRT_VERT_TOTAL_DISP_END_MASK	0x7FF
+
+#define HIBMC_CRT_VERT_SYNC			0x080218
+#define HIBMC_CRT_VERT_SYNC_HEIGHT(x)		((x) << 16)
+#define HIBMC_CRT_VERT_SYNC_HEIGHT_MASK		0x3F0000
+
+#define HIBMC_CRT_VERT_SYNC_START(x)		((x) << 0)
+#define HIBMC_CRT_VERT_SYNC_START_MASK		0x7FF
+
+/* Auto Centering */
+#define HIBMC_CRT_AUTO_CENTERING_TL		0x080280
+#define HIBMC_CRT_AUTO_CENTERING_TL_TOP(x)	((x) << 16)
+#define HIBMC_CRT_AUTO_CENTERING_TL_TOP_MASK	0x7FF0000
+
+#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT(x)	((x) << 0)
+#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT_MASK	0x7FF
+
+#define HIBMC_CRT_AUTO_CENTERING_BR		0x080284
+#define HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM(x)	((x) << 16)
+#define HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM_MASK	0x7FF0000
+
+#define HIBMC_CRT_AUTO_CENTERING_BR_RIGHT(x)	((x) << 0)
+#define HIBMC_CRT_AUTO_CENTERING_BR_RIGHT_MASK	0x7FF
+
+/* register to control panel output */
+#define HIBMC_DISPLAY_CONTROL_HISILE		0x80288
+#define HIBMC_DISPLAY_CONTROL_FPVDDEN(x)	((x) << 0)
+#define HIBMC_DISPLAY_CONTROL_PANELDATE(x)	((x) << 1)
+#define HIBMC_DISPLAY_CONTROL_FPEN(x)		((x) << 2)
+#define HIBMC_DISPLAY_CONTROL_VBIASEN(x)	((x) << 3)
+
+#define HIBMC_RAW_INTERRUPT			0x80290
+#define HIBMC_RAW_INTERRUPT_VBLANK(x)		((x) << 2)
+#define HIBMC_RAW_INTERRUPT_VBLANK_MASK		0x4
+
+#define HIBMC_RAW_INTERRUPT_EN			0x80298
+#define HIBMC_RAW_INTERRUPT_EN_VBLANK(x)	((x) << 2)
+#define HIBMC_RAW_INTERRUPT_EN_VBLANK_MASK	0x4
+
+/* register and values for PLL control */
+#define CRT_PLL1_HS				0x802a8
+#define CRT_PLL1_HS_OUTER_BYPASS(x)		((x) << 30)
+#define CRT_PLL1_HS_INTER_BYPASS(x)		((x) << 29)
+#define CRT_PLL1_HS_POWERON(x)			((x) << 24)
+
+#define CRT_PLL1_HS_25MHZ			0x23d40f02
+#define CRT_PLL1_HS_40MHZ			0x23940801
+#define CRT_PLL1_HS_65MHZ			0x23940d01
+#define CRT_PLL1_HS_78MHZ			0x23540F82
+#define CRT_PLL1_HS_74MHZ			0x23941dc2
+#define CRT_PLL1_HS_80MHZ			0x23941001
+#define CRT_PLL1_HS_80MHZ_1152			0x23540fc2
+#define CRT_PLL1_HS_108MHZ			0x23b41b01
+#define CRT_PLL1_HS_162MHZ			0x23480681
+#define CRT_PLL1_HS_148MHZ			0x23541dc2
+#define CRT_PLL1_HS_193MHZ			0x234807c1
+
+#define CRT_PLL2_HS				0x802ac
+#define CRT_PLL2_HS_25MHZ			0x206B851E
+#define CRT_PLL2_HS_40MHZ			0x30000000
+#define CRT_PLL2_HS_65MHZ			0x40000000
+#define CRT_PLL2_HS_78MHZ			0x50E147AE
+#define CRT_PLL2_HS_74MHZ			0x602B6AE7
+#define CRT_PLL2_HS_80MHZ			0x70000000
+#define CRT_PLL2_HS_108MHZ			0x80000000
+#define CRT_PLL2_HS_162MHZ			0xA0000000
+#define CRT_PLL2_HS_148MHZ			0xB0CCCCCD
+#define CRT_PLL2_HS_193MHZ			0xC0872B02
+
+#define HIBMC_FIELD(field, value) (field(value) & field##_MASK)
+#endif
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v7 1/7] drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
@ 2016-11-16 13:43   ` Rongrong Zou
  0 siblings, 0 replies; 40+ messages in thread
From: Rongrong Zou @ 2016-11-16 13:43 UTC (permalink / raw)
  To: airlied, daniel, seanpaul, seanpaul, dri-devel, emil.l.velikov,
	tomeu.vizoso, benjamin.gaignard, robh, daniel, architt, corbet,
	mark.rutland, xinliang.liu
  Cc: linuxarm, kong.kongxinwei, james.xiong, shenhui, guohanjun,
	lijianhua, linux-arm-kernel

Add DRM master driver for Hisilicon Hibmc SoC which used for
Out-of-band management. Blow is the general hardware connection,
both the Hibmc and the host CPU are on the same mother board.

+----------+       +----------+
|          | PCIe  |  Hibmc   |
|host CPU( |<----->| display  |
|arm64,x86)|       |subsystem |
+----------+       +----------+

Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
---
 drivers/gpu/drm/hisilicon/Kconfig                |   1 +
 drivers/gpu/drm/hisilicon/Makefile               |   1 +
 drivers/gpu/drm/hisilicon/hibmc/Kconfig          |   9 +
 drivers/gpu/drm/hisilicon/hibmc/Makefile         |   4 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c  | 308 +++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h  |  41 +++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h | 196 +++++++++++++++
 7 files changed, 560 insertions(+)
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Kconfig
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Makefile
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h

diff --git a/drivers/gpu/drm/hisilicon/Kconfig b/drivers/gpu/drm/hisilicon/Kconfig
index 558c61b..2fd2724 100644
--- a/drivers/gpu/drm/hisilicon/Kconfig
+++ b/drivers/gpu/drm/hisilicon/Kconfig
@@ -2,4 +2,5 @@
 # hisilicon drm device configuration.
 # Please keep this list sorted alphabetically
 
+source "drivers/gpu/drm/hisilicon/hibmc/Kconfig"
 source "drivers/gpu/drm/hisilicon/kirin/Kconfig"
diff --git a/drivers/gpu/drm/hisilicon/Makefile b/drivers/gpu/drm/hisilicon/Makefile
index e3f6d49..c8155bf 100644
--- a/drivers/gpu/drm/hisilicon/Makefile
+++ b/drivers/gpu/drm/hisilicon/Makefile
@@ -2,4 +2,5 @@
 # Makefile for hisilicon drm drivers.
 # Please keep this list sorted alphabetically
 
+obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc/
 obj-$(CONFIG_DRM_HISI_KIRIN) += kirin/
diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
new file mode 100644
index 0000000..380622a
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
@@ -0,0 +1,9 @@
+config DRM_HISI_HIBMC
+	tristate "DRM Support for Hisilicon Hibmc"
+	depends on DRM && PCI
+	select DRM_KMS_HELPER
+	select DRM_TTM
+
+	help
+	  Choose this option if you have a Hisilicon Hibmc soc chipset.
+	  If M is selected the module will be called hibmc-drm.
diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
new file mode 100644
index 0000000..47962a0
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
@@ -0,0 +1,4 @@
+ccflags-y := -Iinclude/drm
+hibmc-drm-y := hibmc_drm_drv.o
+
+obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
new file mode 100644
index 0000000..6d20580
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -0,0 +1,308 @@
+/* Hisilicon Hibmc SoC drm driver
+ *
+ * Based on the bochs drm driver.
+ *
+ * Copyright (c) 2016 Huawei Limited.
+ *
+ * Author:
+ *	Rongrong Zou <zourongrong@huawei.com>
+ *	Rongrong Zou <zourongrong@gmail.com>
+ *	Jianhua Li <lijianhua@huawei.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/console.h>
+#include <linux/module.h>
+
+#include "hibmc_drm_drv.h"
+#include "hibmc_drm_regs.h"
+
+static const struct file_operations hibmc_fops = {
+	.owner		= THIS_MODULE,
+	.open		= drm_open,
+	.release	= drm_release,
+	.unlocked_ioctl	= drm_ioctl,
+	.compat_ioctl	= drm_compat_ioctl,
+	.poll		= drm_poll,
+	.read		= drm_read,
+	.llseek		= no_llseek,
+};
+
+static int hibmc_enable_vblank(struct drm_device *dev, unsigned int pipe)
+{
+	return 0;
+}
+
+static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
+{
+}
+
+static struct drm_driver hibmc_driver = {
+	.fops			= &hibmc_fops,
+	.name			= "hibmc",
+	.date			= "20160828",
+	.desc			= "hibmc drm driver",
+	.major			= 1,
+	.minor			= 0,
+	.get_vblank_counter	= drm_vblank_no_hw_counter,
+	.enable_vblank		= hibmc_enable_vblank,
+	.disable_vblank		= hibmc_disable_vblank,
+};
+
+static int hibmc_pm_suspend(struct device *dev)
+{
+	return 0;
+}
+
+static int hibmc_pm_resume(struct device *dev)
+{
+	return 0;
+}
+
+static const struct dev_pm_ops hibmc_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(hibmc_pm_suspend,
+				hibmc_pm_resume)
+};
+
+/*
+ * It can operate in one of three modes: 0, 1 or Sleep.
+ */
+void hibmc_set_power_mode(struct hibmc_drm_private *priv,
+			  unsigned int power_mode)
+{
+	unsigned int control_value = 0;
+	void __iomem   *mmio = priv->mmio;
+	unsigned int input = 1;
+
+	if (power_mode > HIBMC_PW_MODE_CTL_MODE_SLEEP)
+		return;
+
+	if (power_mode == HIBMC_PW_MODE_CTL_MODE_SLEEP)
+		input = 0;
+
+	control_value = readl(mmio + HIBMC_POWER_MODE_CTRL);
+	control_value &= ~(HIBMC_PW_MODE_CTL_MODE_MASK |
+			   HIBMC_PW_MODE_CTL_OSC_INPUT_MASK);
+	control_value |= HIBMC_FIELD(HIBMC_PW_MODE_CTL_MODE, power_mode);
+	control_value |= HIBMC_FIELD(HIBMC_PW_MODE_CTL_OSC_INPUT, input);
+	writel(control_value, mmio + HIBMC_POWER_MODE_CTRL);
+}
+
+void hibmc_set_current_gate(struct hibmc_drm_private *priv, unsigned int gate)
+{
+	unsigned int gate_reg;
+	unsigned int mode;
+	void __iomem   *mmio = priv->mmio;
+
+	/* Get current power mode. */
+	mode = (readl(mmio + HIBMC_POWER_MODE_CTRL) &
+		HIBMC_PW_MODE_CTL_MODE_MASK) >> HIBMC_PW_MODE_CTL_MODE_SHIFT;
+
+	switch (mode) {
+	case HIBMC_PW_MODE_CTL_MODE_MODE0:
+		gate_reg = HIBMC_MODE0_GATE;
+		break;
+
+	case HIBMC_PW_MODE_CTL_MODE_MODE1:
+		gate_reg = HIBMC_MODE1_GATE;
+		break;
+
+	default:
+		gate_reg = HIBMC_MODE0_GATE;
+		break;
+	}
+	writel(gate, mmio + gate_reg);
+}
+
+static void hibmc_hw_config(struct hibmc_drm_private *priv)
+{
+	unsigned int reg;
+
+	/* On hardware reset, power mode 0 is default. */
+	hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_MODE0);
+
+	/* Enable display power gate & LOCALMEM power gate*/
+	reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
+	reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
+	reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
+	reg |= HIBMC_CURR_GATE_DISPLAY(1);
+	reg |= HIBMC_CURR_GATE_LOCALMEM(1);
+
+	hibmc_set_current_gate(priv, reg);
+
+	/*
+	 * Reset the memory controller. If the memory controller
+	 * is not reset in chip,the system might hang when sw accesses
+	 * the memory.The memory should be resetted after
+	 * changing the MXCLK.
+	 */
+	reg = readl(priv->mmio + HIBMC_MISC_CTRL);
+	reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
+	reg |= HIBMC_MSCCTL_LOCALMEM_RESET(0);
+	writel(reg, priv->mmio + HIBMC_MISC_CTRL);
+
+	reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
+	reg |= HIBMC_MSCCTL_LOCALMEM_RESET(1);
+
+	writel(reg, priv->mmio + HIBMC_MISC_CTRL);
+}
+
+static int hibmc_hw_map(struct hibmc_drm_private *priv)
+{
+	struct drm_device *dev = priv->dev;
+	struct pci_dev *pdev = dev->pdev;
+	resource_size_t addr, size, ioaddr, iosize;
+
+	ioaddr = pci_resource_start(pdev, 1);
+	iosize = pci_resource_len(pdev, 1);
+	priv->mmio = devm_ioremap_nocache(dev->dev, ioaddr, iosize);
+	if (!priv->mmio) {
+		DRM_ERROR("Cannot map mmio region\n");
+		return -ENOMEM;
+	}
+
+	addr = pci_resource_start(pdev, 0);
+	size = pci_resource_len(pdev, 0);
+	priv->fb_map = devm_ioremap(dev->dev, addr, size);
+	if (!priv->fb_map) {
+		DRM_ERROR("Cannot map framebuffer\n");
+		return -ENOMEM;
+	}
+	priv->fb_base = addr;
+	priv->fb_size = size;
+
+	return 0;
+}
+
+static int hibmc_hw_init(struct hibmc_drm_private *priv)
+{
+	int ret;
+
+	ret = hibmc_hw_map(priv);
+	if (ret)
+		return ret;
+
+	hibmc_hw_config(priv);
+
+	return 0;
+}
+
+static int hibmc_unload(struct drm_device *dev)
+{
+	return 0;
+}
+
+static int hibmc_load(struct drm_device *dev)
+{
+	struct hibmc_drm_private *priv;
+	int ret;
+
+	priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		DRM_ERROR("no memory to allocate for hibmc_drm_private\n");
+		return -ENOMEM;
+	}
+	dev->dev_private = priv;
+	priv->dev = dev;
+
+	ret = hibmc_hw_init(priv);
+	if (ret)
+		goto err;
+
+	return 0;
+
+err:
+	hibmc_unload(dev);
+	DRM_ERROR("failed to initialize drm driver: %d\n", ret);
+	return ret;
+}
+
+static int hibmc_pci_probe(struct pci_dev *pdev,
+			   const struct pci_device_id *ent)
+{
+	struct drm_device *dev;
+	int ret;
+
+	dev = drm_dev_alloc(&hibmc_driver, &pdev->dev);
+	if (!dev) {
+		DRM_ERROR("failed to allocate drm_device\n");
+		return -ENOMEM;
+	}
+
+	dev->pdev = pdev;
+	pci_set_drvdata(pdev, dev);
+
+	ret = pci_enable_device(pdev);
+	if (ret) {
+		DRM_ERROR("failed to enable pci device: %d\n", ret);
+		goto err_free;
+	}
+
+	ret = hibmc_load(dev);
+	if (ret) {
+		DRM_ERROR("failed to load hibmc: %d\n", ret);
+		goto err_disable;
+	}
+
+	ret = drm_dev_register(dev, 0);
+	if (ret) {
+		DRM_ERROR("failed to register drv for userspace access: %d\n",
+			  ret);
+		goto err_unload;
+	}
+	return 0;
+
+err_unload:
+	hibmc_unload(dev);
+err_disable:
+	pci_disable_device(pdev);
+err_free:
+	drm_dev_unref(dev);
+
+	return ret;
+}
+
+static void hibmc_pci_remove(struct pci_dev *pdev)
+{
+	struct drm_device *dev = pci_get_drvdata(pdev);
+
+	drm_dev_unregister(dev);
+	hibmc_unload(dev);
+	drm_dev_unref(dev);
+}
+
+static struct pci_device_id hibmc_pci_table[] = {
+	{0x19e5, 0x1711, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0,}
+};
+
+static struct pci_driver hibmc_pci_driver = {
+	.name =		"hibmc-drm",
+	.id_table =	hibmc_pci_table,
+	.probe =	hibmc_pci_probe,
+	.remove =	hibmc_pci_remove,
+	.driver.pm =    &hibmc_pm_ops,
+};
+
+static int __init hibmc_init(void)
+{
+	return pci_register_driver(&hibmc_pci_driver);
+}
+
+static void __exit hibmc_exit(void)
+{
+	return pci_unregister_driver(&hibmc_pci_driver);
+}
+
+module_init(hibmc_init);
+module_exit(hibmc_exit);
+
+MODULE_DEVICE_TABLE(pci, hibmc_pci_table);
+MODULE_AUTHOR("RongrongZou <zourongrong@huawei.com>");
+MODULE_DESCRIPTION("DRM Driver for Hisilicon Hibmc");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
new file mode 100644
index 0000000..840cd5a
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -0,0 +1,41 @@
+/* Hisilicon Hibmc SoC drm driver
+ *
+ * Based on the bochs drm driver.
+ *
+ * Copyright (c) 2016 Huawei Limited.
+ *
+ * Author:
+ *	Rongrong Zou <zourongrong@huawei.com>
+ *	Rongrong Zou <zourongrong@gmail.com>
+ *	Jianhua Li <lijianhua@huawei.com>
+ *
+ * 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.
+ *
+ */
+
+#ifndef HIBMC_DRM_DRV_H
+#define HIBMC_DRM_DRV_H
+
+#include <drm/drmP.h>
+
+struct hibmc_drm_private {
+	/* hw */
+	void __iomem   *mmio;
+	void __iomem   *fb_map;
+	unsigned long  fb_base;
+	unsigned long  fb_size;
+
+	/* drm */
+	struct drm_device  *dev;
+
+};
+
+void hibmc_set_power_mode(struct hibmc_drm_private *priv,
+			  unsigned int power_mode);
+void hibmc_set_current_gate(struct hibmc_drm_private *priv,
+			    unsigned int gate);
+
+#endif
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
new file mode 100644
index 0000000..f7035bf
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
@@ -0,0 +1,196 @@
+/* Hisilicon Hibmc SoC drm driver
+ *
+ * Based on the bochs drm driver.
+ *
+ * Copyright (c) 2016 Huawei Limited.
+ *
+ * Author:
+ *	Rongrong Zou <zourongrong@huawei.com>
+ *	Rongrong Zou <zourongrong@gmail.com>
+ *	Jianhua Li <lijianhua@huawei.com>
+ *
+ * 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.
+ *
+ */
+
+#ifndef HIBMC_DRM_HW_H
+#define HIBMC_DRM_HW_H
+
+/* register definition */
+#define HIBMC_MISC_CTRL				0x4
+
+#define HIBMC_MSCCTL_LOCALMEM_RESET(x)		((x) << 6)
+#define HIBMC_MSCCTL_LOCALMEM_RESET_MASK	0x40
+
+#define HIBMC_CURRENT_GATE			0x000040
+#define HIBMC_CURR_GATE_DISPLAY(x)		((x) << 2)
+#define HIBMC_CURR_GATE_DISPLAY_MASK		0x4
+
+#define HIBMC_CURR_GATE_LOCALMEM(x)		((x) << 1)
+#define HIBMC_CURR_GATE_LOCALMEM_MASK		0x2
+
+#define HIBMC_MODE0_GATE			0x000044
+#define HIBMC_MODE1_GATE			0x000048
+#define HIBMC_POWER_MODE_CTRL			0x00004C
+
+#define HIBMC_PW_MODE_CTL_OSC_INPUT(x)		((x) << 3)
+#define HIBMC_PW_MODE_CTL_OSC_INPUT_MASK	0x8
+
+#define HIBMC_PW_MODE_CTL_MODE(x)		((x) << 0)
+#define HIBMC_PW_MODE_CTL_MODE_MASK		0x03
+#define HIBMC_PW_MODE_CTL_MODE_SHIFT		0
+
+#define HIBMC_PW_MODE_CTL_MODE_MODE0		0
+#define HIBMC_PW_MODE_CTL_MODE_MODE1		1
+#define HIBMC_PW_MODE_CTL_MODE_SLEEP		2
+
+#define HIBMC_PANEL_PLL_CTRL			0x00005C
+#define HIBMC_CRT_PLL_CTRL			0x000060
+
+#define HIBMC_PLL_CTRL_BYPASS(x)		((x) << 18)
+#define HIBMC_PLL_CTRL_BYPASS_MASK		0x40000
+
+#define HIBMC_PLL_CTRL_POWER(x)			((x) << 17)
+#define HIBMC_PLL_CTRL_POWER_MASK		0x20000
+
+#define HIBMC_PLL_CTRL_INPUT(x)			((x) << 16)
+#define HIBMC_PLL_CTRL_INPUT_MASK		0x10000
+
+#define HIBMC_PLL_CTRL_POD(x)			((x) << 14)
+#define HIBMC_PLL_CTRL_POD_MASK			0xC000
+
+#define HIBMC_PLL_CTRL_OD(x)			((x) << 12)
+#define HIBMC_PLL_CTRL_OD_MASK			0x3000
+
+#define HIBMC_PLL_CTRL_N(x)			((x) << 8)
+#define HIBMC_PLL_CTRL_N_MASK			0xF00
+
+#define HIBMC_PLL_CTRL_M(x)			((x) << 0)
+#define HIBMC_PLL_CTRL_M_MASK			0xFF
+
+#define HIBMC_CRT_DISP_CTL			0x80200
+
+#define HIBMC_CRT_DISP_CTL_CRTSELECT(x)		((x) << 25)
+#define HIBMC_CRT_DISP_CTL_CRTSELECT_MASK	0x2000000
+
+#define HIBMC_CRTSELECT_CRT			1
+
+#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE(x)	((x) << 14)
+#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE_MASK	0x4000
+
+#define HIBMC_CRT_DISP_CTL_VSYNC_PHASE(x)	((x) << 13)
+#define HIBMC_CRT_DISP_CTL_VSYNC_PHASE_MASK	0x2000
+
+#define HIBMC_CRT_DISP_CTL_HSYNC_PHASE(x)	((x) << 12)
+#define HIBMC_CRT_DISP_CTL_HSYNC_PHASE_MASK	0x1000
+
+#define HIBMC_CRT_DISP_CTL_TIMING(x)		((x) << 8)
+#define HIBMC_CRT_DISP_CTL_TIMING_MASK		0x100
+
+#define HIBMC_CRT_DISP_CTL_PLANE(x)		((x) << 2)
+#define HIBMC_CRT_DISP_CTL_PLANE_MASK		4
+
+#define HIBMC_CRT_DISP_CTL_FORMAT(x)		((x) << 0)
+#define HIBMC_CRT_DISP_CTL_FORMAT_MASK		0x03
+
+#define HIBMC_CRT_FB_ADDRESS			0x080204
+
+#define HIBMC_CRT_FB_WIDTH			0x080208
+#define HIBMC_CRT_FB_WIDTH_WIDTH(x)		((x) << 16)
+#define HIBMC_CRT_FB_WIDTH_WIDTH_MASK		0x3FFF0000
+#define HIBMC_CRT_FB_WIDTH_OFFS(x)		((x) << 0)
+#define HIBMC_CRT_FB_WIDTH_OFFS_MASK		0x3FFF
+
+#define HIBMC_CRT_HORZ_TOTAL			0x08020C
+#define HIBMC_CRT_HORZ_TOTAL_TOTAL(x)		((x) << 16)
+#define HIBMC_CRT_HORZ_TOTAL_TOTAL_MASK		0xFFF0000
+
+#define HIBMC_CRT_HORZ_TOTAL_DISP_END(x)	((x) << 0)
+#define HIBMC_CRT_HORZ_TOTAL_DISP_END_MASK	0xFFF
+
+#define HIBMC_CRT_HORZ_SYNC			0x080210
+#define HIBMC_CRT_HORZ_SYNC_WIDTH(x)		((x) << 16)
+#define HIBMC_CRT_HORZ_SYNC_WIDTH_MASK		0xFF0000
+
+#define HIBMC_CRT_HORZ_SYNC_START(x)		((x) << 0)
+#define HIBMC_CRT_HORZ_SYNC_START_MASK		0xFFF
+
+#define HIBMC_CRT_VERT_TOTAL			0x080214
+#define HIBMC_CRT_VERT_TOTAL_TOTAL(x)		((x) << 16)
+#define HIBMC_CRT_VERT_TOTAL_TOTAL_MASK		0x7FFF0000
+
+#define HIBMC_CRT_VERT_TOTAL_DISP_END(x)	((x) << 0)
+#define HIBMC_CRT_VERT_TOTAL_DISP_END_MASK	0x7FF
+
+#define HIBMC_CRT_VERT_SYNC			0x080218
+#define HIBMC_CRT_VERT_SYNC_HEIGHT(x)		((x) << 16)
+#define HIBMC_CRT_VERT_SYNC_HEIGHT_MASK		0x3F0000
+
+#define HIBMC_CRT_VERT_SYNC_START(x)		((x) << 0)
+#define HIBMC_CRT_VERT_SYNC_START_MASK		0x7FF
+
+/* Auto Centering */
+#define HIBMC_CRT_AUTO_CENTERING_TL		0x080280
+#define HIBMC_CRT_AUTO_CENTERING_TL_TOP(x)	((x) << 16)
+#define HIBMC_CRT_AUTO_CENTERING_TL_TOP_MASK	0x7FF0000
+
+#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT(x)	((x) << 0)
+#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT_MASK	0x7FF
+
+#define HIBMC_CRT_AUTO_CENTERING_BR		0x080284
+#define HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM(x)	((x) << 16)
+#define HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM_MASK	0x7FF0000
+
+#define HIBMC_CRT_AUTO_CENTERING_BR_RIGHT(x)	((x) << 0)
+#define HIBMC_CRT_AUTO_CENTERING_BR_RIGHT_MASK	0x7FF
+
+/* register to control panel output */
+#define HIBMC_DISPLAY_CONTROL_HISILE		0x80288
+#define HIBMC_DISPLAY_CONTROL_FPVDDEN(x)	((x) << 0)
+#define HIBMC_DISPLAY_CONTROL_PANELDATE(x)	((x) << 1)
+#define HIBMC_DISPLAY_CONTROL_FPEN(x)		((x) << 2)
+#define HIBMC_DISPLAY_CONTROL_VBIASEN(x)	((x) << 3)
+
+#define HIBMC_RAW_INTERRUPT			0x80290
+#define HIBMC_RAW_INTERRUPT_VBLANK(x)		((x) << 2)
+#define HIBMC_RAW_INTERRUPT_VBLANK_MASK		0x4
+
+#define HIBMC_RAW_INTERRUPT_EN			0x80298
+#define HIBMC_RAW_INTERRUPT_EN_VBLANK(x)	((x) << 2)
+#define HIBMC_RAW_INTERRUPT_EN_VBLANK_MASK	0x4
+
+/* register and values for PLL control */
+#define CRT_PLL1_HS				0x802a8
+#define CRT_PLL1_HS_OUTER_BYPASS(x)		((x) << 30)
+#define CRT_PLL1_HS_INTER_BYPASS(x)		((x) << 29)
+#define CRT_PLL1_HS_POWERON(x)			((x) << 24)
+
+#define CRT_PLL1_HS_25MHZ			0x23d40f02
+#define CRT_PLL1_HS_40MHZ			0x23940801
+#define CRT_PLL1_HS_65MHZ			0x23940d01
+#define CRT_PLL1_HS_78MHZ			0x23540F82
+#define CRT_PLL1_HS_74MHZ			0x23941dc2
+#define CRT_PLL1_HS_80MHZ			0x23941001
+#define CRT_PLL1_HS_80MHZ_1152			0x23540fc2
+#define CRT_PLL1_HS_108MHZ			0x23b41b01
+#define CRT_PLL1_HS_162MHZ			0x23480681
+#define CRT_PLL1_HS_148MHZ			0x23541dc2
+#define CRT_PLL1_HS_193MHZ			0x234807c1
+
+#define CRT_PLL2_HS				0x802ac
+#define CRT_PLL2_HS_25MHZ			0x206B851E
+#define CRT_PLL2_HS_40MHZ			0x30000000
+#define CRT_PLL2_HS_65MHZ			0x40000000
+#define CRT_PLL2_HS_78MHZ			0x50E147AE
+#define CRT_PLL2_HS_74MHZ			0x602B6AE7
+#define CRT_PLL2_HS_80MHZ			0x70000000
+#define CRT_PLL2_HS_108MHZ			0x80000000
+#define CRT_PLL2_HS_162MHZ			0xA0000000
+#define CRT_PLL2_HS_148MHZ			0xB0CCCCCD
+#define CRT_PLL2_HS_193MHZ			0xC0872B02
+
+#define HIBMC_FIELD(field, value) (field(value) & field##_MASK)
+#endif
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v7 2/7] drm/hisilicon/hibmc: Add video memory management
  2016-11-16 13:43 ` Rongrong Zou
@ 2016-11-16 13:43   ` Rongrong Zou
  -1 siblings, 0 replies; 40+ messages in thread
From: Rongrong Zou @ 2016-11-16 13:43 UTC (permalink / raw)
  To: linux-arm-kernel

Hibmc have 32m video memory which can be accessed through PCIe by host,
we use ttm to manage these memory.

Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
---
 drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  14 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |  41 ++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     | 485 ++++++++++++++++++++++++
 4 files changed, 541 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c

diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
index 47962a0..19ed0ef 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
+++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
@@ -1,4 +1,4 @@
 ccflags-y := -Iinclude/drm
-hibmc-drm-y := hibmc_drm_drv.o
+hibmc-drm-y := hibmc_drm_drv.o hibmc_ttm.o
 
 obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index 6d20580..521f69f 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -28,6 +28,7 @@
 	.release	= drm_release,
 	.unlocked_ioctl	= drm_ioctl,
 	.compat_ioctl	= drm_compat_ioctl,
+	.mmap		= hibmc_mmap,
 	.poll		= drm_poll,
 	.read		= drm_read,
 	.llseek		= no_llseek,
@@ -43,6 +44,7 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
 }
 
 static struct drm_driver hibmc_driver = {
+	.driver_features	= DRIVER_GEM,
 	.fops			= &hibmc_fops,
 	.name			= "hibmc",
 	.date			= "20160828",
@@ -52,6 +54,10 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
 	.get_vblank_counter	= drm_vblank_no_hw_counter,
 	.enable_vblank		= hibmc_enable_vblank,
 	.disable_vblank		= hibmc_disable_vblank,
+	.gem_free_object_unlocked = hibmc_gem_free_object,
+	.dumb_create            = hibmc_dumb_create,
+	.dumb_map_offset        = hibmc_dumb_mmap_offset,
+	.dumb_destroy           = drm_gem_dumb_destroy,
 };
 
 static int hibmc_pm_suspend(struct device *dev)
@@ -194,6 +200,10 @@ static int hibmc_hw_init(struct hibmc_drm_private *priv)
 
 static int hibmc_unload(struct drm_device *dev)
 {
+	struct hibmc_drm_private *priv = dev->dev_private;
+
+	hibmc_mm_fini(priv);
+	dev->dev_private = NULL;
 	return 0;
 }
 
@@ -214,6 +224,10 @@ static int hibmc_load(struct drm_device *dev)
 	if (ret)
 		goto err;
 
+	ret = hibmc_mm_init(priv);
+	if (ret)
+		goto err;
+
 	return 0;
 
 err:
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
index 840cd5a..dcd304d 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -20,6 +20,8 @@
 #define HIBMC_DRM_DRV_H
 
 #include <drm/drmP.h>
+#include <drm/drm_gem.h>
+#include <drm/ttm/ttm_bo_driver.h>
 
 struct hibmc_drm_private {
 	/* hw */
@@ -31,11 +33,50 @@ struct hibmc_drm_private {
 	/* drm */
 	struct drm_device  *dev;
 
+	/* ttm */
+	struct drm_global_reference mem_global_ref;
+	struct ttm_bo_global_ref bo_global_ref;
+	struct ttm_bo_device bdev;
+	bool initialized;
+
+	bool mm_inited;
+};
+
+struct hibmc_bo {
+	struct ttm_buffer_object bo;
+	struct ttm_placement placement;
+	struct ttm_bo_kmap_obj kmap;
+	struct drm_gem_object gem;
+	struct ttm_place placements[3];
+	int pin_count;
 };
 
+static inline struct hibmc_bo *hibmc_bo(struct ttm_buffer_object *bo)
+{
+	return container_of(bo, struct hibmc_bo, bo);
+}
+
+static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
+{
+	return container_of(gem, struct hibmc_bo, gem);
+}
+
 void hibmc_set_power_mode(struct hibmc_drm_private *priv,
 			  unsigned int power_mode);
 void hibmc_set_current_gate(struct hibmc_drm_private *priv,
 			    unsigned int gate);
 
+int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
+		     struct drm_gem_object **obj);
+int hibmc_mm_init(struct hibmc_drm_private *hibmc);
+void hibmc_mm_fini(struct hibmc_drm_private *hibmc);
+int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr);
+int hibmc_bo_unpin(struct hibmc_bo *bo);
+void hibmc_gem_free_object(struct drm_gem_object *obj);
+int hibmc_dumb_create(struct drm_file *file, struct drm_device *dev,
+		      struct drm_mode_create_dumb *args);
+int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
+			   u32 handle, u64 *offset);
+int hibmc_mmap(struct file *filp, struct vm_area_struct *vma);
+
 #endif
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
new file mode 100644
index 0000000..036d3ac
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
@@ -0,0 +1,485 @@
+/* Hisilicon Hibmc SoC drm driver
+ *
+ * Based on the bochs drm driver.
+ *
+ * Copyright (c) 2016 Huawei Limited.
+ *
+ * Author:
+ *	Rongrong Zou <zourongrong@huawei.com>
+ *	Rongrong Zou <zourongrong@gmail.com>
+ *	Jianhua Li <lijianhua@huawei.com>
+ *
+ * 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.
+ *
+ */
+
+#include <ttm/ttm_page_alloc.h>
+
+#include "hibmc_drm_drv.h"
+
+#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
+
+static inline struct hibmc_drm_private *
+hibmc_bdev(struct ttm_bo_device *bd)
+{
+	return container_of(bd, struct hibmc_drm_private, bdev);
+}
+
+static int
+hibmc_ttm_mem_global_init(struct drm_global_reference *ref)
+{
+	return ttm_mem_global_init(ref->object);
+}
+
+static void
+hibmc_ttm_mem_global_release(struct drm_global_reference *ref)
+{
+	ttm_mem_global_release(ref->object);
+}
+
+static int hibmc_ttm_global_init(struct hibmc_drm_private *hibmc)
+{
+	int ret;
+
+	hibmc->mem_global_ref.global_type = DRM_GLOBAL_TTM_MEM;
+	hibmc->mem_global_ref.size = sizeof(struct ttm_mem_global);
+	hibmc->mem_global_ref.init = &hibmc_ttm_mem_global_init;
+	hibmc->mem_global_ref.release = &hibmc_ttm_mem_global_release;
+	ret = drm_global_item_ref(&hibmc->mem_global_ref);
+	if (ret) {
+		DRM_ERROR("could not get ref on ttm global: %d\n", ret);
+		return ret;
+	}
+
+	hibmc->bo_global_ref.mem_glob =
+		hibmc->mem_global_ref.object;
+	hibmc->bo_global_ref.ref.global_type = DRM_GLOBAL_TTM_BO;
+	hibmc->bo_global_ref.ref.size = sizeof(struct ttm_bo_global);
+	hibmc->bo_global_ref.ref.init = &ttm_bo_global_init;
+	hibmc->bo_global_ref.ref.release = &ttm_bo_global_release;
+	ret = drm_global_item_ref(&hibmc->bo_global_ref.ref);
+	if (ret) {
+		DRM_ERROR("failed setting up TTM BO subsystem: %d\n", ret);
+		drm_global_item_unref(&hibmc->mem_global_ref);
+		return ret;
+	}
+	return 0;
+}
+
+static void
+hibmc_ttm_global_release(struct hibmc_drm_private *hibmc)
+{
+	drm_global_item_unref(&hibmc->bo_global_ref.ref);
+	drm_global_item_unref(&hibmc->mem_global_ref);
+	hibmc->mem_global_ref.release = NULL;
+}
+
+static void hibmc_bo_ttm_destroy(struct ttm_buffer_object *tbo)
+{
+	struct hibmc_bo *bo = container_of(tbo, struct hibmc_bo, bo);
+
+	drm_gem_object_release(&bo->gem);
+	kfree(bo);
+}
+
+static bool hibmc_ttm_bo_is_hibmc_bo(struct ttm_buffer_object *bo)
+{
+	return bo->destroy == &hibmc_bo_ttm_destroy;
+}
+
+static int
+hibmc_bo_init_mem_type(struct ttm_bo_device *bdev, u32 type,
+		       struct ttm_mem_type_manager *man)
+{
+	switch (type) {
+	case TTM_PL_SYSTEM:
+		man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
+		man->available_caching = TTM_PL_MASK_CACHING;
+		man->default_caching = TTM_PL_FLAG_CACHED;
+		break;
+	case TTM_PL_VRAM:
+		man->func = &ttm_bo_manager_func;
+		man->flags = TTM_MEMTYPE_FLAG_FIXED |
+			TTM_MEMTYPE_FLAG_MAPPABLE;
+		man->available_caching = TTM_PL_FLAG_UNCACHED |
+			TTM_PL_FLAG_WC;
+		man->default_caching = TTM_PL_FLAG_WC;
+		break;
+	default:
+		DRM_ERROR("unsupported memory type %u\n", type);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+void hibmc_ttm_placement(struct hibmc_bo *bo, int domain)
+{
+	u32 count = 0;
+	u32 i;
+
+	bo->placement.placement = bo->placements;
+	bo->placement.busy_placement = bo->placements;
+	if (domain & TTM_PL_FLAG_VRAM)
+		bo->placements[count++].flags = TTM_PL_FLAG_WC |
+			TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
+	if (domain & TTM_PL_FLAG_SYSTEM)
+		bo->placements[count++].flags = TTM_PL_MASK_CACHING |
+			TTM_PL_FLAG_SYSTEM;
+	if (!count)
+		bo->placements[count++].flags = TTM_PL_MASK_CACHING |
+			TTM_PL_FLAG_SYSTEM;
+
+	bo->placement.num_placement = count;
+	bo->placement.num_busy_placement = count;
+	for (i = 0; i < count; i++) {
+		bo->placements[i].fpfn = 0;
+		bo->placements[i].lpfn = 0;
+	}
+}
+
+static void
+hibmc_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
+{
+	struct hibmc_bo *hibmcbo = hibmc_bo(bo);
+
+	if (!hibmc_ttm_bo_is_hibmc_bo(bo))
+		return;
+
+	hibmc_ttm_placement(hibmcbo, TTM_PL_FLAG_SYSTEM);
+	*pl = hibmcbo->placement;
+}
+
+static int hibmc_bo_verify_access(struct ttm_buffer_object *bo,
+				  struct file *filp)
+{
+	struct hibmc_bo *hibmcbo = hibmc_bo(bo);
+
+	return drm_vma_node_verify_access(&hibmcbo->gem.vma_node,
+					  filp->private_data);
+}
+
+static int hibmc_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
+				    struct ttm_mem_reg *mem)
+{
+	struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
+	struct hibmc_drm_private *hibmc = hibmc_bdev(bdev);
+
+	mem->bus.addr = NULL;
+	mem->bus.offset = 0;
+	mem->bus.size = mem->num_pages << PAGE_SHIFT;
+	mem->bus.base = 0;
+	mem->bus.is_iomem = false;
+	if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE))
+		return -EINVAL;
+	switch (mem->mem_type) {
+	case TTM_PL_SYSTEM:
+		/* system memory */
+		return 0;
+	case TTM_PL_VRAM:
+		mem->bus.offset = mem->start << PAGE_SHIFT;
+		mem->bus.base = pci_resource_start(hibmc->dev->pdev, 0);
+		mem->bus.is_iomem = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void hibmc_ttm_backend_destroy(struct ttm_tt *tt)
+{
+	ttm_tt_fini(tt);
+	kfree(tt);
+}
+
+static struct ttm_backend_func hibmc_tt_backend_func = {
+	.destroy = &hibmc_ttm_backend_destroy,
+};
+
+static struct ttm_tt *hibmc_ttm_tt_create(struct ttm_bo_device *bdev,
+					  unsigned long size,
+					  u32 page_flags,
+					  struct page *dummy_read_page)
+{
+	struct ttm_tt *tt;
+	int ret;
+
+	tt = kzalloc(sizeof(*tt), GFP_KERNEL);
+	if (!tt) {
+		DRM_ERROR("failed to allocate ttm_tt\n");
+		return NULL;
+	}
+	tt->func = &hibmc_tt_backend_func;
+	ret = ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page);
+	if (ret) {
+		DRM_ERROR("failed to initialize ttm_tt: %d\n", ret);
+		kfree(tt);
+		return NULL;
+	}
+	return tt;
+}
+
+static int hibmc_ttm_tt_populate(struct ttm_tt *ttm)
+{
+	return ttm_pool_populate(ttm);
+}
+
+static void hibmc_ttm_tt_unpopulate(struct ttm_tt *ttm)
+{
+	ttm_pool_unpopulate(ttm);
+}
+
+struct ttm_bo_driver hibmc_bo_driver = {
+	.ttm_tt_create		= hibmc_ttm_tt_create,
+	.ttm_tt_populate	= hibmc_ttm_tt_populate,
+	.ttm_tt_unpopulate	= hibmc_ttm_tt_unpopulate,
+	.init_mem_type		= hibmc_bo_init_mem_type,
+	.evict_flags		= hibmc_bo_evict_flags,
+	.move			= NULL,
+	.verify_access		= hibmc_bo_verify_access,
+	.io_mem_reserve		= &hibmc_ttm_io_mem_reserve,
+	.io_mem_free		= NULL,
+	.lru_tail		= &ttm_bo_default_lru_tail,
+	.swap_lru_tail		= &ttm_bo_default_swap_lru_tail,
+};
+
+int hibmc_mm_init(struct hibmc_drm_private *hibmc)
+{
+	int ret;
+	struct drm_device *dev = hibmc->dev;
+	struct ttm_bo_device *bdev = &hibmc->bdev;
+
+	ret = hibmc_ttm_global_init(hibmc);
+	if (ret)
+		return ret;
+
+	ret = ttm_bo_device_init(&hibmc->bdev,
+				 hibmc->bo_global_ref.ref.object,
+				 &hibmc_bo_driver,
+				 dev->anon_inode->i_mapping,
+				 DRM_FILE_PAGE_OFFSET,
+				 true);
+	if (ret) {
+		hibmc_ttm_global_release(hibmc);
+		DRM_ERROR("error initializing bo driver: %d\n", ret);
+		return ret;
+	}
+
+	ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
+			     hibmc->fb_size >> PAGE_SHIFT);
+	if (ret) {
+		hibmc_ttm_global_release(hibmc);
+		DRM_ERROR("failed ttm VRAM init: %d\n", ret);
+		return ret;
+	}
+
+	hibmc->mm_inited = true;
+	return 0;
+}
+
+void hibmc_mm_fini(struct hibmc_drm_private *hibmc)
+{
+	if (!hibmc->mm_inited)
+		return;
+
+	ttm_bo_device_release(&hibmc->bdev);
+	hibmc_ttm_global_release(hibmc);
+	hibmc->mm_inited = false;
+}
+
+static void hibmc_bo_unref(struct hibmc_bo **bo)
+{
+	struct ttm_buffer_object *tbo;
+
+	if ((*bo) == NULL)
+		return;
+
+	tbo = &((*bo)->bo);
+	ttm_bo_unref(&tbo);
+	*bo = NULL;
+}
+
+int hibmc_bo_create(struct drm_device *dev, int size, int align,
+		    u32 flags, struct hibmc_bo **phibmcbo)
+{
+	struct hibmc_drm_private *hibmc = dev->dev_private;
+	struct hibmc_bo *hibmcbo;
+	size_t acc_size;
+	int ret;
+
+	hibmcbo = kzalloc(sizeof(*hibmcbo), GFP_KERNEL);
+	if (!hibmcbo) {
+		DRM_ERROR("failed to allocate hibmcbo\n");
+		return -ENOMEM;
+	}
+	ret = drm_gem_object_init(dev, &hibmcbo->gem, size);
+	if (ret) {
+		DRM_ERROR("failed to initialize drm gem object: %d\n", ret);
+		kfree(hibmcbo);
+		return ret;
+	}
+
+	hibmcbo->bo.bdev = &hibmc->bdev;
+
+	hibmc_ttm_placement(hibmcbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
+
+	acc_size = ttm_bo_dma_acc_size(&hibmc->bdev, size,
+				       sizeof(struct hibmc_bo));
+
+	ret = ttm_bo_init(&hibmc->bdev, &hibmcbo->bo, size,
+			  ttm_bo_type_device, &hibmcbo->placement,
+			  align >> PAGE_SHIFT, false, NULL, acc_size,
+			  NULL, NULL, hibmc_bo_ttm_destroy);
+	if (ret) {
+		hibmc_bo_unref(&hibmcbo);
+		DRM_ERROR("failed to initialize ttm_bo: %d\n", ret);
+		return ret;
+	}
+
+	*phibmcbo = hibmcbo;
+	return 0;
+}
+
+int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr)
+{
+	int i, ret;
+
+	if (bo->pin_count) {
+		bo->pin_count++;
+		if (gpu_addr)
+			*gpu_addr = bo->bo.offset;
+		return 0;
+	}
+
+	hibmc_ttm_placement(bo, pl_flag);
+	for (i = 0; i < bo->placement.num_placement; i++)
+		bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
+	ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
+	if (ret)
+		return ret;
+
+	bo->pin_count = 1;
+	if (gpu_addr)
+		*gpu_addr = bo->bo.offset;
+	return 0;
+}
+
+int hibmc_bo_unpin(struct hibmc_bo *bo)
+{
+	int i, ret;
+
+	if (!bo->pin_count) {
+		DRM_ERROR("unpin bad %p\n", bo);
+		return 0;
+	}
+	bo->pin_count--;
+	if (bo->pin_count)
+		return 0;
+
+	for (i = 0; i < bo->placement.num_placement ; i++)
+		bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT;
+	ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
+	if (ret) {
+		DRM_ERROR("validate failed for unpin: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+int hibmc_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct drm_file *file_priv;
+	struct hibmc_drm_private *hibmc;
+
+	if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET))
+		return -EINVAL;
+
+	file_priv = filp->private_data;
+	hibmc = file_priv->minor->dev->dev_private;
+	return ttm_bo_mmap(filp, vma, &hibmc->bdev);
+}
+
+int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
+		     struct drm_gem_object **obj)
+{
+	struct hibmc_bo *hibmcbo;
+	int ret;
+
+	*obj = NULL;
+
+	size = PAGE_ALIGN(size);
+	if (size == 0) {
+		DRM_ERROR("error: zero size\n");
+		return -EINVAL;
+	}
+
+	ret = hibmc_bo_create(dev, size, 0, 0, &hibmcbo);
+	if (ret) {
+		if (ret != -ERESTARTSYS)
+			DRM_ERROR("failed to allocate GEM object: %d\n", ret);
+		return ret;
+	}
+	*obj = &hibmcbo->gem;
+	return 0;
+}
+
+int hibmc_dumb_create(struct drm_file *file, struct drm_device *dev,
+		      struct drm_mode_create_dumb *args)
+{
+	struct drm_gem_object *gobj;
+	u32 handle;
+	int ret;
+
+	args->pitch = ALIGN(args->width * DIV_ROUND_UP(args->bpp, 8), 16);
+	args->size = args->pitch * args->height;
+
+	ret = hibmc_gem_create(dev, args->size, false,
+			       &gobj);
+	if (ret) {
+		DRM_ERROR("failed to create GEM object: %d\n", ret);
+		return ret;
+	}
+
+	ret = drm_gem_handle_create(file, gobj, &handle);
+	drm_gem_object_unreference_unlocked(gobj);
+	if (ret) {
+		DRM_ERROR("failed to unreference GEM object: %d\n", ret);
+		return ret;
+	}
+
+	args->handle = handle;
+	return 0;
+}
+
+void hibmc_gem_free_object(struct drm_gem_object *obj)
+{
+	struct hibmc_bo *hibmcbo = gem_to_hibmc_bo(obj);
+
+	hibmc_bo_unref(&hibmcbo);
+}
+
+static u64 hibmc_bo_mmap_offset(struct hibmc_bo *bo)
+{
+	return drm_vma_node_offset_addr(&bo->bo.vma_node);
+}
+
+int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
+			   u32 handle, u64 *offset)
+{
+	struct drm_gem_object *obj;
+	struct hibmc_bo *bo;
+
+	obj = drm_gem_object_lookup(file, handle);
+	if (!obj)
+		return -ENOENT;
+
+	bo = gem_to_hibmc_bo(obj);
+	*offset = hibmc_bo_mmap_offset(bo);
+
+	drm_gem_object_unreference_unlocked(obj);
+	return 0;
+}
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v7 2/7] drm/hisilicon/hibmc: Add video memory management
@ 2016-11-16 13:43   ` Rongrong Zou
  0 siblings, 0 replies; 40+ messages in thread
From: Rongrong Zou @ 2016-11-16 13:43 UTC (permalink / raw)
  To: airlied, daniel, seanpaul, seanpaul, dri-devel, emil.l.velikov,
	tomeu.vizoso, benjamin.gaignard, robh, daniel, architt, corbet,
	mark.rutland, xinliang.liu
  Cc: linuxarm, kong.kongxinwei, james.xiong, shenhui, guohanjun,
	lijianhua, linux-arm-kernel

Hibmc have 32m video memory which can be accessed through PCIe by host,
we use ttm to manage these memory.

Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
---
 drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  14 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |  41 ++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     | 485 ++++++++++++++++++++++++
 4 files changed, 541 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c

diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
index 47962a0..19ed0ef 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
+++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
@@ -1,4 +1,4 @@
 ccflags-y := -Iinclude/drm
-hibmc-drm-y := hibmc_drm_drv.o
+hibmc-drm-y := hibmc_drm_drv.o hibmc_ttm.o
 
 obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index 6d20580..521f69f 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -28,6 +28,7 @@
 	.release	= drm_release,
 	.unlocked_ioctl	= drm_ioctl,
 	.compat_ioctl	= drm_compat_ioctl,
+	.mmap		= hibmc_mmap,
 	.poll		= drm_poll,
 	.read		= drm_read,
 	.llseek		= no_llseek,
@@ -43,6 +44,7 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
 }
 
 static struct drm_driver hibmc_driver = {
+	.driver_features	= DRIVER_GEM,
 	.fops			= &hibmc_fops,
 	.name			= "hibmc",
 	.date			= "20160828",
@@ -52,6 +54,10 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
 	.get_vblank_counter	= drm_vblank_no_hw_counter,
 	.enable_vblank		= hibmc_enable_vblank,
 	.disable_vblank		= hibmc_disable_vblank,
+	.gem_free_object_unlocked = hibmc_gem_free_object,
+	.dumb_create            = hibmc_dumb_create,
+	.dumb_map_offset        = hibmc_dumb_mmap_offset,
+	.dumb_destroy           = drm_gem_dumb_destroy,
 };
 
 static int hibmc_pm_suspend(struct device *dev)
@@ -194,6 +200,10 @@ static int hibmc_hw_init(struct hibmc_drm_private *priv)
 
 static int hibmc_unload(struct drm_device *dev)
 {
+	struct hibmc_drm_private *priv = dev->dev_private;
+
+	hibmc_mm_fini(priv);
+	dev->dev_private = NULL;
 	return 0;
 }
 
@@ -214,6 +224,10 @@ static int hibmc_load(struct drm_device *dev)
 	if (ret)
 		goto err;
 
+	ret = hibmc_mm_init(priv);
+	if (ret)
+		goto err;
+
 	return 0;
 
 err:
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
index 840cd5a..dcd304d 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -20,6 +20,8 @@
 #define HIBMC_DRM_DRV_H
 
 #include <drm/drmP.h>
+#include <drm/drm_gem.h>
+#include <drm/ttm/ttm_bo_driver.h>
 
 struct hibmc_drm_private {
 	/* hw */
@@ -31,11 +33,50 @@ struct hibmc_drm_private {
 	/* drm */
 	struct drm_device  *dev;
 
+	/* ttm */
+	struct drm_global_reference mem_global_ref;
+	struct ttm_bo_global_ref bo_global_ref;
+	struct ttm_bo_device bdev;
+	bool initialized;
+
+	bool mm_inited;
+};
+
+struct hibmc_bo {
+	struct ttm_buffer_object bo;
+	struct ttm_placement placement;
+	struct ttm_bo_kmap_obj kmap;
+	struct drm_gem_object gem;
+	struct ttm_place placements[3];
+	int pin_count;
 };
 
+static inline struct hibmc_bo *hibmc_bo(struct ttm_buffer_object *bo)
+{
+	return container_of(bo, struct hibmc_bo, bo);
+}
+
+static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
+{
+	return container_of(gem, struct hibmc_bo, gem);
+}
+
 void hibmc_set_power_mode(struct hibmc_drm_private *priv,
 			  unsigned int power_mode);
 void hibmc_set_current_gate(struct hibmc_drm_private *priv,
 			    unsigned int gate);
 
+int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
+		     struct drm_gem_object **obj);
+int hibmc_mm_init(struct hibmc_drm_private *hibmc);
+void hibmc_mm_fini(struct hibmc_drm_private *hibmc);
+int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr);
+int hibmc_bo_unpin(struct hibmc_bo *bo);
+void hibmc_gem_free_object(struct drm_gem_object *obj);
+int hibmc_dumb_create(struct drm_file *file, struct drm_device *dev,
+		      struct drm_mode_create_dumb *args);
+int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
+			   u32 handle, u64 *offset);
+int hibmc_mmap(struct file *filp, struct vm_area_struct *vma);
+
 #endif
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
new file mode 100644
index 0000000..036d3ac
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
@@ -0,0 +1,485 @@
+/* Hisilicon Hibmc SoC drm driver
+ *
+ * Based on the bochs drm driver.
+ *
+ * Copyright (c) 2016 Huawei Limited.
+ *
+ * Author:
+ *	Rongrong Zou <zourongrong@huawei.com>
+ *	Rongrong Zou <zourongrong@gmail.com>
+ *	Jianhua Li <lijianhua@huawei.com>
+ *
+ * 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.
+ *
+ */
+
+#include <ttm/ttm_page_alloc.h>
+
+#include "hibmc_drm_drv.h"
+
+#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
+
+static inline struct hibmc_drm_private *
+hibmc_bdev(struct ttm_bo_device *bd)
+{
+	return container_of(bd, struct hibmc_drm_private, bdev);
+}
+
+static int
+hibmc_ttm_mem_global_init(struct drm_global_reference *ref)
+{
+	return ttm_mem_global_init(ref->object);
+}
+
+static void
+hibmc_ttm_mem_global_release(struct drm_global_reference *ref)
+{
+	ttm_mem_global_release(ref->object);
+}
+
+static int hibmc_ttm_global_init(struct hibmc_drm_private *hibmc)
+{
+	int ret;
+
+	hibmc->mem_global_ref.global_type = DRM_GLOBAL_TTM_MEM;
+	hibmc->mem_global_ref.size = sizeof(struct ttm_mem_global);
+	hibmc->mem_global_ref.init = &hibmc_ttm_mem_global_init;
+	hibmc->mem_global_ref.release = &hibmc_ttm_mem_global_release;
+	ret = drm_global_item_ref(&hibmc->mem_global_ref);
+	if (ret) {
+		DRM_ERROR("could not get ref on ttm global: %d\n", ret);
+		return ret;
+	}
+
+	hibmc->bo_global_ref.mem_glob =
+		hibmc->mem_global_ref.object;
+	hibmc->bo_global_ref.ref.global_type = DRM_GLOBAL_TTM_BO;
+	hibmc->bo_global_ref.ref.size = sizeof(struct ttm_bo_global);
+	hibmc->bo_global_ref.ref.init = &ttm_bo_global_init;
+	hibmc->bo_global_ref.ref.release = &ttm_bo_global_release;
+	ret = drm_global_item_ref(&hibmc->bo_global_ref.ref);
+	if (ret) {
+		DRM_ERROR("failed setting up TTM BO subsystem: %d\n", ret);
+		drm_global_item_unref(&hibmc->mem_global_ref);
+		return ret;
+	}
+	return 0;
+}
+
+static void
+hibmc_ttm_global_release(struct hibmc_drm_private *hibmc)
+{
+	drm_global_item_unref(&hibmc->bo_global_ref.ref);
+	drm_global_item_unref(&hibmc->mem_global_ref);
+	hibmc->mem_global_ref.release = NULL;
+}
+
+static void hibmc_bo_ttm_destroy(struct ttm_buffer_object *tbo)
+{
+	struct hibmc_bo *bo = container_of(tbo, struct hibmc_bo, bo);
+
+	drm_gem_object_release(&bo->gem);
+	kfree(bo);
+}
+
+static bool hibmc_ttm_bo_is_hibmc_bo(struct ttm_buffer_object *bo)
+{
+	return bo->destroy == &hibmc_bo_ttm_destroy;
+}
+
+static int
+hibmc_bo_init_mem_type(struct ttm_bo_device *bdev, u32 type,
+		       struct ttm_mem_type_manager *man)
+{
+	switch (type) {
+	case TTM_PL_SYSTEM:
+		man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
+		man->available_caching = TTM_PL_MASK_CACHING;
+		man->default_caching = TTM_PL_FLAG_CACHED;
+		break;
+	case TTM_PL_VRAM:
+		man->func = &ttm_bo_manager_func;
+		man->flags = TTM_MEMTYPE_FLAG_FIXED |
+			TTM_MEMTYPE_FLAG_MAPPABLE;
+		man->available_caching = TTM_PL_FLAG_UNCACHED |
+			TTM_PL_FLAG_WC;
+		man->default_caching = TTM_PL_FLAG_WC;
+		break;
+	default:
+		DRM_ERROR("unsupported memory type %u\n", type);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+void hibmc_ttm_placement(struct hibmc_bo *bo, int domain)
+{
+	u32 count = 0;
+	u32 i;
+
+	bo->placement.placement = bo->placements;
+	bo->placement.busy_placement = bo->placements;
+	if (domain & TTM_PL_FLAG_VRAM)
+		bo->placements[count++].flags = TTM_PL_FLAG_WC |
+			TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
+	if (domain & TTM_PL_FLAG_SYSTEM)
+		bo->placements[count++].flags = TTM_PL_MASK_CACHING |
+			TTM_PL_FLAG_SYSTEM;
+	if (!count)
+		bo->placements[count++].flags = TTM_PL_MASK_CACHING |
+			TTM_PL_FLAG_SYSTEM;
+
+	bo->placement.num_placement = count;
+	bo->placement.num_busy_placement = count;
+	for (i = 0; i < count; i++) {
+		bo->placements[i].fpfn = 0;
+		bo->placements[i].lpfn = 0;
+	}
+}
+
+static void
+hibmc_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
+{
+	struct hibmc_bo *hibmcbo = hibmc_bo(bo);
+
+	if (!hibmc_ttm_bo_is_hibmc_bo(bo))
+		return;
+
+	hibmc_ttm_placement(hibmcbo, TTM_PL_FLAG_SYSTEM);
+	*pl = hibmcbo->placement;
+}
+
+static int hibmc_bo_verify_access(struct ttm_buffer_object *bo,
+				  struct file *filp)
+{
+	struct hibmc_bo *hibmcbo = hibmc_bo(bo);
+
+	return drm_vma_node_verify_access(&hibmcbo->gem.vma_node,
+					  filp->private_data);
+}
+
+static int hibmc_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
+				    struct ttm_mem_reg *mem)
+{
+	struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
+	struct hibmc_drm_private *hibmc = hibmc_bdev(bdev);
+
+	mem->bus.addr = NULL;
+	mem->bus.offset = 0;
+	mem->bus.size = mem->num_pages << PAGE_SHIFT;
+	mem->bus.base = 0;
+	mem->bus.is_iomem = false;
+	if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE))
+		return -EINVAL;
+	switch (mem->mem_type) {
+	case TTM_PL_SYSTEM:
+		/* system memory */
+		return 0;
+	case TTM_PL_VRAM:
+		mem->bus.offset = mem->start << PAGE_SHIFT;
+		mem->bus.base = pci_resource_start(hibmc->dev->pdev, 0);
+		mem->bus.is_iomem = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void hibmc_ttm_backend_destroy(struct ttm_tt *tt)
+{
+	ttm_tt_fini(tt);
+	kfree(tt);
+}
+
+static struct ttm_backend_func hibmc_tt_backend_func = {
+	.destroy = &hibmc_ttm_backend_destroy,
+};
+
+static struct ttm_tt *hibmc_ttm_tt_create(struct ttm_bo_device *bdev,
+					  unsigned long size,
+					  u32 page_flags,
+					  struct page *dummy_read_page)
+{
+	struct ttm_tt *tt;
+	int ret;
+
+	tt = kzalloc(sizeof(*tt), GFP_KERNEL);
+	if (!tt) {
+		DRM_ERROR("failed to allocate ttm_tt\n");
+		return NULL;
+	}
+	tt->func = &hibmc_tt_backend_func;
+	ret = ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page);
+	if (ret) {
+		DRM_ERROR("failed to initialize ttm_tt: %d\n", ret);
+		kfree(tt);
+		return NULL;
+	}
+	return tt;
+}
+
+static int hibmc_ttm_tt_populate(struct ttm_tt *ttm)
+{
+	return ttm_pool_populate(ttm);
+}
+
+static void hibmc_ttm_tt_unpopulate(struct ttm_tt *ttm)
+{
+	ttm_pool_unpopulate(ttm);
+}
+
+struct ttm_bo_driver hibmc_bo_driver = {
+	.ttm_tt_create		= hibmc_ttm_tt_create,
+	.ttm_tt_populate	= hibmc_ttm_tt_populate,
+	.ttm_tt_unpopulate	= hibmc_ttm_tt_unpopulate,
+	.init_mem_type		= hibmc_bo_init_mem_type,
+	.evict_flags		= hibmc_bo_evict_flags,
+	.move			= NULL,
+	.verify_access		= hibmc_bo_verify_access,
+	.io_mem_reserve		= &hibmc_ttm_io_mem_reserve,
+	.io_mem_free		= NULL,
+	.lru_tail		= &ttm_bo_default_lru_tail,
+	.swap_lru_tail		= &ttm_bo_default_swap_lru_tail,
+};
+
+int hibmc_mm_init(struct hibmc_drm_private *hibmc)
+{
+	int ret;
+	struct drm_device *dev = hibmc->dev;
+	struct ttm_bo_device *bdev = &hibmc->bdev;
+
+	ret = hibmc_ttm_global_init(hibmc);
+	if (ret)
+		return ret;
+
+	ret = ttm_bo_device_init(&hibmc->bdev,
+				 hibmc->bo_global_ref.ref.object,
+				 &hibmc_bo_driver,
+				 dev->anon_inode->i_mapping,
+				 DRM_FILE_PAGE_OFFSET,
+				 true);
+	if (ret) {
+		hibmc_ttm_global_release(hibmc);
+		DRM_ERROR("error initializing bo driver: %d\n", ret);
+		return ret;
+	}
+
+	ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
+			     hibmc->fb_size >> PAGE_SHIFT);
+	if (ret) {
+		hibmc_ttm_global_release(hibmc);
+		DRM_ERROR("failed ttm VRAM init: %d\n", ret);
+		return ret;
+	}
+
+	hibmc->mm_inited = true;
+	return 0;
+}
+
+void hibmc_mm_fini(struct hibmc_drm_private *hibmc)
+{
+	if (!hibmc->mm_inited)
+		return;
+
+	ttm_bo_device_release(&hibmc->bdev);
+	hibmc_ttm_global_release(hibmc);
+	hibmc->mm_inited = false;
+}
+
+static void hibmc_bo_unref(struct hibmc_bo **bo)
+{
+	struct ttm_buffer_object *tbo;
+
+	if ((*bo) == NULL)
+		return;
+
+	tbo = &((*bo)->bo);
+	ttm_bo_unref(&tbo);
+	*bo = NULL;
+}
+
+int hibmc_bo_create(struct drm_device *dev, int size, int align,
+		    u32 flags, struct hibmc_bo **phibmcbo)
+{
+	struct hibmc_drm_private *hibmc = dev->dev_private;
+	struct hibmc_bo *hibmcbo;
+	size_t acc_size;
+	int ret;
+
+	hibmcbo = kzalloc(sizeof(*hibmcbo), GFP_KERNEL);
+	if (!hibmcbo) {
+		DRM_ERROR("failed to allocate hibmcbo\n");
+		return -ENOMEM;
+	}
+	ret = drm_gem_object_init(dev, &hibmcbo->gem, size);
+	if (ret) {
+		DRM_ERROR("failed to initialize drm gem object: %d\n", ret);
+		kfree(hibmcbo);
+		return ret;
+	}
+
+	hibmcbo->bo.bdev = &hibmc->bdev;
+
+	hibmc_ttm_placement(hibmcbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
+
+	acc_size = ttm_bo_dma_acc_size(&hibmc->bdev, size,
+				       sizeof(struct hibmc_bo));
+
+	ret = ttm_bo_init(&hibmc->bdev, &hibmcbo->bo, size,
+			  ttm_bo_type_device, &hibmcbo->placement,
+			  align >> PAGE_SHIFT, false, NULL, acc_size,
+			  NULL, NULL, hibmc_bo_ttm_destroy);
+	if (ret) {
+		hibmc_bo_unref(&hibmcbo);
+		DRM_ERROR("failed to initialize ttm_bo: %d\n", ret);
+		return ret;
+	}
+
+	*phibmcbo = hibmcbo;
+	return 0;
+}
+
+int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr)
+{
+	int i, ret;
+
+	if (bo->pin_count) {
+		bo->pin_count++;
+		if (gpu_addr)
+			*gpu_addr = bo->bo.offset;
+		return 0;
+	}
+
+	hibmc_ttm_placement(bo, pl_flag);
+	for (i = 0; i < bo->placement.num_placement; i++)
+		bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
+	ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
+	if (ret)
+		return ret;
+
+	bo->pin_count = 1;
+	if (gpu_addr)
+		*gpu_addr = bo->bo.offset;
+	return 0;
+}
+
+int hibmc_bo_unpin(struct hibmc_bo *bo)
+{
+	int i, ret;
+
+	if (!bo->pin_count) {
+		DRM_ERROR("unpin bad %p\n", bo);
+		return 0;
+	}
+	bo->pin_count--;
+	if (bo->pin_count)
+		return 0;
+
+	for (i = 0; i < bo->placement.num_placement ; i++)
+		bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT;
+	ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
+	if (ret) {
+		DRM_ERROR("validate failed for unpin: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+int hibmc_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct drm_file *file_priv;
+	struct hibmc_drm_private *hibmc;
+
+	if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET))
+		return -EINVAL;
+
+	file_priv = filp->private_data;
+	hibmc = file_priv->minor->dev->dev_private;
+	return ttm_bo_mmap(filp, vma, &hibmc->bdev);
+}
+
+int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
+		     struct drm_gem_object **obj)
+{
+	struct hibmc_bo *hibmcbo;
+	int ret;
+
+	*obj = NULL;
+
+	size = PAGE_ALIGN(size);
+	if (size == 0) {
+		DRM_ERROR("error: zero size\n");
+		return -EINVAL;
+	}
+
+	ret = hibmc_bo_create(dev, size, 0, 0, &hibmcbo);
+	if (ret) {
+		if (ret != -ERESTARTSYS)
+			DRM_ERROR("failed to allocate GEM object: %d\n", ret);
+		return ret;
+	}
+	*obj = &hibmcbo->gem;
+	return 0;
+}
+
+int hibmc_dumb_create(struct drm_file *file, struct drm_device *dev,
+		      struct drm_mode_create_dumb *args)
+{
+	struct drm_gem_object *gobj;
+	u32 handle;
+	int ret;
+
+	args->pitch = ALIGN(args->width * DIV_ROUND_UP(args->bpp, 8), 16);
+	args->size = args->pitch * args->height;
+
+	ret = hibmc_gem_create(dev, args->size, false,
+			       &gobj);
+	if (ret) {
+		DRM_ERROR("failed to create GEM object: %d\n", ret);
+		return ret;
+	}
+
+	ret = drm_gem_handle_create(file, gobj, &handle);
+	drm_gem_object_unreference_unlocked(gobj);
+	if (ret) {
+		DRM_ERROR("failed to unreference GEM object: %d\n", ret);
+		return ret;
+	}
+
+	args->handle = handle;
+	return 0;
+}
+
+void hibmc_gem_free_object(struct drm_gem_object *obj)
+{
+	struct hibmc_bo *hibmcbo = gem_to_hibmc_bo(obj);
+
+	hibmc_bo_unref(&hibmcbo);
+}
+
+static u64 hibmc_bo_mmap_offset(struct hibmc_bo *bo)
+{
+	return drm_vma_node_offset_addr(&bo->bo.vma_node);
+}
+
+int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
+			   u32 handle, u64 *offset)
+{
+	struct drm_gem_object *obj;
+	struct hibmc_bo *bo;
+
+	obj = drm_gem_object_lookup(file, handle);
+	if (!obj)
+		return -ENOENT;
+
+	bo = gem_to_hibmc_bo(obj);
+	*offset = hibmc_bo_mmap_offset(bo);
+
+	drm_gem_object_unreference_unlocked(obj);
+	return 0;
+}
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v7 3/7] drm/hisilicon/hibmc: Add support for frame buffer
  2016-11-16 13:43 ` Rongrong Zou
@ 2016-11-16 13:43   ` Rongrong Zou
  -1 siblings, 0 replies; 40+ messages in thread
From: Rongrong Zou @ 2016-11-16 13:43 UTC (permalink / raw)
  To: linux-arm-kernel

Add support for fbdev and kms fb management.

Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
---
 drivers/gpu/drm/hisilicon/hibmc/Makefile          |   2 +-
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   |   7 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   |  24 ++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 267 ++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       |  67 ++++++
 5 files changed, 366 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c

diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
index 19ed0ef..ff77a7e 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
+++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
@@ -1,4 +1,4 @@
 ccflags-y := -Iinclude/drm
-hibmc-drm-y := hibmc_drm_drv.o hibmc_ttm.o
+hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_ttm.o
 
 obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index 521f69f..4b52b29 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -202,6 +202,7 @@ static int hibmc_unload(struct drm_device *dev)
 {
 	struct hibmc_drm_private *priv = dev->dev_private;
 
+	hibmc_fbdev_fini(priv);
 	hibmc_mm_fini(priv);
 	dev->dev_private = NULL;
 	return 0;
@@ -228,6 +229,12 @@ static int hibmc_load(struct drm_device *dev)
 	if (ret)
 		goto err;
 
+	ret = hibmc_fbdev_init(priv);
+	if (ret) {
+		DRM_ERROR("failed to initialize fbdev: %d\n", ret);
+		goto err;
+	}
+
 	return 0;
 
 err:
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
index dcd304d..d283d66 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -20,9 +20,21 @@
 #define HIBMC_DRM_DRV_H
 
 #include <drm/drmP.h>
+#include <drm/drm_fb_helper.h>
 #include <drm/drm_gem.h>
 #include <drm/ttm/ttm_bo_driver.h>
 
+struct hibmc_framebuffer {
+	struct drm_framebuffer fb;
+	struct drm_gem_object *obj;
+};
+
+struct hibmc_fbdev {
+	struct drm_fb_helper helper;
+	struct hibmc_framebuffer *fb;
+	int size;
+};
+
 struct hibmc_drm_private {
 	/* hw */
 	void __iomem   *mmio;
@@ -39,9 +51,13 @@ struct hibmc_drm_private {
 	struct ttm_bo_device bdev;
 	bool initialized;
 
+	/* fbdev */
+	struct hibmc_fbdev *fbdev;
 	bool mm_inited;
 };
 
+#define to_hibmc_framebuffer(x) container_of(x, struct hibmc_framebuffer, fb)
+
 struct hibmc_bo {
 	struct ttm_buffer_object bo;
 	struct ttm_placement placement;
@@ -66,8 +82,16 @@ void hibmc_set_power_mode(struct hibmc_drm_private *priv,
 void hibmc_set_current_gate(struct hibmc_drm_private *priv,
 			    unsigned int gate);
 
+int hibmc_fbdev_init(struct hibmc_drm_private *priv);
+void hibmc_fbdev_fini(struct hibmc_drm_private *priv);
+
 int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
 		     struct drm_gem_object **obj);
+struct hibmc_framebuffer *
+hibmc_framebuffer_init(struct drm_device *dev,
+		       const struct drm_mode_fb_cmd2 *mode_cmd,
+		       struct drm_gem_object *obj);
+
 int hibmc_mm_init(struct hibmc_drm_private *hibmc);
 void hibmc_mm_fini(struct hibmc_drm_private *hibmc);
 int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr);
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
new file mode 100644
index 0000000..9b06967
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
@@ -0,0 +1,267 @@
+/* Hisilicon Hibmc SoC drm driver
+ *
+ * Based on the bochs drm driver.
+ *
+ * Copyright (c) 2016 Huawei Limited.
+ *
+ * Author:
+ *	Rongrong Zou <zourongrong@huawei.com>
+ *	Rongrong Zou <zourongrong@gmail.com>
+ *	Jianhua Li <lijianhua@huawei.com>
+ *
+ * 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.
+ *
+ */
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
+
+#include "hibmc_drm_drv.h"
+
+static int hibmcfb_create_object(
+				struct hibmc_drm_private *priv,
+				const struct drm_mode_fb_cmd2 *mode_cmd,
+				struct drm_gem_object **gobj_p)
+{
+	struct drm_gem_object *gobj;
+	struct drm_device *dev = priv->dev;
+	u32 size;
+	int ret = 0;
+
+	size = mode_cmd->pitches[0] * mode_cmd->height;
+	ret = hibmc_gem_create(dev, size, true, &gobj);
+	if (ret)
+		return ret;
+
+	*gobj_p = gobj;
+	return ret;
+}
+
+static struct fb_ops hibmc_drm_fb_ops = {
+	.owner = THIS_MODULE,
+	.fb_check_var = drm_fb_helper_check_var,
+	.fb_set_par = drm_fb_helper_set_par,
+	.fb_fillrect = drm_fb_helper_sys_fillrect,
+	.fb_copyarea = drm_fb_helper_sys_copyarea,
+	.fb_imageblit = drm_fb_helper_sys_imageblit,
+	.fb_pan_display = drm_fb_helper_pan_display,
+	.fb_blank = drm_fb_helper_blank,
+	.fb_setcmap = drm_fb_helper_setcmap,
+};
+
+static int hibmc_drm_fb_create(struct drm_fb_helper *helper,
+			       struct drm_fb_helper_surface_size *sizes)
+{
+	struct hibmc_fbdev *hi_fbdev =
+		container_of(helper, struct hibmc_fbdev, helper);
+	struct hibmc_drm_private *priv = helper->dev->dev_private;
+	struct fb_info *info;
+	struct drm_mode_fb_cmd2 mode_cmd;
+	struct drm_gem_object *gobj = NULL;
+	int ret = 0;
+	int ret1;
+	size_t size;
+	unsigned int bytes_per_pixel;
+	struct hibmc_bo *bo = NULL;
+
+	DRM_DEBUG_DRIVER("surface width(%d), height(%d) and bpp(%d)\n",
+			 sizes->surface_width, sizes->surface_height,
+			 sizes->surface_bpp);
+	sizes->surface_depth = 32;
+
+	bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8);
+
+	mode_cmd.width = sizes->surface_width;
+	mode_cmd.height = sizes->surface_height;
+	mode_cmd.pitches[0] = mode_cmd.width * bytes_per_pixel;
+	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+							  sizes->surface_depth);
+
+	size = PAGE_ALIGN(mode_cmd.pitches[0] * mode_cmd.height);
+
+	ret = hibmcfb_create_object(priv, &mode_cmd, &gobj);
+	if (ret) {
+		DRM_ERROR("failed to create fbcon backing object: %d\n", ret);
+		return -ENOMEM;
+	}
+
+	bo = gem_to_hibmc_bo(gobj);
+
+	ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
+	if (ret) {
+		DRM_ERROR("failed to reserve ttm_bo: %d\n", ret);
+		goto out_unref_gem;
+	}
+
+	ret = hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL);
+	if (ret) {
+		DRM_ERROR("failed to pin fbcon: %d\n", ret);
+		goto out_unreserve_ttm_bo;
+	}
+
+	ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
+	if (ret) {
+		DRM_ERROR("failed to kmap fbcon: %d\n", ret);
+		goto out_unpin_bo;
+	}
+	ttm_bo_unreserve(&bo->bo);
+
+	info = drm_fb_helper_alloc_fbi(helper);
+	if (IS_ERR(info)) {
+		ret = PTR_ERR(info);
+		DRM_ERROR("failed to allocate fbi: %d\n", ret);
+		goto out_release_fbi;
+	}
+
+	info->par = hi_fbdev;
+
+	hi_fbdev->fb = hibmc_framebuffer_init(priv->dev, &mode_cmd, gobj);
+	if (IS_ERR(hi_fbdev->fb)) {
+		ret = PTR_ERR(info);
+		DRM_ERROR("failed to initialize framebuffer: %d\n", ret);
+		goto out_release_fbi;
+	}
+
+	priv->fbdev->size = size;
+	hi_fbdev->helper.fb = &hi_fbdev->fb->fb;
+
+	strcpy(info->fix.id, "hibmcdrmfb");
+
+	info->flags = FBINFO_DEFAULT;
+	info->fbops = &hibmc_drm_fb_ops;
+
+	drm_fb_helper_fill_fix(info, hi_fbdev->fb->fb.pitches[0],
+			       hi_fbdev->fb->fb.depth);
+	drm_fb_helper_fill_var(info, &priv->fbdev->helper, sizes->fb_width,
+			       sizes->fb_height);
+
+	info->screen_base = bo->kmap.virtual;
+	info->screen_size = size;
+
+	info->fix.smem_start = bo->bo.mem.bus.offset + bo->bo.mem.bus.base;
+	info->fix.smem_len = size;
+	return 0;
+
+out_release_fbi:
+	drm_fb_helper_release_fbi(helper);
+	ret1 = ttm_bo_reserve(&bo->bo, true, false, NULL);
+	if (ret1) {
+		DRM_ERROR("failed to rsv ttm_bo when release fbi: %d\n", ret1);
+		goto out_unref_gem;
+	}
+	ttm_bo_kunmap(&bo->kmap);
+out_unpin_bo:
+	hibmc_bo_unpin(bo);
+out_unreserve_ttm_bo:
+	ttm_bo_unreserve(&bo->bo);
+out_unref_gem:
+	drm_gem_object_unreference_unlocked(gobj);
+
+	return ret;
+}
+
+static void hibmc_fbdev_destroy(struct hibmc_fbdev *fbdev)
+{
+	struct hibmc_framebuffer *gfb = fbdev->fb;
+	struct drm_fb_helper *fbh = &fbdev->helper;
+
+	drm_fb_helper_unregister_fbi(fbh);
+	drm_fb_helper_release_fbi(fbh);
+
+	drm_fb_helper_fini(fbh);
+
+	if (gfb)
+		drm_framebuffer_unreference(&gfb->fb);
+}
+
+static const struct drm_fb_helper_funcs hibmc_fbdev_helper_funcs = {
+	.fb_probe = hibmc_drm_fb_create,
+};
+
+int hibmc_fbdev_init(struct hibmc_drm_private *priv)
+{
+	int ret;
+	struct fb_var_screeninfo *var;
+	struct fb_fix_screeninfo *fix;
+	struct hibmc_fbdev *hifbdev;
+
+	hifbdev = devm_kzalloc(priv->dev->dev, sizeof(*hifbdev), GFP_KERNEL);
+	if (!hifbdev) {
+		DRM_ERROR("failed to allocate hibmc_fbdev\n");
+		return -ENOMEM;
+	}
+
+	priv->fbdev = hifbdev;
+	drm_fb_helper_prepare(priv->dev, &hifbdev->helper,
+			      &hibmc_fbdev_helper_funcs);
+
+	/* Now just one crtc and one channel */
+	ret = drm_fb_helper_init(priv->dev,
+				 &hifbdev->helper, 1, 1);
+	if (ret) {
+		DRM_ERROR("failed to initialize fb helper: %d\n", ret);
+		return ret;
+	}
+
+	ret = drm_fb_helper_single_add_all_connectors(&hifbdev->helper);
+	if (ret) {
+		DRM_ERROR("failed to add all connectors: %d\n", ret);
+		goto fini;
+	}
+
+	ret = drm_fb_helper_initial_config(&hifbdev->helper, 16);
+	if (ret) {
+		DRM_ERROR("failed to setup initial conn config: %d\n", ret);
+		goto fini;
+	}
+
+	var = &hifbdev->helper.fbdev->var;
+	fix = &hifbdev->helper.fbdev->fix;
+
+	DRM_DEBUG_DRIVER("Member of info->var is :\n"
+			 "xres=%d\n"
+			 "yres=%d\n"
+			 "xres_virtual=%d\n"
+			 "yres_virtual=%d\n"
+			 "xoffset=%d\n"
+			 "yoffset=%d\n"
+			 "bits_per_pixel=%d\n"
+			 "...\n", var->xres, var->yres, var->xres_virtual,
+			 var->yres_virtual, var->xoffset, var->yoffset,
+			 var->bits_per_pixel);
+	DRM_DEBUG_DRIVER("Member of info->fix is :\n"
+			 "smem_start=%lx\n"
+			 "smem_len=%d\n"
+			 "type=%d\n"
+			 "type_aux=%d\n"
+			 "visual=%d\n"
+			 "xpanstep=%d\n"
+			 "ypanstep=%d\n"
+			 "ywrapstep=%d\n"
+			 "line_length=%d\n"
+			 "accel=%d\n"
+			 "capabilities=%d\n"
+			 "...\n", fix->smem_start, fix->smem_len, fix->type,
+			 fix->type_aux, fix->visual, fix->xpanstep,
+			 fix->ypanstep, fix->ywrapstep, fix->line_length,
+			 fix->accel, fix->capabilities);
+
+	return 0;
+
+fini:
+	drm_fb_helper_fini(&hifbdev->helper);
+	return ret;
+}
+
+void hibmc_fbdev_fini(struct hibmc_drm_private *priv)
+{
+	if (!priv->fbdev)
+		return;
+
+	hibmc_fbdev_destroy(priv->fbdev);
+	priv->fbdev = NULL;
+}
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
index 036d3ac..3ff65f4 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
@@ -16,6 +16,7 @@
  *
  */
 
+#include <drm/drm_atomic_helper.h>
 #include <ttm/ttm_page_alloc.h>
 
 #include "hibmc_drm_drv.h"
@@ -483,3 +484,69 @@ int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
 	drm_gem_object_unreference_unlocked(obj);
 	return 0;
 }
+
+static void hibmc_user_framebuffer_destroy(struct drm_framebuffer *fb)
+{
+	struct hibmc_framebuffer *hibmc_fb = to_hibmc_framebuffer(fb);
+
+	drm_gem_object_unreference_unlocked(hibmc_fb->obj);
+	drm_framebuffer_cleanup(fb);
+	kfree(hibmc_fb);
+}
+
+static const struct drm_framebuffer_funcs hibmc_fb_funcs = {
+	.destroy = hibmc_user_framebuffer_destroy,
+};
+
+struct hibmc_framebuffer *
+hibmc_framebuffer_init(struct drm_device *dev,
+		       const struct drm_mode_fb_cmd2 *mode_cmd,
+		       struct drm_gem_object *obj)
+{
+	struct hibmc_framebuffer *hibmc_fb;
+	int ret;
+
+	hibmc_fb = kzalloc(sizeof(*hibmc_fb), GFP_KERNEL);
+	if (!hibmc_fb) {
+		DRM_ERROR("failed to allocate hibmc_fb\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	drm_helper_mode_fill_fb_struct(&hibmc_fb->fb, mode_cmd);
+	hibmc_fb->obj = obj;
+	ret = drm_framebuffer_init(dev, &hibmc_fb->fb, &hibmc_fb_funcs);
+	if (ret) {
+		DRM_ERROR("drm_framebuffer_init failed: %d\n", ret);
+		kfree(hibmc_fb);
+		return ERR_PTR(ret);
+	}
+
+	return hibmc_fb;
+}
+
+static struct drm_framebuffer *
+hibmc_user_framebuffer_create(struct drm_device *dev,
+			      struct drm_file *filp,
+			      const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+	struct drm_gem_object *obj;
+	struct hibmc_framebuffer *hibmc_fb;
+
+	DRM_DEBUG_DRIVER("%dx%d, format %c%c%c%c\n",
+			 mode_cmd->width, mode_cmd->height,
+			 (mode_cmd->pixel_format) & 0xff,
+			 (mode_cmd->pixel_format >> 8)  & 0xff,
+			 (mode_cmd->pixel_format >> 16) & 0xff,
+			 (mode_cmd->pixel_format >> 24) & 0xff);
+
+	obj = drm_gem_object_lookup(filp, mode_cmd->handles[0]);
+	if (!obj)
+		return ERR_PTR(-ENOENT);
+
+	hibmc_fb = hibmc_framebuffer_init(dev, mode_cmd, obj);
+	if (IS_ERR(hibmc_fb)) {
+		drm_gem_object_unreference_unlocked(obj);
+		return ERR_PTR((long)hibmc_fb);
+	}
+	return &hibmc_fb->fb;
+}
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v7 3/7] drm/hisilicon/hibmc: Add support for frame buffer
@ 2016-11-16 13:43   ` Rongrong Zou
  0 siblings, 0 replies; 40+ messages in thread
From: Rongrong Zou @ 2016-11-16 13:43 UTC (permalink / raw)
  To: airlied, daniel, seanpaul, seanpaul, dri-devel, emil.l.velikov,
	tomeu.vizoso, benjamin.gaignard, robh, daniel, architt, corbet,
	mark.rutland, xinliang.liu
  Cc: linuxarm, kong.kongxinwei, james.xiong, shenhui, guohanjun,
	lijianhua, linux-arm-kernel

Add support for fbdev and kms fb management.

Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
---
 drivers/gpu/drm/hisilicon/hibmc/Makefile          |   2 +-
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   |   7 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   |  24 ++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 267 ++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       |  67 ++++++
 5 files changed, 366 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c

diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
index 19ed0ef..ff77a7e 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
+++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
@@ -1,4 +1,4 @@
 ccflags-y := -Iinclude/drm
-hibmc-drm-y := hibmc_drm_drv.o hibmc_ttm.o
+hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_ttm.o
 
 obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index 521f69f..4b52b29 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -202,6 +202,7 @@ static int hibmc_unload(struct drm_device *dev)
 {
 	struct hibmc_drm_private *priv = dev->dev_private;
 
+	hibmc_fbdev_fini(priv);
 	hibmc_mm_fini(priv);
 	dev->dev_private = NULL;
 	return 0;
@@ -228,6 +229,12 @@ static int hibmc_load(struct drm_device *dev)
 	if (ret)
 		goto err;
 
+	ret = hibmc_fbdev_init(priv);
+	if (ret) {
+		DRM_ERROR("failed to initialize fbdev: %d\n", ret);
+		goto err;
+	}
+
 	return 0;
 
 err:
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
index dcd304d..d283d66 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -20,9 +20,21 @@
 #define HIBMC_DRM_DRV_H
 
 #include <drm/drmP.h>
+#include <drm/drm_fb_helper.h>
 #include <drm/drm_gem.h>
 #include <drm/ttm/ttm_bo_driver.h>
 
+struct hibmc_framebuffer {
+	struct drm_framebuffer fb;
+	struct drm_gem_object *obj;
+};
+
+struct hibmc_fbdev {
+	struct drm_fb_helper helper;
+	struct hibmc_framebuffer *fb;
+	int size;
+};
+
 struct hibmc_drm_private {
 	/* hw */
 	void __iomem   *mmio;
@@ -39,9 +51,13 @@ struct hibmc_drm_private {
 	struct ttm_bo_device bdev;
 	bool initialized;
 
+	/* fbdev */
+	struct hibmc_fbdev *fbdev;
 	bool mm_inited;
 };
 
+#define to_hibmc_framebuffer(x) container_of(x, struct hibmc_framebuffer, fb)
+
 struct hibmc_bo {
 	struct ttm_buffer_object bo;
 	struct ttm_placement placement;
@@ -66,8 +82,16 @@ void hibmc_set_power_mode(struct hibmc_drm_private *priv,
 void hibmc_set_current_gate(struct hibmc_drm_private *priv,
 			    unsigned int gate);
 
+int hibmc_fbdev_init(struct hibmc_drm_private *priv);
+void hibmc_fbdev_fini(struct hibmc_drm_private *priv);
+
 int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
 		     struct drm_gem_object **obj);
+struct hibmc_framebuffer *
+hibmc_framebuffer_init(struct drm_device *dev,
+		       const struct drm_mode_fb_cmd2 *mode_cmd,
+		       struct drm_gem_object *obj);
+
 int hibmc_mm_init(struct hibmc_drm_private *hibmc);
 void hibmc_mm_fini(struct hibmc_drm_private *hibmc);
 int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr);
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
new file mode 100644
index 0000000..9b06967
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
@@ -0,0 +1,267 @@
+/* Hisilicon Hibmc SoC drm driver
+ *
+ * Based on the bochs drm driver.
+ *
+ * Copyright (c) 2016 Huawei Limited.
+ *
+ * Author:
+ *	Rongrong Zou <zourongrong@huawei.com>
+ *	Rongrong Zou <zourongrong@gmail.com>
+ *	Jianhua Li <lijianhua@huawei.com>
+ *
+ * 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.
+ *
+ */
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
+
+#include "hibmc_drm_drv.h"
+
+static int hibmcfb_create_object(
+				struct hibmc_drm_private *priv,
+				const struct drm_mode_fb_cmd2 *mode_cmd,
+				struct drm_gem_object **gobj_p)
+{
+	struct drm_gem_object *gobj;
+	struct drm_device *dev = priv->dev;
+	u32 size;
+	int ret = 0;
+
+	size = mode_cmd->pitches[0] * mode_cmd->height;
+	ret = hibmc_gem_create(dev, size, true, &gobj);
+	if (ret)
+		return ret;
+
+	*gobj_p = gobj;
+	return ret;
+}
+
+static struct fb_ops hibmc_drm_fb_ops = {
+	.owner = THIS_MODULE,
+	.fb_check_var = drm_fb_helper_check_var,
+	.fb_set_par = drm_fb_helper_set_par,
+	.fb_fillrect = drm_fb_helper_sys_fillrect,
+	.fb_copyarea = drm_fb_helper_sys_copyarea,
+	.fb_imageblit = drm_fb_helper_sys_imageblit,
+	.fb_pan_display = drm_fb_helper_pan_display,
+	.fb_blank = drm_fb_helper_blank,
+	.fb_setcmap = drm_fb_helper_setcmap,
+};
+
+static int hibmc_drm_fb_create(struct drm_fb_helper *helper,
+			       struct drm_fb_helper_surface_size *sizes)
+{
+	struct hibmc_fbdev *hi_fbdev =
+		container_of(helper, struct hibmc_fbdev, helper);
+	struct hibmc_drm_private *priv = helper->dev->dev_private;
+	struct fb_info *info;
+	struct drm_mode_fb_cmd2 mode_cmd;
+	struct drm_gem_object *gobj = NULL;
+	int ret = 0;
+	int ret1;
+	size_t size;
+	unsigned int bytes_per_pixel;
+	struct hibmc_bo *bo = NULL;
+
+	DRM_DEBUG_DRIVER("surface width(%d), height(%d) and bpp(%d)\n",
+			 sizes->surface_width, sizes->surface_height,
+			 sizes->surface_bpp);
+	sizes->surface_depth = 32;
+
+	bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8);
+
+	mode_cmd.width = sizes->surface_width;
+	mode_cmd.height = sizes->surface_height;
+	mode_cmd.pitches[0] = mode_cmd.width * bytes_per_pixel;
+	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+							  sizes->surface_depth);
+
+	size = PAGE_ALIGN(mode_cmd.pitches[0] * mode_cmd.height);
+
+	ret = hibmcfb_create_object(priv, &mode_cmd, &gobj);
+	if (ret) {
+		DRM_ERROR("failed to create fbcon backing object: %d\n", ret);
+		return -ENOMEM;
+	}
+
+	bo = gem_to_hibmc_bo(gobj);
+
+	ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
+	if (ret) {
+		DRM_ERROR("failed to reserve ttm_bo: %d\n", ret);
+		goto out_unref_gem;
+	}
+
+	ret = hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL);
+	if (ret) {
+		DRM_ERROR("failed to pin fbcon: %d\n", ret);
+		goto out_unreserve_ttm_bo;
+	}
+
+	ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
+	if (ret) {
+		DRM_ERROR("failed to kmap fbcon: %d\n", ret);
+		goto out_unpin_bo;
+	}
+	ttm_bo_unreserve(&bo->bo);
+
+	info = drm_fb_helper_alloc_fbi(helper);
+	if (IS_ERR(info)) {
+		ret = PTR_ERR(info);
+		DRM_ERROR("failed to allocate fbi: %d\n", ret);
+		goto out_release_fbi;
+	}
+
+	info->par = hi_fbdev;
+
+	hi_fbdev->fb = hibmc_framebuffer_init(priv->dev, &mode_cmd, gobj);
+	if (IS_ERR(hi_fbdev->fb)) {
+		ret = PTR_ERR(info);
+		DRM_ERROR("failed to initialize framebuffer: %d\n", ret);
+		goto out_release_fbi;
+	}
+
+	priv->fbdev->size = size;
+	hi_fbdev->helper.fb = &hi_fbdev->fb->fb;
+
+	strcpy(info->fix.id, "hibmcdrmfb");
+
+	info->flags = FBINFO_DEFAULT;
+	info->fbops = &hibmc_drm_fb_ops;
+
+	drm_fb_helper_fill_fix(info, hi_fbdev->fb->fb.pitches[0],
+			       hi_fbdev->fb->fb.depth);
+	drm_fb_helper_fill_var(info, &priv->fbdev->helper, sizes->fb_width,
+			       sizes->fb_height);
+
+	info->screen_base = bo->kmap.virtual;
+	info->screen_size = size;
+
+	info->fix.smem_start = bo->bo.mem.bus.offset + bo->bo.mem.bus.base;
+	info->fix.smem_len = size;
+	return 0;
+
+out_release_fbi:
+	drm_fb_helper_release_fbi(helper);
+	ret1 = ttm_bo_reserve(&bo->bo, true, false, NULL);
+	if (ret1) {
+		DRM_ERROR("failed to rsv ttm_bo when release fbi: %d\n", ret1);
+		goto out_unref_gem;
+	}
+	ttm_bo_kunmap(&bo->kmap);
+out_unpin_bo:
+	hibmc_bo_unpin(bo);
+out_unreserve_ttm_bo:
+	ttm_bo_unreserve(&bo->bo);
+out_unref_gem:
+	drm_gem_object_unreference_unlocked(gobj);
+
+	return ret;
+}
+
+static void hibmc_fbdev_destroy(struct hibmc_fbdev *fbdev)
+{
+	struct hibmc_framebuffer *gfb = fbdev->fb;
+	struct drm_fb_helper *fbh = &fbdev->helper;
+
+	drm_fb_helper_unregister_fbi(fbh);
+	drm_fb_helper_release_fbi(fbh);
+
+	drm_fb_helper_fini(fbh);
+
+	if (gfb)
+		drm_framebuffer_unreference(&gfb->fb);
+}
+
+static const struct drm_fb_helper_funcs hibmc_fbdev_helper_funcs = {
+	.fb_probe = hibmc_drm_fb_create,
+};
+
+int hibmc_fbdev_init(struct hibmc_drm_private *priv)
+{
+	int ret;
+	struct fb_var_screeninfo *var;
+	struct fb_fix_screeninfo *fix;
+	struct hibmc_fbdev *hifbdev;
+
+	hifbdev = devm_kzalloc(priv->dev->dev, sizeof(*hifbdev), GFP_KERNEL);
+	if (!hifbdev) {
+		DRM_ERROR("failed to allocate hibmc_fbdev\n");
+		return -ENOMEM;
+	}
+
+	priv->fbdev = hifbdev;
+	drm_fb_helper_prepare(priv->dev, &hifbdev->helper,
+			      &hibmc_fbdev_helper_funcs);
+
+	/* Now just one crtc and one channel */
+	ret = drm_fb_helper_init(priv->dev,
+				 &hifbdev->helper, 1, 1);
+	if (ret) {
+		DRM_ERROR("failed to initialize fb helper: %d\n", ret);
+		return ret;
+	}
+
+	ret = drm_fb_helper_single_add_all_connectors(&hifbdev->helper);
+	if (ret) {
+		DRM_ERROR("failed to add all connectors: %d\n", ret);
+		goto fini;
+	}
+
+	ret = drm_fb_helper_initial_config(&hifbdev->helper, 16);
+	if (ret) {
+		DRM_ERROR("failed to setup initial conn config: %d\n", ret);
+		goto fini;
+	}
+
+	var = &hifbdev->helper.fbdev->var;
+	fix = &hifbdev->helper.fbdev->fix;
+
+	DRM_DEBUG_DRIVER("Member of info->var is :\n"
+			 "xres=%d\n"
+			 "yres=%d\n"
+			 "xres_virtual=%d\n"
+			 "yres_virtual=%d\n"
+			 "xoffset=%d\n"
+			 "yoffset=%d\n"
+			 "bits_per_pixel=%d\n"
+			 "...\n", var->xres, var->yres, var->xres_virtual,
+			 var->yres_virtual, var->xoffset, var->yoffset,
+			 var->bits_per_pixel);
+	DRM_DEBUG_DRIVER("Member of info->fix is :\n"
+			 "smem_start=%lx\n"
+			 "smem_len=%d\n"
+			 "type=%d\n"
+			 "type_aux=%d\n"
+			 "visual=%d\n"
+			 "xpanstep=%d\n"
+			 "ypanstep=%d\n"
+			 "ywrapstep=%d\n"
+			 "line_length=%d\n"
+			 "accel=%d\n"
+			 "capabilities=%d\n"
+			 "...\n", fix->smem_start, fix->smem_len, fix->type,
+			 fix->type_aux, fix->visual, fix->xpanstep,
+			 fix->ypanstep, fix->ywrapstep, fix->line_length,
+			 fix->accel, fix->capabilities);
+
+	return 0;
+
+fini:
+	drm_fb_helper_fini(&hifbdev->helper);
+	return ret;
+}
+
+void hibmc_fbdev_fini(struct hibmc_drm_private *priv)
+{
+	if (!priv->fbdev)
+		return;
+
+	hibmc_fbdev_destroy(priv->fbdev);
+	priv->fbdev = NULL;
+}
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
index 036d3ac..3ff65f4 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
@@ -16,6 +16,7 @@
  *
  */
 
+#include <drm/drm_atomic_helper.h>
 #include <ttm/ttm_page_alloc.h>
 
 #include "hibmc_drm_drv.h"
@@ -483,3 +484,69 @@ int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
 	drm_gem_object_unreference_unlocked(obj);
 	return 0;
 }
+
+static void hibmc_user_framebuffer_destroy(struct drm_framebuffer *fb)
+{
+	struct hibmc_framebuffer *hibmc_fb = to_hibmc_framebuffer(fb);
+
+	drm_gem_object_unreference_unlocked(hibmc_fb->obj);
+	drm_framebuffer_cleanup(fb);
+	kfree(hibmc_fb);
+}
+
+static const struct drm_framebuffer_funcs hibmc_fb_funcs = {
+	.destroy = hibmc_user_framebuffer_destroy,
+};
+
+struct hibmc_framebuffer *
+hibmc_framebuffer_init(struct drm_device *dev,
+		       const struct drm_mode_fb_cmd2 *mode_cmd,
+		       struct drm_gem_object *obj)
+{
+	struct hibmc_framebuffer *hibmc_fb;
+	int ret;
+
+	hibmc_fb = kzalloc(sizeof(*hibmc_fb), GFP_KERNEL);
+	if (!hibmc_fb) {
+		DRM_ERROR("failed to allocate hibmc_fb\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	drm_helper_mode_fill_fb_struct(&hibmc_fb->fb, mode_cmd);
+	hibmc_fb->obj = obj;
+	ret = drm_framebuffer_init(dev, &hibmc_fb->fb, &hibmc_fb_funcs);
+	if (ret) {
+		DRM_ERROR("drm_framebuffer_init failed: %d\n", ret);
+		kfree(hibmc_fb);
+		return ERR_PTR(ret);
+	}
+
+	return hibmc_fb;
+}
+
+static struct drm_framebuffer *
+hibmc_user_framebuffer_create(struct drm_device *dev,
+			      struct drm_file *filp,
+			      const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+	struct drm_gem_object *obj;
+	struct hibmc_framebuffer *hibmc_fb;
+
+	DRM_DEBUG_DRIVER("%dx%d, format %c%c%c%c\n",
+			 mode_cmd->width, mode_cmd->height,
+			 (mode_cmd->pixel_format) & 0xff,
+			 (mode_cmd->pixel_format >> 8)  & 0xff,
+			 (mode_cmd->pixel_format >> 16) & 0xff,
+			 (mode_cmd->pixel_format >> 24) & 0xff);
+
+	obj = drm_gem_object_lookup(filp, mode_cmd->handles[0]);
+	if (!obj)
+		return ERR_PTR(-ENOENT);
+
+	hibmc_fb = hibmc_framebuffer_init(dev, mode_cmd, obj);
+	if (IS_ERR(hibmc_fb)) {
+		drm_gem_object_unreference_unlocked(obj);
+		return ERR_PTR((long)hibmc_fb);
+	}
+	return &hibmc_fb->fb;
+}
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v7 4/7] drm/hisilicon/hibmc: Add support for display engine
  2016-11-16 13:43 ` Rongrong Zou
@ 2016-11-16 13:43   ` Rongrong Zou
  -1 siblings, 0 replies; 40+ messages in thread
From: Rongrong Zou @ 2016-11-16 13:43 UTC (permalink / raw)
  To: linux-arm-kernel

Add display engine function, crtc/plane is initialized here.

Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
---
 drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c  | 477 ++++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  69 +++-
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |   6 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     |   6 +
 5 files changed, 558 insertions(+), 2 deletions(-)
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c

diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
index ff77a7e..8e0cf72 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
+++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
@@ -1,4 +1,4 @@
 ccflags-y := -Iinclude/drm
-hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_ttm.o
+hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_fbdev.o hibmc_ttm.o
 
 obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
new file mode 100644
index 0000000..2a1386e
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
@@ -0,0 +1,477 @@
+/* Hisilicon Hibmc SoC drm driver
+ *
+ * Based on the bochs drm driver.
+ *
+ * Copyright (c) 2016 Huawei Limited.
+ *
+ * Author:
+ *	Rongrong Zou <zourongrong@huawei.com>
+ *	Rongrong Zou <zourongrong@gmail.com>
+ *	Jianhua Li <lijianhua@huawei.com>
+ *
+ * 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.
+ *
+ */
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_plane_helper.h>
+
+#include "hibmc_drm_drv.h"
+#include "hibmc_drm_regs.h"
+
+struct hibmc_display_panel_pll {
+	unsigned long M;
+	unsigned long N;
+	unsigned long OD;
+	unsigned long POD;
+};
+
+struct hibmc_dislay_pll_config {
+	unsigned long hdisplay;
+	unsigned long vdisplay;
+	u32 pll1_config_value;
+	u32 pll2_config_value;
+};
+
+static const struct hibmc_dislay_pll_config hibmc_pll_table[] = {
+	{800, 600, CRT_PLL1_HS_40MHZ, CRT_PLL2_HS_40MHZ},
+	{1024, 768, CRT_PLL1_HS_65MHZ, CRT_PLL2_HS_65MHZ},
+	{1152, 864, CRT_PLL1_HS_80MHZ_1152, CRT_PLL2_HS_80MHZ},
+	{1280, 768, CRT_PLL1_HS_80MHZ, CRT_PLL2_HS_80MHZ},
+	{1280, 720, CRT_PLL1_HS_74MHZ, CRT_PLL2_HS_74MHZ},
+	{1280, 960, CRT_PLL1_HS_108MHZ, CRT_PLL2_HS_108MHZ},
+	{1280, 1024, CRT_PLL1_HS_108MHZ, CRT_PLL2_HS_108MHZ},
+	{1600, 1200, CRT_PLL1_HS_162MHZ, CRT_PLL2_HS_162MHZ},
+	{1920, 1080, CRT_PLL1_HS_148MHZ, CRT_PLL2_HS_148MHZ},
+	{1920, 1200, CRT_PLL1_HS_193MHZ, CRT_PLL2_HS_193MHZ},
+};
+
+#define PADDING(align, data) (((data) + (align) - 1) & (~((align) - 1)))
+
+static int hibmc_plane_atomic_check(struct drm_plane *plane,
+				    struct drm_plane_state *state)
+{
+	struct drm_framebuffer *fb = state->fb;
+	struct drm_crtc *crtc = state->crtc;
+	struct drm_crtc_state *crtc_state;
+	u32 src_w = state->src_w >> 16;
+	u32 src_h = state->src_h >> 16;
+
+	if (!crtc || !fb)
+		return 0;
+
+	crtc_state = drm_atomic_get_crtc_state(state->state, crtc);
+	if (IS_ERR(crtc_state))
+		return PTR_ERR(crtc_state);
+
+	if (src_w != state->crtc_w || src_h != state->crtc_h) {
+		DRM_DEBUG_ATOMIC("scale not support\n");
+		return -EINVAL;
+	}
+
+	if (state->crtc_x < 0 || state->crtc_y < 0) {
+		DRM_DEBUG_ATOMIC("crtc_x/y of drm_plane state is invalid\n");
+		return -EINVAL;
+	}
+
+	if (state->crtc_x + state->crtc_w >
+	    crtc_state->adjusted_mode.hdisplay ||
+	    state->crtc_y + state->crtc_h >
+	    crtc_state->adjusted_mode.vdisplay) {
+		DRM_DEBUG_ATOMIC("visible portion of plane is invalid\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void hibmc_plane_atomic_update(struct drm_plane *plane,
+				      struct drm_plane_state *old_state)
+{
+	struct drm_plane_state	*state	= plane->state;
+	u32 reg;
+	int ret;
+	u64 gpu_addr = 0;
+	unsigned int line_l;
+	struct hibmc_drm_private *priv = plane->dev->dev_private;
+	struct hibmc_framebuffer *hibmc_fb;
+	struct hibmc_bo *bo;
+
+	if (!state->fb)
+		return;
+
+	hibmc_fb = to_hibmc_framebuffer(state->fb);
+	bo = gem_to_hibmc_bo(hibmc_fb->obj);
+	ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
+	if (ret) {
+		DRM_ERROR("failed to reserve ttm_bo: %d", ret);
+		return;
+	}
+
+	ret = hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
+	ttm_bo_unreserve(&bo->bo);
+	if (ret) {
+		DRM_ERROR("failed to pin hibmc_bo: %d", ret);
+		return;
+	}
+
+	writel(gpu_addr, priv->mmio + HIBMC_CRT_FB_ADDRESS);
+
+	reg = state->fb->width * (state->fb->bits_per_pixel / 8);
+	/* now line_pad is 16 */
+	reg = PADDING(16, reg);
+
+	line_l = state->fb->width * state->fb->bits_per_pixel / 8;
+	line_l = PADDING(16, line_l);
+	writel(HIBMC_FIELD(HIBMC_CRT_FB_WIDTH_WIDTH, reg) |
+	       HIBMC_FIELD(HIBMC_CRT_FB_WIDTH_OFFS, line_l),
+	       priv->mmio + HIBMC_CRT_FB_WIDTH);
+
+	/* SET PIXEL FORMAT */
+	reg = readl(priv->mmio + HIBMC_CRT_DISP_CTL);
+	reg &= ~HIBMC_CRT_DISP_CTL_FORMAT_MASK;
+	reg |= HIBMC_FIELD(HIBMC_CRT_DISP_CTL_FORMAT,
+			   state->fb->bits_per_pixel / 16);
+	writel(reg, priv->mmio + HIBMC_CRT_DISP_CTL);
+}
+
+static const u32 channel_formats1[] = {
+	DRM_FORMAT_RGB565, DRM_FORMAT_BGR565, DRM_FORMAT_RGB888,
+	DRM_FORMAT_BGR888, DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_RGBA8888, DRM_FORMAT_BGRA8888, DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_ABGR8888
+};
+
+static struct drm_plane_funcs hibmc_plane_funcs = {
+	.update_plane	= drm_atomic_helper_update_plane,
+	.disable_plane	= drm_atomic_helper_disable_plane,
+	.set_property = drm_atomic_helper_plane_set_property,
+	.destroy = drm_plane_cleanup,
+	.reset = drm_atomic_helper_plane_reset,
+	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+};
+
+static const struct drm_plane_helper_funcs hibmc_plane_helper_funcs = {
+	.atomic_check = hibmc_plane_atomic_check,
+	.atomic_update = hibmc_plane_atomic_update,
+};
+
+static struct drm_plane *hibmc_plane_init(struct hibmc_drm_private *priv)
+{
+	struct drm_device *dev = priv->dev;
+	struct drm_plane *plane;
+	int ret = 0;
+
+	plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
+	if (!plane) {
+		DRM_ERROR("failed to alloc memory when init plane\n");
+		return ERR_PTR(-ENOMEM);
+	}
+	/*
+	 * plane init
+	 * TODO: Now only support primary plane, overlay planes
+	 * need to do.
+	 */
+	ret = drm_universal_plane_init(dev, plane, 1, &hibmc_plane_funcs,
+				       channel_formats1,
+				       ARRAY_SIZE(channel_formats1),
+				       DRM_PLANE_TYPE_PRIMARY,
+				       NULL);
+	if (ret) {
+		DRM_ERROR("failed to init plane: %d\n", ret);
+		return ERR_PTR(ret);
+	}
+
+	drm_plane_helper_add(plane, &hibmc_plane_helper_funcs);
+	return plane;
+}
+
+static void hibmc_crtc_enable(struct drm_crtc *crtc)
+{
+	unsigned int reg;
+	struct hibmc_drm_private *priv = crtc->dev->dev_private;
+
+	hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_MODE0);
+
+	/* Enable display power gate & LOCALMEM power gate*/
+	reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
+	reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
+	reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
+	reg |= HIBMC_CURR_GATE_LOCALMEM(1);
+	reg |= HIBMC_CURR_GATE_DISPLAY(1);
+	hibmc_set_current_gate(priv, reg);
+	drm_crtc_vblank_on(crtc);
+}
+
+static void hibmc_crtc_disable(struct drm_crtc *crtc)
+{
+	unsigned int reg;
+	struct hibmc_drm_private *priv = crtc->dev->dev_private;
+
+	drm_crtc_vblank_off(crtc);
+
+	hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_SLEEP);
+
+	/* Enable display power gate & LOCALMEM power gate*/
+	reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
+	reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
+	reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
+	reg |= HIBMC_CURR_GATE_LOCALMEM(0);
+	reg |= HIBMC_CURR_GATE_DISPLAY(0);
+	hibmc_set_current_gate(priv, reg);
+}
+
+static unsigned int format_pll_reg(void)
+{
+	unsigned int pllreg = 0;
+	struct hibmc_display_panel_pll pll = {0};
+
+	/*
+	 * Note that all PLL's have the same format. Here,
+	 * we just use Panel PLL parameter to work out the bit
+	 * fields in the register.On returning a 32 bit number, the value can
+	 * be applied to any PLL in the calling function.
+	 */
+	pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_BYPASS, 0);
+	pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_POWER, 1);
+	pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_INPUT, 0);
+	pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_POD, pll.POD);
+	pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_OD, pll.OD);
+	pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_N, pll.N);
+	pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_M, pll.M);
+
+	return pllreg;
+}
+
+static void set_vclock_hisilicon(struct drm_device *dev, unsigned long pll)
+{
+	u32 val;
+	struct hibmc_drm_private *priv = dev->dev_private;
+
+	val = readl(priv->mmio + CRT_PLL1_HS);
+	val &= ~(CRT_PLL1_HS_OUTER_BYPASS(1));
+	writel(val, priv->mmio + CRT_PLL1_HS);
+
+	val = CRT_PLL1_HS_INTER_BYPASS(1) | CRT_PLL1_HS_POWERON(1);
+	writel(val, priv->mmio + CRT_PLL1_HS);
+
+	writel(pll, priv->mmio + CRT_PLL1_HS);
+
+	usleep_range(1000, 2000);
+
+	val = pll & ~(CRT_PLL1_HS_POWERON(1));
+	writel(val, priv->mmio + CRT_PLL1_HS);
+
+	usleep_range(1000, 2000);
+
+	val &= ~(CRT_PLL1_HS_INTER_BYPASS(1));
+	writel(val, priv->mmio + CRT_PLL1_HS);
+
+	usleep_range(1000, 2000);
+
+	val |= CRT_PLL1_HS_OUTER_BYPASS(1);
+	writel(val, priv->mmio + CRT_PLL1_HS);
+}
+
+static void get_pll_config(unsigned long x, unsigned long y,
+			   u32 *pll1, u32 *pll2)
+{
+	int i;
+	int count = ARRAY_SIZE(hibmc_pll_table);
+
+	for (i = 0; i < count; i++) {
+		if (hibmc_pll_table[i].hdisplay == x &&
+		    hibmc_pll_table[i].vdisplay == y) {
+			*pll1 = hibmc_pll_table[i].pll1_config_value;
+			*pll2 = hibmc_pll_table[i].pll2_config_value;
+			return;
+		}
+	}
+
+	/* if found none, we use default value */
+	*pll1 = CRT_PLL1_HS_25MHZ;
+	*pll2 = CRT_PLL2_HS_25MHZ;
+}
+
+/*
+ * This function takes care the extra registers and bit fields required to
+ * setup a mode in board.
+ * Explanation about Display Control register:
+ * FPGA only supports 7 predefined pixel clocks, and clock select is
+ * in bit 4:0 of new register 0x802a8.
+ */
+static unsigned int display_ctrl_adjust(struct drm_device *dev,
+					struct drm_display_mode *mode,
+					unsigned int ctrl)
+{
+	unsigned long x, y;
+	u32 pll1; /* bit[31:0] of PLL */
+	u32 pll2; /* bit[63:32] of PLL */
+	struct hibmc_drm_private *priv = dev->dev_private;
+
+	x = mode->hdisplay;
+	y = mode->vdisplay;
+
+	get_pll_config(x, y, &pll1, &pll2);
+	writel(pll2, priv->mmio + CRT_PLL2_HS);
+	set_vclock_hisilicon(dev, pll1);
+
+	/*
+	 * Hisilicon has to set up the top-left and bottom-right
+	 * registers as well.
+	 * Note that normal chip only use those two register for
+	 * auto-centering mode.
+	 */
+	writel(HIBMC_FIELD(HIBMC_CRT_AUTO_CENTERING_TL_TOP, 0) |
+	       HIBMC_FIELD(HIBMC_CRT_AUTO_CENTERING_TL_LEFT, 0),
+	       priv->mmio + HIBMC_CRT_AUTO_CENTERING_TL);
+
+	writel(HIBMC_FIELD(HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM, y - 1) |
+	       HIBMC_FIELD(HIBMC_CRT_AUTO_CENTERING_BR_RIGHT, x - 1),
+	       priv->mmio + HIBMC_CRT_AUTO_CENTERING_BR);
+
+	/*
+	 * Assume common fields in ctrl have been properly set before
+	 * calling this function.
+	 * This function only sets the extra fields in ctrl.
+	 */
+
+	/* Set bit 25 of display controller: Select CRT or VGA clock */
+	ctrl &= ~HIBMC_CRT_DISP_CTL_CRTSELECT_MASK;
+	ctrl &= ~HIBMC_CRT_DISP_CTL_CLOCK_PHASE_MASK;
+
+	ctrl |= HIBMC_CRT_DISP_CTL_CRTSELECT(HIBMC_CRTSELECT_CRT);
+
+	/* clock_phase_polarity is 0 */
+	ctrl |= HIBMC_CRT_DISP_CTL_CLOCK_PHASE(0);
+
+	writel(ctrl, priv->mmio + HIBMC_CRT_DISP_CTL);
+
+	return ctrl;
+}
+
+static void hibmc_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+	unsigned int val;
+	struct drm_display_mode *mode = &crtc->state->mode;
+	struct drm_device *dev = crtc->dev;
+	struct hibmc_drm_private *priv = dev->dev_private;
+	int width = mode->hsync_end - mode->hsync_start;
+	int height = mode->vsync_end - mode->vsync_start;
+
+	writel(format_pll_reg(), priv->mmio + HIBMC_CRT_PLL_CTRL);
+	writel(HIBMC_FIELD(HIBMC_CRT_HORZ_TOTAL_TOTAL, mode->htotal - 1) |
+	       HIBMC_FIELD(HIBMC_CRT_HORZ_TOTAL_DISP_END, mode->hdisplay - 1),
+	       priv->mmio + HIBMC_CRT_HORZ_TOTAL);
+
+	writel(HIBMC_FIELD(HIBMC_CRT_HORZ_SYNC_WIDTH, width) |
+	       HIBMC_FIELD(HIBMC_CRT_HORZ_SYNC_START, mode->hsync_start - 1),
+	       priv->mmio + HIBMC_CRT_HORZ_SYNC);
+
+	writel(HIBMC_FIELD(HIBMC_CRT_VERT_TOTAL_TOTAL, mode->vtotal - 1) |
+	       HIBMC_FIELD(HIBMC_CRT_VERT_TOTAL_DISP_END, mode->vdisplay - 1),
+	       priv->mmio + HIBMC_CRT_VERT_TOTAL);
+
+	writel(HIBMC_FIELD(HIBMC_CRT_VERT_SYNC_HEIGHT, height) |
+	       HIBMC_FIELD(HIBMC_CRT_VERT_SYNC_START, mode->vsync_start - 1),
+	       priv->mmio + HIBMC_CRT_VERT_SYNC);
+
+	val = HIBMC_FIELD(HIBMC_CRT_DISP_CTL_VSYNC_PHASE, 0);
+	val |= HIBMC_FIELD(HIBMC_CRT_DISP_CTL_HSYNC_PHASE, 0);
+	val |= HIBMC_CRT_DISP_CTL_TIMING(1);
+	val |= HIBMC_CRT_DISP_CTL_PLANE(1);
+
+	display_ctrl_adjust(dev, mode, val);
+}
+
+static void hibmc_crtc_atomic_begin(struct drm_crtc *crtc,
+				    struct drm_crtc_state *old_state)
+{
+	unsigned int reg;
+	struct drm_device *dev = crtc->dev;
+	struct hibmc_drm_private *priv = dev->dev_private;
+
+	hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_MODE0);
+
+	/* Enable display power gate & LOCALMEM power gate*/
+	reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
+	reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
+	reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
+	reg |= HIBMC_CURR_GATE_DISPLAY(1);
+	reg |= HIBMC_CURR_GATE_LOCALMEM(1);
+	hibmc_set_current_gate(priv, reg);
+
+	/* We can add more initialization as needed. */
+}
+
+static void hibmc_crtc_atomic_flush(struct drm_crtc *crtc,
+				    struct drm_crtc_state *old_state)
+
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&crtc->dev->event_lock, flags);
+	if (crtc->state->event)
+		drm_crtc_send_vblank_event(crtc, crtc->state->event);
+	crtc->state->event = NULL;
+	spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+}
+
+static const struct drm_crtc_funcs hibmc_crtc_funcs = {
+	.page_flip = drm_atomic_helper_page_flip,
+	.set_config = drm_atomic_helper_set_config,
+	.destroy = drm_crtc_cleanup,
+	.reset = drm_atomic_helper_crtc_reset,
+	.atomic_duplicate_state =  drm_atomic_helper_crtc_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+};
+
+static const struct drm_crtc_helper_funcs hibmc_crtc_helper_funcs = {
+	.enable		= hibmc_crtc_enable,
+	.disable	= hibmc_crtc_disable,
+	.mode_set_nofb	= hibmc_crtc_mode_set_nofb,
+	.atomic_begin	= hibmc_crtc_atomic_begin,
+	.atomic_flush	= hibmc_crtc_atomic_flush,
+};
+
+int hibmc_de_init(struct hibmc_drm_private *priv)
+{
+	struct drm_device *dev = priv->dev;
+	struct drm_crtc *crtc;
+	struct drm_plane *plane;
+	int ret;
+
+	plane = hibmc_plane_init(priv);
+	if (IS_ERR(plane)) {
+		DRM_ERROR("failed to create plane: %ld\n", PTR_ERR(plane));
+		return PTR_ERR(plane);
+	}
+
+	crtc = devm_kzalloc(dev->dev, sizeof(*crtc), GFP_KERNEL);
+	if (!crtc) {
+		DRM_ERROR("failed to alloc memory when init crtc\n");
+		return -ENOMEM;
+	}
+
+	ret = drm_crtc_init_with_planes(dev, crtc, plane,
+					NULL, &hibmc_crtc_funcs, NULL);
+	if (ret) {
+		DRM_ERROR("failed to init crtc: %d\n", ret);
+		return ret;
+	}
+
+	ret = drm_mode_crtc_set_gamma_size(crtc, 256);
+	if (ret) {
+		DRM_ERROR("failed to set gamma size: %d\n", ret);
+		return ret;
+	}
+	drm_crtc_helper_add(crtc, &hibmc_crtc_helper_funcs);
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index 4b52b29..9de3564 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -19,6 +19,9 @@
 #include <linux/console.h>
 #include <linux/module.h>
 
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+
 #include "hibmc_drm_drv.h"
 #include "hibmc_drm_regs.h"
 
@@ -44,7 +47,8 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
 }
 
 static struct drm_driver hibmc_driver = {
-	.driver_features	= DRIVER_GEM,
+	.driver_features	= DRIVER_GEM | DRIVER_MODESET |
+				  DRIVER_ATOMIC,
 	.fops			= &hibmc_fops,
 	.name			= "hibmc",
 	.date			= "20160828",
@@ -62,11 +66,31 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
 
 static int hibmc_pm_suspend(struct device *dev)
 {
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct drm_device *drm_dev = pci_get_drvdata(pdev);
+	struct hibmc_drm_private *priv = drm_dev->dev_private;
+
+	drm_kms_helper_poll_disable(drm_dev);
+	priv->suspend_state = drm_atomic_helper_suspend(drm_dev);
+	if (IS_ERR(priv->suspend_state)) {
+		DRM_ERROR("drm_atomic_helper_suspend failed: %ld\n",
+			  PTR_ERR(priv->suspend_state));
+		drm_kms_helper_poll_enable(drm_dev);
+		return PTR_ERR(priv->suspend_state);
+	}
+
 	return 0;
 }
 
 static int hibmc_pm_resume(struct device *dev)
 {
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct drm_device *drm_dev = pci_get_drvdata(pdev);
+	struct hibmc_drm_private *priv = drm_dev->dev_private;
+
+	drm_atomic_helper_resume(drm_dev, priv->suspend_state);
+	drm_kms_helper_poll_enable(drm_dev);
+
 	return 0;
 }
 
@@ -75,6 +99,41 @@ static int hibmc_pm_resume(struct device *dev)
 				hibmc_pm_resume)
 };
 
+static int hibmc_kms_init(struct hibmc_drm_private *priv)
+{
+	int ret;
+
+	drm_mode_config_init(priv->dev);
+	priv->mode_config_initialized = true;
+
+	priv->dev->mode_config.min_width = 0;
+	priv->dev->mode_config.min_height = 0;
+	priv->dev->mode_config.max_width = 1920;
+	priv->dev->mode_config.max_height = 1440;
+
+	priv->dev->mode_config.fb_base = priv->fb_base;
+	priv->dev->mode_config.preferred_depth = 24;
+	priv->dev->mode_config.prefer_shadow = 0;
+
+	priv->dev->mode_config.funcs = (void *)&hibmc_mode_funcs;
+
+	ret = hibmc_de_init(priv);
+	if (ret) {
+		DRM_ERROR("failed to init de: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void hibmc_kms_fini(struct hibmc_drm_private *priv)
+{
+	if (priv->mode_config_initialized) {
+		drm_mode_config_cleanup(priv->dev);
+		priv->mode_config_initialized = false;
+	}
+}
+
 /*
  * It can operate in one of three modes: 0, 1 or Sleep.
  */
@@ -203,6 +262,7 @@ static int hibmc_unload(struct drm_device *dev)
 	struct hibmc_drm_private *priv = dev->dev_private;
 
 	hibmc_fbdev_fini(priv);
+	hibmc_kms_fini(priv);
 	hibmc_mm_fini(priv);
 	dev->dev_private = NULL;
 	return 0;
@@ -229,6 +289,13 @@ static int hibmc_load(struct drm_device *dev)
 	if (ret)
 		goto err;
 
+	ret = hibmc_kms_init(priv);
+	if (ret)
+		goto err;
+
+	/* reset all the states of crtc/plane/encoder/connector */
+	drm_mode_config_reset(dev);
+
 	ret = hibmc_fbdev_init(priv);
 	if (ret) {
 		DRM_ERROR("failed to initialize fbdev: %d\n", ret);
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
index d283d66..87af1eb 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -20,6 +20,7 @@
 #define HIBMC_DRM_DRV_H
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_gem.h>
 #include <drm/ttm/ttm_bo_driver.h>
@@ -44,6 +45,8 @@ struct hibmc_drm_private {
 
 	/* drm */
 	struct drm_device  *dev;
+	bool mode_config_initialized;
+	struct drm_atomic_state *suspend_state;
 
 	/* ttm */
 	struct drm_global_reference mem_global_ref;
@@ -82,6 +85,7 @@ void hibmc_set_power_mode(struct hibmc_drm_private *priv,
 void hibmc_set_current_gate(struct hibmc_drm_private *priv,
 			    unsigned int gate);
 
+int hibmc_de_init(struct hibmc_drm_private *priv);
 int hibmc_fbdev_init(struct hibmc_drm_private *priv);
 void hibmc_fbdev_fini(struct hibmc_drm_private *priv);
 
@@ -103,4 +107,6 @@ int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
 			   u32 handle, u64 *offset);
 int hibmc_mmap(struct file *filp, struct vm_area_struct *vma);
 
+extern const struct drm_mode_config_funcs hibmc_mode_funcs;
+
 #endif
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
index 3ff65f4..e76abf6 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
@@ -550,3 +550,9 @@ struct hibmc_framebuffer *
 	}
 	return &hibmc_fb->fb;
 }
+
+const struct drm_mode_config_funcs hibmc_mode_funcs = {
+	.atomic_check = drm_atomic_helper_check,
+	.atomic_commit = drm_atomic_helper_commit,
+	.fb_create = hibmc_user_framebuffer_create,
+};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v7 4/7] drm/hisilicon/hibmc: Add support for display engine
@ 2016-11-16 13:43   ` Rongrong Zou
  0 siblings, 0 replies; 40+ messages in thread
From: Rongrong Zou @ 2016-11-16 13:43 UTC (permalink / raw)
  To: airlied, daniel, seanpaul, seanpaul, dri-devel, emil.l.velikov,
	tomeu.vizoso, benjamin.gaignard, robh, daniel, architt, corbet,
	mark.rutland, xinliang.liu
  Cc: linuxarm, kong.kongxinwei, james.xiong, shenhui, guohanjun,
	lijianhua, linux-arm-kernel

Add display engine function, crtc/plane is initialized here.

Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
---
 drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c  | 477 ++++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  69 +++-
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |   6 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     |   6 +
 5 files changed, 558 insertions(+), 2 deletions(-)
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c

diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
index ff77a7e..8e0cf72 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
+++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
@@ -1,4 +1,4 @@
 ccflags-y := -Iinclude/drm
-hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_ttm.o
+hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_fbdev.o hibmc_ttm.o
 
 obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
new file mode 100644
index 0000000..2a1386e
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
@@ -0,0 +1,477 @@
+/* Hisilicon Hibmc SoC drm driver
+ *
+ * Based on the bochs drm driver.
+ *
+ * Copyright (c) 2016 Huawei Limited.
+ *
+ * Author:
+ *	Rongrong Zou <zourongrong@huawei.com>
+ *	Rongrong Zou <zourongrong@gmail.com>
+ *	Jianhua Li <lijianhua@huawei.com>
+ *
+ * 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.
+ *
+ */
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_plane_helper.h>
+
+#include "hibmc_drm_drv.h"
+#include "hibmc_drm_regs.h"
+
+struct hibmc_display_panel_pll {
+	unsigned long M;
+	unsigned long N;
+	unsigned long OD;
+	unsigned long POD;
+};
+
+struct hibmc_dislay_pll_config {
+	unsigned long hdisplay;
+	unsigned long vdisplay;
+	u32 pll1_config_value;
+	u32 pll2_config_value;
+};
+
+static const struct hibmc_dislay_pll_config hibmc_pll_table[] = {
+	{800, 600, CRT_PLL1_HS_40MHZ, CRT_PLL2_HS_40MHZ},
+	{1024, 768, CRT_PLL1_HS_65MHZ, CRT_PLL2_HS_65MHZ},
+	{1152, 864, CRT_PLL1_HS_80MHZ_1152, CRT_PLL2_HS_80MHZ},
+	{1280, 768, CRT_PLL1_HS_80MHZ, CRT_PLL2_HS_80MHZ},
+	{1280, 720, CRT_PLL1_HS_74MHZ, CRT_PLL2_HS_74MHZ},
+	{1280, 960, CRT_PLL1_HS_108MHZ, CRT_PLL2_HS_108MHZ},
+	{1280, 1024, CRT_PLL1_HS_108MHZ, CRT_PLL2_HS_108MHZ},
+	{1600, 1200, CRT_PLL1_HS_162MHZ, CRT_PLL2_HS_162MHZ},
+	{1920, 1080, CRT_PLL1_HS_148MHZ, CRT_PLL2_HS_148MHZ},
+	{1920, 1200, CRT_PLL1_HS_193MHZ, CRT_PLL2_HS_193MHZ},
+};
+
+#define PADDING(align, data) (((data) + (align) - 1) & (~((align) - 1)))
+
+static int hibmc_plane_atomic_check(struct drm_plane *plane,
+				    struct drm_plane_state *state)
+{
+	struct drm_framebuffer *fb = state->fb;
+	struct drm_crtc *crtc = state->crtc;
+	struct drm_crtc_state *crtc_state;
+	u32 src_w = state->src_w >> 16;
+	u32 src_h = state->src_h >> 16;
+
+	if (!crtc || !fb)
+		return 0;
+
+	crtc_state = drm_atomic_get_crtc_state(state->state, crtc);
+	if (IS_ERR(crtc_state))
+		return PTR_ERR(crtc_state);
+
+	if (src_w != state->crtc_w || src_h != state->crtc_h) {
+		DRM_DEBUG_ATOMIC("scale not support\n");
+		return -EINVAL;
+	}
+
+	if (state->crtc_x < 0 || state->crtc_y < 0) {
+		DRM_DEBUG_ATOMIC("crtc_x/y of drm_plane state is invalid\n");
+		return -EINVAL;
+	}
+
+	if (state->crtc_x + state->crtc_w >
+	    crtc_state->adjusted_mode.hdisplay ||
+	    state->crtc_y + state->crtc_h >
+	    crtc_state->adjusted_mode.vdisplay) {
+		DRM_DEBUG_ATOMIC("visible portion of plane is invalid\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void hibmc_plane_atomic_update(struct drm_plane *plane,
+				      struct drm_plane_state *old_state)
+{
+	struct drm_plane_state	*state	= plane->state;
+	u32 reg;
+	int ret;
+	u64 gpu_addr = 0;
+	unsigned int line_l;
+	struct hibmc_drm_private *priv = plane->dev->dev_private;
+	struct hibmc_framebuffer *hibmc_fb;
+	struct hibmc_bo *bo;
+
+	if (!state->fb)
+		return;
+
+	hibmc_fb = to_hibmc_framebuffer(state->fb);
+	bo = gem_to_hibmc_bo(hibmc_fb->obj);
+	ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
+	if (ret) {
+		DRM_ERROR("failed to reserve ttm_bo: %d", ret);
+		return;
+	}
+
+	ret = hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
+	ttm_bo_unreserve(&bo->bo);
+	if (ret) {
+		DRM_ERROR("failed to pin hibmc_bo: %d", ret);
+		return;
+	}
+
+	writel(gpu_addr, priv->mmio + HIBMC_CRT_FB_ADDRESS);
+
+	reg = state->fb->width * (state->fb->bits_per_pixel / 8);
+	/* now line_pad is 16 */
+	reg = PADDING(16, reg);
+
+	line_l = state->fb->width * state->fb->bits_per_pixel / 8;
+	line_l = PADDING(16, line_l);
+	writel(HIBMC_FIELD(HIBMC_CRT_FB_WIDTH_WIDTH, reg) |
+	       HIBMC_FIELD(HIBMC_CRT_FB_WIDTH_OFFS, line_l),
+	       priv->mmio + HIBMC_CRT_FB_WIDTH);
+
+	/* SET PIXEL FORMAT */
+	reg = readl(priv->mmio + HIBMC_CRT_DISP_CTL);
+	reg &= ~HIBMC_CRT_DISP_CTL_FORMAT_MASK;
+	reg |= HIBMC_FIELD(HIBMC_CRT_DISP_CTL_FORMAT,
+			   state->fb->bits_per_pixel / 16);
+	writel(reg, priv->mmio + HIBMC_CRT_DISP_CTL);
+}
+
+static const u32 channel_formats1[] = {
+	DRM_FORMAT_RGB565, DRM_FORMAT_BGR565, DRM_FORMAT_RGB888,
+	DRM_FORMAT_BGR888, DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_RGBA8888, DRM_FORMAT_BGRA8888, DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_ABGR8888
+};
+
+static struct drm_plane_funcs hibmc_plane_funcs = {
+	.update_plane	= drm_atomic_helper_update_plane,
+	.disable_plane	= drm_atomic_helper_disable_plane,
+	.set_property = drm_atomic_helper_plane_set_property,
+	.destroy = drm_plane_cleanup,
+	.reset = drm_atomic_helper_plane_reset,
+	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+};
+
+static const struct drm_plane_helper_funcs hibmc_plane_helper_funcs = {
+	.atomic_check = hibmc_plane_atomic_check,
+	.atomic_update = hibmc_plane_atomic_update,
+};
+
+static struct drm_plane *hibmc_plane_init(struct hibmc_drm_private *priv)
+{
+	struct drm_device *dev = priv->dev;
+	struct drm_plane *plane;
+	int ret = 0;
+
+	plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
+	if (!plane) {
+		DRM_ERROR("failed to alloc memory when init plane\n");
+		return ERR_PTR(-ENOMEM);
+	}
+	/*
+	 * plane init
+	 * TODO: Now only support primary plane, overlay planes
+	 * need to do.
+	 */
+	ret = drm_universal_plane_init(dev, plane, 1, &hibmc_plane_funcs,
+				       channel_formats1,
+				       ARRAY_SIZE(channel_formats1),
+				       DRM_PLANE_TYPE_PRIMARY,
+				       NULL);
+	if (ret) {
+		DRM_ERROR("failed to init plane: %d\n", ret);
+		return ERR_PTR(ret);
+	}
+
+	drm_plane_helper_add(plane, &hibmc_plane_helper_funcs);
+	return plane;
+}
+
+static void hibmc_crtc_enable(struct drm_crtc *crtc)
+{
+	unsigned int reg;
+	struct hibmc_drm_private *priv = crtc->dev->dev_private;
+
+	hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_MODE0);
+
+	/* Enable display power gate & LOCALMEM power gate*/
+	reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
+	reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
+	reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
+	reg |= HIBMC_CURR_GATE_LOCALMEM(1);
+	reg |= HIBMC_CURR_GATE_DISPLAY(1);
+	hibmc_set_current_gate(priv, reg);
+	drm_crtc_vblank_on(crtc);
+}
+
+static void hibmc_crtc_disable(struct drm_crtc *crtc)
+{
+	unsigned int reg;
+	struct hibmc_drm_private *priv = crtc->dev->dev_private;
+
+	drm_crtc_vblank_off(crtc);
+
+	hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_SLEEP);
+
+	/* Enable display power gate & LOCALMEM power gate*/
+	reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
+	reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
+	reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
+	reg |= HIBMC_CURR_GATE_LOCALMEM(0);
+	reg |= HIBMC_CURR_GATE_DISPLAY(0);
+	hibmc_set_current_gate(priv, reg);
+}
+
+static unsigned int format_pll_reg(void)
+{
+	unsigned int pllreg = 0;
+	struct hibmc_display_panel_pll pll = {0};
+
+	/*
+	 * Note that all PLL's have the same format. Here,
+	 * we just use Panel PLL parameter to work out the bit
+	 * fields in the register.On returning a 32 bit number, the value can
+	 * be applied to any PLL in the calling function.
+	 */
+	pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_BYPASS, 0);
+	pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_POWER, 1);
+	pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_INPUT, 0);
+	pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_POD, pll.POD);
+	pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_OD, pll.OD);
+	pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_N, pll.N);
+	pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_M, pll.M);
+
+	return pllreg;
+}
+
+static void set_vclock_hisilicon(struct drm_device *dev, unsigned long pll)
+{
+	u32 val;
+	struct hibmc_drm_private *priv = dev->dev_private;
+
+	val = readl(priv->mmio + CRT_PLL1_HS);
+	val &= ~(CRT_PLL1_HS_OUTER_BYPASS(1));
+	writel(val, priv->mmio + CRT_PLL1_HS);
+
+	val = CRT_PLL1_HS_INTER_BYPASS(1) | CRT_PLL1_HS_POWERON(1);
+	writel(val, priv->mmio + CRT_PLL1_HS);
+
+	writel(pll, priv->mmio + CRT_PLL1_HS);
+
+	usleep_range(1000, 2000);
+
+	val = pll & ~(CRT_PLL1_HS_POWERON(1));
+	writel(val, priv->mmio + CRT_PLL1_HS);
+
+	usleep_range(1000, 2000);
+
+	val &= ~(CRT_PLL1_HS_INTER_BYPASS(1));
+	writel(val, priv->mmio + CRT_PLL1_HS);
+
+	usleep_range(1000, 2000);
+
+	val |= CRT_PLL1_HS_OUTER_BYPASS(1);
+	writel(val, priv->mmio + CRT_PLL1_HS);
+}
+
+static void get_pll_config(unsigned long x, unsigned long y,
+			   u32 *pll1, u32 *pll2)
+{
+	int i;
+	int count = ARRAY_SIZE(hibmc_pll_table);
+
+	for (i = 0; i < count; i++) {
+		if (hibmc_pll_table[i].hdisplay == x &&
+		    hibmc_pll_table[i].vdisplay == y) {
+			*pll1 = hibmc_pll_table[i].pll1_config_value;
+			*pll2 = hibmc_pll_table[i].pll2_config_value;
+			return;
+		}
+	}
+
+	/* if found none, we use default value */
+	*pll1 = CRT_PLL1_HS_25MHZ;
+	*pll2 = CRT_PLL2_HS_25MHZ;
+}
+
+/*
+ * This function takes care the extra registers and bit fields required to
+ * setup a mode in board.
+ * Explanation about Display Control register:
+ * FPGA only supports 7 predefined pixel clocks, and clock select is
+ * in bit 4:0 of new register 0x802a8.
+ */
+static unsigned int display_ctrl_adjust(struct drm_device *dev,
+					struct drm_display_mode *mode,
+					unsigned int ctrl)
+{
+	unsigned long x, y;
+	u32 pll1; /* bit[31:0] of PLL */
+	u32 pll2; /* bit[63:32] of PLL */
+	struct hibmc_drm_private *priv = dev->dev_private;
+
+	x = mode->hdisplay;
+	y = mode->vdisplay;
+
+	get_pll_config(x, y, &pll1, &pll2);
+	writel(pll2, priv->mmio + CRT_PLL2_HS);
+	set_vclock_hisilicon(dev, pll1);
+
+	/*
+	 * Hisilicon has to set up the top-left and bottom-right
+	 * registers as well.
+	 * Note that normal chip only use those two register for
+	 * auto-centering mode.
+	 */
+	writel(HIBMC_FIELD(HIBMC_CRT_AUTO_CENTERING_TL_TOP, 0) |
+	       HIBMC_FIELD(HIBMC_CRT_AUTO_CENTERING_TL_LEFT, 0),
+	       priv->mmio + HIBMC_CRT_AUTO_CENTERING_TL);
+
+	writel(HIBMC_FIELD(HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM, y - 1) |
+	       HIBMC_FIELD(HIBMC_CRT_AUTO_CENTERING_BR_RIGHT, x - 1),
+	       priv->mmio + HIBMC_CRT_AUTO_CENTERING_BR);
+
+	/*
+	 * Assume common fields in ctrl have been properly set before
+	 * calling this function.
+	 * This function only sets the extra fields in ctrl.
+	 */
+
+	/* Set bit 25 of display controller: Select CRT or VGA clock */
+	ctrl &= ~HIBMC_CRT_DISP_CTL_CRTSELECT_MASK;
+	ctrl &= ~HIBMC_CRT_DISP_CTL_CLOCK_PHASE_MASK;
+
+	ctrl |= HIBMC_CRT_DISP_CTL_CRTSELECT(HIBMC_CRTSELECT_CRT);
+
+	/* clock_phase_polarity is 0 */
+	ctrl |= HIBMC_CRT_DISP_CTL_CLOCK_PHASE(0);
+
+	writel(ctrl, priv->mmio + HIBMC_CRT_DISP_CTL);
+
+	return ctrl;
+}
+
+static void hibmc_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+	unsigned int val;
+	struct drm_display_mode *mode = &crtc->state->mode;
+	struct drm_device *dev = crtc->dev;
+	struct hibmc_drm_private *priv = dev->dev_private;
+	int width = mode->hsync_end - mode->hsync_start;
+	int height = mode->vsync_end - mode->vsync_start;
+
+	writel(format_pll_reg(), priv->mmio + HIBMC_CRT_PLL_CTRL);
+	writel(HIBMC_FIELD(HIBMC_CRT_HORZ_TOTAL_TOTAL, mode->htotal - 1) |
+	       HIBMC_FIELD(HIBMC_CRT_HORZ_TOTAL_DISP_END, mode->hdisplay - 1),
+	       priv->mmio + HIBMC_CRT_HORZ_TOTAL);
+
+	writel(HIBMC_FIELD(HIBMC_CRT_HORZ_SYNC_WIDTH, width) |
+	       HIBMC_FIELD(HIBMC_CRT_HORZ_SYNC_START, mode->hsync_start - 1),
+	       priv->mmio + HIBMC_CRT_HORZ_SYNC);
+
+	writel(HIBMC_FIELD(HIBMC_CRT_VERT_TOTAL_TOTAL, mode->vtotal - 1) |
+	       HIBMC_FIELD(HIBMC_CRT_VERT_TOTAL_DISP_END, mode->vdisplay - 1),
+	       priv->mmio + HIBMC_CRT_VERT_TOTAL);
+
+	writel(HIBMC_FIELD(HIBMC_CRT_VERT_SYNC_HEIGHT, height) |
+	       HIBMC_FIELD(HIBMC_CRT_VERT_SYNC_START, mode->vsync_start - 1),
+	       priv->mmio + HIBMC_CRT_VERT_SYNC);
+
+	val = HIBMC_FIELD(HIBMC_CRT_DISP_CTL_VSYNC_PHASE, 0);
+	val |= HIBMC_FIELD(HIBMC_CRT_DISP_CTL_HSYNC_PHASE, 0);
+	val |= HIBMC_CRT_DISP_CTL_TIMING(1);
+	val |= HIBMC_CRT_DISP_CTL_PLANE(1);
+
+	display_ctrl_adjust(dev, mode, val);
+}
+
+static void hibmc_crtc_atomic_begin(struct drm_crtc *crtc,
+				    struct drm_crtc_state *old_state)
+{
+	unsigned int reg;
+	struct drm_device *dev = crtc->dev;
+	struct hibmc_drm_private *priv = dev->dev_private;
+
+	hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_MODE0);
+
+	/* Enable display power gate & LOCALMEM power gate*/
+	reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
+	reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
+	reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
+	reg |= HIBMC_CURR_GATE_DISPLAY(1);
+	reg |= HIBMC_CURR_GATE_LOCALMEM(1);
+	hibmc_set_current_gate(priv, reg);
+
+	/* We can add more initialization as needed. */
+}
+
+static void hibmc_crtc_atomic_flush(struct drm_crtc *crtc,
+				    struct drm_crtc_state *old_state)
+
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&crtc->dev->event_lock, flags);
+	if (crtc->state->event)
+		drm_crtc_send_vblank_event(crtc, crtc->state->event);
+	crtc->state->event = NULL;
+	spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+}
+
+static const struct drm_crtc_funcs hibmc_crtc_funcs = {
+	.page_flip = drm_atomic_helper_page_flip,
+	.set_config = drm_atomic_helper_set_config,
+	.destroy = drm_crtc_cleanup,
+	.reset = drm_atomic_helper_crtc_reset,
+	.atomic_duplicate_state =  drm_atomic_helper_crtc_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+};
+
+static const struct drm_crtc_helper_funcs hibmc_crtc_helper_funcs = {
+	.enable		= hibmc_crtc_enable,
+	.disable	= hibmc_crtc_disable,
+	.mode_set_nofb	= hibmc_crtc_mode_set_nofb,
+	.atomic_begin	= hibmc_crtc_atomic_begin,
+	.atomic_flush	= hibmc_crtc_atomic_flush,
+};
+
+int hibmc_de_init(struct hibmc_drm_private *priv)
+{
+	struct drm_device *dev = priv->dev;
+	struct drm_crtc *crtc;
+	struct drm_plane *plane;
+	int ret;
+
+	plane = hibmc_plane_init(priv);
+	if (IS_ERR(plane)) {
+		DRM_ERROR("failed to create plane: %ld\n", PTR_ERR(plane));
+		return PTR_ERR(plane);
+	}
+
+	crtc = devm_kzalloc(dev->dev, sizeof(*crtc), GFP_KERNEL);
+	if (!crtc) {
+		DRM_ERROR("failed to alloc memory when init crtc\n");
+		return -ENOMEM;
+	}
+
+	ret = drm_crtc_init_with_planes(dev, crtc, plane,
+					NULL, &hibmc_crtc_funcs, NULL);
+	if (ret) {
+		DRM_ERROR("failed to init crtc: %d\n", ret);
+		return ret;
+	}
+
+	ret = drm_mode_crtc_set_gamma_size(crtc, 256);
+	if (ret) {
+		DRM_ERROR("failed to set gamma size: %d\n", ret);
+		return ret;
+	}
+	drm_crtc_helper_add(crtc, &hibmc_crtc_helper_funcs);
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index 4b52b29..9de3564 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -19,6 +19,9 @@
 #include <linux/console.h>
 #include <linux/module.h>
 
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+
 #include "hibmc_drm_drv.h"
 #include "hibmc_drm_regs.h"
 
@@ -44,7 +47,8 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
 }
 
 static struct drm_driver hibmc_driver = {
-	.driver_features	= DRIVER_GEM,
+	.driver_features	= DRIVER_GEM | DRIVER_MODESET |
+				  DRIVER_ATOMIC,
 	.fops			= &hibmc_fops,
 	.name			= "hibmc",
 	.date			= "20160828",
@@ -62,11 +66,31 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
 
 static int hibmc_pm_suspend(struct device *dev)
 {
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct drm_device *drm_dev = pci_get_drvdata(pdev);
+	struct hibmc_drm_private *priv = drm_dev->dev_private;
+
+	drm_kms_helper_poll_disable(drm_dev);
+	priv->suspend_state = drm_atomic_helper_suspend(drm_dev);
+	if (IS_ERR(priv->suspend_state)) {
+		DRM_ERROR("drm_atomic_helper_suspend failed: %ld\n",
+			  PTR_ERR(priv->suspend_state));
+		drm_kms_helper_poll_enable(drm_dev);
+		return PTR_ERR(priv->suspend_state);
+	}
+
 	return 0;
 }
 
 static int hibmc_pm_resume(struct device *dev)
 {
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct drm_device *drm_dev = pci_get_drvdata(pdev);
+	struct hibmc_drm_private *priv = drm_dev->dev_private;
+
+	drm_atomic_helper_resume(drm_dev, priv->suspend_state);
+	drm_kms_helper_poll_enable(drm_dev);
+
 	return 0;
 }
 
@@ -75,6 +99,41 @@ static int hibmc_pm_resume(struct device *dev)
 				hibmc_pm_resume)
 };
 
+static int hibmc_kms_init(struct hibmc_drm_private *priv)
+{
+	int ret;
+
+	drm_mode_config_init(priv->dev);
+	priv->mode_config_initialized = true;
+
+	priv->dev->mode_config.min_width = 0;
+	priv->dev->mode_config.min_height = 0;
+	priv->dev->mode_config.max_width = 1920;
+	priv->dev->mode_config.max_height = 1440;
+
+	priv->dev->mode_config.fb_base = priv->fb_base;
+	priv->dev->mode_config.preferred_depth = 24;
+	priv->dev->mode_config.prefer_shadow = 0;
+
+	priv->dev->mode_config.funcs = (void *)&hibmc_mode_funcs;
+
+	ret = hibmc_de_init(priv);
+	if (ret) {
+		DRM_ERROR("failed to init de: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void hibmc_kms_fini(struct hibmc_drm_private *priv)
+{
+	if (priv->mode_config_initialized) {
+		drm_mode_config_cleanup(priv->dev);
+		priv->mode_config_initialized = false;
+	}
+}
+
 /*
  * It can operate in one of three modes: 0, 1 or Sleep.
  */
@@ -203,6 +262,7 @@ static int hibmc_unload(struct drm_device *dev)
 	struct hibmc_drm_private *priv = dev->dev_private;
 
 	hibmc_fbdev_fini(priv);
+	hibmc_kms_fini(priv);
 	hibmc_mm_fini(priv);
 	dev->dev_private = NULL;
 	return 0;
@@ -229,6 +289,13 @@ static int hibmc_load(struct drm_device *dev)
 	if (ret)
 		goto err;
 
+	ret = hibmc_kms_init(priv);
+	if (ret)
+		goto err;
+
+	/* reset all the states of crtc/plane/encoder/connector */
+	drm_mode_config_reset(dev);
+
 	ret = hibmc_fbdev_init(priv);
 	if (ret) {
 		DRM_ERROR("failed to initialize fbdev: %d\n", ret);
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
index d283d66..87af1eb 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -20,6 +20,7 @@
 #define HIBMC_DRM_DRV_H
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_gem.h>
 #include <drm/ttm/ttm_bo_driver.h>
@@ -44,6 +45,8 @@ struct hibmc_drm_private {
 
 	/* drm */
 	struct drm_device  *dev;
+	bool mode_config_initialized;
+	struct drm_atomic_state *suspend_state;
 
 	/* ttm */
 	struct drm_global_reference mem_global_ref;
@@ -82,6 +85,7 @@ void hibmc_set_power_mode(struct hibmc_drm_private *priv,
 void hibmc_set_current_gate(struct hibmc_drm_private *priv,
 			    unsigned int gate);
 
+int hibmc_de_init(struct hibmc_drm_private *priv);
 int hibmc_fbdev_init(struct hibmc_drm_private *priv);
 void hibmc_fbdev_fini(struct hibmc_drm_private *priv);
 
@@ -103,4 +107,6 @@ int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
 			   u32 handle, u64 *offset);
 int hibmc_mmap(struct file *filp, struct vm_area_struct *vma);
 
+extern const struct drm_mode_config_funcs hibmc_mode_funcs;
+
 #endif
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
index 3ff65f4..e76abf6 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
@@ -550,3 +550,9 @@ struct hibmc_framebuffer *
 	}
 	return &hibmc_fb->fb;
 }
+
+const struct drm_mode_config_funcs hibmc_mode_funcs = {
+	.atomic_check = drm_atomic_helper_check,
+	.atomic_commit = drm_atomic_helper_commit,
+	.fb_create = hibmc_user_framebuffer_create,
+};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v7 5/7] drm/hisilicon/hibmc: Add support for VDAC
  2016-11-16 13:43 ` Rongrong Zou
@ 2016-11-16 13:43   ` Rongrong Zou
  -1 siblings, 0 replies; 40+ messages in thread
From: Rongrong Zou @ 2016-11-16 13:43 UTC (permalink / raw)
  To: linux-arm-kernel

VDAC(Video Digital-to-Analog converter) converts the RGB diaital data
stream from DE to VGA analog signals.

Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
---
 drivers/gpu/drm/hisilicon/hibmc/Makefile         |   2 +-
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c  |   6 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h  |   1 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c | 147 +++++++++++++++++++++++
 4 files changed, 155 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c

diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
index 8e0cf72..f2e04c0 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
+++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
@@ -1,4 +1,4 @@
 ccflags-y := -Iinclude/drm
-hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_fbdev.o hibmc_ttm.o
+hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_drm_fbdev.o hibmc_ttm.o
 
 obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index 9de3564..c133644 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -123,6 +123,12 @@ static int hibmc_kms_init(struct hibmc_drm_private *priv)
 		return ret;
 	}
 
+	ret = hibmc_vdac_init(priv);
+	if (ret) {
+		DRM_ERROR("failed to init vdac: %d\n", ret);
+		return ret;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
index 87af1eb..b626caf 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -86,6 +86,7 @@ void hibmc_set_current_gate(struct hibmc_drm_private *priv,
 			    unsigned int gate);
 
 int hibmc_de_init(struct hibmc_drm_private *priv);
+int hibmc_vdac_init(struct hibmc_drm_private *priv);
 int hibmc_fbdev_init(struct hibmc_drm_private *priv);
 void hibmc_fbdev_fini(struct hibmc_drm_private *priv);
 
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
new file mode 100644
index 0000000..d1f67a9
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
@@ -0,0 +1,147 @@
+/* Hisilicon Hibmc SoC drm driver
+ *
+ * Based on the bochs drm driver.
+ *
+ * Copyright (c) 2016 Huawei Limited.
+ *
+ * Author:
+ *	Rongrong Zou <zourongrong@huawei.com>
+ *	Rongrong Zou <zourongrong@gmail.com>
+ *	Jianhua Li <lijianhua@huawei.com>
+ *
+ * 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.
+ *
+ */
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "hibmc_drm_drv.h"
+#include "hibmc_drm_regs.h"
+
+static int hibmc_connector_get_modes(struct drm_connector *connector)
+{
+	return drm_add_modes_noedid(connector, 800, 600);
+}
+
+static int hibmc_connector_mode_valid(struct drm_connector *connector,
+				      struct drm_display_mode *mode)
+{
+	return MODE_OK;
+}
+
+static struct drm_encoder *
+hibmc_connector_best_encoder(struct drm_connector *connector)
+{
+	return drm_encoder_find(connector->dev, connector->encoder_ids[0]);
+}
+
+static enum drm_connector_status hibmc_connector_detect(struct drm_connector
+						 *connector, bool force)
+{
+	return connector_status_connected;
+}
+
+static const struct drm_connector_helper_funcs
+	hibmc_connector_helper_funcs = {
+	.get_modes = hibmc_connector_get_modes,
+	.mode_valid = hibmc_connector_mode_valid,
+	.best_encoder = hibmc_connector_best_encoder,
+};
+
+static const struct drm_connector_funcs hibmc_connector_funcs = {
+	.dpms = drm_atomic_helper_connector_dpms,
+	.detect = hibmc_connector_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = drm_connector_cleanup,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static struct drm_connector *
+hibmc_connector_init(struct hibmc_drm_private *priv)
+{
+	struct drm_device *dev = priv->dev;
+	struct drm_connector *connector;
+	int ret;
+
+	connector = devm_kzalloc(dev->dev, sizeof(*connector), GFP_KERNEL);
+	if (!connector) {
+		DRM_ERROR("failed to alloc memory when init connector\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	ret = drm_connector_init(dev, connector,
+				 &hibmc_connector_funcs,
+				 DRM_MODE_CONNECTOR_VGA);
+	if (ret) {
+		DRM_ERROR("failed to init connector: %d\n", ret);
+		return ERR_PTR(ret);
+	}
+	drm_connector_helper_add(connector,
+				 &hibmc_connector_helper_funcs);
+
+	return connector;
+}
+
+static void hibmc_encoder_mode_set(struct drm_encoder *encoder,
+				   struct drm_display_mode *mode,
+				   struct drm_display_mode *adj_mode)
+{
+	u32 reg;
+	struct drm_device *dev = encoder->dev;
+	struct hibmc_drm_private *priv = dev->dev_private;
+
+	reg = readl(priv->mmio + HIBMC_DISPLAY_CONTROL_HISILE);
+	reg |= HIBMC_DISPLAY_CONTROL_FPVDDEN(1);
+	reg |= HIBMC_DISPLAY_CONTROL_PANELDATE(1);
+	reg |= HIBMC_DISPLAY_CONTROL_FPEN(1);
+	reg |= HIBMC_DISPLAY_CONTROL_VBIASEN(1);
+	writel(reg, priv->mmio + HIBMC_DISPLAY_CONTROL_HISILE);
+}
+
+static const struct drm_encoder_helper_funcs hibmc_encoder_helper_funcs = {
+	.mode_set = hibmc_encoder_mode_set,
+};
+
+static const struct drm_encoder_funcs hibmc_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+int hibmc_vdac_init(struct hibmc_drm_private *priv)
+{
+	struct drm_device *dev = priv->dev;
+	struct drm_encoder *encoder;
+	struct drm_connector *connector;
+	int ret;
+
+	connector = hibmc_connector_init(priv);
+	if (IS_ERR(connector)) {
+		DRM_ERROR("failed to create connector: %ld\n",
+			  PTR_ERR(connector));
+		return PTR_ERR(connector);
+	}
+
+	encoder = devm_kzalloc(dev->dev, sizeof(*encoder), GFP_KERNEL);
+	if (!encoder) {
+		DRM_ERROR("failed to alloc memory when init encoder\n");
+		return -ENOMEM;
+	}
+
+	encoder->possible_crtcs = 0x1;
+	ret = drm_encoder_init(dev, encoder, &hibmc_encoder_funcs,
+			       DRM_MODE_ENCODER_DAC, NULL);
+	if (ret) {
+		DRM_ERROR("failed to init encoder: %d\n", ret);
+		return ret;
+	}
+
+	drm_encoder_helper_add(encoder, &hibmc_encoder_helper_funcs);
+	drm_mode_connector_attach_encoder(connector, encoder);
+
+	return 0;
+}
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v7 5/7] drm/hisilicon/hibmc: Add support for VDAC
@ 2016-11-16 13:43   ` Rongrong Zou
  0 siblings, 0 replies; 40+ messages in thread
From: Rongrong Zou @ 2016-11-16 13:43 UTC (permalink / raw)
  To: airlied, daniel, seanpaul, seanpaul, dri-devel, emil.l.velikov,
	tomeu.vizoso, benjamin.gaignard, robh, daniel, architt, corbet,
	mark.rutland, xinliang.liu
  Cc: linuxarm, kong.kongxinwei, james.xiong, shenhui, guohanjun,
	lijianhua, linux-arm-kernel

VDAC(Video Digital-to-Analog converter) converts the RGB diaital data
stream from DE to VGA analog signals.

Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
---
 drivers/gpu/drm/hisilicon/hibmc/Makefile         |   2 +-
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c  |   6 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h  |   1 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c | 147 +++++++++++++++++++++++
 4 files changed, 155 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c

diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
index 8e0cf72..f2e04c0 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
+++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
@@ -1,4 +1,4 @@
 ccflags-y := -Iinclude/drm
-hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_fbdev.o hibmc_ttm.o
+hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_drm_fbdev.o hibmc_ttm.o
 
 obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index 9de3564..c133644 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -123,6 +123,12 @@ static int hibmc_kms_init(struct hibmc_drm_private *priv)
 		return ret;
 	}
 
+	ret = hibmc_vdac_init(priv);
+	if (ret) {
+		DRM_ERROR("failed to init vdac: %d\n", ret);
+		return ret;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
index 87af1eb..b626caf 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -86,6 +86,7 @@ void hibmc_set_current_gate(struct hibmc_drm_private *priv,
 			    unsigned int gate);
 
 int hibmc_de_init(struct hibmc_drm_private *priv);
+int hibmc_vdac_init(struct hibmc_drm_private *priv);
 int hibmc_fbdev_init(struct hibmc_drm_private *priv);
 void hibmc_fbdev_fini(struct hibmc_drm_private *priv);
 
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
new file mode 100644
index 0000000..d1f67a9
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
@@ -0,0 +1,147 @@
+/* Hisilicon Hibmc SoC drm driver
+ *
+ * Based on the bochs drm driver.
+ *
+ * Copyright (c) 2016 Huawei Limited.
+ *
+ * Author:
+ *	Rongrong Zou <zourongrong@huawei.com>
+ *	Rongrong Zou <zourongrong@gmail.com>
+ *	Jianhua Li <lijianhua@huawei.com>
+ *
+ * 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.
+ *
+ */
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "hibmc_drm_drv.h"
+#include "hibmc_drm_regs.h"
+
+static int hibmc_connector_get_modes(struct drm_connector *connector)
+{
+	return drm_add_modes_noedid(connector, 800, 600);
+}
+
+static int hibmc_connector_mode_valid(struct drm_connector *connector,
+				      struct drm_display_mode *mode)
+{
+	return MODE_OK;
+}
+
+static struct drm_encoder *
+hibmc_connector_best_encoder(struct drm_connector *connector)
+{
+	return drm_encoder_find(connector->dev, connector->encoder_ids[0]);
+}
+
+static enum drm_connector_status hibmc_connector_detect(struct drm_connector
+						 *connector, bool force)
+{
+	return connector_status_connected;
+}
+
+static const struct drm_connector_helper_funcs
+	hibmc_connector_helper_funcs = {
+	.get_modes = hibmc_connector_get_modes,
+	.mode_valid = hibmc_connector_mode_valid,
+	.best_encoder = hibmc_connector_best_encoder,
+};
+
+static const struct drm_connector_funcs hibmc_connector_funcs = {
+	.dpms = drm_atomic_helper_connector_dpms,
+	.detect = hibmc_connector_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = drm_connector_cleanup,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static struct drm_connector *
+hibmc_connector_init(struct hibmc_drm_private *priv)
+{
+	struct drm_device *dev = priv->dev;
+	struct drm_connector *connector;
+	int ret;
+
+	connector = devm_kzalloc(dev->dev, sizeof(*connector), GFP_KERNEL);
+	if (!connector) {
+		DRM_ERROR("failed to alloc memory when init connector\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	ret = drm_connector_init(dev, connector,
+				 &hibmc_connector_funcs,
+				 DRM_MODE_CONNECTOR_VGA);
+	if (ret) {
+		DRM_ERROR("failed to init connector: %d\n", ret);
+		return ERR_PTR(ret);
+	}
+	drm_connector_helper_add(connector,
+				 &hibmc_connector_helper_funcs);
+
+	return connector;
+}
+
+static void hibmc_encoder_mode_set(struct drm_encoder *encoder,
+				   struct drm_display_mode *mode,
+				   struct drm_display_mode *adj_mode)
+{
+	u32 reg;
+	struct drm_device *dev = encoder->dev;
+	struct hibmc_drm_private *priv = dev->dev_private;
+
+	reg = readl(priv->mmio + HIBMC_DISPLAY_CONTROL_HISILE);
+	reg |= HIBMC_DISPLAY_CONTROL_FPVDDEN(1);
+	reg |= HIBMC_DISPLAY_CONTROL_PANELDATE(1);
+	reg |= HIBMC_DISPLAY_CONTROL_FPEN(1);
+	reg |= HIBMC_DISPLAY_CONTROL_VBIASEN(1);
+	writel(reg, priv->mmio + HIBMC_DISPLAY_CONTROL_HISILE);
+}
+
+static const struct drm_encoder_helper_funcs hibmc_encoder_helper_funcs = {
+	.mode_set = hibmc_encoder_mode_set,
+};
+
+static const struct drm_encoder_funcs hibmc_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+int hibmc_vdac_init(struct hibmc_drm_private *priv)
+{
+	struct drm_device *dev = priv->dev;
+	struct drm_encoder *encoder;
+	struct drm_connector *connector;
+	int ret;
+
+	connector = hibmc_connector_init(priv);
+	if (IS_ERR(connector)) {
+		DRM_ERROR("failed to create connector: %ld\n",
+			  PTR_ERR(connector));
+		return PTR_ERR(connector);
+	}
+
+	encoder = devm_kzalloc(dev->dev, sizeof(*encoder), GFP_KERNEL);
+	if (!encoder) {
+		DRM_ERROR("failed to alloc memory when init encoder\n");
+		return -ENOMEM;
+	}
+
+	encoder->possible_crtcs = 0x1;
+	ret = drm_encoder_init(dev, encoder, &hibmc_encoder_funcs,
+			       DRM_MODE_ENCODER_DAC, NULL);
+	if (ret) {
+		DRM_ERROR("failed to init encoder: %d\n", ret);
+		return ret;
+	}
+
+	drm_encoder_helper_add(encoder, &hibmc_encoder_helper_funcs);
+	drm_mode_connector_attach_encoder(connector, encoder);
+
+	return 0;
+}
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v7 6/7] drm/hisilicon/hibmc: Add support for vblank interrupt
  2016-11-16 13:43 ` Rongrong Zou
@ 2016-11-16 13:43   ` Rongrong Zou
  -1 siblings, 0 replies; 40+ messages in thread
From: Rongrong Zou @ 2016-11-16 13:43 UTC (permalink / raw)
  To: linux-arm-kernel

Add vblank interrupt.

Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
---
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 56 ++++++++++++++++++++++++-
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |  1 +
 2 files changed, 56 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index c133644..73ba8b0 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -39,16 +39,45 @@
 
 static int hibmc_enable_vblank(struct drm_device *dev, unsigned int pipe)
 {
+	struct hibmc_drm_private *priv =
+		(struct hibmc_drm_private *)dev->dev_private;
+
+	writel(HIBMC_RAW_INTERRUPT_EN_VBLANK(1),
+	       priv->mmio + HIBMC_RAW_INTERRUPT_EN);
+
 	return 0;
 }
 
 static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
 {
+	struct hibmc_drm_private *priv =
+		(struct hibmc_drm_private *)dev->dev_private;
+
+	writel(HIBMC_RAW_INTERRUPT_EN_VBLANK(0),
+	       priv->mmio + HIBMC_RAW_INTERRUPT_EN);
+}
+
+irqreturn_t hibmc_drm_interrupt(int irq, void *arg)
+{
+	struct drm_device *dev = (struct drm_device *)arg;
+	struct hibmc_drm_private *priv =
+		(struct hibmc_drm_private *)dev->dev_private;
+	u32 status;
+
+	status = readl(priv->mmio + HIBMC_RAW_INTERRUPT);
+
+	if (status & HIBMC_RAW_INTERRUPT_VBLANK(1)) {
+		writel(HIBMC_RAW_INTERRUPT_VBLANK(1),
+		       priv->mmio + HIBMC_RAW_INTERRUPT);
+		drm_handle_vblank(dev, 0);
+	}
+
+	return IRQ_HANDLED;
 }
 
 static struct drm_driver hibmc_driver = {
 	.driver_features	= DRIVER_GEM | DRIVER_MODESET |
-				  DRIVER_ATOMIC,
+				  DRIVER_ATOMIC | DRIVER_HAVE_IRQ,
 	.fops			= &hibmc_fops,
 	.name			= "hibmc",
 	.date			= "20160828",
@@ -62,6 +91,7 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
 	.dumb_create            = hibmc_dumb_create,
 	.dumb_map_offset        = hibmc_dumb_mmap_offset,
 	.dumb_destroy           = drm_gem_dumb_destroy,
+	.irq_handler		= hibmc_drm_interrupt,
 };
 
 static int hibmc_pm_suspend(struct device *dev)
@@ -268,6 +298,13 @@ static int hibmc_unload(struct drm_device *dev)
 	struct hibmc_drm_private *priv = dev->dev_private;
 
 	hibmc_fbdev_fini(priv);
+
+	if (dev->irq_enabled)
+		drm_irq_uninstall(dev);
+	if (priv->msi_enabled)
+		pci_disable_msi(dev->pdev);
+	drm_vblank_cleanup(dev);
+
 	hibmc_kms_fini(priv);
 	hibmc_mm_fini(priv);
 	dev->dev_private = NULL;
@@ -299,6 +336,23 @@ static int hibmc_load(struct drm_device *dev)
 	if (ret)
 		goto err;
 
+	ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
+	if (ret) {
+		DRM_ERROR("failed to initialize vblank: %d\n", ret);
+		goto err;
+	}
+
+	priv->msi_enabled = 0;
+	ret = pci_enable_msi(dev->pdev);
+	if (ret) {
+		DRM_WARN("enabling MSI failed: %d\n", ret);
+	} else {
+		priv->msi_enabled = 1;
+		ret = drm_irq_install(dev, dev->pdev->irq);
+		if (ret)
+			DRM_WARN("install irq failed: %d\n", ret);
+	}
+
 	/* reset all the states of crtc/plane/encoder/connector */
 	drm_mode_config_reset(dev);
 
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
index b626caf..e195521 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -42,6 +42,7 @@ struct hibmc_drm_private {
 	void __iomem   *fb_map;
 	unsigned long  fb_base;
 	unsigned long  fb_size;
+	bool msi_enabled;
 
 	/* drm */
 	struct drm_device  *dev;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v7 6/7] drm/hisilicon/hibmc: Add support for vblank interrupt
@ 2016-11-16 13:43   ` Rongrong Zou
  0 siblings, 0 replies; 40+ messages in thread
From: Rongrong Zou @ 2016-11-16 13:43 UTC (permalink / raw)
  To: airlied, daniel, seanpaul, seanpaul, dri-devel, emil.l.velikov,
	tomeu.vizoso, benjamin.gaignard, robh, daniel, architt, corbet,
	mark.rutland, xinliang.liu
  Cc: linuxarm, kong.kongxinwei, james.xiong, shenhui, guohanjun,
	lijianhua, linux-arm-kernel

Add vblank interrupt.

Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
---
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 56 ++++++++++++++++++++++++-
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |  1 +
 2 files changed, 56 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index c133644..73ba8b0 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -39,16 +39,45 @@
 
 static int hibmc_enable_vblank(struct drm_device *dev, unsigned int pipe)
 {
+	struct hibmc_drm_private *priv =
+		(struct hibmc_drm_private *)dev->dev_private;
+
+	writel(HIBMC_RAW_INTERRUPT_EN_VBLANK(1),
+	       priv->mmio + HIBMC_RAW_INTERRUPT_EN);
+
 	return 0;
 }
 
 static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
 {
+	struct hibmc_drm_private *priv =
+		(struct hibmc_drm_private *)dev->dev_private;
+
+	writel(HIBMC_RAW_INTERRUPT_EN_VBLANK(0),
+	       priv->mmio + HIBMC_RAW_INTERRUPT_EN);
+}
+
+irqreturn_t hibmc_drm_interrupt(int irq, void *arg)
+{
+	struct drm_device *dev = (struct drm_device *)arg;
+	struct hibmc_drm_private *priv =
+		(struct hibmc_drm_private *)dev->dev_private;
+	u32 status;
+
+	status = readl(priv->mmio + HIBMC_RAW_INTERRUPT);
+
+	if (status & HIBMC_RAW_INTERRUPT_VBLANK(1)) {
+		writel(HIBMC_RAW_INTERRUPT_VBLANK(1),
+		       priv->mmio + HIBMC_RAW_INTERRUPT);
+		drm_handle_vblank(dev, 0);
+	}
+
+	return IRQ_HANDLED;
 }
 
 static struct drm_driver hibmc_driver = {
 	.driver_features	= DRIVER_GEM | DRIVER_MODESET |
-				  DRIVER_ATOMIC,
+				  DRIVER_ATOMIC | DRIVER_HAVE_IRQ,
 	.fops			= &hibmc_fops,
 	.name			= "hibmc",
 	.date			= "20160828",
@@ -62,6 +91,7 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
 	.dumb_create            = hibmc_dumb_create,
 	.dumb_map_offset        = hibmc_dumb_mmap_offset,
 	.dumb_destroy           = drm_gem_dumb_destroy,
+	.irq_handler		= hibmc_drm_interrupt,
 };
 
 static int hibmc_pm_suspend(struct device *dev)
@@ -268,6 +298,13 @@ static int hibmc_unload(struct drm_device *dev)
 	struct hibmc_drm_private *priv = dev->dev_private;
 
 	hibmc_fbdev_fini(priv);
+
+	if (dev->irq_enabled)
+		drm_irq_uninstall(dev);
+	if (priv->msi_enabled)
+		pci_disable_msi(dev->pdev);
+	drm_vblank_cleanup(dev);
+
 	hibmc_kms_fini(priv);
 	hibmc_mm_fini(priv);
 	dev->dev_private = NULL;
@@ -299,6 +336,23 @@ static int hibmc_load(struct drm_device *dev)
 	if (ret)
 		goto err;
 
+	ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
+	if (ret) {
+		DRM_ERROR("failed to initialize vblank: %d\n", ret);
+		goto err;
+	}
+
+	priv->msi_enabled = 0;
+	ret = pci_enable_msi(dev->pdev);
+	if (ret) {
+		DRM_WARN("enabling MSI failed: %d\n", ret);
+	} else {
+		priv->msi_enabled = 1;
+		ret = drm_irq_install(dev, dev->pdev->irq);
+		if (ret)
+			DRM_WARN("install irq failed: %d\n", ret);
+	}
+
 	/* reset all the states of crtc/plane/encoder/connector */
 	drm_mode_config_reset(dev);
 
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
index b626caf..e195521 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -42,6 +42,7 @@ struct hibmc_drm_private {
 	void __iomem   *fb_map;
 	unsigned long  fb_base;
 	unsigned long  fb_size;
+	bool msi_enabled;
 
 	/* drm */
 	struct drm_device  *dev;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v7 7/7] MAINTAINERS: Update HISILICON DRM entries
  2016-11-16 13:43 ` Rongrong Zou
@ 2016-11-16 13:43   ` Rongrong Zou
  -1 siblings, 0 replies; 40+ messages in thread
From: Rongrong Zou @ 2016-11-16 13:43 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
---
 MAINTAINERS | 1 +
 1 file changed, 1 insertion(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 2a58eea..84a7296 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4123,6 +4123,7 @@ F:	drivers/gpu/drm/gma500/
 
 DRM DRIVERS FOR HISILICON
 M:	Xinliang Liu <z.liuxinliang@hisilicon.com>
+M:	Rongrong Zou <zourongrong@gmail.com>
 R:	Xinwei Kong <kong.kongxinwei@hisilicon.com>
 R:	Chen Feng <puck.chen@hisilicon.com>
 L:	dri-devel at lists.freedesktop.org
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v7 7/7] MAINTAINERS: Update HISILICON DRM entries
@ 2016-11-16 13:43   ` Rongrong Zou
  0 siblings, 0 replies; 40+ messages in thread
From: Rongrong Zou @ 2016-11-16 13:43 UTC (permalink / raw)
  To: airlied, daniel, seanpaul, seanpaul, dri-devel, emil.l.velikov,
	tomeu.vizoso, benjamin.gaignard, robh, daniel, architt, corbet,
	mark.rutland, xinliang.liu
  Cc: linuxarm, kong.kongxinwei, james.xiong, shenhui, guohanjun,
	lijianhua, linux-arm-kernel

Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
---
 MAINTAINERS | 1 +
 1 file changed, 1 insertion(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 2a58eea..84a7296 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4123,6 +4123,7 @@ F:	drivers/gpu/drm/gma500/
 
 DRM DRIVERS FOR HISILICON
 M:	Xinliang Liu <z.liuxinliang@hisilicon.com>
+M:	Rongrong Zou <zourongrong@gmail.com>
 R:	Xinwei Kong <kong.kongxinwei@hisilicon.com>
 R:	Chen Feng <puck.chen@hisilicon.com>
 L:	dri-devel@lists.freedesktop.org
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH v7 1/7] drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
  2016-11-16 13:43   ` Rongrong Zou
@ 2016-11-16 15:42     ` Sean Paul
  -1 siblings, 0 replies; 40+ messages in thread
From: Sean Paul @ 2016-11-16 15:42 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Add DRM master driver for Hisilicon Hibmc SoC which used for
> Out-of-band management. Blow is the general hardware connection,
> both the Hibmc and the host CPU are on the same mother board.
>
> +----------+       +----------+
> |          | PCIe  |  Hibmc   |
> |host CPU( |<----->| display  |
> |arm64,x86)|       |subsystem |
> +----------+       +----------+
>
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
> ---

In the future, please keep track of the differences between patch
versions. I noticed you have a short changelog in the cover letter,
but it really helps to add one per-patch as well, it makes reviewing
much simpler.

Reviewed-by: Sean Paul <seanpaul@chromium.org>


>  drivers/gpu/drm/hisilicon/Kconfig                |   1 +
>  drivers/gpu/drm/hisilicon/Makefile               |   1 +
>  drivers/gpu/drm/hisilicon/hibmc/Kconfig          |   9 +
>  drivers/gpu/drm/hisilicon/hibmc/Makefile         |   4 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c  | 308 +++++++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h  |  41 +++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h | 196 +++++++++++++++
>  7 files changed, 560 insertions(+)
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Kconfig
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Makefile
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>
> diff --git a/drivers/gpu/drm/hisilicon/Kconfig b/drivers/gpu/drm/hisilicon/Kconfig
> index 558c61b..2fd2724 100644
> --- a/drivers/gpu/drm/hisilicon/Kconfig
> +++ b/drivers/gpu/drm/hisilicon/Kconfig
> @@ -2,4 +2,5 @@
>  # hisilicon drm device configuration.
>  # Please keep this list sorted alphabetically
>
> +source "drivers/gpu/drm/hisilicon/hibmc/Kconfig"
>  source "drivers/gpu/drm/hisilicon/kirin/Kconfig"
> diff --git a/drivers/gpu/drm/hisilicon/Makefile b/drivers/gpu/drm/hisilicon/Makefile
> index e3f6d49..c8155bf 100644
> --- a/drivers/gpu/drm/hisilicon/Makefile
> +++ b/drivers/gpu/drm/hisilicon/Makefile
> @@ -2,4 +2,5 @@
>  # Makefile for hisilicon drm drivers.
>  # Please keep this list sorted alphabetically
>
> +obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc/
>  obj-$(CONFIG_DRM_HISI_KIRIN) += kirin/
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
> new file mode 100644
> index 0000000..380622a
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
> @@ -0,0 +1,9 @@
> +config DRM_HISI_HIBMC
> +       tristate "DRM Support for Hisilicon Hibmc"
> +       depends on DRM && PCI
> +       select DRM_KMS_HELPER
> +       select DRM_TTM
> +
> +       help
> +         Choose this option if you have a Hisilicon Hibmc soc chipset.
> +         If M is selected the module will be called hibmc-drm.
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> new file mode 100644
> index 0000000..47962a0
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> @@ -0,0 +1,4 @@
> +ccflags-y := -Iinclude/drm
> +hibmc-drm-y := hibmc_drm_drv.o
> +
> +obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> new file mode 100644
> index 0000000..6d20580
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -0,0 +1,308 @@
> +/* Hisilicon Hibmc SoC drm driver
> + *
> + * Based on the bochs drm driver.
> + *
> + * Copyright (c) 2016 Huawei Limited.
> + *
> + * Author:
> + *     Rongrong Zou <zourongrong@huawei.com>
> + *     Rongrong Zou <zourongrong@gmail.com>
> + *     Jianhua Li <lijianhua@huawei.com>
> + *
> + * 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.
> + *
> + */
> +
> +#include <linux/console.h>
> +#include <linux/module.h>
> +
> +#include "hibmc_drm_drv.h"
> +#include "hibmc_drm_regs.h"
> +
> +static const struct file_operations hibmc_fops = {
> +       .owner          = THIS_MODULE,
> +       .open           = drm_open,
> +       .release        = drm_release,
> +       .unlocked_ioctl = drm_ioctl,
> +       .compat_ioctl   = drm_compat_ioctl,
> +       .poll           = drm_poll,
> +       .read           = drm_read,
> +       .llseek         = no_llseek,
> +};
> +
> +static int hibmc_enable_vblank(struct drm_device *dev, unsigned int pipe)
> +{
> +       return 0;
> +}
> +
> +static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
> +{
> +}
> +
> +static struct drm_driver hibmc_driver = {
> +       .fops                   = &hibmc_fops,
> +       .name                   = "hibmc",
> +       .date                   = "20160828",
> +       .desc                   = "hibmc drm driver",
> +       .major                  = 1,
> +       .minor                  = 0,
> +       .get_vblank_counter     = drm_vblank_no_hw_counter,
> +       .enable_vblank          = hibmc_enable_vblank,
> +       .disable_vblank         = hibmc_disable_vblank,
> +};
> +
> +static int hibmc_pm_suspend(struct device *dev)
> +{
> +       return 0;
> +}
> +
> +static int hibmc_pm_resume(struct device *dev)
> +{
> +       return 0;
> +}
> +
> +static const struct dev_pm_ops hibmc_pm_ops = {
> +       SET_SYSTEM_SLEEP_PM_OPS(hibmc_pm_suspend,
> +                               hibmc_pm_resume)
> +};
> +
> +/*
> + * It can operate in one of three modes: 0, 1 or Sleep.
> + */
> +void hibmc_set_power_mode(struct hibmc_drm_private *priv,
> +                         unsigned int power_mode)
> +{
> +       unsigned int control_value = 0;
> +       void __iomem   *mmio = priv->mmio;
> +       unsigned int input = 1;
> +
> +       if (power_mode > HIBMC_PW_MODE_CTL_MODE_SLEEP)
> +               return;
> +
> +       if (power_mode == HIBMC_PW_MODE_CTL_MODE_SLEEP)
> +               input = 0;
> +
> +       control_value = readl(mmio + HIBMC_POWER_MODE_CTRL);
> +       control_value &= ~(HIBMC_PW_MODE_CTL_MODE_MASK |
> +                          HIBMC_PW_MODE_CTL_OSC_INPUT_MASK);
> +       control_value |= HIBMC_FIELD(HIBMC_PW_MODE_CTL_MODE, power_mode);
> +       control_value |= HIBMC_FIELD(HIBMC_PW_MODE_CTL_OSC_INPUT, input);
> +       writel(control_value, mmio + HIBMC_POWER_MODE_CTRL);
> +}
> +
> +void hibmc_set_current_gate(struct hibmc_drm_private *priv, unsigned int gate)
> +{
> +       unsigned int gate_reg;
> +       unsigned int mode;
> +       void __iomem   *mmio = priv->mmio;
> +
> +       /* Get current power mode. */
> +       mode = (readl(mmio + HIBMC_POWER_MODE_CTRL) &
> +               HIBMC_PW_MODE_CTL_MODE_MASK) >> HIBMC_PW_MODE_CTL_MODE_SHIFT;
> +
> +       switch (mode) {
> +       case HIBMC_PW_MODE_CTL_MODE_MODE0:
> +               gate_reg = HIBMC_MODE0_GATE;
> +               break;
> +
> +       case HIBMC_PW_MODE_CTL_MODE_MODE1:
> +               gate_reg = HIBMC_MODE1_GATE;
> +               break;
> +
> +       default:
> +               gate_reg = HIBMC_MODE0_GATE;
> +               break;
> +       }
> +       writel(gate, mmio + gate_reg);
> +}
> +
> +static void hibmc_hw_config(struct hibmc_drm_private *priv)
> +{
> +       unsigned int reg;
> +
> +       /* On hardware reset, power mode 0 is default. */
> +       hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_MODE0);
> +
> +       /* Enable display power gate & LOCALMEM power gate*/
> +       reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
> +       reg |= HIBMC_CURR_GATE_DISPLAY(1);
> +       reg |= HIBMC_CURR_GATE_LOCALMEM(1);
> +
> +       hibmc_set_current_gate(priv, reg);
> +
> +       /*
> +        * Reset the memory controller. If the memory controller
> +        * is not reset in chip,the system might hang when sw accesses
> +        * the memory.The memory should be resetted after
> +        * changing the MXCLK.
> +        */
> +       reg = readl(priv->mmio + HIBMC_MISC_CTRL);
> +       reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
> +       reg |= HIBMC_MSCCTL_LOCALMEM_RESET(0);
> +       writel(reg, priv->mmio + HIBMC_MISC_CTRL);
> +
> +       reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
> +       reg |= HIBMC_MSCCTL_LOCALMEM_RESET(1);
> +
> +       writel(reg, priv->mmio + HIBMC_MISC_CTRL);
> +}
> +
> +static int hibmc_hw_map(struct hibmc_drm_private *priv)
> +{
> +       struct drm_device *dev = priv->dev;
> +       struct pci_dev *pdev = dev->pdev;
> +       resource_size_t addr, size, ioaddr, iosize;
> +
> +       ioaddr = pci_resource_start(pdev, 1);
> +       iosize = pci_resource_len(pdev, 1);
> +       priv->mmio = devm_ioremap_nocache(dev->dev, ioaddr, iosize);
> +       if (!priv->mmio) {
> +               DRM_ERROR("Cannot map mmio region\n");
> +               return -ENOMEM;
> +       }
> +
> +       addr = pci_resource_start(pdev, 0);
> +       size = pci_resource_len(pdev, 0);
> +       priv->fb_map = devm_ioremap(dev->dev, addr, size);
> +       if (!priv->fb_map) {
> +               DRM_ERROR("Cannot map framebuffer\n");
> +               return -ENOMEM;
> +       }
> +       priv->fb_base = addr;
> +       priv->fb_size = size;
> +
> +       return 0;
> +}
> +
> +static int hibmc_hw_init(struct hibmc_drm_private *priv)
> +{
> +       int ret;
> +
> +       ret = hibmc_hw_map(priv);
> +       if (ret)
> +               return ret;
> +
> +       hibmc_hw_config(priv);
> +
> +       return 0;
> +}
> +
> +static int hibmc_unload(struct drm_device *dev)
> +{
> +       return 0;
> +}
> +
> +static int hibmc_load(struct drm_device *dev)
> +{
> +       struct hibmc_drm_private *priv;
> +       int ret;
> +
> +       priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
> +       if (!priv) {
> +               DRM_ERROR("no memory to allocate for hibmc_drm_private\n");
> +               return -ENOMEM;
> +       }
> +       dev->dev_private = priv;
> +       priv->dev = dev;
> +
> +       ret = hibmc_hw_init(priv);
> +       if (ret)
> +               goto err;
> +
> +       return 0;
> +
> +err:
> +       hibmc_unload(dev);
> +       DRM_ERROR("failed to initialize drm driver: %d\n", ret);
> +       return ret;
> +}
> +
> +static int hibmc_pci_probe(struct pci_dev *pdev,
> +                          const struct pci_device_id *ent)
> +{
> +       struct drm_device *dev;
> +       int ret;
> +
> +       dev = drm_dev_alloc(&hibmc_driver, &pdev->dev);
> +       if (!dev) {
> +               DRM_ERROR("failed to allocate drm_device\n");
> +               return -ENOMEM;
> +       }
> +
> +       dev->pdev = pdev;
> +       pci_set_drvdata(pdev, dev);
> +
> +       ret = pci_enable_device(pdev);
> +       if (ret) {
> +               DRM_ERROR("failed to enable pci device: %d\n", ret);
> +               goto err_free;
> +       }
> +
> +       ret = hibmc_load(dev);
> +       if (ret) {
> +               DRM_ERROR("failed to load hibmc: %d\n", ret);
> +               goto err_disable;
> +       }
> +
> +       ret = drm_dev_register(dev, 0);
> +       if (ret) {
> +               DRM_ERROR("failed to register drv for userspace access: %d\n",
> +                         ret);
> +               goto err_unload;
> +       }
> +       return 0;
> +
> +err_unload:
> +       hibmc_unload(dev);
> +err_disable:
> +       pci_disable_device(pdev);
> +err_free:
> +       drm_dev_unref(dev);
> +
> +       return ret;
> +}
> +
> +static void hibmc_pci_remove(struct pci_dev *pdev)
> +{
> +       struct drm_device *dev = pci_get_drvdata(pdev);
> +
> +       drm_dev_unregister(dev);
> +       hibmc_unload(dev);
> +       drm_dev_unref(dev);
> +}
> +
> +static struct pci_device_id hibmc_pci_table[] = {
> +       {0x19e5, 0x1711, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
> +       {0,}
> +};
> +
> +static struct pci_driver hibmc_pci_driver = {
> +       .name =         "hibmc-drm",
> +       .id_table =     hibmc_pci_table,
> +       .probe =        hibmc_pci_probe,
> +       .remove =       hibmc_pci_remove,
> +       .driver.pm =    &hibmc_pm_ops,
> +};
> +
> +static int __init hibmc_init(void)
> +{
> +       return pci_register_driver(&hibmc_pci_driver);
> +}
> +
> +static void __exit hibmc_exit(void)
> +{
> +       return pci_unregister_driver(&hibmc_pci_driver);
> +}
> +
> +module_init(hibmc_init);
> +module_exit(hibmc_exit);
> +
> +MODULE_DEVICE_TABLE(pci, hibmc_pci_table);
> +MODULE_AUTHOR("RongrongZou <zourongrong@huawei.com>");
> +MODULE_DESCRIPTION("DRM Driver for Hisilicon Hibmc");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> new file mode 100644
> index 0000000..840cd5a
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -0,0 +1,41 @@
> +/* Hisilicon Hibmc SoC drm driver
> + *
> + * Based on the bochs drm driver.
> + *
> + * Copyright (c) 2016 Huawei Limited.
> + *
> + * Author:
> + *     Rongrong Zou <zourongrong@huawei.com>
> + *     Rongrong Zou <zourongrong@gmail.com>
> + *     Jianhua Li <lijianhua@huawei.com>
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef HIBMC_DRM_DRV_H
> +#define HIBMC_DRM_DRV_H
> +
> +#include <drm/drmP.h>
> +
> +struct hibmc_drm_private {
> +       /* hw */
> +       void __iomem   *mmio;
> +       void __iomem   *fb_map;
> +       unsigned long  fb_base;
> +       unsigned long  fb_size;
> +
> +       /* drm */
> +       struct drm_device  *dev;
> +
> +};
> +
> +void hibmc_set_power_mode(struct hibmc_drm_private *priv,
> +                         unsigned int power_mode);
> +void hibmc_set_current_gate(struct hibmc_drm_private *priv,
> +                           unsigned int gate);
> +
> +#endif
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
> new file mode 100644
> index 0000000..f7035bf
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
> @@ -0,0 +1,196 @@
> +/* Hisilicon Hibmc SoC drm driver
> + *
> + * Based on the bochs drm driver.
> + *
> + * Copyright (c) 2016 Huawei Limited.
> + *
> + * Author:
> + *     Rongrong Zou <zourongrong@huawei.com>
> + *     Rongrong Zou <zourongrong@gmail.com>
> + *     Jianhua Li <lijianhua@huawei.com>
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef HIBMC_DRM_HW_H
> +#define HIBMC_DRM_HW_H
> +
> +/* register definition */
> +#define HIBMC_MISC_CTRL                                0x4
> +
> +#define HIBMC_MSCCTL_LOCALMEM_RESET(x)         ((x) << 6)
> +#define HIBMC_MSCCTL_LOCALMEM_RESET_MASK       0x40
> +
> +#define HIBMC_CURRENT_GATE                     0x000040
> +#define HIBMC_CURR_GATE_DISPLAY(x)             ((x) << 2)
> +#define HIBMC_CURR_GATE_DISPLAY_MASK           0x4
> +
> +#define HIBMC_CURR_GATE_LOCALMEM(x)            ((x) << 1)
> +#define HIBMC_CURR_GATE_LOCALMEM_MASK          0x2
> +
> +#define HIBMC_MODE0_GATE                       0x000044
> +#define HIBMC_MODE1_GATE                       0x000048
> +#define HIBMC_POWER_MODE_CTRL                  0x00004C
> +
> +#define HIBMC_PW_MODE_CTL_OSC_INPUT(x)         ((x) << 3)
> +#define HIBMC_PW_MODE_CTL_OSC_INPUT_MASK       0x8
> +
> +#define HIBMC_PW_MODE_CTL_MODE(x)              ((x) << 0)
> +#define HIBMC_PW_MODE_CTL_MODE_MASK            0x03
> +#define HIBMC_PW_MODE_CTL_MODE_SHIFT           0
> +
> +#define HIBMC_PW_MODE_CTL_MODE_MODE0           0
> +#define HIBMC_PW_MODE_CTL_MODE_MODE1           1
> +#define HIBMC_PW_MODE_CTL_MODE_SLEEP           2
> +
> +#define HIBMC_PANEL_PLL_CTRL                   0x00005C
> +#define HIBMC_CRT_PLL_CTRL                     0x000060
> +
> +#define HIBMC_PLL_CTRL_BYPASS(x)               ((x) << 18)
> +#define HIBMC_PLL_CTRL_BYPASS_MASK             0x40000
> +
> +#define HIBMC_PLL_CTRL_POWER(x)                        ((x) << 17)
> +#define HIBMC_PLL_CTRL_POWER_MASK              0x20000
> +
> +#define HIBMC_PLL_CTRL_INPUT(x)                        ((x) << 16)
> +#define HIBMC_PLL_CTRL_INPUT_MASK              0x10000
> +
> +#define HIBMC_PLL_CTRL_POD(x)                  ((x) << 14)
> +#define HIBMC_PLL_CTRL_POD_MASK                        0xC000
> +
> +#define HIBMC_PLL_CTRL_OD(x)                   ((x) << 12)
> +#define HIBMC_PLL_CTRL_OD_MASK                 0x3000
> +
> +#define HIBMC_PLL_CTRL_N(x)                    ((x) << 8)
> +#define HIBMC_PLL_CTRL_N_MASK                  0xF00
> +
> +#define HIBMC_PLL_CTRL_M(x)                    ((x) << 0)
> +#define HIBMC_PLL_CTRL_M_MASK                  0xFF
> +
> +#define HIBMC_CRT_DISP_CTL                     0x80200
> +
> +#define HIBMC_CRT_DISP_CTL_CRTSELECT(x)                ((x) << 25)
> +#define HIBMC_CRT_DISP_CTL_CRTSELECT_MASK      0x2000000
> +
> +#define HIBMC_CRTSELECT_CRT                    1
> +
> +#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE(x)      ((x) << 14)
> +#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE_MASK    0x4000
> +
> +#define HIBMC_CRT_DISP_CTL_VSYNC_PHASE(x)      ((x) << 13)
> +#define HIBMC_CRT_DISP_CTL_VSYNC_PHASE_MASK    0x2000
> +
> +#define HIBMC_CRT_DISP_CTL_HSYNC_PHASE(x)      ((x) << 12)
> +#define HIBMC_CRT_DISP_CTL_HSYNC_PHASE_MASK    0x1000
> +
> +#define HIBMC_CRT_DISP_CTL_TIMING(x)           ((x) << 8)
> +#define HIBMC_CRT_DISP_CTL_TIMING_MASK         0x100
> +
> +#define HIBMC_CRT_DISP_CTL_PLANE(x)            ((x) << 2)
> +#define HIBMC_CRT_DISP_CTL_PLANE_MASK          4
> +
> +#define HIBMC_CRT_DISP_CTL_FORMAT(x)           ((x) << 0)
> +#define HIBMC_CRT_DISP_CTL_FORMAT_MASK         0x03
> +
> +#define HIBMC_CRT_FB_ADDRESS                   0x080204
> +
> +#define HIBMC_CRT_FB_WIDTH                     0x080208
> +#define HIBMC_CRT_FB_WIDTH_WIDTH(x)            ((x) << 16)
> +#define HIBMC_CRT_FB_WIDTH_WIDTH_MASK          0x3FFF0000
> +#define HIBMC_CRT_FB_WIDTH_OFFS(x)             ((x) << 0)
> +#define HIBMC_CRT_FB_WIDTH_OFFS_MASK           0x3FFF
> +
> +#define HIBMC_CRT_HORZ_TOTAL                   0x08020C
> +#define HIBMC_CRT_HORZ_TOTAL_TOTAL(x)          ((x) << 16)
> +#define HIBMC_CRT_HORZ_TOTAL_TOTAL_MASK                0xFFF0000
> +
> +#define HIBMC_CRT_HORZ_TOTAL_DISP_END(x)       ((x) << 0)
> +#define HIBMC_CRT_HORZ_TOTAL_DISP_END_MASK     0xFFF
> +
> +#define HIBMC_CRT_HORZ_SYNC                    0x080210
> +#define HIBMC_CRT_HORZ_SYNC_WIDTH(x)           ((x) << 16)
> +#define HIBMC_CRT_HORZ_SYNC_WIDTH_MASK         0xFF0000
> +
> +#define HIBMC_CRT_HORZ_SYNC_START(x)           ((x) << 0)
> +#define HIBMC_CRT_HORZ_SYNC_START_MASK         0xFFF
> +
> +#define HIBMC_CRT_VERT_TOTAL                   0x080214
> +#define HIBMC_CRT_VERT_TOTAL_TOTAL(x)          ((x) << 16)
> +#define HIBMC_CRT_VERT_TOTAL_TOTAL_MASK                0x7FFF0000
> +
> +#define HIBMC_CRT_VERT_TOTAL_DISP_END(x)       ((x) << 0)
> +#define HIBMC_CRT_VERT_TOTAL_DISP_END_MASK     0x7FF
> +
> +#define HIBMC_CRT_VERT_SYNC                    0x080218
> +#define HIBMC_CRT_VERT_SYNC_HEIGHT(x)          ((x) << 16)
> +#define HIBMC_CRT_VERT_SYNC_HEIGHT_MASK                0x3F0000
> +
> +#define HIBMC_CRT_VERT_SYNC_START(x)           ((x) << 0)
> +#define HIBMC_CRT_VERT_SYNC_START_MASK         0x7FF
> +
> +/* Auto Centering */
> +#define HIBMC_CRT_AUTO_CENTERING_TL            0x080280
> +#define HIBMC_CRT_AUTO_CENTERING_TL_TOP(x)     ((x) << 16)
> +#define HIBMC_CRT_AUTO_CENTERING_TL_TOP_MASK   0x7FF0000
> +
> +#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT(x)    ((x) << 0)
> +#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT_MASK  0x7FF
> +
> +#define HIBMC_CRT_AUTO_CENTERING_BR            0x080284
> +#define HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM(x)  ((x) << 16)
> +#define HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM_MASK        0x7FF0000
> +
> +#define HIBMC_CRT_AUTO_CENTERING_BR_RIGHT(x)   ((x) << 0)
> +#define HIBMC_CRT_AUTO_CENTERING_BR_RIGHT_MASK 0x7FF
> +
> +/* register to control panel output */
> +#define HIBMC_DISPLAY_CONTROL_HISILE           0x80288
> +#define HIBMC_DISPLAY_CONTROL_FPVDDEN(x)       ((x) << 0)
> +#define HIBMC_DISPLAY_CONTROL_PANELDATE(x)     ((x) << 1)
> +#define HIBMC_DISPLAY_CONTROL_FPEN(x)          ((x) << 2)
> +#define HIBMC_DISPLAY_CONTROL_VBIASEN(x)       ((x) << 3)
> +
> +#define HIBMC_RAW_INTERRUPT                    0x80290
> +#define HIBMC_RAW_INTERRUPT_VBLANK(x)          ((x) << 2)
> +#define HIBMC_RAW_INTERRUPT_VBLANK_MASK                0x4
> +
> +#define HIBMC_RAW_INTERRUPT_EN                 0x80298
> +#define HIBMC_RAW_INTERRUPT_EN_VBLANK(x)       ((x) << 2)
> +#define HIBMC_RAW_INTERRUPT_EN_VBLANK_MASK     0x4
> +
> +/* register and values for PLL control */
> +#define CRT_PLL1_HS                            0x802a8
> +#define CRT_PLL1_HS_OUTER_BYPASS(x)            ((x) << 30)
> +#define CRT_PLL1_HS_INTER_BYPASS(x)            ((x) << 29)
> +#define CRT_PLL1_HS_POWERON(x)                 ((x) << 24)
> +
> +#define CRT_PLL1_HS_25MHZ                      0x23d40f02
> +#define CRT_PLL1_HS_40MHZ                      0x23940801
> +#define CRT_PLL1_HS_65MHZ                      0x23940d01
> +#define CRT_PLL1_HS_78MHZ                      0x23540F82
> +#define CRT_PLL1_HS_74MHZ                      0x23941dc2
> +#define CRT_PLL1_HS_80MHZ                      0x23941001
> +#define CRT_PLL1_HS_80MHZ_1152                 0x23540fc2
> +#define CRT_PLL1_HS_108MHZ                     0x23b41b01
> +#define CRT_PLL1_HS_162MHZ                     0x23480681
> +#define CRT_PLL1_HS_148MHZ                     0x23541dc2
> +#define CRT_PLL1_HS_193MHZ                     0x234807c1
> +
> +#define CRT_PLL2_HS                            0x802ac
> +#define CRT_PLL2_HS_25MHZ                      0x206B851E
> +#define CRT_PLL2_HS_40MHZ                      0x30000000
> +#define CRT_PLL2_HS_65MHZ                      0x40000000
> +#define CRT_PLL2_HS_78MHZ                      0x50E147AE
> +#define CRT_PLL2_HS_74MHZ                      0x602B6AE7
> +#define CRT_PLL2_HS_80MHZ                      0x70000000
> +#define CRT_PLL2_HS_108MHZ                     0x80000000
> +#define CRT_PLL2_HS_162MHZ                     0xA0000000
> +#define CRT_PLL2_HS_148MHZ                     0xB0CCCCCD
> +#define CRT_PLL2_HS_193MHZ                     0xC0872B02
> +
> +#define HIBMC_FIELD(field, value) (field(value) & field##_MASK)
> +#endif
> --
> 1.9.1
>

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v7 1/7] drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
@ 2016-11-16 15:42     ` Sean Paul
  0 siblings, 0 replies; 40+ messages in thread
From: Sean Paul @ 2016-11-16 15:42 UTC (permalink / raw)
  To: Rongrong Zou
  Cc: Mark Rutland, Tomeu Vizoso, seanpaul, Jonathan Corbet,
	Emil Velikov, linuxarm, dri-devel, james.xiong, guohanjun,
	lijianhua, Linux ARM Kernel, shenhui

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Add DRM master driver for Hisilicon Hibmc SoC which used for
> Out-of-band management. Blow is the general hardware connection,
> both the Hibmc and the host CPU are on the same mother board.
>
> +----------+       +----------+
> |          | PCIe  |  Hibmc   |
> |host CPU( |<----->| display  |
> |arm64,x86)|       |subsystem |
> +----------+       +----------+
>
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
> ---

In the future, please keep track of the differences between patch
versions. I noticed you have a short changelog in the cover letter,
but it really helps to add one per-patch as well, it makes reviewing
much simpler.

Reviewed-by: Sean Paul <seanpaul@chromium.org>


>  drivers/gpu/drm/hisilicon/Kconfig                |   1 +
>  drivers/gpu/drm/hisilicon/Makefile               |   1 +
>  drivers/gpu/drm/hisilicon/hibmc/Kconfig          |   9 +
>  drivers/gpu/drm/hisilicon/hibmc/Makefile         |   4 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c  | 308 +++++++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h  |  41 +++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h | 196 +++++++++++++++
>  7 files changed, 560 insertions(+)
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Kconfig
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Makefile
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>
> diff --git a/drivers/gpu/drm/hisilicon/Kconfig b/drivers/gpu/drm/hisilicon/Kconfig
> index 558c61b..2fd2724 100644
> --- a/drivers/gpu/drm/hisilicon/Kconfig
> +++ b/drivers/gpu/drm/hisilicon/Kconfig
> @@ -2,4 +2,5 @@
>  # hisilicon drm device configuration.
>  # Please keep this list sorted alphabetically
>
> +source "drivers/gpu/drm/hisilicon/hibmc/Kconfig"
>  source "drivers/gpu/drm/hisilicon/kirin/Kconfig"
> diff --git a/drivers/gpu/drm/hisilicon/Makefile b/drivers/gpu/drm/hisilicon/Makefile
> index e3f6d49..c8155bf 100644
> --- a/drivers/gpu/drm/hisilicon/Makefile
> +++ b/drivers/gpu/drm/hisilicon/Makefile
> @@ -2,4 +2,5 @@
>  # Makefile for hisilicon drm drivers.
>  # Please keep this list sorted alphabetically
>
> +obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc/
>  obj-$(CONFIG_DRM_HISI_KIRIN) += kirin/
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
> new file mode 100644
> index 0000000..380622a
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
> @@ -0,0 +1,9 @@
> +config DRM_HISI_HIBMC
> +       tristate "DRM Support for Hisilicon Hibmc"
> +       depends on DRM && PCI
> +       select DRM_KMS_HELPER
> +       select DRM_TTM
> +
> +       help
> +         Choose this option if you have a Hisilicon Hibmc soc chipset.
> +         If M is selected the module will be called hibmc-drm.
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> new file mode 100644
> index 0000000..47962a0
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> @@ -0,0 +1,4 @@
> +ccflags-y := -Iinclude/drm
> +hibmc-drm-y := hibmc_drm_drv.o
> +
> +obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> new file mode 100644
> index 0000000..6d20580
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -0,0 +1,308 @@
> +/* Hisilicon Hibmc SoC drm driver
> + *
> + * Based on the bochs drm driver.
> + *
> + * Copyright (c) 2016 Huawei Limited.
> + *
> + * Author:
> + *     Rongrong Zou <zourongrong@huawei.com>
> + *     Rongrong Zou <zourongrong@gmail.com>
> + *     Jianhua Li <lijianhua@huawei.com>
> + *
> + * 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.
> + *
> + */
> +
> +#include <linux/console.h>
> +#include <linux/module.h>
> +
> +#include "hibmc_drm_drv.h"
> +#include "hibmc_drm_regs.h"
> +
> +static const struct file_operations hibmc_fops = {
> +       .owner          = THIS_MODULE,
> +       .open           = drm_open,
> +       .release        = drm_release,
> +       .unlocked_ioctl = drm_ioctl,
> +       .compat_ioctl   = drm_compat_ioctl,
> +       .poll           = drm_poll,
> +       .read           = drm_read,
> +       .llseek         = no_llseek,
> +};
> +
> +static int hibmc_enable_vblank(struct drm_device *dev, unsigned int pipe)
> +{
> +       return 0;
> +}
> +
> +static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
> +{
> +}
> +
> +static struct drm_driver hibmc_driver = {
> +       .fops                   = &hibmc_fops,
> +       .name                   = "hibmc",
> +       .date                   = "20160828",
> +       .desc                   = "hibmc drm driver",
> +       .major                  = 1,
> +       .minor                  = 0,
> +       .get_vblank_counter     = drm_vblank_no_hw_counter,
> +       .enable_vblank          = hibmc_enable_vblank,
> +       .disable_vblank         = hibmc_disable_vblank,
> +};
> +
> +static int hibmc_pm_suspend(struct device *dev)
> +{
> +       return 0;
> +}
> +
> +static int hibmc_pm_resume(struct device *dev)
> +{
> +       return 0;
> +}
> +
> +static const struct dev_pm_ops hibmc_pm_ops = {
> +       SET_SYSTEM_SLEEP_PM_OPS(hibmc_pm_suspend,
> +                               hibmc_pm_resume)
> +};
> +
> +/*
> + * It can operate in one of three modes: 0, 1 or Sleep.
> + */
> +void hibmc_set_power_mode(struct hibmc_drm_private *priv,
> +                         unsigned int power_mode)
> +{
> +       unsigned int control_value = 0;
> +       void __iomem   *mmio = priv->mmio;
> +       unsigned int input = 1;
> +
> +       if (power_mode > HIBMC_PW_MODE_CTL_MODE_SLEEP)
> +               return;
> +
> +       if (power_mode == HIBMC_PW_MODE_CTL_MODE_SLEEP)
> +               input = 0;
> +
> +       control_value = readl(mmio + HIBMC_POWER_MODE_CTRL);
> +       control_value &= ~(HIBMC_PW_MODE_CTL_MODE_MASK |
> +                          HIBMC_PW_MODE_CTL_OSC_INPUT_MASK);
> +       control_value |= HIBMC_FIELD(HIBMC_PW_MODE_CTL_MODE, power_mode);
> +       control_value |= HIBMC_FIELD(HIBMC_PW_MODE_CTL_OSC_INPUT, input);
> +       writel(control_value, mmio + HIBMC_POWER_MODE_CTRL);
> +}
> +
> +void hibmc_set_current_gate(struct hibmc_drm_private *priv, unsigned int gate)
> +{
> +       unsigned int gate_reg;
> +       unsigned int mode;
> +       void __iomem   *mmio = priv->mmio;
> +
> +       /* Get current power mode. */
> +       mode = (readl(mmio + HIBMC_POWER_MODE_CTRL) &
> +               HIBMC_PW_MODE_CTL_MODE_MASK) >> HIBMC_PW_MODE_CTL_MODE_SHIFT;
> +
> +       switch (mode) {
> +       case HIBMC_PW_MODE_CTL_MODE_MODE0:
> +               gate_reg = HIBMC_MODE0_GATE;
> +               break;
> +
> +       case HIBMC_PW_MODE_CTL_MODE_MODE1:
> +               gate_reg = HIBMC_MODE1_GATE;
> +               break;
> +
> +       default:
> +               gate_reg = HIBMC_MODE0_GATE;
> +               break;
> +       }
> +       writel(gate, mmio + gate_reg);
> +}
> +
> +static void hibmc_hw_config(struct hibmc_drm_private *priv)
> +{
> +       unsigned int reg;
> +
> +       /* On hardware reset, power mode 0 is default. */
> +       hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_MODE0);
> +
> +       /* Enable display power gate & LOCALMEM power gate*/
> +       reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
> +       reg |= HIBMC_CURR_GATE_DISPLAY(1);
> +       reg |= HIBMC_CURR_GATE_LOCALMEM(1);
> +
> +       hibmc_set_current_gate(priv, reg);
> +
> +       /*
> +        * Reset the memory controller. If the memory controller
> +        * is not reset in chip,the system might hang when sw accesses
> +        * the memory.The memory should be resetted after
> +        * changing the MXCLK.
> +        */
> +       reg = readl(priv->mmio + HIBMC_MISC_CTRL);
> +       reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
> +       reg |= HIBMC_MSCCTL_LOCALMEM_RESET(0);
> +       writel(reg, priv->mmio + HIBMC_MISC_CTRL);
> +
> +       reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
> +       reg |= HIBMC_MSCCTL_LOCALMEM_RESET(1);
> +
> +       writel(reg, priv->mmio + HIBMC_MISC_CTRL);
> +}
> +
> +static int hibmc_hw_map(struct hibmc_drm_private *priv)
> +{
> +       struct drm_device *dev = priv->dev;
> +       struct pci_dev *pdev = dev->pdev;
> +       resource_size_t addr, size, ioaddr, iosize;
> +
> +       ioaddr = pci_resource_start(pdev, 1);
> +       iosize = pci_resource_len(pdev, 1);
> +       priv->mmio = devm_ioremap_nocache(dev->dev, ioaddr, iosize);
> +       if (!priv->mmio) {
> +               DRM_ERROR("Cannot map mmio region\n");
> +               return -ENOMEM;
> +       }
> +
> +       addr = pci_resource_start(pdev, 0);
> +       size = pci_resource_len(pdev, 0);
> +       priv->fb_map = devm_ioremap(dev->dev, addr, size);
> +       if (!priv->fb_map) {
> +               DRM_ERROR("Cannot map framebuffer\n");
> +               return -ENOMEM;
> +       }
> +       priv->fb_base = addr;
> +       priv->fb_size = size;
> +
> +       return 0;
> +}
> +
> +static int hibmc_hw_init(struct hibmc_drm_private *priv)
> +{
> +       int ret;
> +
> +       ret = hibmc_hw_map(priv);
> +       if (ret)
> +               return ret;
> +
> +       hibmc_hw_config(priv);
> +
> +       return 0;
> +}
> +
> +static int hibmc_unload(struct drm_device *dev)
> +{
> +       return 0;
> +}
> +
> +static int hibmc_load(struct drm_device *dev)
> +{
> +       struct hibmc_drm_private *priv;
> +       int ret;
> +
> +       priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
> +       if (!priv) {
> +               DRM_ERROR("no memory to allocate for hibmc_drm_private\n");
> +               return -ENOMEM;
> +       }
> +       dev->dev_private = priv;
> +       priv->dev = dev;
> +
> +       ret = hibmc_hw_init(priv);
> +       if (ret)
> +               goto err;
> +
> +       return 0;
> +
> +err:
> +       hibmc_unload(dev);
> +       DRM_ERROR("failed to initialize drm driver: %d\n", ret);
> +       return ret;
> +}
> +
> +static int hibmc_pci_probe(struct pci_dev *pdev,
> +                          const struct pci_device_id *ent)
> +{
> +       struct drm_device *dev;
> +       int ret;
> +
> +       dev = drm_dev_alloc(&hibmc_driver, &pdev->dev);
> +       if (!dev) {
> +               DRM_ERROR("failed to allocate drm_device\n");
> +               return -ENOMEM;
> +       }
> +
> +       dev->pdev = pdev;
> +       pci_set_drvdata(pdev, dev);
> +
> +       ret = pci_enable_device(pdev);
> +       if (ret) {
> +               DRM_ERROR("failed to enable pci device: %d\n", ret);
> +               goto err_free;
> +       }
> +
> +       ret = hibmc_load(dev);
> +       if (ret) {
> +               DRM_ERROR("failed to load hibmc: %d\n", ret);
> +               goto err_disable;
> +       }
> +
> +       ret = drm_dev_register(dev, 0);
> +       if (ret) {
> +               DRM_ERROR("failed to register drv for userspace access: %d\n",
> +                         ret);
> +               goto err_unload;
> +       }
> +       return 0;
> +
> +err_unload:
> +       hibmc_unload(dev);
> +err_disable:
> +       pci_disable_device(pdev);
> +err_free:
> +       drm_dev_unref(dev);
> +
> +       return ret;
> +}
> +
> +static void hibmc_pci_remove(struct pci_dev *pdev)
> +{
> +       struct drm_device *dev = pci_get_drvdata(pdev);
> +
> +       drm_dev_unregister(dev);
> +       hibmc_unload(dev);
> +       drm_dev_unref(dev);
> +}
> +
> +static struct pci_device_id hibmc_pci_table[] = {
> +       {0x19e5, 0x1711, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
> +       {0,}
> +};
> +
> +static struct pci_driver hibmc_pci_driver = {
> +       .name =         "hibmc-drm",
> +       .id_table =     hibmc_pci_table,
> +       .probe =        hibmc_pci_probe,
> +       .remove =       hibmc_pci_remove,
> +       .driver.pm =    &hibmc_pm_ops,
> +};
> +
> +static int __init hibmc_init(void)
> +{
> +       return pci_register_driver(&hibmc_pci_driver);
> +}
> +
> +static void __exit hibmc_exit(void)
> +{
> +       return pci_unregister_driver(&hibmc_pci_driver);
> +}
> +
> +module_init(hibmc_init);
> +module_exit(hibmc_exit);
> +
> +MODULE_DEVICE_TABLE(pci, hibmc_pci_table);
> +MODULE_AUTHOR("RongrongZou <zourongrong@huawei.com>");
> +MODULE_DESCRIPTION("DRM Driver for Hisilicon Hibmc");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> new file mode 100644
> index 0000000..840cd5a
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -0,0 +1,41 @@
> +/* Hisilicon Hibmc SoC drm driver
> + *
> + * Based on the bochs drm driver.
> + *
> + * Copyright (c) 2016 Huawei Limited.
> + *
> + * Author:
> + *     Rongrong Zou <zourongrong@huawei.com>
> + *     Rongrong Zou <zourongrong@gmail.com>
> + *     Jianhua Li <lijianhua@huawei.com>
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef HIBMC_DRM_DRV_H
> +#define HIBMC_DRM_DRV_H
> +
> +#include <drm/drmP.h>
> +
> +struct hibmc_drm_private {
> +       /* hw */
> +       void __iomem   *mmio;
> +       void __iomem   *fb_map;
> +       unsigned long  fb_base;
> +       unsigned long  fb_size;
> +
> +       /* drm */
> +       struct drm_device  *dev;
> +
> +};
> +
> +void hibmc_set_power_mode(struct hibmc_drm_private *priv,
> +                         unsigned int power_mode);
> +void hibmc_set_current_gate(struct hibmc_drm_private *priv,
> +                           unsigned int gate);
> +
> +#endif
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
> new file mode 100644
> index 0000000..f7035bf
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
> @@ -0,0 +1,196 @@
> +/* Hisilicon Hibmc SoC drm driver
> + *
> + * Based on the bochs drm driver.
> + *
> + * Copyright (c) 2016 Huawei Limited.
> + *
> + * Author:
> + *     Rongrong Zou <zourongrong@huawei.com>
> + *     Rongrong Zou <zourongrong@gmail.com>
> + *     Jianhua Li <lijianhua@huawei.com>
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef HIBMC_DRM_HW_H
> +#define HIBMC_DRM_HW_H
> +
> +/* register definition */
> +#define HIBMC_MISC_CTRL                                0x4
> +
> +#define HIBMC_MSCCTL_LOCALMEM_RESET(x)         ((x) << 6)
> +#define HIBMC_MSCCTL_LOCALMEM_RESET_MASK       0x40
> +
> +#define HIBMC_CURRENT_GATE                     0x000040
> +#define HIBMC_CURR_GATE_DISPLAY(x)             ((x) << 2)
> +#define HIBMC_CURR_GATE_DISPLAY_MASK           0x4
> +
> +#define HIBMC_CURR_GATE_LOCALMEM(x)            ((x) << 1)
> +#define HIBMC_CURR_GATE_LOCALMEM_MASK          0x2
> +
> +#define HIBMC_MODE0_GATE                       0x000044
> +#define HIBMC_MODE1_GATE                       0x000048
> +#define HIBMC_POWER_MODE_CTRL                  0x00004C
> +
> +#define HIBMC_PW_MODE_CTL_OSC_INPUT(x)         ((x) << 3)
> +#define HIBMC_PW_MODE_CTL_OSC_INPUT_MASK       0x8
> +
> +#define HIBMC_PW_MODE_CTL_MODE(x)              ((x) << 0)
> +#define HIBMC_PW_MODE_CTL_MODE_MASK            0x03
> +#define HIBMC_PW_MODE_CTL_MODE_SHIFT           0
> +
> +#define HIBMC_PW_MODE_CTL_MODE_MODE0           0
> +#define HIBMC_PW_MODE_CTL_MODE_MODE1           1
> +#define HIBMC_PW_MODE_CTL_MODE_SLEEP           2
> +
> +#define HIBMC_PANEL_PLL_CTRL                   0x00005C
> +#define HIBMC_CRT_PLL_CTRL                     0x000060
> +
> +#define HIBMC_PLL_CTRL_BYPASS(x)               ((x) << 18)
> +#define HIBMC_PLL_CTRL_BYPASS_MASK             0x40000
> +
> +#define HIBMC_PLL_CTRL_POWER(x)                        ((x) << 17)
> +#define HIBMC_PLL_CTRL_POWER_MASK              0x20000
> +
> +#define HIBMC_PLL_CTRL_INPUT(x)                        ((x) << 16)
> +#define HIBMC_PLL_CTRL_INPUT_MASK              0x10000
> +
> +#define HIBMC_PLL_CTRL_POD(x)                  ((x) << 14)
> +#define HIBMC_PLL_CTRL_POD_MASK                        0xC000
> +
> +#define HIBMC_PLL_CTRL_OD(x)                   ((x) << 12)
> +#define HIBMC_PLL_CTRL_OD_MASK                 0x3000
> +
> +#define HIBMC_PLL_CTRL_N(x)                    ((x) << 8)
> +#define HIBMC_PLL_CTRL_N_MASK                  0xF00
> +
> +#define HIBMC_PLL_CTRL_M(x)                    ((x) << 0)
> +#define HIBMC_PLL_CTRL_M_MASK                  0xFF
> +
> +#define HIBMC_CRT_DISP_CTL                     0x80200
> +
> +#define HIBMC_CRT_DISP_CTL_CRTSELECT(x)                ((x) << 25)
> +#define HIBMC_CRT_DISP_CTL_CRTSELECT_MASK      0x2000000
> +
> +#define HIBMC_CRTSELECT_CRT                    1
> +
> +#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE(x)      ((x) << 14)
> +#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE_MASK    0x4000
> +
> +#define HIBMC_CRT_DISP_CTL_VSYNC_PHASE(x)      ((x) << 13)
> +#define HIBMC_CRT_DISP_CTL_VSYNC_PHASE_MASK    0x2000
> +
> +#define HIBMC_CRT_DISP_CTL_HSYNC_PHASE(x)      ((x) << 12)
> +#define HIBMC_CRT_DISP_CTL_HSYNC_PHASE_MASK    0x1000
> +
> +#define HIBMC_CRT_DISP_CTL_TIMING(x)           ((x) << 8)
> +#define HIBMC_CRT_DISP_CTL_TIMING_MASK         0x100
> +
> +#define HIBMC_CRT_DISP_CTL_PLANE(x)            ((x) << 2)
> +#define HIBMC_CRT_DISP_CTL_PLANE_MASK          4
> +
> +#define HIBMC_CRT_DISP_CTL_FORMAT(x)           ((x) << 0)
> +#define HIBMC_CRT_DISP_CTL_FORMAT_MASK         0x03
> +
> +#define HIBMC_CRT_FB_ADDRESS                   0x080204
> +
> +#define HIBMC_CRT_FB_WIDTH                     0x080208
> +#define HIBMC_CRT_FB_WIDTH_WIDTH(x)            ((x) << 16)
> +#define HIBMC_CRT_FB_WIDTH_WIDTH_MASK          0x3FFF0000
> +#define HIBMC_CRT_FB_WIDTH_OFFS(x)             ((x) << 0)
> +#define HIBMC_CRT_FB_WIDTH_OFFS_MASK           0x3FFF
> +
> +#define HIBMC_CRT_HORZ_TOTAL                   0x08020C
> +#define HIBMC_CRT_HORZ_TOTAL_TOTAL(x)          ((x) << 16)
> +#define HIBMC_CRT_HORZ_TOTAL_TOTAL_MASK                0xFFF0000
> +
> +#define HIBMC_CRT_HORZ_TOTAL_DISP_END(x)       ((x) << 0)
> +#define HIBMC_CRT_HORZ_TOTAL_DISP_END_MASK     0xFFF
> +
> +#define HIBMC_CRT_HORZ_SYNC                    0x080210
> +#define HIBMC_CRT_HORZ_SYNC_WIDTH(x)           ((x) << 16)
> +#define HIBMC_CRT_HORZ_SYNC_WIDTH_MASK         0xFF0000
> +
> +#define HIBMC_CRT_HORZ_SYNC_START(x)           ((x) << 0)
> +#define HIBMC_CRT_HORZ_SYNC_START_MASK         0xFFF
> +
> +#define HIBMC_CRT_VERT_TOTAL                   0x080214
> +#define HIBMC_CRT_VERT_TOTAL_TOTAL(x)          ((x) << 16)
> +#define HIBMC_CRT_VERT_TOTAL_TOTAL_MASK                0x7FFF0000
> +
> +#define HIBMC_CRT_VERT_TOTAL_DISP_END(x)       ((x) << 0)
> +#define HIBMC_CRT_VERT_TOTAL_DISP_END_MASK     0x7FF
> +
> +#define HIBMC_CRT_VERT_SYNC                    0x080218
> +#define HIBMC_CRT_VERT_SYNC_HEIGHT(x)          ((x) << 16)
> +#define HIBMC_CRT_VERT_SYNC_HEIGHT_MASK                0x3F0000
> +
> +#define HIBMC_CRT_VERT_SYNC_START(x)           ((x) << 0)
> +#define HIBMC_CRT_VERT_SYNC_START_MASK         0x7FF
> +
> +/* Auto Centering */
> +#define HIBMC_CRT_AUTO_CENTERING_TL            0x080280
> +#define HIBMC_CRT_AUTO_CENTERING_TL_TOP(x)     ((x) << 16)
> +#define HIBMC_CRT_AUTO_CENTERING_TL_TOP_MASK   0x7FF0000
> +
> +#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT(x)    ((x) << 0)
> +#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT_MASK  0x7FF
> +
> +#define HIBMC_CRT_AUTO_CENTERING_BR            0x080284
> +#define HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM(x)  ((x) << 16)
> +#define HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM_MASK        0x7FF0000
> +
> +#define HIBMC_CRT_AUTO_CENTERING_BR_RIGHT(x)   ((x) << 0)
> +#define HIBMC_CRT_AUTO_CENTERING_BR_RIGHT_MASK 0x7FF
> +
> +/* register to control panel output */
> +#define HIBMC_DISPLAY_CONTROL_HISILE           0x80288
> +#define HIBMC_DISPLAY_CONTROL_FPVDDEN(x)       ((x) << 0)
> +#define HIBMC_DISPLAY_CONTROL_PANELDATE(x)     ((x) << 1)
> +#define HIBMC_DISPLAY_CONTROL_FPEN(x)          ((x) << 2)
> +#define HIBMC_DISPLAY_CONTROL_VBIASEN(x)       ((x) << 3)
> +
> +#define HIBMC_RAW_INTERRUPT                    0x80290
> +#define HIBMC_RAW_INTERRUPT_VBLANK(x)          ((x) << 2)
> +#define HIBMC_RAW_INTERRUPT_VBLANK_MASK                0x4
> +
> +#define HIBMC_RAW_INTERRUPT_EN                 0x80298
> +#define HIBMC_RAW_INTERRUPT_EN_VBLANK(x)       ((x) << 2)
> +#define HIBMC_RAW_INTERRUPT_EN_VBLANK_MASK     0x4
> +
> +/* register and values for PLL control */
> +#define CRT_PLL1_HS                            0x802a8
> +#define CRT_PLL1_HS_OUTER_BYPASS(x)            ((x) << 30)
> +#define CRT_PLL1_HS_INTER_BYPASS(x)            ((x) << 29)
> +#define CRT_PLL1_HS_POWERON(x)                 ((x) << 24)
> +
> +#define CRT_PLL1_HS_25MHZ                      0x23d40f02
> +#define CRT_PLL1_HS_40MHZ                      0x23940801
> +#define CRT_PLL1_HS_65MHZ                      0x23940d01
> +#define CRT_PLL1_HS_78MHZ                      0x23540F82
> +#define CRT_PLL1_HS_74MHZ                      0x23941dc2
> +#define CRT_PLL1_HS_80MHZ                      0x23941001
> +#define CRT_PLL1_HS_80MHZ_1152                 0x23540fc2
> +#define CRT_PLL1_HS_108MHZ                     0x23b41b01
> +#define CRT_PLL1_HS_162MHZ                     0x23480681
> +#define CRT_PLL1_HS_148MHZ                     0x23541dc2
> +#define CRT_PLL1_HS_193MHZ                     0x234807c1
> +
> +#define CRT_PLL2_HS                            0x802ac
> +#define CRT_PLL2_HS_25MHZ                      0x206B851E
> +#define CRT_PLL2_HS_40MHZ                      0x30000000
> +#define CRT_PLL2_HS_65MHZ                      0x40000000
> +#define CRT_PLL2_HS_78MHZ                      0x50E147AE
> +#define CRT_PLL2_HS_74MHZ                      0x602B6AE7
> +#define CRT_PLL2_HS_80MHZ                      0x70000000
> +#define CRT_PLL2_HS_108MHZ                     0x80000000
> +#define CRT_PLL2_HS_162MHZ                     0xA0000000
> +#define CRT_PLL2_HS_148MHZ                     0xB0CCCCCD
> +#define CRT_PLL2_HS_193MHZ                     0xC0872B02
> +
> +#define HIBMC_FIELD(field, value) (field(value) & field##_MASK)
> +#endif
> --
> 1.9.1
>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v7 2/7] drm/hisilicon/hibmc: Add video memory management
  2016-11-16 13:43   ` Rongrong Zou
@ 2016-11-16 15:52     ` Sean Paul
  -1 siblings, 0 replies; 40+ messages in thread
From: Sean Paul @ 2016-11-16 15:52 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Hibmc have 32m video memory which can be accessed through PCIe by host,
> we use ttm to manage these memory.
>
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  14 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |  41 ++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     | 485 ++++++++++++++++++++++++
>  4 files changed, 541 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> index 47962a0..19ed0ef 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> @@ -1,4 +1,4 @@
>  ccflags-y := -Iinclude/drm
> -hibmc-drm-y := hibmc_drm_drv.o
> +hibmc-drm-y := hibmc_drm_drv.o hibmc_ttm.o
>
>  obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> index 6d20580..521f69f 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -28,6 +28,7 @@
>         .release        = drm_release,
>         .unlocked_ioctl = drm_ioctl,
>         .compat_ioctl   = drm_compat_ioctl,
> +       .mmap           = hibmc_mmap,
>         .poll           = drm_poll,
>         .read           = drm_read,
>         .llseek         = no_llseek,
> @@ -43,6 +44,7 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>  }
>
>  static struct drm_driver hibmc_driver = {
> +       .driver_features        = DRIVER_GEM,
>         .fops                   = &hibmc_fops,
>         .name                   = "hibmc",
>         .date                   = "20160828",
> @@ -52,6 +54,10 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>         .get_vblank_counter     = drm_vblank_no_hw_counter,
>         .enable_vblank          = hibmc_enable_vblank,
>         .disable_vblank         = hibmc_disable_vblank,
> +       .gem_free_object_unlocked = hibmc_gem_free_object,
> +       .dumb_create            = hibmc_dumb_create,
> +       .dumb_map_offset        = hibmc_dumb_mmap_offset,
> +       .dumb_destroy           = drm_gem_dumb_destroy,
>  };
>
>  static int hibmc_pm_suspend(struct device *dev)
> @@ -194,6 +200,10 @@ static int hibmc_hw_init(struct hibmc_drm_private *priv)
>
>  static int hibmc_unload(struct drm_device *dev)
>  {
> +       struct hibmc_drm_private *priv = dev->dev_private;
> +
> +       hibmc_mm_fini(priv);
> +       dev->dev_private = NULL;
>         return 0;
>  }
>
> @@ -214,6 +224,10 @@ static int hibmc_load(struct drm_device *dev)
>         if (ret)
>                 goto err;
>
> +       ret = hibmc_mm_init(priv);
> +       if (ret)
> +               goto err;
> +
>         return 0;
>
>  err:
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> index 840cd5a..dcd304d 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -20,6 +20,8 @@
>  #define HIBMC_DRM_DRV_H
>
>  #include <drm/drmP.h>
> +#include <drm/drm_gem.h>
> +#include <drm/ttm/ttm_bo_driver.h>
>
>  struct hibmc_drm_private {
>         /* hw */
> @@ -31,11 +33,50 @@ struct hibmc_drm_private {
>         /* drm */
>         struct drm_device  *dev;
>
> +       /* ttm */
> +       struct drm_global_reference mem_global_ref;
> +       struct ttm_bo_global_ref bo_global_ref;
> +       struct ttm_bo_device bdev;
> +       bool initialized;
> +
> +       bool mm_inited;
> +};
> +
> +struct hibmc_bo {
> +       struct ttm_buffer_object bo;
> +       struct ttm_placement placement;
> +       struct ttm_bo_kmap_obj kmap;
> +       struct drm_gem_object gem;
> +       struct ttm_place placements[3];
> +       int pin_count;
>  };
>
> +static inline struct hibmc_bo *hibmc_bo(struct ttm_buffer_object *bo)
> +{
> +       return container_of(bo, struct hibmc_bo, bo);
> +}
> +
> +static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
> +{
> +       return container_of(gem, struct hibmc_bo, gem);
> +}
> +
>  void hibmc_set_power_mode(struct hibmc_drm_private *priv,
>                           unsigned int power_mode);
>  void hibmc_set_current_gate(struct hibmc_drm_private *priv,
>                             unsigned int gate);
>
> +int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
> +                    struct drm_gem_object **obj);
> +int hibmc_mm_init(struct hibmc_drm_private *hibmc);
> +void hibmc_mm_fini(struct hibmc_drm_private *hibmc);
> +int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr);
> +int hibmc_bo_unpin(struct hibmc_bo *bo);
> +void hibmc_gem_free_object(struct drm_gem_object *obj);
> +int hibmc_dumb_create(struct drm_file *file, struct drm_device *dev,
> +                     struct drm_mode_create_dumb *args);
> +int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
> +                          u32 handle, u64 *offset);
> +int hibmc_mmap(struct file *filp, struct vm_area_struct *vma);
> +
>  #endif
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> new file mode 100644
> index 0000000..036d3ac
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> @@ -0,0 +1,485 @@
> +/* Hisilicon Hibmc SoC drm driver
> + *
> + * Based on the bochs drm driver.
> + *
> + * Copyright (c) 2016 Huawei Limited.
> + *
> + * Author:
> + *     Rongrong Zou <zourongrong@huawei.com>
> + *     Rongrong Zou <zourongrong@gmail.com>
> + *     Jianhua Li <lijianhua@huawei.com>
> + *
> + * 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.
> + *
> + */
> +
> +#include <ttm/ttm_page_alloc.h>
> +
> +#include "hibmc_drm_drv.h"
> +
> +#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
> +
> +static inline struct hibmc_drm_private *
> +hibmc_bdev(struct ttm_bo_device *bd)
> +{
> +       return container_of(bd, struct hibmc_drm_private, bdev);
> +}
> +
> +static int
> +hibmc_ttm_mem_global_init(struct drm_global_reference *ref)
> +{
> +       return ttm_mem_global_init(ref->object);
> +}
> +
> +static void
> +hibmc_ttm_mem_global_release(struct drm_global_reference *ref)
> +{
> +       ttm_mem_global_release(ref->object);
> +}
> +
> +static int hibmc_ttm_global_init(struct hibmc_drm_private *hibmc)
> +{
> +       int ret;
> +
> +       hibmc->mem_global_ref.global_type = DRM_GLOBAL_TTM_MEM;
> +       hibmc->mem_global_ref.size = sizeof(struct ttm_mem_global);
> +       hibmc->mem_global_ref.init = &hibmc_ttm_mem_global_init;
> +       hibmc->mem_global_ref.release = &hibmc_ttm_mem_global_release;
> +       ret = drm_global_item_ref(&hibmc->mem_global_ref);
> +       if (ret) {
> +               DRM_ERROR("could not get ref on ttm global: %d\n", ret);
> +               return ret;
> +       }
> +
> +       hibmc->bo_global_ref.mem_glob =
> +               hibmc->mem_global_ref.object;
> +       hibmc->bo_global_ref.ref.global_type = DRM_GLOBAL_TTM_BO;
> +       hibmc->bo_global_ref.ref.size = sizeof(struct ttm_bo_global);
> +       hibmc->bo_global_ref.ref.init = &ttm_bo_global_init;
> +       hibmc->bo_global_ref.ref.release = &ttm_bo_global_release;
> +       ret = drm_global_item_ref(&hibmc->bo_global_ref.ref);
> +       if (ret) {
> +               DRM_ERROR("failed setting up TTM BO subsystem: %d\n", ret);
> +               drm_global_item_unref(&hibmc->mem_global_ref);
> +               return ret;
> +       }
> +       return 0;
> +}
> +
> +static void
> +hibmc_ttm_global_release(struct hibmc_drm_private *hibmc)
> +{
> +       drm_global_item_unref(&hibmc->bo_global_ref.ref);
> +       drm_global_item_unref(&hibmc->mem_global_ref);
> +       hibmc->mem_global_ref.release = NULL;
> +}
> +
> +static void hibmc_bo_ttm_destroy(struct ttm_buffer_object *tbo)
> +{
> +       struct hibmc_bo *bo = container_of(tbo, struct hibmc_bo, bo);
> +
> +       drm_gem_object_release(&bo->gem);
> +       kfree(bo);
> +}
> +
> +static bool hibmc_ttm_bo_is_hibmc_bo(struct ttm_buffer_object *bo)
> +{
> +       return bo->destroy == &hibmc_bo_ttm_destroy;
> +}
> +
> +static int
> +hibmc_bo_init_mem_type(struct ttm_bo_device *bdev, u32 type,
> +                      struct ttm_mem_type_manager *man)
> +{
> +       switch (type) {
> +       case TTM_PL_SYSTEM:
> +               man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
> +               man->available_caching = TTM_PL_MASK_CACHING;
> +               man->default_caching = TTM_PL_FLAG_CACHED;
> +               break;
> +       case TTM_PL_VRAM:
> +               man->func = &ttm_bo_manager_func;
> +               man->flags = TTM_MEMTYPE_FLAG_FIXED |
> +                       TTM_MEMTYPE_FLAG_MAPPABLE;
> +               man->available_caching = TTM_PL_FLAG_UNCACHED |
> +                       TTM_PL_FLAG_WC;
> +               man->default_caching = TTM_PL_FLAG_WC;
> +               break;
> +       default:
> +               DRM_ERROR("unsupported memory type %u\n", type);
> +               return -EINVAL;
> +       }
> +       return 0;
> +}
> +
> +void hibmc_ttm_placement(struct hibmc_bo *bo, int domain)
> +{
> +       u32 count = 0;
> +       u32 i;
> +
> +       bo->placement.placement = bo->placements;
> +       bo->placement.busy_placement = bo->placements;
> +       if (domain & TTM_PL_FLAG_VRAM)
> +               bo->placements[count++].flags = TTM_PL_FLAG_WC |
> +                       TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
> +       if (domain & TTM_PL_FLAG_SYSTEM)
> +               bo->placements[count++].flags = TTM_PL_MASK_CACHING |
> +                       TTM_PL_FLAG_SYSTEM;
> +       if (!count)
> +               bo->placements[count++].flags = TTM_PL_MASK_CACHING |
> +                       TTM_PL_FLAG_SYSTEM;
> +
> +       bo->placement.num_placement = count;
> +       bo->placement.num_busy_placement = count;
> +       for (i = 0; i < count; i++) {
> +               bo->placements[i].fpfn = 0;
> +               bo->placements[i].lpfn = 0;
> +       }
> +}
> +
> +static void
> +hibmc_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
> +{
> +       struct hibmc_bo *hibmcbo = hibmc_bo(bo);
> +
> +       if (!hibmc_ttm_bo_is_hibmc_bo(bo))
> +               return;
> +
> +       hibmc_ttm_placement(hibmcbo, TTM_PL_FLAG_SYSTEM);
> +       *pl = hibmcbo->placement;
> +}
> +
> +static int hibmc_bo_verify_access(struct ttm_buffer_object *bo,
> +                                 struct file *filp)
> +{
> +       struct hibmc_bo *hibmcbo = hibmc_bo(bo);
> +
> +       return drm_vma_node_verify_access(&hibmcbo->gem.vma_node,
> +                                         filp->private_data);
> +}
> +
> +static int hibmc_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
> +                                   struct ttm_mem_reg *mem)
> +{
> +       struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
> +       struct hibmc_drm_private *hibmc = hibmc_bdev(bdev);
> +
> +       mem->bus.addr = NULL;
> +       mem->bus.offset = 0;
> +       mem->bus.size = mem->num_pages << PAGE_SHIFT;
> +       mem->bus.base = 0;
> +       mem->bus.is_iomem = false;
> +       if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE))
> +               return -EINVAL;
> +       switch (mem->mem_type) {
> +       case TTM_PL_SYSTEM:
> +               /* system memory */
> +               return 0;
> +       case TTM_PL_VRAM:
> +               mem->bus.offset = mem->start << PAGE_SHIFT;
> +               mem->bus.base = pci_resource_start(hibmc->dev->pdev, 0);
> +               mem->bus.is_iomem = true;
> +               break;
> +       default:
> +               return -EINVAL;
> +       }
> +       return 0;
> +}
> +
> +static void hibmc_ttm_backend_destroy(struct ttm_tt *tt)
> +{
> +       ttm_tt_fini(tt);
> +       kfree(tt);
> +}
> +
> +static struct ttm_backend_func hibmc_tt_backend_func = {
> +       .destroy = &hibmc_ttm_backend_destroy,
> +};
> +
> +static struct ttm_tt *hibmc_ttm_tt_create(struct ttm_bo_device *bdev,
> +                                         unsigned long size,
> +                                         u32 page_flags,
> +                                         struct page *dummy_read_page)
> +{
> +       struct ttm_tt *tt;
> +       int ret;
> +
> +       tt = kzalloc(sizeof(*tt), GFP_KERNEL);
> +       if (!tt) {
> +               DRM_ERROR("failed to allocate ttm_tt\n");
> +               return NULL;
> +       }
> +       tt->func = &hibmc_tt_backend_func;
> +       ret = ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page);
> +       if (ret) {
> +               DRM_ERROR("failed to initialize ttm_tt: %d\n", ret);
> +               kfree(tt);
> +               return NULL;
> +       }
> +       return tt;
> +}
> +
> +static int hibmc_ttm_tt_populate(struct ttm_tt *ttm)
> +{
> +       return ttm_pool_populate(ttm);
> +}
> +
> +static void hibmc_ttm_tt_unpopulate(struct ttm_tt *ttm)
> +{
> +       ttm_pool_unpopulate(ttm);
> +}
> +
> +struct ttm_bo_driver hibmc_bo_driver = {
> +       .ttm_tt_create          = hibmc_ttm_tt_create,
> +       .ttm_tt_populate        = hibmc_ttm_tt_populate,
> +       .ttm_tt_unpopulate      = hibmc_ttm_tt_unpopulate,
> +       .init_mem_type          = hibmc_bo_init_mem_type,
> +       .evict_flags            = hibmc_bo_evict_flags,
> +       .move                   = NULL,
> +       .verify_access          = hibmc_bo_verify_access,
> +       .io_mem_reserve         = &hibmc_ttm_io_mem_reserve,
> +       .io_mem_free            = NULL,
> +       .lru_tail               = &ttm_bo_default_lru_tail,
> +       .swap_lru_tail          = &ttm_bo_default_swap_lru_tail,
> +};
> +
> +int hibmc_mm_init(struct hibmc_drm_private *hibmc)
> +{
> +       int ret;
> +       struct drm_device *dev = hibmc->dev;
> +       struct ttm_bo_device *bdev = &hibmc->bdev;
> +
> +       ret = hibmc_ttm_global_init(hibmc);
> +       if (ret)
> +               return ret;
> +
> +       ret = ttm_bo_device_init(&hibmc->bdev,
> +                                hibmc->bo_global_ref.ref.object,
> +                                &hibmc_bo_driver,
> +                                dev->anon_inode->i_mapping,
> +                                DRM_FILE_PAGE_OFFSET,
> +                                true);
> +       if (ret) {
> +               hibmc_ttm_global_release(hibmc);
> +               DRM_ERROR("error initializing bo driver: %d\n", ret);
> +               return ret;
> +       }
> +
> +       ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
> +                            hibmc->fb_size >> PAGE_SHIFT);
> +       if (ret) {
> +               hibmc_ttm_global_release(hibmc);
> +               DRM_ERROR("failed ttm VRAM init: %d\n", ret);
> +               return ret;
> +       }
> +
> +       hibmc->mm_inited = true;
> +       return 0;
> +}
> +
> +void hibmc_mm_fini(struct hibmc_drm_private *hibmc)
> +{
> +       if (!hibmc->mm_inited)
> +               return;
> +
> +       ttm_bo_device_release(&hibmc->bdev);
> +       hibmc_ttm_global_release(hibmc);
> +       hibmc->mm_inited = false;
> +}
> +
> +static void hibmc_bo_unref(struct hibmc_bo **bo)
> +{
> +       struct ttm_buffer_object *tbo;
> +
> +       if ((*bo) == NULL)
> +               return;
> +
> +       tbo = &((*bo)->bo);
> +       ttm_bo_unref(&tbo);
> +       *bo = NULL;
> +}
> +
> +int hibmc_bo_create(struct drm_device *dev, int size, int align,
> +                   u32 flags, struct hibmc_bo **phibmcbo)
> +{
> +       struct hibmc_drm_private *hibmc = dev->dev_private;
> +       struct hibmc_bo *hibmcbo;
> +       size_t acc_size;
> +       int ret;
> +
> +       hibmcbo = kzalloc(sizeof(*hibmcbo), GFP_KERNEL);
> +       if (!hibmcbo) {
> +               DRM_ERROR("failed to allocate hibmcbo\n");
> +               return -ENOMEM;
> +       }
> +       ret = drm_gem_object_init(dev, &hibmcbo->gem, size);
> +       if (ret) {
> +               DRM_ERROR("failed to initialize drm gem object: %d\n", ret);
> +               kfree(hibmcbo);
> +               return ret;
> +       }
> +
> +       hibmcbo->bo.bdev = &hibmc->bdev;
> +
> +       hibmc_ttm_placement(hibmcbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
> +
> +       acc_size = ttm_bo_dma_acc_size(&hibmc->bdev, size,
> +                                      sizeof(struct hibmc_bo));
> +
> +       ret = ttm_bo_init(&hibmc->bdev, &hibmcbo->bo, size,
> +                         ttm_bo_type_device, &hibmcbo->placement,
> +                         align >> PAGE_SHIFT, false, NULL, acc_size,
> +                         NULL, NULL, hibmc_bo_ttm_destroy);
> +       if (ret) {
> +               hibmc_bo_unref(&hibmcbo);
> +               DRM_ERROR("failed to initialize ttm_bo: %d\n", ret);
> +               return ret;
> +       }
> +
> +       *phibmcbo = hibmcbo;
> +       return 0;
> +}
> +
> +int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr)
> +{
> +       int i, ret;
> +
> +       if (bo->pin_count) {
> +               bo->pin_count++;
> +               if (gpu_addr)
> +                       *gpu_addr = bo->bo.offset;
> +               return 0;
> +       }
> +
> +       hibmc_ttm_placement(bo, pl_flag);
> +       for (i = 0; i < bo->placement.num_placement; i++)
> +               bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
> +       ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
> +       if (ret)
> +               return ret;
> +
> +       bo->pin_count = 1;
> +       if (gpu_addr)
> +               *gpu_addr = bo->bo.offset;
> +       return 0;
> +}
> +
> +int hibmc_bo_unpin(struct hibmc_bo *bo)
> +{
> +       int i, ret;
> +
> +       if (!bo->pin_count) {
> +               DRM_ERROR("unpin bad %p\n", bo);
> +               return 0;
> +       }
> +       bo->pin_count--;
> +       if (bo->pin_count)
> +               return 0;
> +
> +       for (i = 0; i < bo->placement.num_placement ; i++)
> +               bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT;
> +       ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
> +       if (ret) {
> +               DRM_ERROR("validate failed for unpin: %d\n", ret);
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +int hibmc_mmap(struct file *filp, struct vm_area_struct *vma)
> +{
> +       struct drm_file *file_priv;
> +       struct hibmc_drm_private *hibmc;
> +
> +       if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET))
> +               return -EINVAL;
> +
> +       file_priv = filp->private_data;
> +       hibmc = file_priv->minor->dev->dev_private;
> +       return ttm_bo_mmap(filp, vma, &hibmc->bdev);
> +}
> +
> +int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
> +                    struct drm_gem_object **obj)
> +{
> +       struct hibmc_bo *hibmcbo;
> +       int ret;
> +
> +       *obj = NULL;
> +
> +       size = PAGE_ALIGN(size);
> +       if (size == 0) {
> +               DRM_ERROR("error: zero size\n");
> +               return -EINVAL;
> +       }
> +
> +       ret = hibmc_bo_create(dev, size, 0, 0, &hibmcbo);
> +       if (ret) {
> +               if (ret != -ERESTARTSYS)
> +                       DRM_ERROR("failed to allocate GEM object: %d\n", ret);
> +               return ret;
> +       }
> +       *obj = &hibmcbo->gem;
> +       return 0;
> +}
> +
> +int hibmc_dumb_create(struct drm_file *file, struct drm_device *dev,
> +                     struct drm_mode_create_dumb *args)
> +{
> +       struct drm_gem_object *gobj;
> +       u32 handle;
> +       int ret;
> +
> +       args->pitch = ALIGN(args->width * DIV_ROUND_UP(args->bpp, 8), 16);
> +       args->size = args->pitch * args->height;
> +
> +       ret = hibmc_gem_create(dev, args->size, false,
> +                              &gobj);
> +       if (ret) {
> +               DRM_ERROR("failed to create GEM object: %d\n", ret);
> +               return ret;
> +       }
> +
> +       ret = drm_gem_handle_create(file, gobj, &handle);
> +       drm_gem_object_unreference_unlocked(gobj);
> +       if (ret) {
> +               DRM_ERROR("failed to unreference GEM object: %d\n", ret);
> +               return ret;
> +       }
> +
> +       args->handle = handle;
> +       return 0;
> +}
> +
> +void hibmc_gem_free_object(struct drm_gem_object *obj)
> +{
> +       struct hibmc_bo *hibmcbo = gem_to_hibmc_bo(obj);
> +
> +       hibmc_bo_unref(&hibmcbo);
> +}
> +
> +static u64 hibmc_bo_mmap_offset(struct hibmc_bo *bo)
> +{
> +       return drm_vma_node_offset_addr(&bo->bo.vma_node);
> +}
> +
> +int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
> +                          u32 handle, u64 *offset)
> +{
> +       struct drm_gem_object *obj;
> +       struct hibmc_bo *bo;
> +
> +       obj = drm_gem_object_lookup(file, handle);
> +       if (!obj)
> +               return -ENOENT;
> +
> +       bo = gem_to_hibmc_bo(obj);
> +       *offset = hibmc_bo_mmap_offset(bo);
> +
> +       drm_gem_object_unreference_unlocked(obj);
> +       return 0;
> +}
> --
> 1.9.1
>

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v7 2/7] drm/hisilicon/hibmc: Add video memory management
@ 2016-11-16 15:52     ` Sean Paul
  0 siblings, 0 replies; 40+ messages in thread
From: Sean Paul @ 2016-11-16 15:52 UTC (permalink / raw)
  To: Rongrong Zou
  Cc: Mark Rutland, Tomeu Vizoso, seanpaul, Jonathan Corbet,
	Emil Velikov, linuxarm, dri-devel, james.xiong, guohanjun,
	lijianhua, Linux ARM Kernel, shenhui

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Hibmc have 32m video memory which can be accessed through PCIe by host,
> we use ttm to manage these memory.
>
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  14 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |  41 ++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     | 485 ++++++++++++++++++++++++
>  4 files changed, 541 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> index 47962a0..19ed0ef 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> @@ -1,4 +1,4 @@
>  ccflags-y := -Iinclude/drm
> -hibmc-drm-y := hibmc_drm_drv.o
> +hibmc-drm-y := hibmc_drm_drv.o hibmc_ttm.o
>
>  obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> index 6d20580..521f69f 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -28,6 +28,7 @@
>         .release        = drm_release,
>         .unlocked_ioctl = drm_ioctl,
>         .compat_ioctl   = drm_compat_ioctl,
> +       .mmap           = hibmc_mmap,
>         .poll           = drm_poll,
>         .read           = drm_read,
>         .llseek         = no_llseek,
> @@ -43,6 +44,7 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>  }
>
>  static struct drm_driver hibmc_driver = {
> +       .driver_features        = DRIVER_GEM,
>         .fops                   = &hibmc_fops,
>         .name                   = "hibmc",
>         .date                   = "20160828",
> @@ -52,6 +54,10 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>         .get_vblank_counter     = drm_vblank_no_hw_counter,
>         .enable_vblank          = hibmc_enable_vblank,
>         .disable_vblank         = hibmc_disable_vblank,
> +       .gem_free_object_unlocked = hibmc_gem_free_object,
> +       .dumb_create            = hibmc_dumb_create,
> +       .dumb_map_offset        = hibmc_dumb_mmap_offset,
> +       .dumb_destroy           = drm_gem_dumb_destroy,
>  };
>
>  static int hibmc_pm_suspend(struct device *dev)
> @@ -194,6 +200,10 @@ static int hibmc_hw_init(struct hibmc_drm_private *priv)
>
>  static int hibmc_unload(struct drm_device *dev)
>  {
> +       struct hibmc_drm_private *priv = dev->dev_private;
> +
> +       hibmc_mm_fini(priv);
> +       dev->dev_private = NULL;
>         return 0;
>  }
>
> @@ -214,6 +224,10 @@ static int hibmc_load(struct drm_device *dev)
>         if (ret)
>                 goto err;
>
> +       ret = hibmc_mm_init(priv);
> +       if (ret)
> +               goto err;
> +
>         return 0;
>
>  err:
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> index 840cd5a..dcd304d 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -20,6 +20,8 @@
>  #define HIBMC_DRM_DRV_H
>
>  #include <drm/drmP.h>
> +#include <drm/drm_gem.h>
> +#include <drm/ttm/ttm_bo_driver.h>
>
>  struct hibmc_drm_private {
>         /* hw */
> @@ -31,11 +33,50 @@ struct hibmc_drm_private {
>         /* drm */
>         struct drm_device  *dev;
>
> +       /* ttm */
> +       struct drm_global_reference mem_global_ref;
> +       struct ttm_bo_global_ref bo_global_ref;
> +       struct ttm_bo_device bdev;
> +       bool initialized;
> +
> +       bool mm_inited;
> +};
> +
> +struct hibmc_bo {
> +       struct ttm_buffer_object bo;
> +       struct ttm_placement placement;
> +       struct ttm_bo_kmap_obj kmap;
> +       struct drm_gem_object gem;
> +       struct ttm_place placements[3];
> +       int pin_count;
>  };
>
> +static inline struct hibmc_bo *hibmc_bo(struct ttm_buffer_object *bo)
> +{
> +       return container_of(bo, struct hibmc_bo, bo);
> +}
> +
> +static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
> +{
> +       return container_of(gem, struct hibmc_bo, gem);
> +}
> +
>  void hibmc_set_power_mode(struct hibmc_drm_private *priv,
>                           unsigned int power_mode);
>  void hibmc_set_current_gate(struct hibmc_drm_private *priv,
>                             unsigned int gate);
>
> +int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
> +                    struct drm_gem_object **obj);
> +int hibmc_mm_init(struct hibmc_drm_private *hibmc);
> +void hibmc_mm_fini(struct hibmc_drm_private *hibmc);
> +int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr);
> +int hibmc_bo_unpin(struct hibmc_bo *bo);
> +void hibmc_gem_free_object(struct drm_gem_object *obj);
> +int hibmc_dumb_create(struct drm_file *file, struct drm_device *dev,
> +                     struct drm_mode_create_dumb *args);
> +int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
> +                          u32 handle, u64 *offset);
> +int hibmc_mmap(struct file *filp, struct vm_area_struct *vma);
> +
>  #endif
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> new file mode 100644
> index 0000000..036d3ac
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> @@ -0,0 +1,485 @@
> +/* Hisilicon Hibmc SoC drm driver
> + *
> + * Based on the bochs drm driver.
> + *
> + * Copyright (c) 2016 Huawei Limited.
> + *
> + * Author:
> + *     Rongrong Zou <zourongrong@huawei.com>
> + *     Rongrong Zou <zourongrong@gmail.com>
> + *     Jianhua Li <lijianhua@huawei.com>
> + *
> + * 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.
> + *
> + */
> +
> +#include <ttm/ttm_page_alloc.h>
> +
> +#include "hibmc_drm_drv.h"
> +
> +#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
> +
> +static inline struct hibmc_drm_private *
> +hibmc_bdev(struct ttm_bo_device *bd)
> +{
> +       return container_of(bd, struct hibmc_drm_private, bdev);
> +}
> +
> +static int
> +hibmc_ttm_mem_global_init(struct drm_global_reference *ref)
> +{
> +       return ttm_mem_global_init(ref->object);
> +}
> +
> +static void
> +hibmc_ttm_mem_global_release(struct drm_global_reference *ref)
> +{
> +       ttm_mem_global_release(ref->object);
> +}
> +
> +static int hibmc_ttm_global_init(struct hibmc_drm_private *hibmc)
> +{
> +       int ret;
> +
> +       hibmc->mem_global_ref.global_type = DRM_GLOBAL_TTM_MEM;
> +       hibmc->mem_global_ref.size = sizeof(struct ttm_mem_global);
> +       hibmc->mem_global_ref.init = &hibmc_ttm_mem_global_init;
> +       hibmc->mem_global_ref.release = &hibmc_ttm_mem_global_release;
> +       ret = drm_global_item_ref(&hibmc->mem_global_ref);
> +       if (ret) {
> +               DRM_ERROR("could not get ref on ttm global: %d\n", ret);
> +               return ret;
> +       }
> +
> +       hibmc->bo_global_ref.mem_glob =
> +               hibmc->mem_global_ref.object;
> +       hibmc->bo_global_ref.ref.global_type = DRM_GLOBAL_TTM_BO;
> +       hibmc->bo_global_ref.ref.size = sizeof(struct ttm_bo_global);
> +       hibmc->bo_global_ref.ref.init = &ttm_bo_global_init;
> +       hibmc->bo_global_ref.ref.release = &ttm_bo_global_release;
> +       ret = drm_global_item_ref(&hibmc->bo_global_ref.ref);
> +       if (ret) {
> +               DRM_ERROR("failed setting up TTM BO subsystem: %d\n", ret);
> +               drm_global_item_unref(&hibmc->mem_global_ref);
> +               return ret;
> +       }
> +       return 0;
> +}
> +
> +static void
> +hibmc_ttm_global_release(struct hibmc_drm_private *hibmc)
> +{
> +       drm_global_item_unref(&hibmc->bo_global_ref.ref);
> +       drm_global_item_unref(&hibmc->mem_global_ref);
> +       hibmc->mem_global_ref.release = NULL;
> +}
> +
> +static void hibmc_bo_ttm_destroy(struct ttm_buffer_object *tbo)
> +{
> +       struct hibmc_bo *bo = container_of(tbo, struct hibmc_bo, bo);
> +
> +       drm_gem_object_release(&bo->gem);
> +       kfree(bo);
> +}
> +
> +static bool hibmc_ttm_bo_is_hibmc_bo(struct ttm_buffer_object *bo)
> +{
> +       return bo->destroy == &hibmc_bo_ttm_destroy;
> +}
> +
> +static int
> +hibmc_bo_init_mem_type(struct ttm_bo_device *bdev, u32 type,
> +                      struct ttm_mem_type_manager *man)
> +{
> +       switch (type) {
> +       case TTM_PL_SYSTEM:
> +               man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
> +               man->available_caching = TTM_PL_MASK_CACHING;
> +               man->default_caching = TTM_PL_FLAG_CACHED;
> +               break;
> +       case TTM_PL_VRAM:
> +               man->func = &ttm_bo_manager_func;
> +               man->flags = TTM_MEMTYPE_FLAG_FIXED |
> +                       TTM_MEMTYPE_FLAG_MAPPABLE;
> +               man->available_caching = TTM_PL_FLAG_UNCACHED |
> +                       TTM_PL_FLAG_WC;
> +               man->default_caching = TTM_PL_FLAG_WC;
> +               break;
> +       default:
> +               DRM_ERROR("unsupported memory type %u\n", type);
> +               return -EINVAL;
> +       }
> +       return 0;
> +}
> +
> +void hibmc_ttm_placement(struct hibmc_bo *bo, int domain)
> +{
> +       u32 count = 0;
> +       u32 i;
> +
> +       bo->placement.placement = bo->placements;
> +       bo->placement.busy_placement = bo->placements;
> +       if (domain & TTM_PL_FLAG_VRAM)
> +               bo->placements[count++].flags = TTM_PL_FLAG_WC |
> +                       TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
> +       if (domain & TTM_PL_FLAG_SYSTEM)
> +               bo->placements[count++].flags = TTM_PL_MASK_CACHING |
> +                       TTM_PL_FLAG_SYSTEM;
> +       if (!count)
> +               bo->placements[count++].flags = TTM_PL_MASK_CACHING |
> +                       TTM_PL_FLAG_SYSTEM;
> +
> +       bo->placement.num_placement = count;
> +       bo->placement.num_busy_placement = count;
> +       for (i = 0; i < count; i++) {
> +               bo->placements[i].fpfn = 0;
> +               bo->placements[i].lpfn = 0;
> +       }
> +}
> +
> +static void
> +hibmc_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
> +{
> +       struct hibmc_bo *hibmcbo = hibmc_bo(bo);
> +
> +       if (!hibmc_ttm_bo_is_hibmc_bo(bo))
> +               return;
> +
> +       hibmc_ttm_placement(hibmcbo, TTM_PL_FLAG_SYSTEM);
> +       *pl = hibmcbo->placement;
> +}
> +
> +static int hibmc_bo_verify_access(struct ttm_buffer_object *bo,
> +                                 struct file *filp)
> +{
> +       struct hibmc_bo *hibmcbo = hibmc_bo(bo);
> +
> +       return drm_vma_node_verify_access(&hibmcbo->gem.vma_node,
> +                                         filp->private_data);
> +}
> +
> +static int hibmc_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
> +                                   struct ttm_mem_reg *mem)
> +{
> +       struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
> +       struct hibmc_drm_private *hibmc = hibmc_bdev(bdev);
> +
> +       mem->bus.addr = NULL;
> +       mem->bus.offset = 0;
> +       mem->bus.size = mem->num_pages << PAGE_SHIFT;
> +       mem->bus.base = 0;
> +       mem->bus.is_iomem = false;
> +       if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE))
> +               return -EINVAL;
> +       switch (mem->mem_type) {
> +       case TTM_PL_SYSTEM:
> +               /* system memory */
> +               return 0;
> +       case TTM_PL_VRAM:
> +               mem->bus.offset = mem->start << PAGE_SHIFT;
> +               mem->bus.base = pci_resource_start(hibmc->dev->pdev, 0);
> +               mem->bus.is_iomem = true;
> +               break;
> +       default:
> +               return -EINVAL;
> +       }
> +       return 0;
> +}
> +
> +static void hibmc_ttm_backend_destroy(struct ttm_tt *tt)
> +{
> +       ttm_tt_fini(tt);
> +       kfree(tt);
> +}
> +
> +static struct ttm_backend_func hibmc_tt_backend_func = {
> +       .destroy = &hibmc_ttm_backend_destroy,
> +};
> +
> +static struct ttm_tt *hibmc_ttm_tt_create(struct ttm_bo_device *bdev,
> +                                         unsigned long size,
> +                                         u32 page_flags,
> +                                         struct page *dummy_read_page)
> +{
> +       struct ttm_tt *tt;
> +       int ret;
> +
> +       tt = kzalloc(sizeof(*tt), GFP_KERNEL);
> +       if (!tt) {
> +               DRM_ERROR("failed to allocate ttm_tt\n");
> +               return NULL;
> +       }
> +       tt->func = &hibmc_tt_backend_func;
> +       ret = ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page);
> +       if (ret) {
> +               DRM_ERROR("failed to initialize ttm_tt: %d\n", ret);
> +               kfree(tt);
> +               return NULL;
> +       }
> +       return tt;
> +}
> +
> +static int hibmc_ttm_tt_populate(struct ttm_tt *ttm)
> +{
> +       return ttm_pool_populate(ttm);
> +}
> +
> +static void hibmc_ttm_tt_unpopulate(struct ttm_tt *ttm)
> +{
> +       ttm_pool_unpopulate(ttm);
> +}
> +
> +struct ttm_bo_driver hibmc_bo_driver = {
> +       .ttm_tt_create          = hibmc_ttm_tt_create,
> +       .ttm_tt_populate        = hibmc_ttm_tt_populate,
> +       .ttm_tt_unpopulate      = hibmc_ttm_tt_unpopulate,
> +       .init_mem_type          = hibmc_bo_init_mem_type,
> +       .evict_flags            = hibmc_bo_evict_flags,
> +       .move                   = NULL,
> +       .verify_access          = hibmc_bo_verify_access,
> +       .io_mem_reserve         = &hibmc_ttm_io_mem_reserve,
> +       .io_mem_free            = NULL,
> +       .lru_tail               = &ttm_bo_default_lru_tail,
> +       .swap_lru_tail          = &ttm_bo_default_swap_lru_tail,
> +};
> +
> +int hibmc_mm_init(struct hibmc_drm_private *hibmc)
> +{
> +       int ret;
> +       struct drm_device *dev = hibmc->dev;
> +       struct ttm_bo_device *bdev = &hibmc->bdev;
> +
> +       ret = hibmc_ttm_global_init(hibmc);
> +       if (ret)
> +               return ret;
> +
> +       ret = ttm_bo_device_init(&hibmc->bdev,
> +                                hibmc->bo_global_ref.ref.object,
> +                                &hibmc_bo_driver,
> +                                dev->anon_inode->i_mapping,
> +                                DRM_FILE_PAGE_OFFSET,
> +                                true);
> +       if (ret) {
> +               hibmc_ttm_global_release(hibmc);
> +               DRM_ERROR("error initializing bo driver: %d\n", ret);
> +               return ret;
> +       }
> +
> +       ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
> +                            hibmc->fb_size >> PAGE_SHIFT);
> +       if (ret) {
> +               hibmc_ttm_global_release(hibmc);
> +               DRM_ERROR("failed ttm VRAM init: %d\n", ret);
> +               return ret;
> +       }
> +
> +       hibmc->mm_inited = true;
> +       return 0;
> +}
> +
> +void hibmc_mm_fini(struct hibmc_drm_private *hibmc)
> +{
> +       if (!hibmc->mm_inited)
> +               return;
> +
> +       ttm_bo_device_release(&hibmc->bdev);
> +       hibmc_ttm_global_release(hibmc);
> +       hibmc->mm_inited = false;
> +}
> +
> +static void hibmc_bo_unref(struct hibmc_bo **bo)
> +{
> +       struct ttm_buffer_object *tbo;
> +
> +       if ((*bo) == NULL)
> +               return;
> +
> +       tbo = &((*bo)->bo);
> +       ttm_bo_unref(&tbo);
> +       *bo = NULL;
> +}
> +
> +int hibmc_bo_create(struct drm_device *dev, int size, int align,
> +                   u32 flags, struct hibmc_bo **phibmcbo)
> +{
> +       struct hibmc_drm_private *hibmc = dev->dev_private;
> +       struct hibmc_bo *hibmcbo;
> +       size_t acc_size;
> +       int ret;
> +
> +       hibmcbo = kzalloc(sizeof(*hibmcbo), GFP_KERNEL);
> +       if (!hibmcbo) {
> +               DRM_ERROR("failed to allocate hibmcbo\n");
> +               return -ENOMEM;
> +       }
> +       ret = drm_gem_object_init(dev, &hibmcbo->gem, size);
> +       if (ret) {
> +               DRM_ERROR("failed to initialize drm gem object: %d\n", ret);
> +               kfree(hibmcbo);
> +               return ret;
> +       }
> +
> +       hibmcbo->bo.bdev = &hibmc->bdev;
> +
> +       hibmc_ttm_placement(hibmcbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
> +
> +       acc_size = ttm_bo_dma_acc_size(&hibmc->bdev, size,
> +                                      sizeof(struct hibmc_bo));
> +
> +       ret = ttm_bo_init(&hibmc->bdev, &hibmcbo->bo, size,
> +                         ttm_bo_type_device, &hibmcbo->placement,
> +                         align >> PAGE_SHIFT, false, NULL, acc_size,
> +                         NULL, NULL, hibmc_bo_ttm_destroy);
> +       if (ret) {
> +               hibmc_bo_unref(&hibmcbo);
> +               DRM_ERROR("failed to initialize ttm_bo: %d\n", ret);
> +               return ret;
> +       }
> +
> +       *phibmcbo = hibmcbo;
> +       return 0;
> +}
> +
> +int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr)
> +{
> +       int i, ret;
> +
> +       if (bo->pin_count) {
> +               bo->pin_count++;
> +               if (gpu_addr)
> +                       *gpu_addr = bo->bo.offset;
> +               return 0;
> +       }
> +
> +       hibmc_ttm_placement(bo, pl_flag);
> +       for (i = 0; i < bo->placement.num_placement; i++)
> +               bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
> +       ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
> +       if (ret)
> +               return ret;
> +
> +       bo->pin_count = 1;
> +       if (gpu_addr)
> +               *gpu_addr = bo->bo.offset;
> +       return 0;
> +}
> +
> +int hibmc_bo_unpin(struct hibmc_bo *bo)
> +{
> +       int i, ret;
> +
> +       if (!bo->pin_count) {
> +               DRM_ERROR("unpin bad %p\n", bo);
> +               return 0;
> +       }
> +       bo->pin_count--;
> +       if (bo->pin_count)
> +               return 0;
> +
> +       for (i = 0; i < bo->placement.num_placement ; i++)
> +               bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT;
> +       ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
> +       if (ret) {
> +               DRM_ERROR("validate failed for unpin: %d\n", ret);
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +int hibmc_mmap(struct file *filp, struct vm_area_struct *vma)
> +{
> +       struct drm_file *file_priv;
> +       struct hibmc_drm_private *hibmc;
> +
> +       if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET))
> +               return -EINVAL;
> +
> +       file_priv = filp->private_data;
> +       hibmc = file_priv->minor->dev->dev_private;
> +       return ttm_bo_mmap(filp, vma, &hibmc->bdev);
> +}
> +
> +int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
> +                    struct drm_gem_object **obj)
> +{
> +       struct hibmc_bo *hibmcbo;
> +       int ret;
> +
> +       *obj = NULL;
> +
> +       size = PAGE_ALIGN(size);
> +       if (size == 0) {
> +               DRM_ERROR("error: zero size\n");
> +               return -EINVAL;
> +       }
> +
> +       ret = hibmc_bo_create(dev, size, 0, 0, &hibmcbo);
> +       if (ret) {
> +               if (ret != -ERESTARTSYS)
> +                       DRM_ERROR("failed to allocate GEM object: %d\n", ret);
> +               return ret;
> +       }
> +       *obj = &hibmcbo->gem;
> +       return 0;
> +}
> +
> +int hibmc_dumb_create(struct drm_file *file, struct drm_device *dev,
> +                     struct drm_mode_create_dumb *args)
> +{
> +       struct drm_gem_object *gobj;
> +       u32 handle;
> +       int ret;
> +
> +       args->pitch = ALIGN(args->width * DIV_ROUND_UP(args->bpp, 8), 16);
> +       args->size = args->pitch * args->height;
> +
> +       ret = hibmc_gem_create(dev, args->size, false,
> +                              &gobj);
> +       if (ret) {
> +               DRM_ERROR("failed to create GEM object: %d\n", ret);
> +               return ret;
> +       }
> +
> +       ret = drm_gem_handle_create(file, gobj, &handle);
> +       drm_gem_object_unreference_unlocked(gobj);
> +       if (ret) {
> +               DRM_ERROR("failed to unreference GEM object: %d\n", ret);
> +               return ret;
> +       }
> +
> +       args->handle = handle;
> +       return 0;
> +}
> +
> +void hibmc_gem_free_object(struct drm_gem_object *obj)
> +{
> +       struct hibmc_bo *hibmcbo = gem_to_hibmc_bo(obj);
> +
> +       hibmc_bo_unref(&hibmcbo);
> +}
> +
> +static u64 hibmc_bo_mmap_offset(struct hibmc_bo *bo)
> +{
> +       return drm_vma_node_offset_addr(&bo->bo.vma_node);
> +}
> +
> +int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
> +                          u32 handle, u64 *offset)
> +{
> +       struct drm_gem_object *obj;
> +       struct hibmc_bo *bo;
> +
> +       obj = drm_gem_object_lookup(file, handle);
> +       if (!obj)
> +               return -ENOENT;
> +
> +       bo = gem_to_hibmc_bo(obj);
> +       *offset = hibmc_bo_mmap_offset(bo);
> +
> +       drm_gem_object_unreference_unlocked(obj);
> +       return 0;
> +}
> --
> 1.9.1
>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v7 3/7] drm/hisilicon/hibmc: Add support for frame buffer
  2016-11-16 13:43   ` Rongrong Zou
@ 2016-11-16 15:56     ` Sean Paul
  -1 siblings, 0 replies; 40+ messages in thread
From: Sean Paul @ 2016-11-16 15:56 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Add support for fbdev and kms fb management.
>
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  drivers/gpu/drm/hisilicon/hibmc/Makefile          |   2 +-
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   |   7 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   |  24 ++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 267 ++++++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       |  67 ++++++
>  5 files changed, 366 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> index 19ed0ef..ff77a7e 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> @@ -1,4 +1,4 @@
>  ccflags-y := -Iinclude/drm
> -hibmc-drm-y := hibmc_drm_drv.o hibmc_ttm.o
> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_ttm.o
>
>  obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> index 521f69f..4b52b29 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -202,6 +202,7 @@ static int hibmc_unload(struct drm_device *dev)
>  {
>         struct hibmc_drm_private *priv = dev->dev_private;
>
> +       hibmc_fbdev_fini(priv);
>         hibmc_mm_fini(priv);
>         dev->dev_private = NULL;
>         return 0;
> @@ -228,6 +229,12 @@ static int hibmc_load(struct drm_device *dev)
>         if (ret)
>                 goto err;
>
> +       ret = hibmc_fbdev_init(priv);
> +       if (ret) {
> +               DRM_ERROR("failed to initialize fbdev: %d\n", ret);
> +               goto err;
> +       }
> +
>         return 0;
>
>  err:
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> index dcd304d..d283d66 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -20,9 +20,21 @@
>  #define HIBMC_DRM_DRV_H
>
>  #include <drm/drmP.h>
> +#include <drm/drm_fb_helper.h>
>  #include <drm/drm_gem.h>
>  #include <drm/ttm/ttm_bo_driver.h>
>
> +struct hibmc_framebuffer {
> +       struct drm_framebuffer fb;
> +       struct drm_gem_object *obj;
> +};
> +
> +struct hibmc_fbdev {
> +       struct drm_fb_helper helper;
> +       struct hibmc_framebuffer *fb;
> +       int size;
> +};
> +
>  struct hibmc_drm_private {
>         /* hw */
>         void __iomem   *mmio;
> @@ -39,9 +51,13 @@ struct hibmc_drm_private {
>         struct ttm_bo_device bdev;
>         bool initialized;
>
> +       /* fbdev */
> +       struct hibmc_fbdev *fbdev;
>         bool mm_inited;
>  };
>
> +#define to_hibmc_framebuffer(x) container_of(x, struct hibmc_framebuffer, fb)
> +
>  struct hibmc_bo {
>         struct ttm_buffer_object bo;
>         struct ttm_placement placement;
> @@ -66,8 +82,16 @@ void hibmc_set_power_mode(struct hibmc_drm_private *priv,
>  void hibmc_set_current_gate(struct hibmc_drm_private *priv,
>                             unsigned int gate);
>
> +int hibmc_fbdev_init(struct hibmc_drm_private *priv);
> +void hibmc_fbdev_fini(struct hibmc_drm_private *priv);
> +
>  int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
>                      struct drm_gem_object **obj);
> +struct hibmc_framebuffer *
> +hibmc_framebuffer_init(struct drm_device *dev,
> +                      const struct drm_mode_fb_cmd2 *mode_cmd,
> +                      struct drm_gem_object *obj);
> +
>  int hibmc_mm_init(struct hibmc_drm_private *hibmc);
>  void hibmc_mm_fini(struct hibmc_drm_private *hibmc);
>  int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr);
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
> new file mode 100644
> index 0000000..9b06967
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
> @@ -0,0 +1,267 @@
> +/* Hisilicon Hibmc SoC drm driver
> + *
> + * Based on the bochs drm driver.
> + *
> + * Copyright (c) 2016 Huawei Limited.
> + *
> + * Author:
> + *     Rongrong Zou <zourongrong@huawei.com>
> + *     Rongrong Zou <zourongrong@gmail.com>
> + *     Jianhua Li <lijianhua@huawei.com>
> + *
> + * 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.
> + *
> + */
> +
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_fb_helper.h>
> +
> +#include "hibmc_drm_drv.h"
> +
> +static int hibmcfb_create_object(
> +                               struct hibmc_drm_private *priv,
> +                               const struct drm_mode_fb_cmd2 *mode_cmd,
> +                               struct drm_gem_object **gobj_p)
> +{
> +       struct drm_gem_object *gobj;
> +       struct drm_device *dev = priv->dev;
> +       u32 size;
> +       int ret = 0;
> +
> +       size = mode_cmd->pitches[0] * mode_cmd->height;
> +       ret = hibmc_gem_create(dev, size, true, &gobj);
> +       if (ret)
> +               return ret;
> +
> +       *gobj_p = gobj;
> +       return ret;
> +}
> +
> +static struct fb_ops hibmc_drm_fb_ops = {
> +       .owner = THIS_MODULE,
> +       .fb_check_var = drm_fb_helper_check_var,
> +       .fb_set_par = drm_fb_helper_set_par,
> +       .fb_fillrect = drm_fb_helper_sys_fillrect,
> +       .fb_copyarea = drm_fb_helper_sys_copyarea,
> +       .fb_imageblit = drm_fb_helper_sys_imageblit,
> +       .fb_pan_display = drm_fb_helper_pan_display,
> +       .fb_blank = drm_fb_helper_blank,
> +       .fb_setcmap = drm_fb_helper_setcmap,
> +};
> +
> +static int hibmc_drm_fb_create(struct drm_fb_helper *helper,
> +                              struct drm_fb_helper_surface_size *sizes)
> +{
> +       struct hibmc_fbdev *hi_fbdev =
> +               container_of(helper, struct hibmc_fbdev, helper);
> +       struct hibmc_drm_private *priv = helper->dev->dev_private;
> +       struct fb_info *info;
> +       struct drm_mode_fb_cmd2 mode_cmd;
> +       struct drm_gem_object *gobj = NULL;
> +       int ret = 0;
> +       int ret1;
> +       size_t size;
> +       unsigned int bytes_per_pixel;
> +       struct hibmc_bo *bo = NULL;
> +
> +       DRM_DEBUG_DRIVER("surface width(%d), height(%d) and bpp(%d)\n",
> +                        sizes->surface_width, sizes->surface_height,
> +                        sizes->surface_bpp);
> +       sizes->surface_depth = 32;
> +
> +       bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8);
> +
> +       mode_cmd.width = sizes->surface_width;
> +       mode_cmd.height = sizes->surface_height;
> +       mode_cmd.pitches[0] = mode_cmd.width * bytes_per_pixel;
> +       mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
> +                                                         sizes->surface_depth);
> +
> +       size = PAGE_ALIGN(mode_cmd.pitches[0] * mode_cmd.height);
> +
> +       ret = hibmcfb_create_object(priv, &mode_cmd, &gobj);
> +       if (ret) {
> +               DRM_ERROR("failed to create fbcon backing object: %d\n", ret);
> +               return -ENOMEM;
> +       }
> +
> +       bo = gem_to_hibmc_bo(gobj);
> +
> +       ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
> +       if (ret) {
> +               DRM_ERROR("failed to reserve ttm_bo: %d\n", ret);
> +               goto out_unref_gem;
> +       }
> +
> +       ret = hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL);
> +       if (ret) {
> +               DRM_ERROR("failed to pin fbcon: %d\n", ret);
> +               goto out_unreserve_ttm_bo;
> +       }
> +
> +       ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
> +       if (ret) {
> +               DRM_ERROR("failed to kmap fbcon: %d\n", ret);
> +               goto out_unpin_bo;
> +       }
> +       ttm_bo_unreserve(&bo->bo);
> +
> +       info = drm_fb_helper_alloc_fbi(helper);
> +       if (IS_ERR(info)) {
> +               ret = PTR_ERR(info);
> +               DRM_ERROR("failed to allocate fbi: %d\n", ret);
> +               goto out_release_fbi;
> +       }
> +
> +       info->par = hi_fbdev;
> +
> +       hi_fbdev->fb = hibmc_framebuffer_init(priv->dev, &mode_cmd, gobj);
> +       if (IS_ERR(hi_fbdev->fb)) {
> +               ret = PTR_ERR(info);
> +               DRM_ERROR("failed to initialize framebuffer: %d\n", ret);
> +               goto out_release_fbi;
> +       }
> +
> +       priv->fbdev->size = size;
> +       hi_fbdev->helper.fb = &hi_fbdev->fb->fb;
> +
> +       strcpy(info->fix.id, "hibmcdrmfb");
> +
> +       info->flags = FBINFO_DEFAULT;
> +       info->fbops = &hibmc_drm_fb_ops;
> +
> +       drm_fb_helper_fill_fix(info, hi_fbdev->fb->fb.pitches[0],
> +                              hi_fbdev->fb->fb.depth);
> +       drm_fb_helper_fill_var(info, &priv->fbdev->helper, sizes->fb_width,
> +                              sizes->fb_height);
> +
> +       info->screen_base = bo->kmap.virtual;
> +       info->screen_size = size;
> +
> +       info->fix.smem_start = bo->bo.mem.bus.offset + bo->bo.mem.bus.base;
> +       info->fix.smem_len = size;
> +       return 0;
> +
> +out_release_fbi:
> +       drm_fb_helper_release_fbi(helper);
> +       ret1 = ttm_bo_reserve(&bo->bo, true, false, NULL);
> +       if (ret1) {
> +               DRM_ERROR("failed to rsv ttm_bo when release fbi: %d\n", ret1);
> +               goto out_unref_gem;
> +       }
> +       ttm_bo_kunmap(&bo->kmap);
> +out_unpin_bo:
> +       hibmc_bo_unpin(bo);
> +out_unreserve_ttm_bo:
> +       ttm_bo_unreserve(&bo->bo);
> +out_unref_gem:
> +       drm_gem_object_unreference_unlocked(gobj);
> +
> +       return ret;
> +}
> +
> +static void hibmc_fbdev_destroy(struct hibmc_fbdev *fbdev)
> +{
> +       struct hibmc_framebuffer *gfb = fbdev->fb;
> +       struct drm_fb_helper *fbh = &fbdev->helper;
> +
> +       drm_fb_helper_unregister_fbi(fbh);
> +       drm_fb_helper_release_fbi(fbh);
> +
> +       drm_fb_helper_fini(fbh);
> +
> +       if (gfb)
> +               drm_framebuffer_unreference(&gfb->fb);
> +}
> +
> +static const struct drm_fb_helper_funcs hibmc_fbdev_helper_funcs = {
> +       .fb_probe = hibmc_drm_fb_create,
> +};
> +
> +int hibmc_fbdev_init(struct hibmc_drm_private *priv)
> +{
> +       int ret;
> +       struct fb_var_screeninfo *var;
> +       struct fb_fix_screeninfo *fix;
> +       struct hibmc_fbdev *hifbdev;
> +
> +       hifbdev = devm_kzalloc(priv->dev->dev, sizeof(*hifbdev), GFP_KERNEL);
> +       if (!hifbdev) {
> +               DRM_ERROR("failed to allocate hibmc_fbdev\n");
> +               return -ENOMEM;
> +       }
> +
> +       priv->fbdev = hifbdev;
> +       drm_fb_helper_prepare(priv->dev, &hifbdev->helper,
> +                             &hibmc_fbdev_helper_funcs);
> +
> +       /* Now just one crtc and one channel */
> +       ret = drm_fb_helper_init(priv->dev,
> +                                &hifbdev->helper, 1, 1);
> +       if (ret) {
> +               DRM_ERROR("failed to initialize fb helper: %d\n", ret);
> +               return ret;
> +       }
> +
> +       ret = drm_fb_helper_single_add_all_connectors(&hifbdev->helper);
> +       if (ret) {
> +               DRM_ERROR("failed to add all connectors: %d\n", ret);
> +               goto fini;
> +       }
> +
> +       ret = drm_fb_helper_initial_config(&hifbdev->helper, 16);
> +       if (ret) {
> +               DRM_ERROR("failed to setup initial conn config: %d\n", ret);
> +               goto fini;
> +       }
> +
> +       var = &hifbdev->helper.fbdev->var;
> +       fix = &hifbdev->helper.fbdev->fix;
> +
> +       DRM_DEBUG_DRIVER("Member of info->var is :\n"
> +                        "xres=%d\n"
> +                        "yres=%d\n"
> +                        "xres_virtual=%d\n"
> +                        "yres_virtual=%d\n"
> +                        "xoffset=%d\n"
> +                        "yoffset=%d\n"
> +                        "bits_per_pixel=%d\n"
> +                        "...\n", var->xres, var->yres, var->xres_virtual,
> +                        var->yres_virtual, var->xoffset, var->yoffset,
> +                        var->bits_per_pixel);
> +       DRM_DEBUG_DRIVER("Member of info->fix is :\n"
> +                        "smem_start=%lx\n"
> +                        "smem_len=%d\n"
> +                        "type=%d\n"
> +                        "type_aux=%d\n"
> +                        "visual=%d\n"
> +                        "xpanstep=%d\n"
> +                        "ypanstep=%d\n"
> +                        "ywrapstep=%d\n"
> +                        "line_length=%d\n"
> +                        "accel=%d\n"
> +                        "capabilities=%d\n"
> +                        "...\n", fix->smem_start, fix->smem_len, fix->type,
> +                        fix->type_aux, fix->visual, fix->xpanstep,
> +                        fix->ypanstep, fix->ywrapstep, fix->line_length,
> +                        fix->accel, fix->capabilities);
> +
> +       return 0;
> +
> +fini:
> +       drm_fb_helper_fini(&hifbdev->helper);
> +       return ret;
> +}
> +
> +void hibmc_fbdev_fini(struct hibmc_drm_private *priv)
> +{
> +       if (!priv->fbdev)
> +               return;
> +
> +       hibmc_fbdev_destroy(priv->fbdev);
> +       priv->fbdev = NULL;
> +}
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> index 036d3ac..3ff65f4 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> @@ -16,6 +16,7 @@
>   *
>   */
>
> +#include <drm/drm_atomic_helper.h>
>  #include <ttm/ttm_page_alloc.h>
>
>  #include "hibmc_drm_drv.h"
> @@ -483,3 +484,69 @@ int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
>         drm_gem_object_unreference_unlocked(obj);
>         return 0;
>  }
> +
> +static void hibmc_user_framebuffer_destroy(struct drm_framebuffer *fb)
> +{
> +       struct hibmc_framebuffer *hibmc_fb = to_hibmc_framebuffer(fb);
> +
> +       drm_gem_object_unreference_unlocked(hibmc_fb->obj);
> +       drm_framebuffer_cleanup(fb);
> +       kfree(hibmc_fb);
> +}
> +
> +static const struct drm_framebuffer_funcs hibmc_fb_funcs = {
> +       .destroy = hibmc_user_framebuffer_destroy,
> +};
> +
> +struct hibmc_framebuffer *
> +hibmc_framebuffer_init(struct drm_device *dev,
> +                      const struct drm_mode_fb_cmd2 *mode_cmd,
> +                      struct drm_gem_object *obj)
> +{
> +       struct hibmc_framebuffer *hibmc_fb;
> +       int ret;
> +
> +       hibmc_fb = kzalloc(sizeof(*hibmc_fb), GFP_KERNEL);
> +       if (!hibmc_fb) {
> +               DRM_ERROR("failed to allocate hibmc_fb\n");
> +               return ERR_PTR(-ENOMEM);
> +       }
> +
> +       drm_helper_mode_fill_fb_struct(&hibmc_fb->fb, mode_cmd);
> +       hibmc_fb->obj = obj;
> +       ret = drm_framebuffer_init(dev, &hibmc_fb->fb, &hibmc_fb_funcs);
> +       if (ret) {
> +               DRM_ERROR("drm_framebuffer_init failed: %d\n", ret);
> +               kfree(hibmc_fb);
> +               return ERR_PTR(ret);
> +       }
> +
> +       return hibmc_fb;
> +}
> +
> +static struct drm_framebuffer *
> +hibmc_user_framebuffer_create(struct drm_device *dev,
> +                             struct drm_file *filp,
> +                             const struct drm_mode_fb_cmd2 *mode_cmd)
> +{
> +       struct drm_gem_object *obj;
> +       struct hibmc_framebuffer *hibmc_fb;
> +
> +       DRM_DEBUG_DRIVER("%dx%d, format %c%c%c%c\n",
> +                        mode_cmd->width, mode_cmd->height,
> +                        (mode_cmd->pixel_format) & 0xff,
> +                        (mode_cmd->pixel_format >> 8)  & 0xff,
> +                        (mode_cmd->pixel_format >> 16) & 0xff,
> +                        (mode_cmd->pixel_format >> 24) & 0xff);
> +
> +       obj = drm_gem_object_lookup(filp, mode_cmd->handles[0]);
> +       if (!obj)
> +               return ERR_PTR(-ENOENT);
> +
> +       hibmc_fb = hibmc_framebuffer_init(dev, mode_cmd, obj);
> +       if (IS_ERR(hibmc_fb)) {
> +               drm_gem_object_unreference_unlocked(obj);
> +               return ERR_PTR((long)hibmc_fb);
> +       }
> +       return &hibmc_fb->fb;
> +}
> --
> 1.9.1
>

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v7 3/7] drm/hisilicon/hibmc: Add support for frame buffer
@ 2016-11-16 15:56     ` Sean Paul
  0 siblings, 0 replies; 40+ messages in thread
From: Sean Paul @ 2016-11-16 15:56 UTC (permalink / raw)
  To: Rongrong Zou
  Cc: Mark Rutland, Tomeu Vizoso, Jonathan Corbet, Emil Velikov,
	linuxarm, dri-devel, james.xiong, guohanjun, lijianhua,
	Linux ARM Kernel, shenhui

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Add support for fbdev and kms fb management.
>
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  drivers/gpu/drm/hisilicon/hibmc/Makefile          |   2 +-
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   |   7 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   |  24 ++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 267 ++++++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       |  67 ++++++
>  5 files changed, 366 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> index 19ed0ef..ff77a7e 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> @@ -1,4 +1,4 @@
>  ccflags-y := -Iinclude/drm
> -hibmc-drm-y := hibmc_drm_drv.o hibmc_ttm.o
> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_ttm.o
>
>  obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> index 521f69f..4b52b29 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -202,6 +202,7 @@ static int hibmc_unload(struct drm_device *dev)
>  {
>         struct hibmc_drm_private *priv = dev->dev_private;
>
> +       hibmc_fbdev_fini(priv);
>         hibmc_mm_fini(priv);
>         dev->dev_private = NULL;
>         return 0;
> @@ -228,6 +229,12 @@ static int hibmc_load(struct drm_device *dev)
>         if (ret)
>                 goto err;
>
> +       ret = hibmc_fbdev_init(priv);
> +       if (ret) {
> +               DRM_ERROR("failed to initialize fbdev: %d\n", ret);
> +               goto err;
> +       }
> +
>         return 0;
>
>  err:
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> index dcd304d..d283d66 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -20,9 +20,21 @@
>  #define HIBMC_DRM_DRV_H
>
>  #include <drm/drmP.h>
> +#include <drm/drm_fb_helper.h>
>  #include <drm/drm_gem.h>
>  #include <drm/ttm/ttm_bo_driver.h>
>
> +struct hibmc_framebuffer {
> +       struct drm_framebuffer fb;
> +       struct drm_gem_object *obj;
> +};
> +
> +struct hibmc_fbdev {
> +       struct drm_fb_helper helper;
> +       struct hibmc_framebuffer *fb;
> +       int size;
> +};
> +
>  struct hibmc_drm_private {
>         /* hw */
>         void __iomem   *mmio;
> @@ -39,9 +51,13 @@ struct hibmc_drm_private {
>         struct ttm_bo_device bdev;
>         bool initialized;
>
> +       /* fbdev */
> +       struct hibmc_fbdev *fbdev;
>         bool mm_inited;
>  };
>
> +#define to_hibmc_framebuffer(x) container_of(x, struct hibmc_framebuffer, fb)
> +
>  struct hibmc_bo {
>         struct ttm_buffer_object bo;
>         struct ttm_placement placement;
> @@ -66,8 +82,16 @@ void hibmc_set_power_mode(struct hibmc_drm_private *priv,
>  void hibmc_set_current_gate(struct hibmc_drm_private *priv,
>                             unsigned int gate);
>
> +int hibmc_fbdev_init(struct hibmc_drm_private *priv);
> +void hibmc_fbdev_fini(struct hibmc_drm_private *priv);
> +
>  int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
>                      struct drm_gem_object **obj);
> +struct hibmc_framebuffer *
> +hibmc_framebuffer_init(struct drm_device *dev,
> +                      const struct drm_mode_fb_cmd2 *mode_cmd,
> +                      struct drm_gem_object *obj);
> +
>  int hibmc_mm_init(struct hibmc_drm_private *hibmc);
>  void hibmc_mm_fini(struct hibmc_drm_private *hibmc);
>  int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr);
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
> new file mode 100644
> index 0000000..9b06967
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
> @@ -0,0 +1,267 @@
> +/* Hisilicon Hibmc SoC drm driver
> + *
> + * Based on the bochs drm driver.
> + *
> + * Copyright (c) 2016 Huawei Limited.
> + *
> + * Author:
> + *     Rongrong Zou <zourongrong@huawei.com>
> + *     Rongrong Zou <zourongrong@gmail.com>
> + *     Jianhua Li <lijianhua@huawei.com>
> + *
> + * 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.
> + *
> + */
> +
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_fb_helper.h>
> +
> +#include "hibmc_drm_drv.h"
> +
> +static int hibmcfb_create_object(
> +                               struct hibmc_drm_private *priv,
> +                               const struct drm_mode_fb_cmd2 *mode_cmd,
> +                               struct drm_gem_object **gobj_p)
> +{
> +       struct drm_gem_object *gobj;
> +       struct drm_device *dev = priv->dev;
> +       u32 size;
> +       int ret = 0;
> +
> +       size = mode_cmd->pitches[0] * mode_cmd->height;
> +       ret = hibmc_gem_create(dev, size, true, &gobj);
> +       if (ret)
> +               return ret;
> +
> +       *gobj_p = gobj;
> +       return ret;
> +}
> +
> +static struct fb_ops hibmc_drm_fb_ops = {
> +       .owner = THIS_MODULE,
> +       .fb_check_var = drm_fb_helper_check_var,
> +       .fb_set_par = drm_fb_helper_set_par,
> +       .fb_fillrect = drm_fb_helper_sys_fillrect,
> +       .fb_copyarea = drm_fb_helper_sys_copyarea,
> +       .fb_imageblit = drm_fb_helper_sys_imageblit,
> +       .fb_pan_display = drm_fb_helper_pan_display,
> +       .fb_blank = drm_fb_helper_blank,
> +       .fb_setcmap = drm_fb_helper_setcmap,
> +};
> +
> +static int hibmc_drm_fb_create(struct drm_fb_helper *helper,
> +                              struct drm_fb_helper_surface_size *sizes)
> +{
> +       struct hibmc_fbdev *hi_fbdev =
> +               container_of(helper, struct hibmc_fbdev, helper);
> +       struct hibmc_drm_private *priv = helper->dev->dev_private;
> +       struct fb_info *info;
> +       struct drm_mode_fb_cmd2 mode_cmd;
> +       struct drm_gem_object *gobj = NULL;
> +       int ret = 0;
> +       int ret1;
> +       size_t size;
> +       unsigned int bytes_per_pixel;
> +       struct hibmc_bo *bo = NULL;
> +
> +       DRM_DEBUG_DRIVER("surface width(%d), height(%d) and bpp(%d)\n",
> +                        sizes->surface_width, sizes->surface_height,
> +                        sizes->surface_bpp);
> +       sizes->surface_depth = 32;
> +
> +       bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8);
> +
> +       mode_cmd.width = sizes->surface_width;
> +       mode_cmd.height = sizes->surface_height;
> +       mode_cmd.pitches[0] = mode_cmd.width * bytes_per_pixel;
> +       mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
> +                                                         sizes->surface_depth);
> +
> +       size = PAGE_ALIGN(mode_cmd.pitches[0] * mode_cmd.height);
> +
> +       ret = hibmcfb_create_object(priv, &mode_cmd, &gobj);
> +       if (ret) {
> +               DRM_ERROR("failed to create fbcon backing object: %d\n", ret);
> +               return -ENOMEM;
> +       }
> +
> +       bo = gem_to_hibmc_bo(gobj);
> +
> +       ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
> +       if (ret) {
> +               DRM_ERROR("failed to reserve ttm_bo: %d\n", ret);
> +               goto out_unref_gem;
> +       }
> +
> +       ret = hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL);
> +       if (ret) {
> +               DRM_ERROR("failed to pin fbcon: %d\n", ret);
> +               goto out_unreserve_ttm_bo;
> +       }
> +
> +       ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
> +       if (ret) {
> +               DRM_ERROR("failed to kmap fbcon: %d\n", ret);
> +               goto out_unpin_bo;
> +       }
> +       ttm_bo_unreserve(&bo->bo);
> +
> +       info = drm_fb_helper_alloc_fbi(helper);
> +       if (IS_ERR(info)) {
> +               ret = PTR_ERR(info);
> +               DRM_ERROR("failed to allocate fbi: %d\n", ret);
> +               goto out_release_fbi;
> +       }
> +
> +       info->par = hi_fbdev;
> +
> +       hi_fbdev->fb = hibmc_framebuffer_init(priv->dev, &mode_cmd, gobj);
> +       if (IS_ERR(hi_fbdev->fb)) {
> +               ret = PTR_ERR(info);
> +               DRM_ERROR("failed to initialize framebuffer: %d\n", ret);
> +               goto out_release_fbi;
> +       }
> +
> +       priv->fbdev->size = size;
> +       hi_fbdev->helper.fb = &hi_fbdev->fb->fb;
> +
> +       strcpy(info->fix.id, "hibmcdrmfb");
> +
> +       info->flags = FBINFO_DEFAULT;
> +       info->fbops = &hibmc_drm_fb_ops;
> +
> +       drm_fb_helper_fill_fix(info, hi_fbdev->fb->fb.pitches[0],
> +                              hi_fbdev->fb->fb.depth);
> +       drm_fb_helper_fill_var(info, &priv->fbdev->helper, sizes->fb_width,
> +                              sizes->fb_height);
> +
> +       info->screen_base = bo->kmap.virtual;
> +       info->screen_size = size;
> +
> +       info->fix.smem_start = bo->bo.mem.bus.offset + bo->bo.mem.bus.base;
> +       info->fix.smem_len = size;
> +       return 0;
> +
> +out_release_fbi:
> +       drm_fb_helper_release_fbi(helper);
> +       ret1 = ttm_bo_reserve(&bo->bo, true, false, NULL);
> +       if (ret1) {
> +               DRM_ERROR("failed to rsv ttm_bo when release fbi: %d\n", ret1);
> +               goto out_unref_gem;
> +       }
> +       ttm_bo_kunmap(&bo->kmap);
> +out_unpin_bo:
> +       hibmc_bo_unpin(bo);
> +out_unreserve_ttm_bo:
> +       ttm_bo_unreserve(&bo->bo);
> +out_unref_gem:
> +       drm_gem_object_unreference_unlocked(gobj);
> +
> +       return ret;
> +}
> +
> +static void hibmc_fbdev_destroy(struct hibmc_fbdev *fbdev)
> +{
> +       struct hibmc_framebuffer *gfb = fbdev->fb;
> +       struct drm_fb_helper *fbh = &fbdev->helper;
> +
> +       drm_fb_helper_unregister_fbi(fbh);
> +       drm_fb_helper_release_fbi(fbh);
> +
> +       drm_fb_helper_fini(fbh);
> +
> +       if (gfb)
> +               drm_framebuffer_unreference(&gfb->fb);
> +}
> +
> +static const struct drm_fb_helper_funcs hibmc_fbdev_helper_funcs = {
> +       .fb_probe = hibmc_drm_fb_create,
> +};
> +
> +int hibmc_fbdev_init(struct hibmc_drm_private *priv)
> +{
> +       int ret;
> +       struct fb_var_screeninfo *var;
> +       struct fb_fix_screeninfo *fix;
> +       struct hibmc_fbdev *hifbdev;
> +
> +       hifbdev = devm_kzalloc(priv->dev->dev, sizeof(*hifbdev), GFP_KERNEL);
> +       if (!hifbdev) {
> +               DRM_ERROR("failed to allocate hibmc_fbdev\n");
> +               return -ENOMEM;
> +       }
> +
> +       priv->fbdev = hifbdev;
> +       drm_fb_helper_prepare(priv->dev, &hifbdev->helper,
> +                             &hibmc_fbdev_helper_funcs);
> +
> +       /* Now just one crtc and one channel */
> +       ret = drm_fb_helper_init(priv->dev,
> +                                &hifbdev->helper, 1, 1);
> +       if (ret) {
> +               DRM_ERROR("failed to initialize fb helper: %d\n", ret);
> +               return ret;
> +       }
> +
> +       ret = drm_fb_helper_single_add_all_connectors(&hifbdev->helper);
> +       if (ret) {
> +               DRM_ERROR("failed to add all connectors: %d\n", ret);
> +               goto fini;
> +       }
> +
> +       ret = drm_fb_helper_initial_config(&hifbdev->helper, 16);
> +       if (ret) {
> +               DRM_ERROR("failed to setup initial conn config: %d\n", ret);
> +               goto fini;
> +       }
> +
> +       var = &hifbdev->helper.fbdev->var;
> +       fix = &hifbdev->helper.fbdev->fix;
> +
> +       DRM_DEBUG_DRIVER("Member of info->var is :\n"
> +                        "xres=%d\n"
> +                        "yres=%d\n"
> +                        "xres_virtual=%d\n"
> +                        "yres_virtual=%d\n"
> +                        "xoffset=%d\n"
> +                        "yoffset=%d\n"
> +                        "bits_per_pixel=%d\n"
> +                        "...\n", var->xres, var->yres, var->xres_virtual,
> +                        var->yres_virtual, var->xoffset, var->yoffset,
> +                        var->bits_per_pixel);
> +       DRM_DEBUG_DRIVER("Member of info->fix is :\n"
> +                        "smem_start=%lx\n"
> +                        "smem_len=%d\n"
> +                        "type=%d\n"
> +                        "type_aux=%d\n"
> +                        "visual=%d\n"
> +                        "xpanstep=%d\n"
> +                        "ypanstep=%d\n"
> +                        "ywrapstep=%d\n"
> +                        "line_length=%d\n"
> +                        "accel=%d\n"
> +                        "capabilities=%d\n"
> +                        "...\n", fix->smem_start, fix->smem_len, fix->type,
> +                        fix->type_aux, fix->visual, fix->xpanstep,
> +                        fix->ypanstep, fix->ywrapstep, fix->line_length,
> +                        fix->accel, fix->capabilities);
> +
> +       return 0;
> +
> +fini:
> +       drm_fb_helper_fini(&hifbdev->helper);
> +       return ret;
> +}
> +
> +void hibmc_fbdev_fini(struct hibmc_drm_private *priv)
> +{
> +       if (!priv->fbdev)
> +               return;
> +
> +       hibmc_fbdev_destroy(priv->fbdev);
> +       priv->fbdev = NULL;
> +}
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> index 036d3ac..3ff65f4 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> @@ -16,6 +16,7 @@
>   *
>   */
>
> +#include <drm/drm_atomic_helper.h>
>  #include <ttm/ttm_page_alloc.h>
>
>  #include "hibmc_drm_drv.h"
> @@ -483,3 +484,69 @@ int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
>         drm_gem_object_unreference_unlocked(obj);
>         return 0;
>  }
> +
> +static void hibmc_user_framebuffer_destroy(struct drm_framebuffer *fb)
> +{
> +       struct hibmc_framebuffer *hibmc_fb = to_hibmc_framebuffer(fb);
> +
> +       drm_gem_object_unreference_unlocked(hibmc_fb->obj);
> +       drm_framebuffer_cleanup(fb);
> +       kfree(hibmc_fb);
> +}
> +
> +static const struct drm_framebuffer_funcs hibmc_fb_funcs = {
> +       .destroy = hibmc_user_framebuffer_destroy,
> +};
> +
> +struct hibmc_framebuffer *
> +hibmc_framebuffer_init(struct drm_device *dev,
> +                      const struct drm_mode_fb_cmd2 *mode_cmd,
> +                      struct drm_gem_object *obj)
> +{
> +       struct hibmc_framebuffer *hibmc_fb;
> +       int ret;
> +
> +       hibmc_fb = kzalloc(sizeof(*hibmc_fb), GFP_KERNEL);
> +       if (!hibmc_fb) {
> +               DRM_ERROR("failed to allocate hibmc_fb\n");
> +               return ERR_PTR(-ENOMEM);
> +       }
> +
> +       drm_helper_mode_fill_fb_struct(&hibmc_fb->fb, mode_cmd);
> +       hibmc_fb->obj = obj;
> +       ret = drm_framebuffer_init(dev, &hibmc_fb->fb, &hibmc_fb_funcs);
> +       if (ret) {
> +               DRM_ERROR("drm_framebuffer_init failed: %d\n", ret);
> +               kfree(hibmc_fb);
> +               return ERR_PTR(ret);
> +       }
> +
> +       return hibmc_fb;
> +}
> +
> +static struct drm_framebuffer *
> +hibmc_user_framebuffer_create(struct drm_device *dev,
> +                             struct drm_file *filp,
> +                             const struct drm_mode_fb_cmd2 *mode_cmd)
> +{
> +       struct drm_gem_object *obj;
> +       struct hibmc_framebuffer *hibmc_fb;
> +
> +       DRM_DEBUG_DRIVER("%dx%d, format %c%c%c%c\n",
> +                        mode_cmd->width, mode_cmd->height,
> +                        (mode_cmd->pixel_format) & 0xff,
> +                        (mode_cmd->pixel_format >> 8)  & 0xff,
> +                        (mode_cmd->pixel_format >> 16) & 0xff,
> +                        (mode_cmd->pixel_format >> 24) & 0xff);
> +
> +       obj = drm_gem_object_lookup(filp, mode_cmd->handles[0]);
> +       if (!obj)
> +               return ERR_PTR(-ENOENT);
> +
> +       hibmc_fb = hibmc_framebuffer_init(dev, mode_cmd, obj);
> +       if (IS_ERR(hibmc_fb)) {
> +               drm_gem_object_unreference_unlocked(obj);
> +               return ERR_PTR((long)hibmc_fb);
> +       }
> +       return &hibmc_fb->fb;
> +}
> --
> 1.9.1
>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v7 4/7] drm/hisilicon/hibmc: Add support for display engine
  2016-11-16 13:43   ` Rongrong Zou
@ 2016-11-16 15:58     ` Sean Paul
  -1 siblings, 0 replies; 40+ messages in thread
From: Sean Paul @ 2016-11-16 15:58 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Add display engine function, crtc/plane is initialized here.
>
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c  | 477 ++++++++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  69 +++-
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |   6 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     |   6 +
>  5 files changed, 558 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> index ff77a7e..8e0cf72 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> @@ -1,4 +1,4 @@
>  ccflags-y := -Iinclude/drm
> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_ttm.o
> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_fbdev.o hibmc_ttm.o
>
>  obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
> new file mode 100644
> index 0000000..2a1386e
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
> @@ -0,0 +1,477 @@
> +/* Hisilicon Hibmc SoC drm driver
> + *
> + * Based on the bochs drm driver.
> + *
> + * Copyright (c) 2016 Huawei Limited.
> + *
> + * Author:
> + *     Rongrong Zou <zourongrong@huawei.com>
> + *     Rongrong Zou <zourongrong@gmail.com>
> + *     Jianhua Li <lijianhua@huawei.com>
> + *
> + * 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.
> + *
> + */
> +
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_plane_helper.h>
> +
> +#include "hibmc_drm_drv.h"
> +#include "hibmc_drm_regs.h"
> +
> +struct hibmc_display_panel_pll {
> +       unsigned long M;
> +       unsigned long N;
> +       unsigned long OD;
> +       unsigned long POD;
> +};
> +
> +struct hibmc_dislay_pll_config {
> +       unsigned long hdisplay;
> +       unsigned long vdisplay;
> +       u32 pll1_config_value;
> +       u32 pll2_config_value;
> +};
> +
> +static const struct hibmc_dislay_pll_config hibmc_pll_table[] = {
> +       {800, 600, CRT_PLL1_HS_40MHZ, CRT_PLL2_HS_40MHZ},
> +       {1024, 768, CRT_PLL1_HS_65MHZ, CRT_PLL2_HS_65MHZ},
> +       {1152, 864, CRT_PLL1_HS_80MHZ_1152, CRT_PLL2_HS_80MHZ},
> +       {1280, 768, CRT_PLL1_HS_80MHZ, CRT_PLL2_HS_80MHZ},
> +       {1280, 720, CRT_PLL1_HS_74MHZ, CRT_PLL2_HS_74MHZ},
> +       {1280, 960, CRT_PLL1_HS_108MHZ, CRT_PLL2_HS_108MHZ},
> +       {1280, 1024, CRT_PLL1_HS_108MHZ, CRT_PLL2_HS_108MHZ},
> +       {1600, 1200, CRT_PLL1_HS_162MHZ, CRT_PLL2_HS_162MHZ},
> +       {1920, 1080, CRT_PLL1_HS_148MHZ, CRT_PLL2_HS_148MHZ},
> +       {1920, 1200, CRT_PLL1_HS_193MHZ, CRT_PLL2_HS_193MHZ},
> +};
> +
> +#define PADDING(align, data) (((data) + (align) - 1) & (~((align) - 1)))
> +
> +static int hibmc_plane_atomic_check(struct drm_plane *plane,
> +                                   struct drm_plane_state *state)
> +{
> +       struct drm_framebuffer *fb = state->fb;
> +       struct drm_crtc *crtc = state->crtc;
> +       struct drm_crtc_state *crtc_state;
> +       u32 src_w = state->src_w >> 16;
> +       u32 src_h = state->src_h >> 16;
> +
> +       if (!crtc || !fb)
> +               return 0;
> +
> +       crtc_state = drm_atomic_get_crtc_state(state->state, crtc);
> +       if (IS_ERR(crtc_state))
> +               return PTR_ERR(crtc_state);
> +
> +       if (src_w != state->crtc_w || src_h != state->crtc_h) {
> +               DRM_DEBUG_ATOMIC("scale not support\n");
> +               return -EINVAL;
> +       }
> +
> +       if (state->crtc_x < 0 || state->crtc_y < 0) {
> +               DRM_DEBUG_ATOMIC("crtc_x/y of drm_plane state is invalid\n");
> +               return -EINVAL;
> +       }
> +
> +       if (state->crtc_x + state->crtc_w >
> +           crtc_state->adjusted_mode.hdisplay ||
> +           state->crtc_y + state->crtc_h >
> +           crtc_state->adjusted_mode.vdisplay) {
> +               DRM_DEBUG_ATOMIC("visible portion of plane is invalid\n");
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
> +static void hibmc_plane_atomic_update(struct drm_plane *plane,
> +                                     struct drm_plane_state *old_state)
> +{
> +       struct drm_plane_state  *state  = plane->state;
> +       u32 reg;
> +       int ret;
> +       u64 gpu_addr = 0;
> +       unsigned int line_l;
> +       struct hibmc_drm_private *priv = plane->dev->dev_private;
> +       struct hibmc_framebuffer *hibmc_fb;
> +       struct hibmc_bo *bo;
> +
> +       if (!state->fb)
> +               return;
> +
> +       hibmc_fb = to_hibmc_framebuffer(state->fb);
> +       bo = gem_to_hibmc_bo(hibmc_fb->obj);
> +       ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
> +       if (ret) {
> +               DRM_ERROR("failed to reserve ttm_bo: %d", ret);
> +               return;
> +       }
> +
> +       ret = hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
> +       ttm_bo_unreserve(&bo->bo);
> +       if (ret) {
> +               DRM_ERROR("failed to pin hibmc_bo: %d", ret);
> +               return;
> +       }
> +
> +       writel(gpu_addr, priv->mmio + HIBMC_CRT_FB_ADDRESS);
> +
> +       reg = state->fb->width * (state->fb->bits_per_pixel / 8);
> +       /* now line_pad is 16 */
> +       reg = PADDING(16, reg);
> +
> +       line_l = state->fb->width * state->fb->bits_per_pixel / 8;
> +       line_l = PADDING(16, line_l);
> +       writel(HIBMC_FIELD(HIBMC_CRT_FB_WIDTH_WIDTH, reg) |
> +              HIBMC_FIELD(HIBMC_CRT_FB_WIDTH_OFFS, line_l),
> +              priv->mmio + HIBMC_CRT_FB_WIDTH);
> +
> +       /* SET PIXEL FORMAT */
> +       reg = readl(priv->mmio + HIBMC_CRT_DISP_CTL);
> +       reg &= ~HIBMC_CRT_DISP_CTL_FORMAT_MASK;
> +       reg |= HIBMC_FIELD(HIBMC_CRT_DISP_CTL_FORMAT,
> +                          state->fb->bits_per_pixel / 16);
> +       writel(reg, priv->mmio + HIBMC_CRT_DISP_CTL);
> +}
> +
> +static const u32 channel_formats1[] = {
> +       DRM_FORMAT_RGB565, DRM_FORMAT_BGR565, DRM_FORMAT_RGB888,
> +       DRM_FORMAT_BGR888, DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888,
> +       DRM_FORMAT_RGBA8888, DRM_FORMAT_BGRA8888, DRM_FORMAT_ARGB8888,
> +       DRM_FORMAT_ABGR8888
> +};
> +
> +static struct drm_plane_funcs hibmc_plane_funcs = {
> +       .update_plane   = drm_atomic_helper_update_plane,
> +       .disable_plane  = drm_atomic_helper_disable_plane,
> +       .set_property = drm_atomic_helper_plane_set_property,
> +       .destroy = drm_plane_cleanup,
> +       .reset = drm_atomic_helper_plane_reset,
> +       .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
> +       .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
> +};
> +
> +static const struct drm_plane_helper_funcs hibmc_plane_helper_funcs = {
> +       .atomic_check = hibmc_plane_atomic_check,
> +       .atomic_update = hibmc_plane_atomic_update,
> +};
> +
> +static struct drm_plane *hibmc_plane_init(struct hibmc_drm_private *priv)
> +{
> +       struct drm_device *dev = priv->dev;
> +       struct drm_plane *plane;
> +       int ret = 0;
> +
> +       plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
> +       if (!plane) {
> +               DRM_ERROR("failed to alloc memory when init plane\n");
> +               return ERR_PTR(-ENOMEM);
> +       }
> +       /*
> +        * plane init
> +        * TODO: Now only support primary plane, overlay planes
> +        * need to do.
> +        */
> +       ret = drm_universal_plane_init(dev, plane, 1, &hibmc_plane_funcs,
> +                                      channel_formats1,
> +                                      ARRAY_SIZE(channel_formats1),
> +                                      DRM_PLANE_TYPE_PRIMARY,
> +                                      NULL);
> +       if (ret) {
> +               DRM_ERROR("failed to init plane: %d\n", ret);
> +               return ERR_PTR(ret);
> +       }
> +
> +       drm_plane_helper_add(plane, &hibmc_plane_helper_funcs);
> +       return plane;
> +}
> +
> +static void hibmc_crtc_enable(struct drm_crtc *crtc)
> +{
> +       unsigned int reg;
> +       struct hibmc_drm_private *priv = crtc->dev->dev_private;
> +
> +       hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_MODE0);
> +
> +       /* Enable display power gate & LOCALMEM power gate*/
> +       reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
> +       reg |= HIBMC_CURR_GATE_LOCALMEM(1);
> +       reg |= HIBMC_CURR_GATE_DISPLAY(1);
> +       hibmc_set_current_gate(priv, reg);
> +       drm_crtc_vblank_on(crtc);
> +}
> +
> +static void hibmc_crtc_disable(struct drm_crtc *crtc)
> +{
> +       unsigned int reg;
> +       struct hibmc_drm_private *priv = crtc->dev->dev_private;
> +
> +       drm_crtc_vblank_off(crtc);
> +
> +       hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_SLEEP);
> +
> +       /* Enable display power gate & LOCALMEM power gate*/
> +       reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
> +       reg |= HIBMC_CURR_GATE_LOCALMEM(0);
> +       reg |= HIBMC_CURR_GATE_DISPLAY(0);
> +       hibmc_set_current_gate(priv, reg);
> +}
> +
> +static unsigned int format_pll_reg(void)
> +{
> +       unsigned int pllreg = 0;
> +       struct hibmc_display_panel_pll pll = {0};
> +
> +       /*
> +        * Note that all PLL's have the same format. Here,
> +        * we just use Panel PLL parameter to work out the bit
> +        * fields in the register.On returning a 32 bit number, the value can
> +        * be applied to any PLL in the calling function.
> +        */
> +       pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_BYPASS, 0);
> +       pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_POWER, 1);
> +       pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_INPUT, 0);
> +       pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_POD, pll.POD);
> +       pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_OD, pll.OD);
> +       pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_N, pll.N);
> +       pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_M, pll.M);
> +
> +       return pllreg;
> +}
> +
> +static void set_vclock_hisilicon(struct drm_device *dev, unsigned long pll)
> +{
> +       u32 val;
> +       struct hibmc_drm_private *priv = dev->dev_private;
> +
> +       val = readl(priv->mmio + CRT_PLL1_HS);
> +       val &= ~(CRT_PLL1_HS_OUTER_BYPASS(1));
> +       writel(val, priv->mmio + CRT_PLL1_HS);
> +
> +       val = CRT_PLL1_HS_INTER_BYPASS(1) | CRT_PLL1_HS_POWERON(1);
> +       writel(val, priv->mmio + CRT_PLL1_HS);
> +
> +       writel(pll, priv->mmio + CRT_PLL1_HS);
> +
> +       usleep_range(1000, 2000);
> +
> +       val = pll & ~(CRT_PLL1_HS_POWERON(1));
> +       writel(val, priv->mmio + CRT_PLL1_HS);
> +
> +       usleep_range(1000, 2000);
> +
> +       val &= ~(CRT_PLL1_HS_INTER_BYPASS(1));
> +       writel(val, priv->mmio + CRT_PLL1_HS);
> +
> +       usleep_range(1000, 2000);
> +
> +       val |= CRT_PLL1_HS_OUTER_BYPASS(1);
> +       writel(val, priv->mmio + CRT_PLL1_HS);
> +}
> +
> +static void get_pll_config(unsigned long x, unsigned long y,
> +                          u32 *pll1, u32 *pll2)
> +{
> +       int i;
> +       int count = ARRAY_SIZE(hibmc_pll_table);
> +
> +       for (i = 0; i < count; i++) {
> +               if (hibmc_pll_table[i].hdisplay == x &&
> +                   hibmc_pll_table[i].vdisplay == y) {
> +                       *pll1 = hibmc_pll_table[i].pll1_config_value;
> +                       *pll2 = hibmc_pll_table[i].pll2_config_value;
> +                       return;
> +               }
> +       }
> +
> +       /* if found none, we use default value */
> +       *pll1 = CRT_PLL1_HS_25MHZ;
> +       *pll2 = CRT_PLL2_HS_25MHZ;
> +}
> +
> +/*
> + * This function takes care the extra registers and bit fields required to
> + * setup a mode in board.
> + * Explanation about Display Control register:
> + * FPGA only supports 7 predefined pixel clocks, and clock select is
> + * in bit 4:0 of new register 0x802a8.
> + */
> +static unsigned int display_ctrl_adjust(struct drm_device *dev,
> +                                       struct drm_display_mode *mode,
> +                                       unsigned int ctrl)
> +{
> +       unsigned long x, y;
> +       u32 pll1; /* bit[31:0] of PLL */
> +       u32 pll2; /* bit[63:32] of PLL */
> +       struct hibmc_drm_private *priv = dev->dev_private;
> +
> +       x = mode->hdisplay;
> +       y = mode->vdisplay;
> +
> +       get_pll_config(x, y, &pll1, &pll2);
> +       writel(pll2, priv->mmio + CRT_PLL2_HS);
> +       set_vclock_hisilicon(dev, pll1);
> +
> +       /*
> +        * Hisilicon has to set up the top-left and bottom-right
> +        * registers as well.
> +        * Note that normal chip only use those two register for
> +        * auto-centering mode.
> +        */
> +       writel(HIBMC_FIELD(HIBMC_CRT_AUTO_CENTERING_TL_TOP, 0) |
> +              HIBMC_FIELD(HIBMC_CRT_AUTO_CENTERING_TL_LEFT, 0),
> +              priv->mmio + HIBMC_CRT_AUTO_CENTERING_TL);
> +
> +       writel(HIBMC_FIELD(HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM, y - 1) |
> +              HIBMC_FIELD(HIBMC_CRT_AUTO_CENTERING_BR_RIGHT, x - 1),
> +              priv->mmio + HIBMC_CRT_AUTO_CENTERING_BR);
> +
> +       /*
> +        * Assume common fields in ctrl have been properly set before
> +        * calling this function.
> +        * This function only sets the extra fields in ctrl.
> +        */
> +
> +       /* Set bit 25 of display controller: Select CRT or VGA clock */
> +       ctrl &= ~HIBMC_CRT_DISP_CTL_CRTSELECT_MASK;
> +       ctrl &= ~HIBMC_CRT_DISP_CTL_CLOCK_PHASE_MASK;
> +
> +       ctrl |= HIBMC_CRT_DISP_CTL_CRTSELECT(HIBMC_CRTSELECT_CRT);
> +
> +       /* clock_phase_polarity is 0 */
> +       ctrl |= HIBMC_CRT_DISP_CTL_CLOCK_PHASE(0);
> +
> +       writel(ctrl, priv->mmio + HIBMC_CRT_DISP_CTL);
> +
> +       return ctrl;
> +}
> +
> +static void hibmc_crtc_mode_set_nofb(struct drm_crtc *crtc)
> +{
> +       unsigned int val;
> +       struct drm_display_mode *mode = &crtc->state->mode;
> +       struct drm_device *dev = crtc->dev;
> +       struct hibmc_drm_private *priv = dev->dev_private;
> +       int width = mode->hsync_end - mode->hsync_start;
> +       int height = mode->vsync_end - mode->vsync_start;
> +
> +       writel(format_pll_reg(), priv->mmio + HIBMC_CRT_PLL_CTRL);
> +       writel(HIBMC_FIELD(HIBMC_CRT_HORZ_TOTAL_TOTAL, mode->htotal - 1) |
> +              HIBMC_FIELD(HIBMC_CRT_HORZ_TOTAL_DISP_END, mode->hdisplay - 1),
> +              priv->mmio + HIBMC_CRT_HORZ_TOTAL);
> +
> +       writel(HIBMC_FIELD(HIBMC_CRT_HORZ_SYNC_WIDTH, width) |
> +              HIBMC_FIELD(HIBMC_CRT_HORZ_SYNC_START, mode->hsync_start - 1),
> +              priv->mmio + HIBMC_CRT_HORZ_SYNC);
> +
> +       writel(HIBMC_FIELD(HIBMC_CRT_VERT_TOTAL_TOTAL, mode->vtotal - 1) |
> +              HIBMC_FIELD(HIBMC_CRT_VERT_TOTAL_DISP_END, mode->vdisplay - 1),
> +              priv->mmio + HIBMC_CRT_VERT_TOTAL);
> +
> +       writel(HIBMC_FIELD(HIBMC_CRT_VERT_SYNC_HEIGHT, height) |
> +              HIBMC_FIELD(HIBMC_CRT_VERT_SYNC_START, mode->vsync_start - 1),
> +              priv->mmio + HIBMC_CRT_VERT_SYNC);
> +
> +       val = HIBMC_FIELD(HIBMC_CRT_DISP_CTL_VSYNC_PHASE, 0);
> +       val |= HIBMC_FIELD(HIBMC_CRT_DISP_CTL_HSYNC_PHASE, 0);
> +       val |= HIBMC_CRT_DISP_CTL_TIMING(1);
> +       val |= HIBMC_CRT_DISP_CTL_PLANE(1);
> +
> +       display_ctrl_adjust(dev, mode, val);
> +}
> +
> +static void hibmc_crtc_atomic_begin(struct drm_crtc *crtc,
> +                                   struct drm_crtc_state *old_state)
> +{
> +       unsigned int reg;
> +       struct drm_device *dev = crtc->dev;
> +       struct hibmc_drm_private *priv = dev->dev_private;
> +
> +       hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_MODE0);
> +
> +       /* Enable display power gate & LOCALMEM power gate*/
> +       reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
> +       reg |= HIBMC_CURR_GATE_DISPLAY(1);
> +       reg |= HIBMC_CURR_GATE_LOCALMEM(1);
> +       hibmc_set_current_gate(priv, reg);
> +
> +       /* We can add more initialization as needed. */
> +}
> +
> +static void hibmc_crtc_atomic_flush(struct drm_crtc *crtc,
> +                                   struct drm_crtc_state *old_state)
> +
> +{
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&crtc->dev->event_lock, flags);
> +       if (crtc->state->event)
> +               drm_crtc_send_vblank_event(crtc, crtc->state->event);
> +       crtc->state->event = NULL;
> +       spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
> +}
> +
> +static const struct drm_crtc_funcs hibmc_crtc_funcs = {
> +       .page_flip = drm_atomic_helper_page_flip,
> +       .set_config = drm_atomic_helper_set_config,
> +       .destroy = drm_crtc_cleanup,
> +       .reset = drm_atomic_helper_crtc_reset,
> +       .atomic_duplicate_state =  drm_atomic_helper_crtc_duplicate_state,
> +       .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
> +};
> +
> +static const struct drm_crtc_helper_funcs hibmc_crtc_helper_funcs = {
> +       .enable         = hibmc_crtc_enable,
> +       .disable        = hibmc_crtc_disable,
> +       .mode_set_nofb  = hibmc_crtc_mode_set_nofb,
> +       .atomic_begin   = hibmc_crtc_atomic_begin,
> +       .atomic_flush   = hibmc_crtc_atomic_flush,
> +};
> +
> +int hibmc_de_init(struct hibmc_drm_private *priv)
> +{
> +       struct drm_device *dev = priv->dev;
> +       struct drm_crtc *crtc;
> +       struct drm_plane *plane;
> +       int ret;
> +
> +       plane = hibmc_plane_init(priv);
> +       if (IS_ERR(plane)) {
> +               DRM_ERROR("failed to create plane: %ld\n", PTR_ERR(plane));
> +               return PTR_ERR(plane);
> +       }
> +
> +       crtc = devm_kzalloc(dev->dev, sizeof(*crtc), GFP_KERNEL);
> +       if (!crtc) {
> +               DRM_ERROR("failed to alloc memory when init crtc\n");
> +               return -ENOMEM;
> +       }
> +
> +       ret = drm_crtc_init_with_planes(dev, crtc, plane,
> +                                       NULL, &hibmc_crtc_funcs, NULL);
> +       if (ret) {
> +               DRM_ERROR("failed to init crtc: %d\n", ret);
> +               return ret;
> +       }
> +
> +       ret = drm_mode_crtc_set_gamma_size(crtc, 256);
> +       if (ret) {
> +               DRM_ERROR("failed to set gamma size: %d\n", ret);
> +               return ret;
> +       }
> +       drm_crtc_helper_add(crtc, &hibmc_crtc_helper_funcs);
> +
> +       return 0;
> +}
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> index 4b52b29..9de3564 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -19,6 +19,9 @@
>  #include <linux/console.h>
>  #include <linux/module.h>
>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +
>  #include "hibmc_drm_drv.h"
>  #include "hibmc_drm_regs.h"
>
> @@ -44,7 +47,8 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>  }
>
>  static struct drm_driver hibmc_driver = {
> -       .driver_features        = DRIVER_GEM,
> +       .driver_features        = DRIVER_GEM | DRIVER_MODESET |
> +                                 DRIVER_ATOMIC,
>         .fops                   = &hibmc_fops,
>         .name                   = "hibmc",
>         .date                   = "20160828",
> @@ -62,11 +66,31 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>
>  static int hibmc_pm_suspend(struct device *dev)
>  {
> +       struct pci_dev *pdev = to_pci_dev(dev);
> +       struct drm_device *drm_dev = pci_get_drvdata(pdev);
> +       struct hibmc_drm_private *priv = drm_dev->dev_private;
> +
> +       drm_kms_helper_poll_disable(drm_dev);
> +       priv->suspend_state = drm_atomic_helper_suspend(drm_dev);
> +       if (IS_ERR(priv->suspend_state)) {
> +               DRM_ERROR("drm_atomic_helper_suspend failed: %ld\n",
> +                         PTR_ERR(priv->suspend_state));
> +               drm_kms_helper_poll_enable(drm_dev);
> +               return PTR_ERR(priv->suspend_state);
> +       }
> +
>         return 0;
>  }
>
>  static int hibmc_pm_resume(struct device *dev)
>  {
> +       struct pci_dev *pdev = to_pci_dev(dev);
> +       struct drm_device *drm_dev = pci_get_drvdata(pdev);
> +       struct hibmc_drm_private *priv = drm_dev->dev_private;
> +
> +       drm_atomic_helper_resume(drm_dev, priv->suspend_state);
> +       drm_kms_helper_poll_enable(drm_dev);
> +
>         return 0;
>  }
>
> @@ -75,6 +99,41 @@ static int hibmc_pm_resume(struct device *dev)
>                                 hibmc_pm_resume)
>  };
>
> +static int hibmc_kms_init(struct hibmc_drm_private *priv)
> +{
> +       int ret;
> +
> +       drm_mode_config_init(priv->dev);
> +       priv->mode_config_initialized = true;
> +
> +       priv->dev->mode_config.min_width = 0;
> +       priv->dev->mode_config.min_height = 0;
> +       priv->dev->mode_config.max_width = 1920;
> +       priv->dev->mode_config.max_height = 1440;
> +
> +       priv->dev->mode_config.fb_base = priv->fb_base;
> +       priv->dev->mode_config.preferred_depth = 24;
> +       priv->dev->mode_config.prefer_shadow = 0;
> +
> +       priv->dev->mode_config.funcs = (void *)&hibmc_mode_funcs;
> +
> +       ret = hibmc_de_init(priv);
> +       if (ret) {
> +               DRM_ERROR("failed to init de: %d\n", ret);
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +static void hibmc_kms_fini(struct hibmc_drm_private *priv)
> +{
> +       if (priv->mode_config_initialized) {
> +               drm_mode_config_cleanup(priv->dev);
> +               priv->mode_config_initialized = false;
> +       }
> +}
> +
>  /*
>   * It can operate in one of three modes: 0, 1 or Sleep.
>   */
> @@ -203,6 +262,7 @@ static int hibmc_unload(struct drm_device *dev)
>         struct hibmc_drm_private *priv = dev->dev_private;
>
>         hibmc_fbdev_fini(priv);
> +       hibmc_kms_fini(priv);
>         hibmc_mm_fini(priv);
>         dev->dev_private = NULL;
>         return 0;
> @@ -229,6 +289,13 @@ static int hibmc_load(struct drm_device *dev)
>         if (ret)
>                 goto err;
>
> +       ret = hibmc_kms_init(priv);
> +       if (ret)
> +               goto err;
> +
> +       /* reset all the states of crtc/plane/encoder/connector */
> +       drm_mode_config_reset(dev);
> +
>         ret = hibmc_fbdev_init(priv);
>         if (ret) {
>                 DRM_ERROR("failed to initialize fbdev: %d\n", ret);
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> index d283d66..87af1eb 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -20,6 +20,7 @@
>  #define HIBMC_DRM_DRV_H
>
>  #include <drm/drmP.h>
> +#include <drm/drm_atomic.h>
>  #include <drm/drm_fb_helper.h>
>  #include <drm/drm_gem.h>
>  #include <drm/ttm/ttm_bo_driver.h>
> @@ -44,6 +45,8 @@ struct hibmc_drm_private {
>
>         /* drm */
>         struct drm_device  *dev;
> +       bool mode_config_initialized;
> +       struct drm_atomic_state *suspend_state;
>
>         /* ttm */
>         struct drm_global_reference mem_global_ref;
> @@ -82,6 +85,7 @@ void hibmc_set_power_mode(struct hibmc_drm_private *priv,
>  void hibmc_set_current_gate(struct hibmc_drm_private *priv,
>                             unsigned int gate);
>
> +int hibmc_de_init(struct hibmc_drm_private *priv);
>  int hibmc_fbdev_init(struct hibmc_drm_private *priv);
>  void hibmc_fbdev_fini(struct hibmc_drm_private *priv);
>
> @@ -103,4 +107,6 @@ int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
>                            u32 handle, u64 *offset);
>  int hibmc_mmap(struct file *filp, struct vm_area_struct *vma);
>
> +extern const struct drm_mode_config_funcs hibmc_mode_funcs;
> +
>  #endif
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> index 3ff65f4..e76abf6 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> @@ -550,3 +550,9 @@ struct hibmc_framebuffer *
>         }
>         return &hibmc_fb->fb;
>  }
> +
> +const struct drm_mode_config_funcs hibmc_mode_funcs = {
> +       .atomic_check = drm_atomic_helper_check,
> +       .atomic_commit = drm_atomic_helper_commit,
> +       .fb_create = hibmc_user_framebuffer_create,
> +};
> --
> 1.9.1
>

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v7 4/7] drm/hisilicon/hibmc: Add support for display engine
@ 2016-11-16 15:58     ` Sean Paul
  0 siblings, 0 replies; 40+ messages in thread
From: Sean Paul @ 2016-11-16 15:58 UTC (permalink / raw)
  To: Rongrong Zou
  Cc: Mark Rutland, Tomeu Vizoso, seanpaul, Jonathan Corbet,
	Emil Velikov, linuxarm, dri-devel, james.xiong, guohanjun,
	lijianhua, Linux ARM Kernel, shenhui

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Add display engine function, crtc/plane is initialized here.
>
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c  | 477 ++++++++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  69 +++-
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |   6 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     |   6 +
>  5 files changed, 558 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> index ff77a7e..8e0cf72 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> @@ -1,4 +1,4 @@
>  ccflags-y := -Iinclude/drm
> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_ttm.o
> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_fbdev.o hibmc_ttm.o
>
>  obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
> new file mode 100644
> index 0000000..2a1386e
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
> @@ -0,0 +1,477 @@
> +/* Hisilicon Hibmc SoC drm driver
> + *
> + * Based on the bochs drm driver.
> + *
> + * Copyright (c) 2016 Huawei Limited.
> + *
> + * Author:
> + *     Rongrong Zou <zourongrong@huawei.com>
> + *     Rongrong Zou <zourongrong@gmail.com>
> + *     Jianhua Li <lijianhua@huawei.com>
> + *
> + * 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.
> + *
> + */
> +
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_plane_helper.h>
> +
> +#include "hibmc_drm_drv.h"
> +#include "hibmc_drm_regs.h"
> +
> +struct hibmc_display_panel_pll {
> +       unsigned long M;
> +       unsigned long N;
> +       unsigned long OD;
> +       unsigned long POD;
> +};
> +
> +struct hibmc_dislay_pll_config {
> +       unsigned long hdisplay;
> +       unsigned long vdisplay;
> +       u32 pll1_config_value;
> +       u32 pll2_config_value;
> +};
> +
> +static const struct hibmc_dislay_pll_config hibmc_pll_table[] = {
> +       {800, 600, CRT_PLL1_HS_40MHZ, CRT_PLL2_HS_40MHZ},
> +       {1024, 768, CRT_PLL1_HS_65MHZ, CRT_PLL2_HS_65MHZ},
> +       {1152, 864, CRT_PLL1_HS_80MHZ_1152, CRT_PLL2_HS_80MHZ},
> +       {1280, 768, CRT_PLL1_HS_80MHZ, CRT_PLL2_HS_80MHZ},
> +       {1280, 720, CRT_PLL1_HS_74MHZ, CRT_PLL2_HS_74MHZ},
> +       {1280, 960, CRT_PLL1_HS_108MHZ, CRT_PLL2_HS_108MHZ},
> +       {1280, 1024, CRT_PLL1_HS_108MHZ, CRT_PLL2_HS_108MHZ},
> +       {1600, 1200, CRT_PLL1_HS_162MHZ, CRT_PLL2_HS_162MHZ},
> +       {1920, 1080, CRT_PLL1_HS_148MHZ, CRT_PLL2_HS_148MHZ},
> +       {1920, 1200, CRT_PLL1_HS_193MHZ, CRT_PLL2_HS_193MHZ},
> +};
> +
> +#define PADDING(align, data) (((data) + (align) - 1) & (~((align) - 1)))
> +
> +static int hibmc_plane_atomic_check(struct drm_plane *plane,
> +                                   struct drm_plane_state *state)
> +{
> +       struct drm_framebuffer *fb = state->fb;
> +       struct drm_crtc *crtc = state->crtc;
> +       struct drm_crtc_state *crtc_state;
> +       u32 src_w = state->src_w >> 16;
> +       u32 src_h = state->src_h >> 16;
> +
> +       if (!crtc || !fb)
> +               return 0;
> +
> +       crtc_state = drm_atomic_get_crtc_state(state->state, crtc);
> +       if (IS_ERR(crtc_state))
> +               return PTR_ERR(crtc_state);
> +
> +       if (src_w != state->crtc_w || src_h != state->crtc_h) {
> +               DRM_DEBUG_ATOMIC("scale not support\n");
> +               return -EINVAL;
> +       }
> +
> +       if (state->crtc_x < 0 || state->crtc_y < 0) {
> +               DRM_DEBUG_ATOMIC("crtc_x/y of drm_plane state is invalid\n");
> +               return -EINVAL;
> +       }
> +
> +       if (state->crtc_x + state->crtc_w >
> +           crtc_state->adjusted_mode.hdisplay ||
> +           state->crtc_y + state->crtc_h >
> +           crtc_state->adjusted_mode.vdisplay) {
> +               DRM_DEBUG_ATOMIC("visible portion of plane is invalid\n");
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
> +static void hibmc_plane_atomic_update(struct drm_plane *plane,
> +                                     struct drm_plane_state *old_state)
> +{
> +       struct drm_plane_state  *state  = plane->state;
> +       u32 reg;
> +       int ret;
> +       u64 gpu_addr = 0;
> +       unsigned int line_l;
> +       struct hibmc_drm_private *priv = plane->dev->dev_private;
> +       struct hibmc_framebuffer *hibmc_fb;
> +       struct hibmc_bo *bo;
> +
> +       if (!state->fb)
> +               return;
> +
> +       hibmc_fb = to_hibmc_framebuffer(state->fb);
> +       bo = gem_to_hibmc_bo(hibmc_fb->obj);
> +       ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
> +       if (ret) {
> +               DRM_ERROR("failed to reserve ttm_bo: %d", ret);
> +               return;
> +       }
> +
> +       ret = hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
> +       ttm_bo_unreserve(&bo->bo);
> +       if (ret) {
> +               DRM_ERROR("failed to pin hibmc_bo: %d", ret);
> +               return;
> +       }
> +
> +       writel(gpu_addr, priv->mmio + HIBMC_CRT_FB_ADDRESS);
> +
> +       reg = state->fb->width * (state->fb->bits_per_pixel / 8);
> +       /* now line_pad is 16 */
> +       reg = PADDING(16, reg);
> +
> +       line_l = state->fb->width * state->fb->bits_per_pixel / 8;
> +       line_l = PADDING(16, line_l);
> +       writel(HIBMC_FIELD(HIBMC_CRT_FB_WIDTH_WIDTH, reg) |
> +              HIBMC_FIELD(HIBMC_CRT_FB_WIDTH_OFFS, line_l),
> +              priv->mmio + HIBMC_CRT_FB_WIDTH);
> +
> +       /* SET PIXEL FORMAT */
> +       reg = readl(priv->mmio + HIBMC_CRT_DISP_CTL);
> +       reg &= ~HIBMC_CRT_DISP_CTL_FORMAT_MASK;
> +       reg |= HIBMC_FIELD(HIBMC_CRT_DISP_CTL_FORMAT,
> +                          state->fb->bits_per_pixel / 16);
> +       writel(reg, priv->mmio + HIBMC_CRT_DISP_CTL);
> +}
> +
> +static const u32 channel_formats1[] = {
> +       DRM_FORMAT_RGB565, DRM_FORMAT_BGR565, DRM_FORMAT_RGB888,
> +       DRM_FORMAT_BGR888, DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888,
> +       DRM_FORMAT_RGBA8888, DRM_FORMAT_BGRA8888, DRM_FORMAT_ARGB8888,
> +       DRM_FORMAT_ABGR8888
> +};
> +
> +static struct drm_plane_funcs hibmc_plane_funcs = {
> +       .update_plane   = drm_atomic_helper_update_plane,
> +       .disable_plane  = drm_atomic_helper_disable_plane,
> +       .set_property = drm_atomic_helper_plane_set_property,
> +       .destroy = drm_plane_cleanup,
> +       .reset = drm_atomic_helper_plane_reset,
> +       .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
> +       .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
> +};
> +
> +static const struct drm_plane_helper_funcs hibmc_plane_helper_funcs = {
> +       .atomic_check = hibmc_plane_atomic_check,
> +       .atomic_update = hibmc_plane_atomic_update,
> +};
> +
> +static struct drm_plane *hibmc_plane_init(struct hibmc_drm_private *priv)
> +{
> +       struct drm_device *dev = priv->dev;
> +       struct drm_plane *plane;
> +       int ret = 0;
> +
> +       plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
> +       if (!plane) {
> +               DRM_ERROR("failed to alloc memory when init plane\n");
> +               return ERR_PTR(-ENOMEM);
> +       }
> +       /*
> +        * plane init
> +        * TODO: Now only support primary plane, overlay planes
> +        * need to do.
> +        */
> +       ret = drm_universal_plane_init(dev, plane, 1, &hibmc_plane_funcs,
> +                                      channel_formats1,
> +                                      ARRAY_SIZE(channel_formats1),
> +                                      DRM_PLANE_TYPE_PRIMARY,
> +                                      NULL);
> +       if (ret) {
> +               DRM_ERROR("failed to init plane: %d\n", ret);
> +               return ERR_PTR(ret);
> +       }
> +
> +       drm_plane_helper_add(plane, &hibmc_plane_helper_funcs);
> +       return plane;
> +}
> +
> +static void hibmc_crtc_enable(struct drm_crtc *crtc)
> +{
> +       unsigned int reg;
> +       struct hibmc_drm_private *priv = crtc->dev->dev_private;
> +
> +       hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_MODE0);
> +
> +       /* Enable display power gate & LOCALMEM power gate*/
> +       reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
> +       reg |= HIBMC_CURR_GATE_LOCALMEM(1);
> +       reg |= HIBMC_CURR_GATE_DISPLAY(1);
> +       hibmc_set_current_gate(priv, reg);
> +       drm_crtc_vblank_on(crtc);
> +}
> +
> +static void hibmc_crtc_disable(struct drm_crtc *crtc)
> +{
> +       unsigned int reg;
> +       struct hibmc_drm_private *priv = crtc->dev->dev_private;
> +
> +       drm_crtc_vblank_off(crtc);
> +
> +       hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_SLEEP);
> +
> +       /* Enable display power gate & LOCALMEM power gate*/
> +       reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
> +       reg |= HIBMC_CURR_GATE_LOCALMEM(0);
> +       reg |= HIBMC_CURR_GATE_DISPLAY(0);
> +       hibmc_set_current_gate(priv, reg);
> +}
> +
> +static unsigned int format_pll_reg(void)
> +{
> +       unsigned int pllreg = 0;
> +       struct hibmc_display_panel_pll pll = {0};
> +
> +       /*
> +        * Note that all PLL's have the same format. Here,
> +        * we just use Panel PLL parameter to work out the bit
> +        * fields in the register.On returning a 32 bit number, the value can
> +        * be applied to any PLL in the calling function.
> +        */
> +       pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_BYPASS, 0);
> +       pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_POWER, 1);
> +       pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_INPUT, 0);
> +       pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_POD, pll.POD);
> +       pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_OD, pll.OD);
> +       pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_N, pll.N);
> +       pllreg |= HIBMC_FIELD(HIBMC_PLL_CTRL_M, pll.M);
> +
> +       return pllreg;
> +}
> +
> +static void set_vclock_hisilicon(struct drm_device *dev, unsigned long pll)
> +{
> +       u32 val;
> +       struct hibmc_drm_private *priv = dev->dev_private;
> +
> +       val = readl(priv->mmio + CRT_PLL1_HS);
> +       val &= ~(CRT_PLL1_HS_OUTER_BYPASS(1));
> +       writel(val, priv->mmio + CRT_PLL1_HS);
> +
> +       val = CRT_PLL1_HS_INTER_BYPASS(1) | CRT_PLL1_HS_POWERON(1);
> +       writel(val, priv->mmio + CRT_PLL1_HS);
> +
> +       writel(pll, priv->mmio + CRT_PLL1_HS);
> +
> +       usleep_range(1000, 2000);
> +
> +       val = pll & ~(CRT_PLL1_HS_POWERON(1));
> +       writel(val, priv->mmio + CRT_PLL1_HS);
> +
> +       usleep_range(1000, 2000);
> +
> +       val &= ~(CRT_PLL1_HS_INTER_BYPASS(1));
> +       writel(val, priv->mmio + CRT_PLL1_HS);
> +
> +       usleep_range(1000, 2000);
> +
> +       val |= CRT_PLL1_HS_OUTER_BYPASS(1);
> +       writel(val, priv->mmio + CRT_PLL1_HS);
> +}
> +
> +static void get_pll_config(unsigned long x, unsigned long y,
> +                          u32 *pll1, u32 *pll2)
> +{
> +       int i;
> +       int count = ARRAY_SIZE(hibmc_pll_table);
> +
> +       for (i = 0; i < count; i++) {
> +               if (hibmc_pll_table[i].hdisplay == x &&
> +                   hibmc_pll_table[i].vdisplay == y) {
> +                       *pll1 = hibmc_pll_table[i].pll1_config_value;
> +                       *pll2 = hibmc_pll_table[i].pll2_config_value;
> +                       return;
> +               }
> +       }
> +
> +       /* if found none, we use default value */
> +       *pll1 = CRT_PLL1_HS_25MHZ;
> +       *pll2 = CRT_PLL2_HS_25MHZ;
> +}
> +
> +/*
> + * This function takes care the extra registers and bit fields required to
> + * setup a mode in board.
> + * Explanation about Display Control register:
> + * FPGA only supports 7 predefined pixel clocks, and clock select is
> + * in bit 4:0 of new register 0x802a8.
> + */
> +static unsigned int display_ctrl_adjust(struct drm_device *dev,
> +                                       struct drm_display_mode *mode,
> +                                       unsigned int ctrl)
> +{
> +       unsigned long x, y;
> +       u32 pll1; /* bit[31:0] of PLL */
> +       u32 pll2; /* bit[63:32] of PLL */
> +       struct hibmc_drm_private *priv = dev->dev_private;
> +
> +       x = mode->hdisplay;
> +       y = mode->vdisplay;
> +
> +       get_pll_config(x, y, &pll1, &pll2);
> +       writel(pll2, priv->mmio + CRT_PLL2_HS);
> +       set_vclock_hisilicon(dev, pll1);
> +
> +       /*
> +        * Hisilicon has to set up the top-left and bottom-right
> +        * registers as well.
> +        * Note that normal chip only use those two register for
> +        * auto-centering mode.
> +        */
> +       writel(HIBMC_FIELD(HIBMC_CRT_AUTO_CENTERING_TL_TOP, 0) |
> +              HIBMC_FIELD(HIBMC_CRT_AUTO_CENTERING_TL_LEFT, 0),
> +              priv->mmio + HIBMC_CRT_AUTO_CENTERING_TL);
> +
> +       writel(HIBMC_FIELD(HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM, y - 1) |
> +              HIBMC_FIELD(HIBMC_CRT_AUTO_CENTERING_BR_RIGHT, x - 1),
> +              priv->mmio + HIBMC_CRT_AUTO_CENTERING_BR);
> +
> +       /*
> +        * Assume common fields in ctrl have been properly set before
> +        * calling this function.
> +        * This function only sets the extra fields in ctrl.
> +        */
> +
> +       /* Set bit 25 of display controller: Select CRT or VGA clock */
> +       ctrl &= ~HIBMC_CRT_DISP_CTL_CRTSELECT_MASK;
> +       ctrl &= ~HIBMC_CRT_DISP_CTL_CLOCK_PHASE_MASK;
> +
> +       ctrl |= HIBMC_CRT_DISP_CTL_CRTSELECT(HIBMC_CRTSELECT_CRT);
> +
> +       /* clock_phase_polarity is 0 */
> +       ctrl |= HIBMC_CRT_DISP_CTL_CLOCK_PHASE(0);
> +
> +       writel(ctrl, priv->mmio + HIBMC_CRT_DISP_CTL);
> +
> +       return ctrl;
> +}
> +
> +static void hibmc_crtc_mode_set_nofb(struct drm_crtc *crtc)
> +{
> +       unsigned int val;
> +       struct drm_display_mode *mode = &crtc->state->mode;
> +       struct drm_device *dev = crtc->dev;
> +       struct hibmc_drm_private *priv = dev->dev_private;
> +       int width = mode->hsync_end - mode->hsync_start;
> +       int height = mode->vsync_end - mode->vsync_start;
> +
> +       writel(format_pll_reg(), priv->mmio + HIBMC_CRT_PLL_CTRL);
> +       writel(HIBMC_FIELD(HIBMC_CRT_HORZ_TOTAL_TOTAL, mode->htotal - 1) |
> +              HIBMC_FIELD(HIBMC_CRT_HORZ_TOTAL_DISP_END, mode->hdisplay - 1),
> +              priv->mmio + HIBMC_CRT_HORZ_TOTAL);
> +
> +       writel(HIBMC_FIELD(HIBMC_CRT_HORZ_SYNC_WIDTH, width) |
> +              HIBMC_FIELD(HIBMC_CRT_HORZ_SYNC_START, mode->hsync_start - 1),
> +              priv->mmio + HIBMC_CRT_HORZ_SYNC);
> +
> +       writel(HIBMC_FIELD(HIBMC_CRT_VERT_TOTAL_TOTAL, mode->vtotal - 1) |
> +              HIBMC_FIELD(HIBMC_CRT_VERT_TOTAL_DISP_END, mode->vdisplay - 1),
> +              priv->mmio + HIBMC_CRT_VERT_TOTAL);
> +
> +       writel(HIBMC_FIELD(HIBMC_CRT_VERT_SYNC_HEIGHT, height) |
> +              HIBMC_FIELD(HIBMC_CRT_VERT_SYNC_START, mode->vsync_start - 1),
> +              priv->mmio + HIBMC_CRT_VERT_SYNC);
> +
> +       val = HIBMC_FIELD(HIBMC_CRT_DISP_CTL_VSYNC_PHASE, 0);
> +       val |= HIBMC_FIELD(HIBMC_CRT_DISP_CTL_HSYNC_PHASE, 0);
> +       val |= HIBMC_CRT_DISP_CTL_TIMING(1);
> +       val |= HIBMC_CRT_DISP_CTL_PLANE(1);
> +
> +       display_ctrl_adjust(dev, mode, val);
> +}
> +
> +static void hibmc_crtc_atomic_begin(struct drm_crtc *crtc,
> +                                   struct drm_crtc_state *old_state)
> +{
> +       unsigned int reg;
> +       struct drm_device *dev = crtc->dev;
> +       struct hibmc_drm_private *priv = dev->dev_private;
> +
> +       hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_MODE0);
> +
> +       /* Enable display power gate & LOCALMEM power gate*/
> +       reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
> +       reg |= HIBMC_CURR_GATE_DISPLAY(1);
> +       reg |= HIBMC_CURR_GATE_LOCALMEM(1);
> +       hibmc_set_current_gate(priv, reg);
> +
> +       /* We can add more initialization as needed. */
> +}
> +
> +static void hibmc_crtc_atomic_flush(struct drm_crtc *crtc,
> +                                   struct drm_crtc_state *old_state)
> +
> +{
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&crtc->dev->event_lock, flags);
> +       if (crtc->state->event)
> +               drm_crtc_send_vblank_event(crtc, crtc->state->event);
> +       crtc->state->event = NULL;
> +       spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
> +}
> +
> +static const struct drm_crtc_funcs hibmc_crtc_funcs = {
> +       .page_flip = drm_atomic_helper_page_flip,
> +       .set_config = drm_atomic_helper_set_config,
> +       .destroy = drm_crtc_cleanup,
> +       .reset = drm_atomic_helper_crtc_reset,
> +       .atomic_duplicate_state =  drm_atomic_helper_crtc_duplicate_state,
> +       .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
> +};
> +
> +static const struct drm_crtc_helper_funcs hibmc_crtc_helper_funcs = {
> +       .enable         = hibmc_crtc_enable,
> +       .disable        = hibmc_crtc_disable,
> +       .mode_set_nofb  = hibmc_crtc_mode_set_nofb,
> +       .atomic_begin   = hibmc_crtc_atomic_begin,
> +       .atomic_flush   = hibmc_crtc_atomic_flush,
> +};
> +
> +int hibmc_de_init(struct hibmc_drm_private *priv)
> +{
> +       struct drm_device *dev = priv->dev;
> +       struct drm_crtc *crtc;
> +       struct drm_plane *plane;
> +       int ret;
> +
> +       plane = hibmc_plane_init(priv);
> +       if (IS_ERR(plane)) {
> +               DRM_ERROR("failed to create plane: %ld\n", PTR_ERR(plane));
> +               return PTR_ERR(plane);
> +       }
> +
> +       crtc = devm_kzalloc(dev->dev, sizeof(*crtc), GFP_KERNEL);
> +       if (!crtc) {
> +               DRM_ERROR("failed to alloc memory when init crtc\n");
> +               return -ENOMEM;
> +       }
> +
> +       ret = drm_crtc_init_with_planes(dev, crtc, plane,
> +                                       NULL, &hibmc_crtc_funcs, NULL);
> +       if (ret) {
> +               DRM_ERROR("failed to init crtc: %d\n", ret);
> +               return ret;
> +       }
> +
> +       ret = drm_mode_crtc_set_gamma_size(crtc, 256);
> +       if (ret) {
> +               DRM_ERROR("failed to set gamma size: %d\n", ret);
> +               return ret;
> +       }
> +       drm_crtc_helper_add(crtc, &hibmc_crtc_helper_funcs);
> +
> +       return 0;
> +}
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> index 4b52b29..9de3564 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -19,6 +19,9 @@
>  #include <linux/console.h>
>  #include <linux/module.h>
>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +
>  #include "hibmc_drm_drv.h"
>  #include "hibmc_drm_regs.h"
>
> @@ -44,7 +47,8 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>  }
>
>  static struct drm_driver hibmc_driver = {
> -       .driver_features        = DRIVER_GEM,
> +       .driver_features        = DRIVER_GEM | DRIVER_MODESET |
> +                                 DRIVER_ATOMIC,
>         .fops                   = &hibmc_fops,
>         .name                   = "hibmc",
>         .date                   = "20160828",
> @@ -62,11 +66,31 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>
>  static int hibmc_pm_suspend(struct device *dev)
>  {
> +       struct pci_dev *pdev = to_pci_dev(dev);
> +       struct drm_device *drm_dev = pci_get_drvdata(pdev);
> +       struct hibmc_drm_private *priv = drm_dev->dev_private;
> +
> +       drm_kms_helper_poll_disable(drm_dev);
> +       priv->suspend_state = drm_atomic_helper_suspend(drm_dev);
> +       if (IS_ERR(priv->suspend_state)) {
> +               DRM_ERROR("drm_atomic_helper_suspend failed: %ld\n",
> +                         PTR_ERR(priv->suspend_state));
> +               drm_kms_helper_poll_enable(drm_dev);
> +               return PTR_ERR(priv->suspend_state);
> +       }
> +
>         return 0;
>  }
>
>  static int hibmc_pm_resume(struct device *dev)
>  {
> +       struct pci_dev *pdev = to_pci_dev(dev);
> +       struct drm_device *drm_dev = pci_get_drvdata(pdev);
> +       struct hibmc_drm_private *priv = drm_dev->dev_private;
> +
> +       drm_atomic_helper_resume(drm_dev, priv->suspend_state);
> +       drm_kms_helper_poll_enable(drm_dev);
> +
>         return 0;
>  }
>
> @@ -75,6 +99,41 @@ static int hibmc_pm_resume(struct device *dev)
>                                 hibmc_pm_resume)
>  };
>
> +static int hibmc_kms_init(struct hibmc_drm_private *priv)
> +{
> +       int ret;
> +
> +       drm_mode_config_init(priv->dev);
> +       priv->mode_config_initialized = true;
> +
> +       priv->dev->mode_config.min_width = 0;
> +       priv->dev->mode_config.min_height = 0;
> +       priv->dev->mode_config.max_width = 1920;
> +       priv->dev->mode_config.max_height = 1440;
> +
> +       priv->dev->mode_config.fb_base = priv->fb_base;
> +       priv->dev->mode_config.preferred_depth = 24;
> +       priv->dev->mode_config.prefer_shadow = 0;
> +
> +       priv->dev->mode_config.funcs = (void *)&hibmc_mode_funcs;
> +
> +       ret = hibmc_de_init(priv);
> +       if (ret) {
> +               DRM_ERROR("failed to init de: %d\n", ret);
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +static void hibmc_kms_fini(struct hibmc_drm_private *priv)
> +{
> +       if (priv->mode_config_initialized) {
> +               drm_mode_config_cleanup(priv->dev);
> +               priv->mode_config_initialized = false;
> +       }
> +}
> +
>  /*
>   * It can operate in one of three modes: 0, 1 or Sleep.
>   */
> @@ -203,6 +262,7 @@ static int hibmc_unload(struct drm_device *dev)
>         struct hibmc_drm_private *priv = dev->dev_private;
>
>         hibmc_fbdev_fini(priv);
> +       hibmc_kms_fini(priv);
>         hibmc_mm_fini(priv);
>         dev->dev_private = NULL;
>         return 0;
> @@ -229,6 +289,13 @@ static int hibmc_load(struct drm_device *dev)
>         if (ret)
>                 goto err;
>
> +       ret = hibmc_kms_init(priv);
> +       if (ret)
> +               goto err;
> +
> +       /* reset all the states of crtc/plane/encoder/connector */
> +       drm_mode_config_reset(dev);
> +
>         ret = hibmc_fbdev_init(priv);
>         if (ret) {
>                 DRM_ERROR("failed to initialize fbdev: %d\n", ret);
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> index d283d66..87af1eb 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -20,6 +20,7 @@
>  #define HIBMC_DRM_DRV_H
>
>  #include <drm/drmP.h>
> +#include <drm/drm_atomic.h>
>  #include <drm/drm_fb_helper.h>
>  #include <drm/drm_gem.h>
>  #include <drm/ttm/ttm_bo_driver.h>
> @@ -44,6 +45,8 @@ struct hibmc_drm_private {
>
>         /* drm */
>         struct drm_device  *dev;
> +       bool mode_config_initialized;
> +       struct drm_atomic_state *suspend_state;
>
>         /* ttm */
>         struct drm_global_reference mem_global_ref;
> @@ -82,6 +85,7 @@ void hibmc_set_power_mode(struct hibmc_drm_private *priv,
>  void hibmc_set_current_gate(struct hibmc_drm_private *priv,
>                             unsigned int gate);
>
> +int hibmc_de_init(struct hibmc_drm_private *priv);
>  int hibmc_fbdev_init(struct hibmc_drm_private *priv);
>  void hibmc_fbdev_fini(struct hibmc_drm_private *priv);
>
> @@ -103,4 +107,6 @@ int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
>                            u32 handle, u64 *offset);
>  int hibmc_mmap(struct file *filp, struct vm_area_struct *vma);
>
> +extern const struct drm_mode_config_funcs hibmc_mode_funcs;
> +
>  #endif
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> index 3ff65f4..e76abf6 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> @@ -550,3 +550,9 @@ struct hibmc_framebuffer *
>         }
>         return &hibmc_fb->fb;
>  }
> +
> +const struct drm_mode_config_funcs hibmc_mode_funcs = {
> +       .atomic_check = drm_atomic_helper_check,
> +       .atomic_commit = drm_atomic_helper_commit,
> +       .fb_create = hibmc_user_framebuffer_create,
> +};
> --
> 1.9.1
>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v7 5/7] drm/hisilicon/hibmc: Add support for VDAC
  2016-11-16 13:43   ` Rongrong Zou
@ 2016-11-16 15:59     ` Sean Paul
  -1 siblings, 0 replies; 40+ messages in thread
From: Sean Paul @ 2016-11-16 15:59 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> VDAC(Video Digital-to-Analog converter) converts the RGB diaital data
> stream from DE to VGA analog signals.
>
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  drivers/gpu/drm/hisilicon/hibmc/Makefile         |   2 +-
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c  |   6 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h  |   1 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c | 147 +++++++++++++++++++++++
>  4 files changed, 155 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> index 8e0cf72..f2e04c0 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> @@ -1,4 +1,4 @@
>  ccflags-y := -Iinclude/drm
> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_fbdev.o hibmc_ttm.o
> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_drm_fbdev.o hibmc_ttm.o
>
>  obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> index 9de3564..c133644 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -123,6 +123,12 @@ static int hibmc_kms_init(struct hibmc_drm_private *priv)
>                 return ret;
>         }
>
> +       ret = hibmc_vdac_init(priv);
> +       if (ret) {
> +               DRM_ERROR("failed to init vdac: %d\n", ret);
> +               return ret;
> +       }
> +
>         return 0;
>  }
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> index 87af1eb..b626caf 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -86,6 +86,7 @@ void hibmc_set_current_gate(struct hibmc_drm_private *priv,
>                             unsigned int gate);
>
>  int hibmc_de_init(struct hibmc_drm_private *priv);
> +int hibmc_vdac_init(struct hibmc_drm_private *priv);
>  int hibmc_fbdev_init(struct hibmc_drm_private *priv);
>  void hibmc_fbdev_fini(struct hibmc_drm_private *priv);
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
> new file mode 100644
> index 0000000..d1f67a9
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
> @@ -0,0 +1,147 @@
> +/* Hisilicon Hibmc SoC drm driver
> + *
> + * Based on the bochs drm driver.
> + *
> + * Copyright (c) 2016 Huawei Limited.
> + *
> + * Author:
> + *     Rongrong Zou <zourongrong@huawei.com>
> + *     Rongrong Zou <zourongrong@gmail.com>
> + *     Jianhua Li <lijianhua@huawei.com>
> + *
> + * 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.
> + *
> + */
> +
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +
> +#include "hibmc_drm_drv.h"
> +#include "hibmc_drm_regs.h"
> +
> +static int hibmc_connector_get_modes(struct drm_connector *connector)
> +{
> +       return drm_add_modes_noedid(connector, 800, 600);
> +}
> +
> +static int hibmc_connector_mode_valid(struct drm_connector *connector,
> +                                     struct drm_display_mode *mode)
> +{
> +       return MODE_OK;
> +}
> +
> +static struct drm_encoder *
> +hibmc_connector_best_encoder(struct drm_connector *connector)
> +{
> +       return drm_encoder_find(connector->dev, connector->encoder_ids[0]);
> +}
> +
> +static enum drm_connector_status hibmc_connector_detect(struct drm_connector
> +                                                *connector, bool force)
> +{
> +       return connector_status_connected;
> +}
> +
> +static const struct drm_connector_helper_funcs
> +       hibmc_connector_helper_funcs = {
> +       .get_modes = hibmc_connector_get_modes,
> +       .mode_valid = hibmc_connector_mode_valid,
> +       .best_encoder = hibmc_connector_best_encoder,
> +};
> +
> +static const struct drm_connector_funcs hibmc_connector_funcs = {
> +       .dpms = drm_atomic_helper_connector_dpms,
> +       .detect = hibmc_connector_detect,
> +       .fill_modes = drm_helper_probe_single_connector_modes,
> +       .destroy = drm_connector_cleanup,
> +       .reset = drm_atomic_helper_connector_reset,
> +       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> +       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> +};
> +
> +static struct drm_connector *
> +hibmc_connector_init(struct hibmc_drm_private *priv)
> +{
> +       struct drm_device *dev = priv->dev;
> +       struct drm_connector *connector;
> +       int ret;
> +
> +       connector = devm_kzalloc(dev->dev, sizeof(*connector), GFP_KERNEL);
> +       if (!connector) {
> +               DRM_ERROR("failed to alloc memory when init connector\n");
> +               return ERR_PTR(-ENOMEM);
> +       }
> +
> +       ret = drm_connector_init(dev, connector,
> +                                &hibmc_connector_funcs,
> +                                DRM_MODE_CONNECTOR_VGA);
> +       if (ret) {
> +               DRM_ERROR("failed to init connector: %d\n", ret);
> +               return ERR_PTR(ret);
> +       }
> +       drm_connector_helper_add(connector,
> +                                &hibmc_connector_helper_funcs);
> +
> +       return connector;
> +}
> +
> +static void hibmc_encoder_mode_set(struct drm_encoder *encoder,
> +                                  struct drm_display_mode *mode,
> +                                  struct drm_display_mode *adj_mode)
> +{
> +       u32 reg;
> +       struct drm_device *dev = encoder->dev;
> +       struct hibmc_drm_private *priv = dev->dev_private;
> +
> +       reg = readl(priv->mmio + HIBMC_DISPLAY_CONTROL_HISILE);
> +       reg |= HIBMC_DISPLAY_CONTROL_FPVDDEN(1);
> +       reg |= HIBMC_DISPLAY_CONTROL_PANELDATE(1);
> +       reg |= HIBMC_DISPLAY_CONTROL_FPEN(1);
> +       reg |= HIBMC_DISPLAY_CONTROL_VBIASEN(1);
> +       writel(reg, priv->mmio + HIBMC_DISPLAY_CONTROL_HISILE);
> +}
> +
> +static const struct drm_encoder_helper_funcs hibmc_encoder_helper_funcs = {
> +       .mode_set = hibmc_encoder_mode_set,
> +};
> +
> +static const struct drm_encoder_funcs hibmc_encoder_funcs = {
> +       .destroy = drm_encoder_cleanup,
> +};
> +
> +int hibmc_vdac_init(struct hibmc_drm_private *priv)
> +{
> +       struct drm_device *dev = priv->dev;
> +       struct drm_encoder *encoder;
> +       struct drm_connector *connector;
> +       int ret;
> +
> +       connector = hibmc_connector_init(priv);
> +       if (IS_ERR(connector)) {
> +               DRM_ERROR("failed to create connector: %ld\n",
> +                         PTR_ERR(connector));
> +               return PTR_ERR(connector);
> +       }
> +
> +       encoder = devm_kzalloc(dev->dev, sizeof(*encoder), GFP_KERNEL);
> +       if (!encoder) {
> +               DRM_ERROR("failed to alloc memory when init encoder\n");
> +               return -ENOMEM;
> +       }
> +
> +       encoder->possible_crtcs = 0x1;
> +       ret = drm_encoder_init(dev, encoder, &hibmc_encoder_funcs,
> +                              DRM_MODE_ENCODER_DAC, NULL);
> +       if (ret) {
> +               DRM_ERROR("failed to init encoder: %d\n", ret);
> +               return ret;
> +       }
> +
> +       drm_encoder_helper_add(encoder, &hibmc_encoder_helper_funcs);
> +       drm_mode_connector_attach_encoder(connector, encoder);
> +
> +       return 0;
> +}
> --
> 1.9.1
>

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v7 5/7] drm/hisilicon/hibmc: Add support for VDAC
@ 2016-11-16 15:59     ` Sean Paul
  0 siblings, 0 replies; 40+ messages in thread
From: Sean Paul @ 2016-11-16 15:59 UTC (permalink / raw)
  To: Rongrong Zou
  Cc: Mark Rutland, Tomeu Vizoso, Jonathan Corbet, Emil Velikov,
	linuxarm, dri-devel, james.xiong, guohanjun, lijianhua,
	Linux ARM Kernel, shenhui

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> VDAC(Video Digital-to-Analog converter) converts the RGB diaital data
> stream from DE to VGA analog signals.
>
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  drivers/gpu/drm/hisilicon/hibmc/Makefile         |   2 +-
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c  |   6 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h  |   1 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c | 147 +++++++++++++++++++++++
>  4 files changed, 155 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> index 8e0cf72..f2e04c0 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> @@ -1,4 +1,4 @@
>  ccflags-y := -Iinclude/drm
> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_fbdev.o hibmc_ttm.o
> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_drm_fbdev.o hibmc_ttm.o
>
>  obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> index 9de3564..c133644 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -123,6 +123,12 @@ static int hibmc_kms_init(struct hibmc_drm_private *priv)
>                 return ret;
>         }
>
> +       ret = hibmc_vdac_init(priv);
> +       if (ret) {
> +               DRM_ERROR("failed to init vdac: %d\n", ret);
> +               return ret;
> +       }
> +
>         return 0;
>  }
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> index 87af1eb..b626caf 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -86,6 +86,7 @@ void hibmc_set_current_gate(struct hibmc_drm_private *priv,
>                             unsigned int gate);
>
>  int hibmc_de_init(struct hibmc_drm_private *priv);
> +int hibmc_vdac_init(struct hibmc_drm_private *priv);
>  int hibmc_fbdev_init(struct hibmc_drm_private *priv);
>  void hibmc_fbdev_fini(struct hibmc_drm_private *priv);
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
> new file mode 100644
> index 0000000..d1f67a9
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
> @@ -0,0 +1,147 @@
> +/* Hisilicon Hibmc SoC drm driver
> + *
> + * Based on the bochs drm driver.
> + *
> + * Copyright (c) 2016 Huawei Limited.
> + *
> + * Author:
> + *     Rongrong Zou <zourongrong@huawei.com>
> + *     Rongrong Zou <zourongrong@gmail.com>
> + *     Jianhua Li <lijianhua@huawei.com>
> + *
> + * 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.
> + *
> + */
> +
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +
> +#include "hibmc_drm_drv.h"
> +#include "hibmc_drm_regs.h"
> +
> +static int hibmc_connector_get_modes(struct drm_connector *connector)
> +{
> +       return drm_add_modes_noedid(connector, 800, 600);
> +}
> +
> +static int hibmc_connector_mode_valid(struct drm_connector *connector,
> +                                     struct drm_display_mode *mode)
> +{
> +       return MODE_OK;
> +}
> +
> +static struct drm_encoder *
> +hibmc_connector_best_encoder(struct drm_connector *connector)
> +{
> +       return drm_encoder_find(connector->dev, connector->encoder_ids[0]);
> +}
> +
> +static enum drm_connector_status hibmc_connector_detect(struct drm_connector
> +                                                *connector, bool force)
> +{
> +       return connector_status_connected;
> +}
> +
> +static const struct drm_connector_helper_funcs
> +       hibmc_connector_helper_funcs = {
> +       .get_modes = hibmc_connector_get_modes,
> +       .mode_valid = hibmc_connector_mode_valid,
> +       .best_encoder = hibmc_connector_best_encoder,
> +};
> +
> +static const struct drm_connector_funcs hibmc_connector_funcs = {
> +       .dpms = drm_atomic_helper_connector_dpms,
> +       .detect = hibmc_connector_detect,
> +       .fill_modes = drm_helper_probe_single_connector_modes,
> +       .destroy = drm_connector_cleanup,
> +       .reset = drm_atomic_helper_connector_reset,
> +       .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> +       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> +};
> +
> +static struct drm_connector *
> +hibmc_connector_init(struct hibmc_drm_private *priv)
> +{
> +       struct drm_device *dev = priv->dev;
> +       struct drm_connector *connector;
> +       int ret;
> +
> +       connector = devm_kzalloc(dev->dev, sizeof(*connector), GFP_KERNEL);
> +       if (!connector) {
> +               DRM_ERROR("failed to alloc memory when init connector\n");
> +               return ERR_PTR(-ENOMEM);
> +       }
> +
> +       ret = drm_connector_init(dev, connector,
> +                                &hibmc_connector_funcs,
> +                                DRM_MODE_CONNECTOR_VGA);
> +       if (ret) {
> +               DRM_ERROR("failed to init connector: %d\n", ret);
> +               return ERR_PTR(ret);
> +       }
> +       drm_connector_helper_add(connector,
> +                                &hibmc_connector_helper_funcs);
> +
> +       return connector;
> +}
> +
> +static void hibmc_encoder_mode_set(struct drm_encoder *encoder,
> +                                  struct drm_display_mode *mode,
> +                                  struct drm_display_mode *adj_mode)
> +{
> +       u32 reg;
> +       struct drm_device *dev = encoder->dev;
> +       struct hibmc_drm_private *priv = dev->dev_private;
> +
> +       reg = readl(priv->mmio + HIBMC_DISPLAY_CONTROL_HISILE);
> +       reg |= HIBMC_DISPLAY_CONTROL_FPVDDEN(1);
> +       reg |= HIBMC_DISPLAY_CONTROL_PANELDATE(1);
> +       reg |= HIBMC_DISPLAY_CONTROL_FPEN(1);
> +       reg |= HIBMC_DISPLAY_CONTROL_VBIASEN(1);
> +       writel(reg, priv->mmio + HIBMC_DISPLAY_CONTROL_HISILE);
> +}
> +
> +static const struct drm_encoder_helper_funcs hibmc_encoder_helper_funcs = {
> +       .mode_set = hibmc_encoder_mode_set,
> +};
> +
> +static const struct drm_encoder_funcs hibmc_encoder_funcs = {
> +       .destroy = drm_encoder_cleanup,
> +};
> +
> +int hibmc_vdac_init(struct hibmc_drm_private *priv)
> +{
> +       struct drm_device *dev = priv->dev;
> +       struct drm_encoder *encoder;
> +       struct drm_connector *connector;
> +       int ret;
> +
> +       connector = hibmc_connector_init(priv);
> +       if (IS_ERR(connector)) {
> +               DRM_ERROR("failed to create connector: %ld\n",
> +                         PTR_ERR(connector));
> +               return PTR_ERR(connector);
> +       }
> +
> +       encoder = devm_kzalloc(dev->dev, sizeof(*encoder), GFP_KERNEL);
> +       if (!encoder) {
> +               DRM_ERROR("failed to alloc memory when init encoder\n");
> +               return -ENOMEM;
> +       }
> +
> +       encoder->possible_crtcs = 0x1;
> +       ret = drm_encoder_init(dev, encoder, &hibmc_encoder_funcs,
> +                              DRM_MODE_ENCODER_DAC, NULL);
> +       if (ret) {
> +               DRM_ERROR("failed to init encoder: %d\n", ret);
> +               return ret;
> +       }
> +
> +       drm_encoder_helper_add(encoder, &hibmc_encoder_helper_funcs);
> +       drm_mode_connector_attach_encoder(connector, encoder);
> +
> +       return 0;
> +}
> --
> 1.9.1
>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v7 6/7] drm/hisilicon/hibmc: Add support for vblank interrupt
  2016-11-16 13:43   ` Rongrong Zou
@ 2016-11-16 16:00     ` Sean Paul
  -1 siblings, 0 replies; 40+ messages in thread
From: Sean Paul @ 2016-11-16 16:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Add vblank interrupt.
>
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 56 ++++++++++++++++++++++++-
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |  1 +
>  2 files changed, 56 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> index c133644..73ba8b0 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -39,16 +39,45 @@
>
>  static int hibmc_enable_vblank(struct drm_device *dev, unsigned int pipe)
>  {
> +       struct hibmc_drm_private *priv =
> +               (struct hibmc_drm_private *)dev->dev_private;
> +
> +       writel(HIBMC_RAW_INTERRUPT_EN_VBLANK(1),
> +              priv->mmio + HIBMC_RAW_INTERRUPT_EN);
> +
>         return 0;
>  }
>
>  static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>  {
> +       struct hibmc_drm_private *priv =
> +               (struct hibmc_drm_private *)dev->dev_private;
> +
> +       writel(HIBMC_RAW_INTERRUPT_EN_VBLANK(0),
> +              priv->mmio + HIBMC_RAW_INTERRUPT_EN);
> +}
> +
> +irqreturn_t hibmc_drm_interrupt(int irq, void *arg)
> +{
> +       struct drm_device *dev = (struct drm_device *)arg;
> +       struct hibmc_drm_private *priv =
> +               (struct hibmc_drm_private *)dev->dev_private;
> +       u32 status;
> +
> +       status = readl(priv->mmio + HIBMC_RAW_INTERRUPT);
> +
> +       if (status & HIBMC_RAW_INTERRUPT_VBLANK(1)) {
> +               writel(HIBMC_RAW_INTERRUPT_VBLANK(1),
> +                      priv->mmio + HIBMC_RAW_INTERRUPT);
> +               drm_handle_vblank(dev, 0);
> +       }
> +
> +       return IRQ_HANDLED;
>  }
>
>  static struct drm_driver hibmc_driver = {
>         .driver_features        = DRIVER_GEM | DRIVER_MODESET |
> -                                 DRIVER_ATOMIC,
> +                                 DRIVER_ATOMIC | DRIVER_HAVE_IRQ,
>         .fops                   = &hibmc_fops,
>         .name                   = "hibmc",
>         .date                   = "20160828",
> @@ -62,6 +91,7 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>         .dumb_create            = hibmc_dumb_create,
>         .dumb_map_offset        = hibmc_dumb_mmap_offset,
>         .dumb_destroy           = drm_gem_dumb_destroy,
> +       .irq_handler            = hibmc_drm_interrupt,
>  };
>
>  static int hibmc_pm_suspend(struct device *dev)
> @@ -268,6 +298,13 @@ static int hibmc_unload(struct drm_device *dev)
>         struct hibmc_drm_private *priv = dev->dev_private;
>
>         hibmc_fbdev_fini(priv);
> +
> +       if (dev->irq_enabled)
> +               drm_irq_uninstall(dev);
> +       if (priv->msi_enabled)
> +               pci_disable_msi(dev->pdev);
> +       drm_vblank_cleanup(dev);
> +
>         hibmc_kms_fini(priv);
>         hibmc_mm_fini(priv);
>         dev->dev_private = NULL;
> @@ -299,6 +336,23 @@ static int hibmc_load(struct drm_device *dev)
>         if (ret)
>                 goto err;
>
> +       ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
> +       if (ret) {
> +               DRM_ERROR("failed to initialize vblank: %d\n", ret);
> +               goto err;
> +       }
> +
> +       priv->msi_enabled = 0;
> +       ret = pci_enable_msi(dev->pdev);
> +       if (ret) {
> +               DRM_WARN("enabling MSI failed: %d\n", ret);
> +       } else {
> +               priv->msi_enabled = 1;
> +               ret = drm_irq_install(dev, dev->pdev->irq);
> +               if (ret)
> +                       DRM_WARN("install irq failed: %d\n", ret);
> +       }
> +
>         /* reset all the states of crtc/plane/encoder/connector */
>         drm_mode_config_reset(dev);
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> index b626caf..e195521 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -42,6 +42,7 @@ struct hibmc_drm_private {
>         void __iomem   *fb_map;
>         unsigned long  fb_base;
>         unsigned long  fb_size;
> +       bool msi_enabled;
>
>         /* drm */
>         struct drm_device  *dev;
> --
> 1.9.1
>

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v7 6/7] drm/hisilicon/hibmc: Add support for vblank interrupt
@ 2016-11-16 16:00     ` Sean Paul
  0 siblings, 0 replies; 40+ messages in thread
From: Sean Paul @ 2016-11-16 16:00 UTC (permalink / raw)
  To: Rongrong Zou
  Cc: Mark Rutland, Tomeu Vizoso, seanpaul, Jonathan Corbet,
	Emil Velikov, linuxarm, dri-devel, james.xiong, guohanjun,
	lijianhua, Linux ARM Kernel, shenhui

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Add vblank interrupt.
>
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 56 ++++++++++++++++++++++++-
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |  1 +
>  2 files changed, 56 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> index c133644..73ba8b0 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -39,16 +39,45 @@
>
>  static int hibmc_enable_vblank(struct drm_device *dev, unsigned int pipe)
>  {
> +       struct hibmc_drm_private *priv =
> +               (struct hibmc_drm_private *)dev->dev_private;
> +
> +       writel(HIBMC_RAW_INTERRUPT_EN_VBLANK(1),
> +              priv->mmio + HIBMC_RAW_INTERRUPT_EN);
> +
>         return 0;
>  }
>
>  static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>  {
> +       struct hibmc_drm_private *priv =
> +               (struct hibmc_drm_private *)dev->dev_private;
> +
> +       writel(HIBMC_RAW_INTERRUPT_EN_VBLANK(0),
> +              priv->mmio + HIBMC_RAW_INTERRUPT_EN);
> +}
> +
> +irqreturn_t hibmc_drm_interrupt(int irq, void *arg)
> +{
> +       struct drm_device *dev = (struct drm_device *)arg;
> +       struct hibmc_drm_private *priv =
> +               (struct hibmc_drm_private *)dev->dev_private;
> +       u32 status;
> +
> +       status = readl(priv->mmio + HIBMC_RAW_INTERRUPT);
> +
> +       if (status & HIBMC_RAW_INTERRUPT_VBLANK(1)) {
> +               writel(HIBMC_RAW_INTERRUPT_VBLANK(1),
> +                      priv->mmio + HIBMC_RAW_INTERRUPT);
> +               drm_handle_vblank(dev, 0);
> +       }
> +
> +       return IRQ_HANDLED;
>  }
>
>  static struct drm_driver hibmc_driver = {
>         .driver_features        = DRIVER_GEM | DRIVER_MODESET |
> -                                 DRIVER_ATOMIC,
> +                                 DRIVER_ATOMIC | DRIVER_HAVE_IRQ,
>         .fops                   = &hibmc_fops,
>         .name                   = "hibmc",
>         .date                   = "20160828",
> @@ -62,6 +91,7 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>         .dumb_create            = hibmc_dumb_create,
>         .dumb_map_offset        = hibmc_dumb_mmap_offset,
>         .dumb_destroy           = drm_gem_dumb_destroy,
> +       .irq_handler            = hibmc_drm_interrupt,
>  };
>
>  static int hibmc_pm_suspend(struct device *dev)
> @@ -268,6 +298,13 @@ static int hibmc_unload(struct drm_device *dev)
>         struct hibmc_drm_private *priv = dev->dev_private;
>
>         hibmc_fbdev_fini(priv);
> +
> +       if (dev->irq_enabled)
> +               drm_irq_uninstall(dev);
> +       if (priv->msi_enabled)
> +               pci_disable_msi(dev->pdev);
> +       drm_vblank_cleanup(dev);
> +
>         hibmc_kms_fini(priv);
>         hibmc_mm_fini(priv);
>         dev->dev_private = NULL;
> @@ -299,6 +336,23 @@ static int hibmc_load(struct drm_device *dev)
>         if (ret)
>                 goto err;
>
> +       ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
> +       if (ret) {
> +               DRM_ERROR("failed to initialize vblank: %d\n", ret);
> +               goto err;
> +       }
> +
> +       priv->msi_enabled = 0;
> +       ret = pci_enable_msi(dev->pdev);
> +       if (ret) {
> +               DRM_WARN("enabling MSI failed: %d\n", ret);
> +       } else {
> +               priv->msi_enabled = 1;
> +               ret = drm_irq_install(dev, dev->pdev->irq);
> +               if (ret)
> +                       DRM_WARN("install irq failed: %d\n", ret);
> +       }
> +
>         /* reset all the states of crtc/plane/encoder/connector */
>         drm_mode_config_reset(dev);
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> index b626caf..e195521 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -42,6 +42,7 @@ struct hibmc_drm_private {
>         void __iomem   *fb_map;
>         unsigned long  fb_base;
>         unsigned long  fb_size;
> +       bool msi_enabled;
>
>         /* drm */
>         struct drm_device  *dev;
> --
> 1.9.1
>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v7 7/7] MAINTAINERS: Update HISILICON DRM entries
  2016-11-16 13:43   ` Rongrong Zou
@ 2016-11-16 16:00     ` Sean Paul
  -1 siblings, 0 replies; 40+ messages in thread
From: Sean Paul @ 2016-11-16 16:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  MAINTAINERS | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 2a58eea..84a7296 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -4123,6 +4123,7 @@ F:        drivers/gpu/drm/gma500/
>
>  DRM DRIVERS FOR HISILICON
>  M:     Xinliang Liu <z.liuxinliang@hisilicon.com>
> +M:     Rongrong Zou <zourongrong@gmail.com>
>  R:     Xinwei Kong <kong.kongxinwei@hisilicon.com>
>  R:     Chen Feng <puck.chen@hisilicon.com>
>  L:     dri-devel at lists.freedesktop.org
> --
> 1.9.1
>

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v7 7/7] MAINTAINERS: Update HISILICON DRM entries
@ 2016-11-16 16:00     ` Sean Paul
  0 siblings, 0 replies; 40+ messages in thread
From: Sean Paul @ 2016-11-16 16:00 UTC (permalink / raw)
  To: Rongrong Zou
  Cc: Mark Rutland, Tomeu Vizoso, seanpaul, Jonathan Corbet,
	Emil Velikov, linuxarm, dri-devel, james.xiong, guohanjun,
	lijianhua, Linux ARM Kernel, shenhui

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>

Reviewed-by: Sean Paul <seanpaul@chromium.org>

> ---
>  MAINTAINERS | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 2a58eea..84a7296 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -4123,6 +4123,7 @@ F:        drivers/gpu/drm/gma500/
>
>  DRM DRIVERS FOR HISILICON
>  M:     Xinliang Liu <z.liuxinliang@hisilicon.com>
> +M:     Rongrong Zou <zourongrong@gmail.com>
>  R:     Xinwei Kong <kong.kongxinwei@hisilicon.com>
>  R:     Chen Feng <puck.chen@hisilicon.com>
>  L:     dri-devel@lists.freedesktop.org
> --
> 1.9.1
>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v7 0/7] Add DRM driver for Hisilicon Hibmc
  2016-11-16 13:43 ` Rongrong Zou
@ 2016-11-16 16:01   ` Sean Paul
  -1 siblings, 0 replies; 40+ messages in thread
From: Sean Paul @ 2016-11-16 16:01 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> This patch set adds a new drm driver for Hisilicon Hibmc. Hibmc is a
> BMC SoC with a display controller intergrated, usually it is used on
> server for Out-of-band management purpose. In this patch set, we just
> support basic function for Hibmc display subsystem. Hibmc display
> subsystem is connected to host CPU by PCIe as blow:
>
> +----------+       +----------+
> |          | PCIe  |  Hibmc   |
> |host CPU( |<----->| display  |
> |arm64,x86)|       |subsystem |
> +----------+       +----------+
>
> Hardware Detail for Hibmc display subsystem
> -----------
>
>   The display subsystem of Hibmc is show as bellow:
>   +----+      +----+      +----+     +--------+
>   |    |      |    |      |    |     |        |
>   | FB |----->| DE |----->|VDAC|---->|external|
>   |    |      |    |      |    |     | VGA    |
>   +----+      +----+      +----+     +--------+
>
>   -DE(Display Engine) is the display controller.
>   -VDAC(Video Digital-to-Analog converter) converts the RGB diaital data
>   stream from DE to VGA analog signals.
>

For the whole series/driver:

Acked-by: Sean Paul <seanpaul@chromium.org>



> Change History
> ------------
> Changes in v7:
>   -remove hibmc_drm_power.c/hibmc_drm_power.h, move the functions to
>    hibmc_drm_drv.c.
>   -remove hibmc_drm_de.h and move the struct defined in head file to
>    hibmc_drm_de.c.
>   -plane is initialized inside crtc, not in hibmc_kms_init().
>   -connector is initialized inside encoder, not in hibmc_kms_init().
>   -remove plane/crtc/encoder/connector from hibmc_drm_private struct.
>   -call drm_atomic_helper_suspend/resume in hibmc_pm_suspend/resume.
>   -remove these empty stubs because caller will do NULL check.
>     hibmc_plane_atomic_disable
>     hibmc_crtc_atomic_check
>     hibmc_encoder_disable
>     hibmc_encoder_enable
>     hibmc_encoder_atomic_check
>   -clean up in all error paths of creating driver-private framebuffer.
>
> Changes in v6:
>   -remove the embedded framebuffer and use a pointer of hibmc_framebuffer
>    instead.
>   -remove the deprecated drm_framebuffer_unregister_private(),
>    drm_framebuffer_unreference() will be called in hibmc_fbdev_destroy().
>   -uninstall irq in hibmc_unload().
>
> Changes in v5:
>   -rebase on v4.9-rc2.
>   -replace drm_fb_helper_set_suspend with drm_fb_helper_set_suspend_unlocked.
>    and remove redundant console_lock and console_unlock.
>
> Changes in v4:
>   -remove unused include files, and include header file when it is needed.
>   -remove unused FLAG in Kconfig: DRM_GEM_CMA_HELPER/DRM_KMS_CMA_HELPER.
>   -remove drm_helper_disable_unused_functions, since we use DRIVER_ATOMIC.
>
> Changes in v3:
>   -enable KMS, in v2, only fbdev is enabled.
>   -management video memory with ttm.
>   -add vblank interrupt.
>   -remove drm_connector_register_all() and drm_connector_unregister_all().
>   -I have a basic test with igt.
>
> Changes in v2:
>   -Remove self-defined macros for bit operations.
>   -Remove unused register.
>   -Replace those deprecated functions with new version of them.
>   -use drm_connector_register_all() to register connector after
>    drm_dev_register().
>
> The patch v2 is at
> https://lists.freedesktop.org/archives/dri-devel/2016-May/108661.html
>
> Rongrong Zou (7):
>   drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
>   drm/hisilicon/hibmc: Add video memory management
>   drm/hisilicon/hibmc: Add support for frame buffer
>   drm/hisilicon/hibmc: Add support for display engine
>   drm/hisilicon/hibmc: Add support for VDAC
>   drm/hisilicon/hibmc: Add support for vblank interrupt
>   MAINTAINERS: Update HISILICON DRM entries
>
>  MAINTAINERS                                       |   1 +
>  drivers/gpu/drm/hisilicon/Kconfig                 |   1 +
>  drivers/gpu/drm/hisilicon/Makefile                |   1 +
>  drivers/gpu/drm/hisilicon/hibmc/Kconfig           |   9 +
>  drivers/gpu/drm/hisilicon/hibmc/Makefile          |   4 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c    | 477 ++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   | 456 ++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   | 114 +++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 267 +++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h  | 196 ++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c  | 147 ++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       | 558 ++++++++++++++++++++++
>  12 files changed, 2231 insertions(+)
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Kconfig
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Makefile
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>
> --
> 1.9.1
>

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v7 0/7] Add DRM driver for Hisilicon Hibmc
@ 2016-11-16 16:01   ` Sean Paul
  0 siblings, 0 replies; 40+ messages in thread
From: Sean Paul @ 2016-11-16 16:01 UTC (permalink / raw)
  To: Rongrong Zou
  Cc: Mark Rutland, Tomeu Vizoso, Jonathan Corbet, Emil Velikov,
	linuxarm, dri-devel, james.xiong, guohanjun, lijianhua,
	Linux ARM Kernel, shenhui

On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> This patch set adds a new drm driver for Hisilicon Hibmc. Hibmc is a
> BMC SoC with a display controller intergrated, usually it is used on
> server for Out-of-band management purpose. In this patch set, we just
> support basic function for Hibmc display subsystem. Hibmc display
> subsystem is connected to host CPU by PCIe as blow:
>
> +----------+       +----------+
> |          | PCIe  |  Hibmc   |
> |host CPU( |<----->| display  |
> |arm64,x86)|       |subsystem |
> +----------+       +----------+
>
> Hardware Detail for Hibmc display subsystem
> -----------
>
>   The display subsystem of Hibmc is show as bellow:
>   +----+      +----+      +----+     +--------+
>   |    |      |    |      |    |     |        |
>   | FB |----->| DE |----->|VDAC|---->|external|
>   |    |      |    |      |    |     | VGA    |
>   +----+      +----+      +----+     +--------+
>
>   -DE(Display Engine) is the display controller.
>   -VDAC(Video Digital-to-Analog converter) converts the RGB diaital data
>   stream from DE to VGA analog signals.
>

For the whole series/driver:

Acked-by: Sean Paul <seanpaul@chromium.org>



> Change History
> ------------
> Changes in v7:
>   -remove hibmc_drm_power.c/hibmc_drm_power.h, move the functions to
>    hibmc_drm_drv.c.
>   -remove hibmc_drm_de.h and move the struct defined in head file to
>    hibmc_drm_de.c.
>   -plane is initialized inside crtc, not in hibmc_kms_init().
>   -connector is initialized inside encoder, not in hibmc_kms_init().
>   -remove plane/crtc/encoder/connector from hibmc_drm_private struct.
>   -call drm_atomic_helper_suspend/resume in hibmc_pm_suspend/resume.
>   -remove these empty stubs because caller will do NULL check.
>     hibmc_plane_atomic_disable
>     hibmc_crtc_atomic_check
>     hibmc_encoder_disable
>     hibmc_encoder_enable
>     hibmc_encoder_atomic_check
>   -clean up in all error paths of creating driver-private framebuffer.
>
> Changes in v6:
>   -remove the embedded framebuffer and use a pointer of hibmc_framebuffer
>    instead.
>   -remove the deprecated drm_framebuffer_unregister_private(),
>    drm_framebuffer_unreference() will be called in hibmc_fbdev_destroy().
>   -uninstall irq in hibmc_unload().
>
> Changes in v5:
>   -rebase on v4.9-rc2.
>   -replace drm_fb_helper_set_suspend with drm_fb_helper_set_suspend_unlocked.
>    and remove redundant console_lock and console_unlock.
>
> Changes in v4:
>   -remove unused include files, and include header file when it is needed.
>   -remove unused FLAG in Kconfig: DRM_GEM_CMA_HELPER/DRM_KMS_CMA_HELPER.
>   -remove drm_helper_disable_unused_functions, since we use DRIVER_ATOMIC.
>
> Changes in v3:
>   -enable KMS, in v2, only fbdev is enabled.
>   -management video memory with ttm.
>   -add vblank interrupt.
>   -remove drm_connector_register_all() and drm_connector_unregister_all().
>   -I have a basic test with igt.
>
> Changes in v2:
>   -Remove self-defined macros for bit operations.
>   -Remove unused register.
>   -Replace those deprecated functions with new version of them.
>   -use drm_connector_register_all() to register connector after
>    drm_dev_register().
>
> The patch v2 is at
> https://lists.freedesktop.org/archives/dri-devel/2016-May/108661.html
>
> Rongrong Zou (7):
>   drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
>   drm/hisilicon/hibmc: Add video memory management
>   drm/hisilicon/hibmc: Add support for frame buffer
>   drm/hisilicon/hibmc: Add support for display engine
>   drm/hisilicon/hibmc: Add support for VDAC
>   drm/hisilicon/hibmc: Add support for vblank interrupt
>   MAINTAINERS: Update HISILICON DRM entries
>
>  MAINTAINERS                                       |   1 +
>  drivers/gpu/drm/hisilicon/Kconfig                 |   1 +
>  drivers/gpu/drm/hisilicon/Makefile                |   1 +
>  drivers/gpu/drm/hisilicon/hibmc/Kconfig           |   9 +
>  drivers/gpu/drm/hisilicon/hibmc/Makefile          |   4 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c    | 477 ++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   | 456 ++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   | 114 +++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 267 +++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h  | 196 ++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c  | 147 ++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       | 558 ++++++++++++++++++++++
>  12 files changed, 2231 insertions(+)
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Kconfig
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Makefile
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>
> --
> 1.9.1
>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v7 0/7] Add DRM driver for Hisilicon Hibmc
  2016-11-16 16:01   ` Sean Paul
@ 2016-11-16 16:02     ` Sean Paul
  -1 siblings, 0 replies; 40+ messages in thread
From: Sean Paul @ 2016-11-16 16:02 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Nov 16, 2016 at 11:01 AM, Sean Paul <seanpaul@chromium.org> wrote:
> On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
>> This patch set adds a new drm driver for Hisilicon Hibmc. Hibmc is a
>> BMC SoC with a display controller intergrated, usually it is used on
>> server for Out-of-band management purpose. In this patch set, we just
>> support basic function for Hibmc display subsystem. Hibmc display
>> subsystem is connected to host CPU by PCIe as blow:
>>
>> +----------+       +----------+
>> |          | PCIe  |  Hibmc   |
>> |host CPU( |<----->| display  |
>> |arm64,x86)|       |subsystem |
>> +----------+       +----------+
>>
>> Hardware Detail for Hibmc display subsystem
>> -----------
>>
>>   The display subsystem of Hibmc is show as bellow:
>>   +----+      +----+      +----+     +--------+
>>   |    |      |    |      |    |     |        |
>>   | FB |----->| DE |----->|VDAC|---->|external|
>>   |    |      |    |      |    |     | VGA    |
>>   +----+      +----+      +----+     +--------+
>>
>>   -DE(Display Engine) is the display controller.
>>   -VDAC(Video Digital-to-Analog converter) converts the RGB diaital data
>>   stream from DE to VGA analog signals.
>>
>
> For the whole series/driver:
>
> Acked-by: Sean Paul <seanpaul@chromium.org>
>
>

Also, please send those fixups for the other ttm drivers ;)

>
>> Change History
>> ------------
>> Changes in v7:
>>   -remove hibmc_drm_power.c/hibmc_drm_power.h, move the functions to
>>    hibmc_drm_drv.c.
>>   -remove hibmc_drm_de.h and move the struct defined in head file to
>>    hibmc_drm_de.c.
>>   -plane is initialized inside crtc, not in hibmc_kms_init().
>>   -connector is initialized inside encoder, not in hibmc_kms_init().
>>   -remove plane/crtc/encoder/connector from hibmc_drm_private struct.
>>   -call drm_atomic_helper_suspend/resume in hibmc_pm_suspend/resume.
>>   -remove these empty stubs because caller will do NULL check.
>>     hibmc_plane_atomic_disable
>>     hibmc_crtc_atomic_check
>>     hibmc_encoder_disable
>>     hibmc_encoder_enable
>>     hibmc_encoder_atomic_check
>>   -clean up in all error paths of creating driver-private framebuffer.
>>
>> Changes in v6:
>>   -remove the embedded framebuffer and use a pointer of hibmc_framebuffer
>>    instead.
>>   -remove the deprecated drm_framebuffer_unregister_private(),
>>    drm_framebuffer_unreference() will be called in hibmc_fbdev_destroy().
>>   -uninstall irq in hibmc_unload().
>>
>> Changes in v5:
>>   -rebase on v4.9-rc2.
>>   -replace drm_fb_helper_set_suspend with drm_fb_helper_set_suspend_unlocked.
>>    and remove redundant console_lock and console_unlock.
>>
>> Changes in v4:
>>   -remove unused include files, and include header file when it is needed.
>>   -remove unused FLAG in Kconfig: DRM_GEM_CMA_HELPER/DRM_KMS_CMA_HELPER.
>>   -remove drm_helper_disable_unused_functions, since we use DRIVER_ATOMIC.
>>
>> Changes in v3:
>>   -enable KMS, in v2, only fbdev is enabled.
>>   -management video memory with ttm.
>>   -add vblank interrupt.
>>   -remove drm_connector_register_all() and drm_connector_unregister_all().
>>   -I have a basic test with igt.
>>
>> Changes in v2:
>>   -Remove self-defined macros for bit operations.
>>   -Remove unused register.
>>   -Replace those deprecated functions with new version of them.
>>   -use drm_connector_register_all() to register connector after
>>    drm_dev_register().
>>
>> The patch v2 is at
>> https://lists.freedesktop.org/archives/dri-devel/2016-May/108661.html
>>
>> Rongrong Zou (7):
>>   drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
>>   drm/hisilicon/hibmc: Add video memory management
>>   drm/hisilicon/hibmc: Add support for frame buffer
>>   drm/hisilicon/hibmc: Add support for display engine
>>   drm/hisilicon/hibmc: Add support for VDAC
>>   drm/hisilicon/hibmc: Add support for vblank interrupt
>>   MAINTAINERS: Update HISILICON DRM entries
>>
>>  MAINTAINERS                                       |   1 +
>>  drivers/gpu/drm/hisilicon/Kconfig                 |   1 +
>>  drivers/gpu/drm/hisilicon/Makefile                |   1 +
>>  drivers/gpu/drm/hisilicon/hibmc/Kconfig           |   9 +
>>  drivers/gpu/drm/hisilicon/hibmc/Makefile          |   4 +
>>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c    | 477 ++++++++++++++++++
>>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   | 456 ++++++++++++++++++
>>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   | 114 +++++
>>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 267 +++++++++++
>>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h  | 196 ++++++++
>>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c  | 147 ++++++
>>  drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       | 558 ++++++++++++++++++++++
>>  12 files changed, 2231 insertions(+)
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Makefile
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>
>> --
>> 1.9.1
>>

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v7 0/7] Add DRM driver for Hisilicon Hibmc
@ 2016-11-16 16:02     ` Sean Paul
  0 siblings, 0 replies; 40+ messages in thread
From: Sean Paul @ 2016-11-16 16:02 UTC (permalink / raw)
  To: Rongrong Zou
  Cc: Mark Rutland, Tomeu Vizoso, Jonathan Corbet, Emil Velikov,
	linuxarm, dri-devel, james.xiong, guohanjun, lijianhua,
	Linux ARM Kernel, shenhui

On Wed, Nov 16, 2016 at 11:01 AM, Sean Paul <seanpaul@chromium.org> wrote:
> On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
>> This patch set adds a new drm driver for Hisilicon Hibmc. Hibmc is a
>> BMC SoC with a display controller intergrated, usually it is used on
>> server for Out-of-band management purpose. In this patch set, we just
>> support basic function for Hibmc display subsystem. Hibmc display
>> subsystem is connected to host CPU by PCIe as blow:
>>
>> +----------+       +----------+
>> |          | PCIe  |  Hibmc   |
>> |host CPU( |<----->| display  |
>> |arm64,x86)|       |subsystem |
>> +----------+       +----------+
>>
>> Hardware Detail for Hibmc display subsystem
>> -----------
>>
>>   The display subsystem of Hibmc is show as bellow:
>>   +----+      +----+      +----+     +--------+
>>   |    |      |    |      |    |     |        |
>>   | FB |----->| DE |----->|VDAC|---->|external|
>>   |    |      |    |      |    |     | VGA    |
>>   +----+      +----+      +----+     +--------+
>>
>>   -DE(Display Engine) is the display controller.
>>   -VDAC(Video Digital-to-Analog converter) converts the RGB diaital data
>>   stream from DE to VGA analog signals.
>>
>
> For the whole series/driver:
>
> Acked-by: Sean Paul <seanpaul@chromium.org>
>
>

Also, please send those fixups for the other ttm drivers ;)

>
>> Change History
>> ------------
>> Changes in v7:
>>   -remove hibmc_drm_power.c/hibmc_drm_power.h, move the functions to
>>    hibmc_drm_drv.c.
>>   -remove hibmc_drm_de.h and move the struct defined in head file to
>>    hibmc_drm_de.c.
>>   -plane is initialized inside crtc, not in hibmc_kms_init().
>>   -connector is initialized inside encoder, not in hibmc_kms_init().
>>   -remove plane/crtc/encoder/connector from hibmc_drm_private struct.
>>   -call drm_atomic_helper_suspend/resume in hibmc_pm_suspend/resume.
>>   -remove these empty stubs because caller will do NULL check.
>>     hibmc_plane_atomic_disable
>>     hibmc_crtc_atomic_check
>>     hibmc_encoder_disable
>>     hibmc_encoder_enable
>>     hibmc_encoder_atomic_check
>>   -clean up in all error paths of creating driver-private framebuffer.
>>
>> Changes in v6:
>>   -remove the embedded framebuffer and use a pointer of hibmc_framebuffer
>>    instead.
>>   -remove the deprecated drm_framebuffer_unregister_private(),
>>    drm_framebuffer_unreference() will be called in hibmc_fbdev_destroy().
>>   -uninstall irq in hibmc_unload().
>>
>> Changes in v5:
>>   -rebase on v4.9-rc2.
>>   -replace drm_fb_helper_set_suspend with drm_fb_helper_set_suspend_unlocked.
>>    and remove redundant console_lock and console_unlock.
>>
>> Changes in v4:
>>   -remove unused include files, and include header file when it is needed.
>>   -remove unused FLAG in Kconfig: DRM_GEM_CMA_HELPER/DRM_KMS_CMA_HELPER.
>>   -remove drm_helper_disable_unused_functions, since we use DRIVER_ATOMIC.
>>
>> Changes in v3:
>>   -enable KMS, in v2, only fbdev is enabled.
>>   -management video memory with ttm.
>>   -add vblank interrupt.
>>   -remove drm_connector_register_all() and drm_connector_unregister_all().
>>   -I have a basic test with igt.
>>
>> Changes in v2:
>>   -Remove self-defined macros for bit operations.
>>   -Remove unused register.
>>   -Replace those deprecated functions with new version of them.
>>   -use drm_connector_register_all() to register connector after
>>    drm_dev_register().
>>
>> The patch v2 is at
>> https://lists.freedesktop.org/archives/dri-devel/2016-May/108661.html
>>
>> Rongrong Zou (7):
>>   drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
>>   drm/hisilicon/hibmc: Add video memory management
>>   drm/hisilicon/hibmc: Add support for frame buffer
>>   drm/hisilicon/hibmc: Add support for display engine
>>   drm/hisilicon/hibmc: Add support for VDAC
>>   drm/hisilicon/hibmc: Add support for vblank interrupt
>>   MAINTAINERS: Update HISILICON DRM entries
>>
>>  MAINTAINERS                                       |   1 +
>>  drivers/gpu/drm/hisilicon/Kconfig                 |   1 +
>>  drivers/gpu/drm/hisilicon/Makefile                |   1 +
>>  drivers/gpu/drm/hisilicon/hibmc/Kconfig           |   9 +
>>  drivers/gpu/drm/hisilicon/hibmc/Makefile          |   4 +
>>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c    | 477 ++++++++++++++++++
>>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   | 456 ++++++++++++++++++
>>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   | 114 +++++
>>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 267 +++++++++++
>>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h  | 196 ++++++++
>>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c  | 147 ++++++
>>  drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       | 558 ++++++++++++++++++++++
>>  12 files changed, 2231 insertions(+)
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Makefile
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
>>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>
>> --
>> 1.9.1
>>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v7 1/7] drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
  2016-11-16 15:42     ` Sean Paul
@ 2016-11-17  4:05       ` Rongrong Zou
  -1 siblings, 0 replies; 40+ messages in thread
From: Rongrong Zou @ 2016-11-17  4:05 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Sean,

Thanks for reviewing.

? 2016/11/16 23:42, Sean Paul ??:
> On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
>> Add DRM master driver for Hisilicon Hibmc SoC which used for
>> Out-of-band management. Blow is the general hardware connection,
>> both the Hibmc and the host CPU are on the same mother board.
>>
>> +----------+       +----------+
>> |          | PCIe  |  Hibmc   |
>> |host CPU( |<----->| display  |
>> |arm64,x86)|       |subsystem |
>> +----------+       +----------+
>>
>> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
>> ---
>
> In the future, please keep track of the differences between patch
> versions. I noticed you have a short changelog in the cover letter,
> but it really helps to add one per-patch as well, it makes reviewing
> much simpler.
>
> Reviewed-by: Sean Paul <seanpaul@chromium.org>

Sorry for that, I will pay attention to it later, thanks.

Regards,
Rongrong.

>
>
>>   drivers/gpu/drm/hisilicon/Kconfig                |   1 +
>>   drivers/gpu/drm/hisilicon/Makefile               |   1 +
>>   drivers/gpu/drm/hisilicon/hibmc/Kconfig          |   9 +
>>   drivers/gpu/drm/hisilicon/hibmc/Makefile         |   4 +
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c  | 308 +++++++++++++++++++++++
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h  |  41 +++
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h | 196 +++++++++++++++
>>   7 files changed, 560 insertions(+)
>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Makefile
>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>>
>> diff --git a/drivers/gpu/drm/hisilicon/Kconfig b/drivers/gpu/drm/hisilicon/Kconfig
>> index 558c61b..2fd2724 100644
>> --- a/drivers/gpu/drm/hisilicon/Kconfig
>> +++ b/drivers/gpu/drm/hisilicon/Kconfig
>> @@ -2,4 +2,5 @@
>>   # hisilicon drm device configuration.
>>   # Please keep this list sorted alphabetically
>>
>> +source "drivers/gpu/drm/hisilicon/hibmc/Kconfig"
>>   source "drivers/gpu/drm/hisilicon/kirin/Kconfig"
>> diff --git a/drivers/gpu/drm/hisilicon/Makefile b/drivers/gpu/drm/hisilicon/Makefile
>> index e3f6d49..c8155bf 100644
>> --- a/drivers/gpu/drm/hisilicon/Makefile
>> +++ b/drivers/gpu/drm/hisilicon/Makefile
>> @@ -2,4 +2,5 @@
>>   # Makefile for hisilicon drm drivers.
>>   # Please keep this list sorted alphabetically
>>
>> +obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc/
>>   obj-$(CONFIG_DRM_HISI_KIRIN) += kirin/
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>> new file mode 100644
>> index 0000000..380622a
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>> @@ -0,0 +1,9 @@
>> +config DRM_HISI_HIBMC
>> +       tristate "DRM Support for Hisilicon Hibmc"
>> +       depends on DRM && PCI
>> +       select DRM_KMS_HELPER
>> +       select DRM_TTM
>> +
>> +       help
>> +         Choose this option if you have a Hisilicon Hibmc soc chipset.
>> +         If M is selected the module will be called hibmc-drm.
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>> new file mode 100644
>> index 0000000..47962a0
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>> @@ -0,0 +1,4 @@
>> +ccflags-y := -Iinclude/drm
>> +hibmc-drm-y := hibmc_drm_drv.o
>> +
>> +obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> new file mode 100644
>> index 0000000..6d20580
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> @@ -0,0 +1,308 @@
>> +/* Hisilicon Hibmc SoC drm driver
>> + *
>> + * Based on the bochs drm driver.
>> + *
>> + * Copyright (c) 2016 Huawei Limited.
>> + *
>> + * Author:
>> + *     Rongrong Zou <zourongrong@huawei.com>
>> + *     Rongrong Zou <zourongrong@gmail.com>
>> + *     Jianhua Li <lijianhua@huawei.com>
>> + *
>> + * 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.
>> + *
>> + */
>> +
>> +#include <linux/console.h>
>> +#include <linux/module.h>
>> +
>> +#include "hibmc_drm_drv.h"
>> +#include "hibmc_drm_regs.h"
>> +
>> +static const struct file_operations hibmc_fops = {
>> +       .owner          = THIS_MODULE,
>> +       .open           = drm_open,
>> +       .release        = drm_release,
>> +       .unlocked_ioctl = drm_ioctl,
>> +       .compat_ioctl   = drm_compat_ioctl,
>> +       .poll           = drm_poll,
>> +       .read           = drm_read,
>> +       .llseek         = no_llseek,
>> +};
>> +
>> +static int hibmc_enable_vblank(struct drm_device *dev, unsigned int pipe)
>> +{
>> +       return 0;
>> +}
>> +
>> +static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>> +{
>> +}
>> +
>> +static struct drm_driver hibmc_driver = {
>> +       .fops                   = &hibmc_fops,
>> +       .name                   = "hibmc",
>> +       .date                   = "20160828",
>> +       .desc                   = "hibmc drm driver",
>> +       .major                  = 1,
>> +       .minor                  = 0,
>> +       .get_vblank_counter     = drm_vblank_no_hw_counter,
>> +       .enable_vblank          = hibmc_enable_vblank,
>> +       .disable_vblank         = hibmc_disable_vblank,
>> +};
>> +
>> +static int hibmc_pm_suspend(struct device *dev)
>> +{
>> +       return 0;
>> +}
>> +
>> +static int hibmc_pm_resume(struct device *dev)
>> +{
>> +       return 0;
>> +}
>> +
>> +static const struct dev_pm_ops hibmc_pm_ops = {
>> +       SET_SYSTEM_SLEEP_PM_OPS(hibmc_pm_suspend,
>> +                               hibmc_pm_resume)
>> +};
>> +
>> +/*
>> + * It can operate in one of three modes: 0, 1 or Sleep.
>> + */
>> +void hibmc_set_power_mode(struct hibmc_drm_private *priv,
>> +                         unsigned int power_mode)
>> +{
>> +       unsigned int control_value = 0;
>> +       void __iomem   *mmio = priv->mmio;
>> +       unsigned int input = 1;
>> +
>> +       if (power_mode > HIBMC_PW_MODE_CTL_MODE_SLEEP)
>> +               return;
>> +
>> +       if (power_mode == HIBMC_PW_MODE_CTL_MODE_SLEEP)
>> +               input = 0;
>> +
>> +       control_value = readl(mmio + HIBMC_POWER_MODE_CTRL);
>> +       control_value &= ~(HIBMC_PW_MODE_CTL_MODE_MASK |
>> +                          HIBMC_PW_MODE_CTL_OSC_INPUT_MASK);
>> +       control_value |= HIBMC_FIELD(HIBMC_PW_MODE_CTL_MODE, power_mode);
>> +       control_value |= HIBMC_FIELD(HIBMC_PW_MODE_CTL_OSC_INPUT, input);
>> +       writel(control_value, mmio + HIBMC_POWER_MODE_CTRL);
>> +}
>> +
>> +void hibmc_set_current_gate(struct hibmc_drm_private *priv, unsigned int gate)
>> +{
>> +       unsigned int gate_reg;
>> +       unsigned int mode;
>> +       void __iomem   *mmio = priv->mmio;
>> +
>> +       /* Get current power mode. */
>> +       mode = (readl(mmio + HIBMC_POWER_MODE_CTRL) &
>> +               HIBMC_PW_MODE_CTL_MODE_MASK) >> HIBMC_PW_MODE_CTL_MODE_SHIFT;
>> +
>> +       switch (mode) {
>> +       case HIBMC_PW_MODE_CTL_MODE_MODE0:
>> +               gate_reg = HIBMC_MODE0_GATE;
>> +               break;
>> +
>> +       case HIBMC_PW_MODE_CTL_MODE_MODE1:
>> +               gate_reg = HIBMC_MODE1_GATE;
>> +               break;
>> +
>> +       default:
>> +               gate_reg = HIBMC_MODE0_GATE;
>> +               break;
>> +       }
>> +       writel(gate, mmio + gate_reg);
>> +}
>> +
>> +static void hibmc_hw_config(struct hibmc_drm_private *priv)
>> +{
>> +       unsigned int reg;
>> +
>> +       /* On hardware reset, power mode 0 is default. */
>> +       hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_MODE0);
>> +
>> +       /* Enable display power gate & LOCALMEM power gate*/
>> +       reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
>> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
>> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
>> +       reg |= HIBMC_CURR_GATE_DISPLAY(1);
>> +       reg |= HIBMC_CURR_GATE_LOCALMEM(1);
>> +
>> +       hibmc_set_current_gate(priv, reg);
>> +
>> +       /*
>> +        * Reset the memory controller. If the memory controller
>> +        * is not reset in chip,the system might hang when sw accesses
>> +        * the memory.The memory should be resetted after
>> +        * changing the MXCLK.
>> +        */
>> +       reg = readl(priv->mmio + HIBMC_MISC_CTRL);
>> +       reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
>> +       reg |= HIBMC_MSCCTL_LOCALMEM_RESET(0);
>> +       writel(reg, priv->mmio + HIBMC_MISC_CTRL);
>> +
>> +       reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
>> +       reg |= HIBMC_MSCCTL_LOCALMEM_RESET(1);
>> +
>> +       writel(reg, priv->mmio + HIBMC_MISC_CTRL);
>> +}
>> +
>> +static int hibmc_hw_map(struct hibmc_drm_private *priv)
>> +{
>> +       struct drm_device *dev = priv->dev;
>> +       struct pci_dev *pdev = dev->pdev;
>> +       resource_size_t addr, size, ioaddr, iosize;
>> +
>> +       ioaddr = pci_resource_start(pdev, 1);
>> +       iosize = pci_resource_len(pdev, 1);
>> +       priv->mmio = devm_ioremap_nocache(dev->dev, ioaddr, iosize);
>> +       if (!priv->mmio) {
>> +               DRM_ERROR("Cannot map mmio region\n");
>> +               return -ENOMEM;
>> +       }
>> +
>> +       addr = pci_resource_start(pdev, 0);
>> +       size = pci_resource_len(pdev, 0);
>> +       priv->fb_map = devm_ioremap(dev->dev, addr, size);
>> +       if (!priv->fb_map) {
>> +               DRM_ERROR("Cannot map framebuffer\n");
>> +               return -ENOMEM;
>> +       }
>> +       priv->fb_base = addr;
>> +       priv->fb_size = size;
>> +
>> +       return 0;
>> +}
>> +
>> +static int hibmc_hw_init(struct hibmc_drm_private *priv)
>> +{
>> +       int ret;
>> +
>> +       ret = hibmc_hw_map(priv);
>> +       if (ret)
>> +               return ret;
>> +
>> +       hibmc_hw_config(priv);
>> +
>> +       return 0;
>> +}
>> +
>> +static int hibmc_unload(struct drm_device *dev)
>> +{
>> +       return 0;
>> +}
>> +
>> +static int hibmc_load(struct drm_device *dev)
>> +{
>> +       struct hibmc_drm_private *priv;
>> +       int ret;
>> +
>> +       priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
>> +       if (!priv) {
>> +               DRM_ERROR("no memory to allocate for hibmc_drm_private\n");
>> +               return -ENOMEM;
>> +       }
>> +       dev->dev_private = priv;
>> +       priv->dev = dev;
>> +
>> +       ret = hibmc_hw_init(priv);
>> +       if (ret)
>> +               goto err;
>> +
>> +       return 0;
>> +
>> +err:
>> +       hibmc_unload(dev);
>> +       DRM_ERROR("failed to initialize drm driver: %d\n", ret);
>> +       return ret;
>> +}
>> +
>> +static int hibmc_pci_probe(struct pci_dev *pdev,
>> +                          const struct pci_device_id *ent)
>> +{
>> +       struct drm_device *dev;
>> +       int ret;
>> +
>> +       dev = drm_dev_alloc(&hibmc_driver, &pdev->dev);
>> +       if (!dev) {
>> +               DRM_ERROR("failed to allocate drm_device\n");
>> +               return -ENOMEM;
>> +       }
>> +
>> +       dev->pdev = pdev;
>> +       pci_set_drvdata(pdev, dev);
>> +
>> +       ret = pci_enable_device(pdev);
>> +       if (ret) {
>> +               DRM_ERROR("failed to enable pci device: %d\n", ret);
>> +               goto err_free;
>> +       }
>> +
>> +       ret = hibmc_load(dev);
>> +       if (ret) {
>> +               DRM_ERROR("failed to load hibmc: %d\n", ret);
>> +               goto err_disable;
>> +       }
>> +
>> +       ret = drm_dev_register(dev, 0);
>> +       if (ret) {
>> +               DRM_ERROR("failed to register drv for userspace access: %d\n",
>> +                         ret);
>> +               goto err_unload;
>> +       }
>> +       return 0;
>> +
>> +err_unload:
>> +       hibmc_unload(dev);
>> +err_disable:
>> +       pci_disable_device(pdev);
>> +err_free:
>> +       drm_dev_unref(dev);
>> +
>> +       return ret;
>> +}
>> +
>> +static void hibmc_pci_remove(struct pci_dev *pdev)
>> +{
>> +       struct drm_device *dev = pci_get_drvdata(pdev);
>> +
>> +       drm_dev_unregister(dev);
>> +       hibmc_unload(dev);
>> +       drm_dev_unref(dev);
>> +}
>> +
>> +static struct pci_device_id hibmc_pci_table[] = {
>> +       {0x19e5, 0x1711, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
>> +       {0,}
>> +};
>> +
>> +static struct pci_driver hibmc_pci_driver = {
>> +       .name =         "hibmc-drm",
>> +       .id_table =     hibmc_pci_table,
>> +       .probe =        hibmc_pci_probe,
>> +       .remove =       hibmc_pci_remove,
>> +       .driver.pm =    &hibmc_pm_ops,
>> +};
>> +
>> +static int __init hibmc_init(void)
>> +{
>> +       return pci_register_driver(&hibmc_pci_driver);
>> +}
>> +
>> +static void __exit hibmc_exit(void)
>> +{
>> +       return pci_unregister_driver(&hibmc_pci_driver);
>> +}
>> +
>> +module_init(hibmc_init);
>> +module_exit(hibmc_exit);
>> +
>> +MODULE_DEVICE_TABLE(pci, hibmc_pci_table);
>> +MODULE_AUTHOR("RongrongZou <zourongrong@huawei.com>");
>> +MODULE_DESCRIPTION("DRM Driver for Hisilicon Hibmc");
>> +MODULE_LICENSE("GPL v2");
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> new file mode 100644
>> index 0000000..840cd5a
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> @@ -0,0 +1,41 @@
>> +/* Hisilicon Hibmc SoC drm driver
>> + *
>> + * Based on the bochs drm driver.
>> + *
>> + * Copyright (c) 2016 Huawei Limited.
>> + *
>> + * Author:
>> + *     Rongrong Zou <zourongrong@huawei.com>
>> + *     Rongrong Zou <zourongrong@gmail.com>
>> + *     Jianhua Li <lijianhua@huawei.com>
>> + *
>> + * 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.
>> + *
>> + */
>> +
>> +#ifndef HIBMC_DRM_DRV_H
>> +#define HIBMC_DRM_DRV_H
>> +
>> +#include <drm/drmP.h>
>> +
>> +struct hibmc_drm_private {
>> +       /* hw */
>> +       void __iomem   *mmio;
>> +       void __iomem   *fb_map;
>> +       unsigned long  fb_base;
>> +       unsigned long  fb_size;
>> +
>> +       /* drm */
>> +       struct drm_device  *dev;
>> +
>> +};
>> +
>> +void hibmc_set_power_mode(struct hibmc_drm_private *priv,
>> +                         unsigned int power_mode);
>> +void hibmc_set_current_gate(struct hibmc_drm_private *priv,
>> +                           unsigned int gate);
>> +
>> +#endif
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>> new file mode 100644
>> index 0000000..f7035bf
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>> @@ -0,0 +1,196 @@
>> +/* Hisilicon Hibmc SoC drm driver
>> + *
>> + * Based on the bochs drm driver.
>> + *
>> + * Copyright (c) 2016 Huawei Limited.
>> + *
>> + * Author:
>> + *     Rongrong Zou <zourongrong@huawei.com>
>> + *     Rongrong Zou <zourongrong@gmail.com>
>> + *     Jianhua Li <lijianhua@huawei.com>
>> + *
>> + * 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.
>> + *
>> + */
>> +
>> +#ifndef HIBMC_DRM_HW_H
>> +#define HIBMC_DRM_HW_H
>> +
>> +/* register definition */
>> +#define HIBMC_MISC_CTRL                                0x4
>> +
>> +#define HIBMC_MSCCTL_LOCALMEM_RESET(x)         ((x) << 6)
>> +#define HIBMC_MSCCTL_LOCALMEM_RESET_MASK       0x40
>> +
>> +#define HIBMC_CURRENT_GATE                     0x000040
>> +#define HIBMC_CURR_GATE_DISPLAY(x)             ((x) << 2)
>> +#define HIBMC_CURR_GATE_DISPLAY_MASK           0x4
>> +
>> +#define HIBMC_CURR_GATE_LOCALMEM(x)            ((x) << 1)
>> +#define HIBMC_CURR_GATE_LOCALMEM_MASK          0x2
>> +
>> +#define HIBMC_MODE0_GATE                       0x000044
>> +#define HIBMC_MODE1_GATE                       0x000048
>> +#define HIBMC_POWER_MODE_CTRL                  0x00004C
>> +
>> +#define HIBMC_PW_MODE_CTL_OSC_INPUT(x)         ((x) << 3)
>> +#define HIBMC_PW_MODE_CTL_OSC_INPUT_MASK       0x8
>> +
>> +#define HIBMC_PW_MODE_CTL_MODE(x)              ((x) << 0)
>> +#define HIBMC_PW_MODE_CTL_MODE_MASK            0x03
>> +#define HIBMC_PW_MODE_CTL_MODE_SHIFT           0
>> +
>> +#define HIBMC_PW_MODE_CTL_MODE_MODE0           0
>> +#define HIBMC_PW_MODE_CTL_MODE_MODE1           1
>> +#define HIBMC_PW_MODE_CTL_MODE_SLEEP           2
>> +
>> +#define HIBMC_PANEL_PLL_CTRL                   0x00005C
>> +#define HIBMC_CRT_PLL_CTRL                     0x000060
>> +
>> +#define HIBMC_PLL_CTRL_BYPASS(x)               ((x) << 18)
>> +#define HIBMC_PLL_CTRL_BYPASS_MASK             0x40000
>> +
>> +#define HIBMC_PLL_CTRL_POWER(x)                        ((x) << 17)
>> +#define HIBMC_PLL_CTRL_POWER_MASK              0x20000
>> +
>> +#define HIBMC_PLL_CTRL_INPUT(x)                        ((x) << 16)
>> +#define HIBMC_PLL_CTRL_INPUT_MASK              0x10000
>> +
>> +#define HIBMC_PLL_CTRL_POD(x)                  ((x) << 14)
>> +#define HIBMC_PLL_CTRL_POD_MASK                        0xC000
>> +
>> +#define HIBMC_PLL_CTRL_OD(x)                   ((x) << 12)
>> +#define HIBMC_PLL_CTRL_OD_MASK                 0x3000
>> +
>> +#define HIBMC_PLL_CTRL_N(x)                    ((x) << 8)
>> +#define HIBMC_PLL_CTRL_N_MASK                  0xF00
>> +
>> +#define HIBMC_PLL_CTRL_M(x)                    ((x) << 0)
>> +#define HIBMC_PLL_CTRL_M_MASK                  0xFF
>> +
>> +#define HIBMC_CRT_DISP_CTL                     0x80200
>> +
>> +#define HIBMC_CRT_DISP_CTL_CRTSELECT(x)                ((x) << 25)
>> +#define HIBMC_CRT_DISP_CTL_CRTSELECT_MASK      0x2000000
>> +
>> +#define HIBMC_CRTSELECT_CRT                    1
>> +
>> +#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE(x)      ((x) << 14)
>> +#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE_MASK    0x4000
>> +
>> +#define HIBMC_CRT_DISP_CTL_VSYNC_PHASE(x)      ((x) << 13)
>> +#define HIBMC_CRT_DISP_CTL_VSYNC_PHASE_MASK    0x2000
>> +
>> +#define HIBMC_CRT_DISP_CTL_HSYNC_PHASE(x)      ((x) << 12)
>> +#define HIBMC_CRT_DISP_CTL_HSYNC_PHASE_MASK    0x1000
>> +
>> +#define HIBMC_CRT_DISP_CTL_TIMING(x)           ((x) << 8)
>> +#define HIBMC_CRT_DISP_CTL_TIMING_MASK         0x100
>> +
>> +#define HIBMC_CRT_DISP_CTL_PLANE(x)            ((x) << 2)
>> +#define HIBMC_CRT_DISP_CTL_PLANE_MASK          4
>> +
>> +#define HIBMC_CRT_DISP_CTL_FORMAT(x)           ((x) << 0)
>> +#define HIBMC_CRT_DISP_CTL_FORMAT_MASK         0x03
>> +
>> +#define HIBMC_CRT_FB_ADDRESS                   0x080204
>> +
>> +#define HIBMC_CRT_FB_WIDTH                     0x080208
>> +#define HIBMC_CRT_FB_WIDTH_WIDTH(x)            ((x) << 16)
>> +#define HIBMC_CRT_FB_WIDTH_WIDTH_MASK          0x3FFF0000
>> +#define HIBMC_CRT_FB_WIDTH_OFFS(x)             ((x) << 0)
>> +#define HIBMC_CRT_FB_WIDTH_OFFS_MASK           0x3FFF
>> +
>> +#define HIBMC_CRT_HORZ_TOTAL                   0x08020C
>> +#define HIBMC_CRT_HORZ_TOTAL_TOTAL(x)          ((x) << 16)
>> +#define HIBMC_CRT_HORZ_TOTAL_TOTAL_MASK                0xFFF0000
>> +
>> +#define HIBMC_CRT_HORZ_TOTAL_DISP_END(x)       ((x) << 0)
>> +#define HIBMC_CRT_HORZ_TOTAL_DISP_END_MASK     0xFFF
>> +
>> +#define HIBMC_CRT_HORZ_SYNC                    0x080210
>> +#define HIBMC_CRT_HORZ_SYNC_WIDTH(x)           ((x) << 16)
>> +#define HIBMC_CRT_HORZ_SYNC_WIDTH_MASK         0xFF0000
>> +
>> +#define HIBMC_CRT_HORZ_SYNC_START(x)           ((x) << 0)
>> +#define HIBMC_CRT_HORZ_SYNC_START_MASK         0xFFF
>> +
>> +#define HIBMC_CRT_VERT_TOTAL                   0x080214
>> +#define HIBMC_CRT_VERT_TOTAL_TOTAL(x)          ((x) << 16)
>> +#define HIBMC_CRT_VERT_TOTAL_TOTAL_MASK                0x7FFF0000
>> +
>> +#define HIBMC_CRT_VERT_TOTAL_DISP_END(x)       ((x) << 0)
>> +#define HIBMC_CRT_VERT_TOTAL_DISP_END_MASK     0x7FF
>> +
>> +#define HIBMC_CRT_VERT_SYNC                    0x080218
>> +#define HIBMC_CRT_VERT_SYNC_HEIGHT(x)          ((x) << 16)
>> +#define HIBMC_CRT_VERT_SYNC_HEIGHT_MASK                0x3F0000
>> +
>> +#define HIBMC_CRT_VERT_SYNC_START(x)           ((x) << 0)
>> +#define HIBMC_CRT_VERT_SYNC_START_MASK         0x7FF
>> +
>> +/* Auto Centering */
>> +#define HIBMC_CRT_AUTO_CENTERING_TL            0x080280
>> +#define HIBMC_CRT_AUTO_CENTERING_TL_TOP(x)     ((x) << 16)
>> +#define HIBMC_CRT_AUTO_CENTERING_TL_TOP_MASK   0x7FF0000
>> +
>> +#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT(x)    ((x) << 0)
>> +#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT_MASK  0x7FF
>> +
>> +#define HIBMC_CRT_AUTO_CENTERING_BR            0x080284
>> +#define HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM(x)  ((x) << 16)
>> +#define HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM_MASK        0x7FF0000
>> +
>> +#define HIBMC_CRT_AUTO_CENTERING_BR_RIGHT(x)   ((x) << 0)
>> +#define HIBMC_CRT_AUTO_CENTERING_BR_RIGHT_MASK 0x7FF
>> +
>> +/* register to control panel output */
>> +#define HIBMC_DISPLAY_CONTROL_HISILE           0x80288
>> +#define HIBMC_DISPLAY_CONTROL_FPVDDEN(x)       ((x) << 0)
>> +#define HIBMC_DISPLAY_CONTROL_PANELDATE(x)     ((x) << 1)
>> +#define HIBMC_DISPLAY_CONTROL_FPEN(x)          ((x) << 2)
>> +#define HIBMC_DISPLAY_CONTROL_VBIASEN(x)       ((x) << 3)
>> +
>> +#define HIBMC_RAW_INTERRUPT                    0x80290
>> +#define HIBMC_RAW_INTERRUPT_VBLANK(x)          ((x) << 2)
>> +#define HIBMC_RAW_INTERRUPT_VBLANK_MASK                0x4
>> +
>> +#define HIBMC_RAW_INTERRUPT_EN                 0x80298
>> +#define HIBMC_RAW_INTERRUPT_EN_VBLANK(x)       ((x) << 2)
>> +#define HIBMC_RAW_INTERRUPT_EN_VBLANK_MASK     0x4
>> +
>> +/* register and values for PLL control */
>> +#define CRT_PLL1_HS                            0x802a8
>> +#define CRT_PLL1_HS_OUTER_BYPASS(x)            ((x) << 30)
>> +#define CRT_PLL1_HS_INTER_BYPASS(x)            ((x) << 29)
>> +#define CRT_PLL1_HS_POWERON(x)                 ((x) << 24)
>> +
>> +#define CRT_PLL1_HS_25MHZ                      0x23d40f02
>> +#define CRT_PLL1_HS_40MHZ                      0x23940801
>> +#define CRT_PLL1_HS_65MHZ                      0x23940d01
>> +#define CRT_PLL1_HS_78MHZ                      0x23540F82
>> +#define CRT_PLL1_HS_74MHZ                      0x23941dc2
>> +#define CRT_PLL1_HS_80MHZ                      0x23941001
>> +#define CRT_PLL1_HS_80MHZ_1152                 0x23540fc2
>> +#define CRT_PLL1_HS_108MHZ                     0x23b41b01
>> +#define CRT_PLL1_HS_162MHZ                     0x23480681
>> +#define CRT_PLL1_HS_148MHZ                     0x23541dc2
>> +#define CRT_PLL1_HS_193MHZ                     0x234807c1
>> +
>> +#define CRT_PLL2_HS                            0x802ac
>> +#define CRT_PLL2_HS_25MHZ                      0x206B851E
>> +#define CRT_PLL2_HS_40MHZ                      0x30000000
>> +#define CRT_PLL2_HS_65MHZ                      0x40000000
>> +#define CRT_PLL2_HS_78MHZ                      0x50E147AE
>> +#define CRT_PLL2_HS_74MHZ                      0x602B6AE7
>> +#define CRT_PLL2_HS_80MHZ                      0x70000000
>> +#define CRT_PLL2_HS_108MHZ                     0x80000000
>> +#define CRT_PLL2_HS_162MHZ                     0xA0000000
>> +#define CRT_PLL2_HS_148MHZ                     0xB0CCCCCD
>> +#define CRT_PLL2_HS_193MHZ                     0xC0872B02
>> +
>> +#define HIBMC_FIELD(field, value) (field(value) & field##_MASK)
>> +#endif
>> --
>> 1.9.1
>>
> _______________________________________________
> linuxarm mailing list
> linuxarm at huawei.com
> http://rnd-openeuler.huawei.com/mailman/listinfo/linuxarm
>
> .
>

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v7 1/7] drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
@ 2016-11-17  4:05       ` Rongrong Zou
  0 siblings, 0 replies; 40+ messages in thread
From: Rongrong Zou @ 2016-11-17  4:05 UTC (permalink / raw)
  To: Sean Paul, Rongrong Zou
  Cc: Mark Rutland, Archit, lijianhua, Daniel Vetter, Tomeu Vizoso,
	seanpaul, Dave Airlie, Jonathan Corbet, Emil Velikov, linuxarm,
	dri-devel, Xinliang Liu, james.xiong, Benjamin Gaignard,
	Daniel Stone, Linux ARM Kernel, shenhui

Hi Sean,

Thanks for reviewing.

在 2016/11/16 23:42, Sean Paul 写道:
> On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
>> Add DRM master driver for Hisilicon Hibmc SoC which used for
>> Out-of-band management. Blow is the general hardware connection,
>> both the Hibmc and the host CPU are on the same mother board.
>>
>> +----------+       +----------+
>> |          | PCIe  |  Hibmc   |
>> |host CPU( |<----->| display  |
>> |arm64,x86)|       |subsystem |
>> +----------+       +----------+
>>
>> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
>> ---
>
> In the future, please keep track of the differences between patch
> versions. I noticed you have a short changelog in the cover letter,
> but it really helps to add one per-patch as well, it makes reviewing
> much simpler.
>
> Reviewed-by: Sean Paul <seanpaul@chromium.org>

Sorry for that, I will pay attention to it later, thanks.

Regards,
Rongrong.

>
>
>>   drivers/gpu/drm/hisilicon/Kconfig                |   1 +
>>   drivers/gpu/drm/hisilicon/Makefile               |   1 +
>>   drivers/gpu/drm/hisilicon/hibmc/Kconfig          |   9 +
>>   drivers/gpu/drm/hisilicon/hibmc/Makefile         |   4 +
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c  | 308 +++++++++++++++++++++++
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h  |  41 +++
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h | 196 +++++++++++++++
>>   7 files changed, 560 insertions(+)
>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Makefile
>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>>
>> diff --git a/drivers/gpu/drm/hisilicon/Kconfig b/drivers/gpu/drm/hisilicon/Kconfig
>> index 558c61b..2fd2724 100644
>> --- a/drivers/gpu/drm/hisilicon/Kconfig
>> +++ b/drivers/gpu/drm/hisilicon/Kconfig
>> @@ -2,4 +2,5 @@
>>   # hisilicon drm device configuration.
>>   # Please keep this list sorted alphabetically
>>
>> +source "drivers/gpu/drm/hisilicon/hibmc/Kconfig"
>>   source "drivers/gpu/drm/hisilicon/kirin/Kconfig"
>> diff --git a/drivers/gpu/drm/hisilicon/Makefile b/drivers/gpu/drm/hisilicon/Makefile
>> index e3f6d49..c8155bf 100644
>> --- a/drivers/gpu/drm/hisilicon/Makefile
>> +++ b/drivers/gpu/drm/hisilicon/Makefile
>> @@ -2,4 +2,5 @@
>>   # Makefile for hisilicon drm drivers.
>>   # Please keep this list sorted alphabetically
>>
>> +obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc/
>>   obj-$(CONFIG_DRM_HISI_KIRIN) += kirin/
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>> new file mode 100644
>> index 0000000..380622a
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>> @@ -0,0 +1,9 @@
>> +config DRM_HISI_HIBMC
>> +       tristate "DRM Support for Hisilicon Hibmc"
>> +       depends on DRM && PCI
>> +       select DRM_KMS_HELPER
>> +       select DRM_TTM
>> +
>> +       help
>> +         Choose this option if you have a Hisilicon Hibmc soc chipset.
>> +         If M is selected the module will be called hibmc-drm.
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>> new file mode 100644
>> index 0000000..47962a0
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>> @@ -0,0 +1,4 @@
>> +ccflags-y := -Iinclude/drm
>> +hibmc-drm-y := hibmc_drm_drv.o
>> +
>> +obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> new file mode 100644
>> index 0000000..6d20580
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> @@ -0,0 +1,308 @@
>> +/* Hisilicon Hibmc SoC drm driver
>> + *
>> + * Based on the bochs drm driver.
>> + *
>> + * Copyright (c) 2016 Huawei Limited.
>> + *
>> + * Author:
>> + *     Rongrong Zou <zourongrong@huawei.com>
>> + *     Rongrong Zou <zourongrong@gmail.com>
>> + *     Jianhua Li <lijianhua@huawei.com>
>> + *
>> + * 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.
>> + *
>> + */
>> +
>> +#include <linux/console.h>
>> +#include <linux/module.h>
>> +
>> +#include "hibmc_drm_drv.h"
>> +#include "hibmc_drm_regs.h"
>> +
>> +static const struct file_operations hibmc_fops = {
>> +       .owner          = THIS_MODULE,
>> +       .open           = drm_open,
>> +       .release        = drm_release,
>> +       .unlocked_ioctl = drm_ioctl,
>> +       .compat_ioctl   = drm_compat_ioctl,
>> +       .poll           = drm_poll,
>> +       .read           = drm_read,
>> +       .llseek         = no_llseek,
>> +};
>> +
>> +static int hibmc_enable_vblank(struct drm_device *dev, unsigned int pipe)
>> +{
>> +       return 0;
>> +}
>> +
>> +static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>> +{
>> +}
>> +
>> +static struct drm_driver hibmc_driver = {
>> +       .fops                   = &hibmc_fops,
>> +       .name                   = "hibmc",
>> +       .date                   = "20160828",
>> +       .desc                   = "hibmc drm driver",
>> +       .major                  = 1,
>> +       .minor                  = 0,
>> +       .get_vblank_counter     = drm_vblank_no_hw_counter,
>> +       .enable_vblank          = hibmc_enable_vblank,
>> +       .disable_vblank         = hibmc_disable_vblank,
>> +};
>> +
>> +static int hibmc_pm_suspend(struct device *dev)
>> +{
>> +       return 0;
>> +}
>> +
>> +static int hibmc_pm_resume(struct device *dev)
>> +{
>> +       return 0;
>> +}
>> +
>> +static const struct dev_pm_ops hibmc_pm_ops = {
>> +       SET_SYSTEM_SLEEP_PM_OPS(hibmc_pm_suspend,
>> +                               hibmc_pm_resume)
>> +};
>> +
>> +/*
>> + * It can operate in one of three modes: 0, 1 or Sleep.
>> + */
>> +void hibmc_set_power_mode(struct hibmc_drm_private *priv,
>> +                         unsigned int power_mode)
>> +{
>> +       unsigned int control_value = 0;
>> +       void __iomem   *mmio = priv->mmio;
>> +       unsigned int input = 1;
>> +
>> +       if (power_mode > HIBMC_PW_MODE_CTL_MODE_SLEEP)
>> +               return;
>> +
>> +       if (power_mode == HIBMC_PW_MODE_CTL_MODE_SLEEP)
>> +               input = 0;
>> +
>> +       control_value = readl(mmio + HIBMC_POWER_MODE_CTRL);
>> +       control_value &= ~(HIBMC_PW_MODE_CTL_MODE_MASK |
>> +                          HIBMC_PW_MODE_CTL_OSC_INPUT_MASK);
>> +       control_value |= HIBMC_FIELD(HIBMC_PW_MODE_CTL_MODE, power_mode);
>> +       control_value |= HIBMC_FIELD(HIBMC_PW_MODE_CTL_OSC_INPUT, input);
>> +       writel(control_value, mmio + HIBMC_POWER_MODE_CTRL);
>> +}
>> +
>> +void hibmc_set_current_gate(struct hibmc_drm_private *priv, unsigned int gate)
>> +{
>> +       unsigned int gate_reg;
>> +       unsigned int mode;
>> +       void __iomem   *mmio = priv->mmio;
>> +
>> +       /* Get current power mode. */
>> +       mode = (readl(mmio + HIBMC_POWER_MODE_CTRL) &
>> +               HIBMC_PW_MODE_CTL_MODE_MASK) >> HIBMC_PW_MODE_CTL_MODE_SHIFT;
>> +
>> +       switch (mode) {
>> +       case HIBMC_PW_MODE_CTL_MODE_MODE0:
>> +               gate_reg = HIBMC_MODE0_GATE;
>> +               break;
>> +
>> +       case HIBMC_PW_MODE_CTL_MODE_MODE1:
>> +               gate_reg = HIBMC_MODE1_GATE;
>> +               break;
>> +
>> +       default:
>> +               gate_reg = HIBMC_MODE0_GATE;
>> +               break;
>> +       }
>> +       writel(gate, mmio + gate_reg);
>> +}
>> +
>> +static void hibmc_hw_config(struct hibmc_drm_private *priv)
>> +{
>> +       unsigned int reg;
>> +
>> +       /* On hardware reset, power mode 0 is default. */
>> +       hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_MODE0);
>> +
>> +       /* Enable display power gate & LOCALMEM power gate*/
>> +       reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
>> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
>> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
>> +       reg |= HIBMC_CURR_GATE_DISPLAY(1);
>> +       reg |= HIBMC_CURR_GATE_LOCALMEM(1);
>> +
>> +       hibmc_set_current_gate(priv, reg);
>> +
>> +       /*
>> +        * Reset the memory controller. If the memory controller
>> +        * is not reset in chip,the system might hang when sw accesses
>> +        * the memory.The memory should be resetted after
>> +        * changing the MXCLK.
>> +        */
>> +       reg = readl(priv->mmio + HIBMC_MISC_CTRL);
>> +       reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
>> +       reg |= HIBMC_MSCCTL_LOCALMEM_RESET(0);
>> +       writel(reg, priv->mmio + HIBMC_MISC_CTRL);
>> +
>> +       reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
>> +       reg |= HIBMC_MSCCTL_LOCALMEM_RESET(1);
>> +
>> +       writel(reg, priv->mmio + HIBMC_MISC_CTRL);
>> +}
>> +
>> +static int hibmc_hw_map(struct hibmc_drm_private *priv)
>> +{
>> +       struct drm_device *dev = priv->dev;
>> +       struct pci_dev *pdev = dev->pdev;
>> +       resource_size_t addr, size, ioaddr, iosize;
>> +
>> +       ioaddr = pci_resource_start(pdev, 1);
>> +       iosize = pci_resource_len(pdev, 1);
>> +       priv->mmio = devm_ioremap_nocache(dev->dev, ioaddr, iosize);
>> +       if (!priv->mmio) {
>> +               DRM_ERROR("Cannot map mmio region\n");
>> +               return -ENOMEM;
>> +       }
>> +
>> +       addr = pci_resource_start(pdev, 0);
>> +       size = pci_resource_len(pdev, 0);
>> +       priv->fb_map = devm_ioremap(dev->dev, addr, size);
>> +       if (!priv->fb_map) {
>> +               DRM_ERROR("Cannot map framebuffer\n");
>> +               return -ENOMEM;
>> +       }
>> +       priv->fb_base = addr;
>> +       priv->fb_size = size;
>> +
>> +       return 0;
>> +}
>> +
>> +static int hibmc_hw_init(struct hibmc_drm_private *priv)
>> +{
>> +       int ret;
>> +
>> +       ret = hibmc_hw_map(priv);
>> +       if (ret)
>> +               return ret;
>> +
>> +       hibmc_hw_config(priv);
>> +
>> +       return 0;
>> +}
>> +
>> +static int hibmc_unload(struct drm_device *dev)
>> +{
>> +       return 0;
>> +}
>> +
>> +static int hibmc_load(struct drm_device *dev)
>> +{
>> +       struct hibmc_drm_private *priv;
>> +       int ret;
>> +
>> +       priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
>> +       if (!priv) {
>> +               DRM_ERROR("no memory to allocate for hibmc_drm_private\n");
>> +               return -ENOMEM;
>> +       }
>> +       dev->dev_private = priv;
>> +       priv->dev = dev;
>> +
>> +       ret = hibmc_hw_init(priv);
>> +       if (ret)
>> +               goto err;
>> +
>> +       return 0;
>> +
>> +err:
>> +       hibmc_unload(dev);
>> +       DRM_ERROR("failed to initialize drm driver: %d\n", ret);
>> +       return ret;
>> +}
>> +
>> +static int hibmc_pci_probe(struct pci_dev *pdev,
>> +                          const struct pci_device_id *ent)
>> +{
>> +       struct drm_device *dev;
>> +       int ret;
>> +
>> +       dev = drm_dev_alloc(&hibmc_driver, &pdev->dev);
>> +       if (!dev) {
>> +               DRM_ERROR("failed to allocate drm_device\n");
>> +               return -ENOMEM;
>> +       }
>> +
>> +       dev->pdev = pdev;
>> +       pci_set_drvdata(pdev, dev);
>> +
>> +       ret = pci_enable_device(pdev);
>> +       if (ret) {
>> +               DRM_ERROR("failed to enable pci device: %d\n", ret);
>> +               goto err_free;
>> +       }
>> +
>> +       ret = hibmc_load(dev);
>> +       if (ret) {
>> +               DRM_ERROR("failed to load hibmc: %d\n", ret);
>> +               goto err_disable;
>> +       }
>> +
>> +       ret = drm_dev_register(dev, 0);
>> +       if (ret) {
>> +               DRM_ERROR("failed to register drv for userspace access: %d\n",
>> +                         ret);
>> +               goto err_unload;
>> +       }
>> +       return 0;
>> +
>> +err_unload:
>> +       hibmc_unload(dev);
>> +err_disable:
>> +       pci_disable_device(pdev);
>> +err_free:
>> +       drm_dev_unref(dev);
>> +
>> +       return ret;
>> +}
>> +
>> +static void hibmc_pci_remove(struct pci_dev *pdev)
>> +{
>> +       struct drm_device *dev = pci_get_drvdata(pdev);
>> +
>> +       drm_dev_unregister(dev);
>> +       hibmc_unload(dev);
>> +       drm_dev_unref(dev);
>> +}
>> +
>> +static struct pci_device_id hibmc_pci_table[] = {
>> +       {0x19e5, 0x1711, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
>> +       {0,}
>> +};
>> +
>> +static struct pci_driver hibmc_pci_driver = {
>> +       .name =         "hibmc-drm",
>> +       .id_table =     hibmc_pci_table,
>> +       .probe =        hibmc_pci_probe,
>> +       .remove =       hibmc_pci_remove,
>> +       .driver.pm =    &hibmc_pm_ops,
>> +};
>> +
>> +static int __init hibmc_init(void)
>> +{
>> +       return pci_register_driver(&hibmc_pci_driver);
>> +}
>> +
>> +static void __exit hibmc_exit(void)
>> +{
>> +       return pci_unregister_driver(&hibmc_pci_driver);
>> +}
>> +
>> +module_init(hibmc_init);
>> +module_exit(hibmc_exit);
>> +
>> +MODULE_DEVICE_TABLE(pci, hibmc_pci_table);
>> +MODULE_AUTHOR("RongrongZou <zourongrong@huawei.com>");
>> +MODULE_DESCRIPTION("DRM Driver for Hisilicon Hibmc");
>> +MODULE_LICENSE("GPL v2");
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> new file mode 100644
>> index 0000000..840cd5a
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> @@ -0,0 +1,41 @@
>> +/* Hisilicon Hibmc SoC drm driver
>> + *
>> + * Based on the bochs drm driver.
>> + *
>> + * Copyright (c) 2016 Huawei Limited.
>> + *
>> + * Author:
>> + *     Rongrong Zou <zourongrong@huawei.com>
>> + *     Rongrong Zou <zourongrong@gmail.com>
>> + *     Jianhua Li <lijianhua@huawei.com>
>> + *
>> + * 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.
>> + *
>> + */
>> +
>> +#ifndef HIBMC_DRM_DRV_H
>> +#define HIBMC_DRM_DRV_H
>> +
>> +#include <drm/drmP.h>
>> +
>> +struct hibmc_drm_private {
>> +       /* hw */
>> +       void __iomem   *mmio;
>> +       void __iomem   *fb_map;
>> +       unsigned long  fb_base;
>> +       unsigned long  fb_size;
>> +
>> +       /* drm */
>> +       struct drm_device  *dev;
>> +
>> +};
>> +
>> +void hibmc_set_power_mode(struct hibmc_drm_private *priv,
>> +                         unsigned int power_mode);
>> +void hibmc_set_current_gate(struct hibmc_drm_private *priv,
>> +                           unsigned int gate);
>> +
>> +#endif
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>> new file mode 100644
>> index 0000000..f7035bf
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>> @@ -0,0 +1,196 @@
>> +/* Hisilicon Hibmc SoC drm driver
>> + *
>> + * Based on the bochs drm driver.
>> + *
>> + * Copyright (c) 2016 Huawei Limited.
>> + *
>> + * Author:
>> + *     Rongrong Zou <zourongrong@huawei.com>
>> + *     Rongrong Zou <zourongrong@gmail.com>
>> + *     Jianhua Li <lijianhua@huawei.com>
>> + *
>> + * 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.
>> + *
>> + */
>> +
>> +#ifndef HIBMC_DRM_HW_H
>> +#define HIBMC_DRM_HW_H
>> +
>> +/* register definition */
>> +#define HIBMC_MISC_CTRL                                0x4
>> +
>> +#define HIBMC_MSCCTL_LOCALMEM_RESET(x)         ((x) << 6)
>> +#define HIBMC_MSCCTL_LOCALMEM_RESET_MASK       0x40
>> +
>> +#define HIBMC_CURRENT_GATE                     0x000040
>> +#define HIBMC_CURR_GATE_DISPLAY(x)             ((x) << 2)
>> +#define HIBMC_CURR_GATE_DISPLAY_MASK           0x4
>> +
>> +#define HIBMC_CURR_GATE_LOCALMEM(x)            ((x) << 1)
>> +#define HIBMC_CURR_GATE_LOCALMEM_MASK          0x2
>> +
>> +#define HIBMC_MODE0_GATE                       0x000044
>> +#define HIBMC_MODE1_GATE                       0x000048
>> +#define HIBMC_POWER_MODE_CTRL                  0x00004C
>> +
>> +#define HIBMC_PW_MODE_CTL_OSC_INPUT(x)         ((x) << 3)
>> +#define HIBMC_PW_MODE_CTL_OSC_INPUT_MASK       0x8
>> +
>> +#define HIBMC_PW_MODE_CTL_MODE(x)              ((x) << 0)
>> +#define HIBMC_PW_MODE_CTL_MODE_MASK            0x03
>> +#define HIBMC_PW_MODE_CTL_MODE_SHIFT           0
>> +
>> +#define HIBMC_PW_MODE_CTL_MODE_MODE0           0
>> +#define HIBMC_PW_MODE_CTL_MODE_MODE1           1
>> +#define HIBMC_PW_MODE_CTL_MODE_SLEEP           2
>> +
>> +#define HIBMC_PANEL_PLL_CTRL                   0x00005C
>> +#define HIBMC_CRT_PLL_CTRL                     0x000060
>> +
>> +#define HIBMC_PLL_CTRL_BYPASS(x)               ((x) << 18)
>> +#define HIBMC_PLL_CTRL_BYPASS_MASK             0x40000
>> +
>> +#define HIBMC_PLL_CTRL_POWER(x)                        ((x) << 17)
>> +#define HIBMC_PLL_CTRL_POWER_MASK              0x20000
>> +
>> +#define HIBMC_PLL_CTRL_INPUT(x)                        ((x) << 16)
>> +#define HIBMC_PLL_CTRL_INPUT_MASK              0x10000
>> +
>> +#define HIBMC_PLL_CTRL_POD(x)                  ((x) << 14)
>> +#define HIBMC_PLL_CTRL_POD_MASK                        0xC000
>> +
>> +#define HIBMC_PLL_CTRL_OD(x)                   ((x) << 12)
>> +#define HIBMC_PLL_CTRL_OD_MASK                 0x3000
>> +
>> +#define HIBMC_PLL_CTRL_N(x)                    ((x) << 8)
>> +#define HIBMC_PLL_CTRL_N_MASK                  0xF00
>> +
>> +#define HIBMC_PLL_CTRL_M(x)                    ((x) << 0)
>> +#define HIBMC_PLL_CTRL_M_MASK                  0xFF
>> +
>> +#define HIBMC_CRT_DISP_CTL                     0x80200
>> +
>> +#define HIBMC_CRT_DISP_CTL_CRTSELECT(x)                ((x) << 25)
>> +#define HIBMC_CRT_DISP_CTL_CRTSELECT_MASK      0x2000000
>> +
>> +#define HIBMC_CRTSELECT_CRT                    1
>> +
>> +#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE(x)      ((x) << 14)
>> +#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE_MASK    0x4000
>> +
>> +#define HIBMC_CRT_DISP_CTL_VSYNC_PHASE(x)      ((x) << 13)
>> +#define HIBMC_CRT_DISP_CTL_VSYNC_PHASE_MASK    0x2000
>> +
>> +#define HIBMC_CRT_DISP_CTL_HSYNC_PHASE(x)      ((x) << 12)
>> +#define HIBMC_CRT_DISP_CTL_HSYNC_PHASE_MASK    0x1000
>> +
>> +#define HIBMC_CRT_DISP_CTL_TIMING(x)           ((x) << 8)
>> +#define HIBMC_CRT_DISP_CTL_TIMING_MASK         0x100
>> +
>> +#define HIBMC_CRT_DISP_CTL_PLANE(x)            ((x) << 2)
>> +#define HIBMC_CRT_DISP_CTL_PLANE_MASK          4
>> +
>> +#define HIBMC_CRT_DISP_CTL_FORMAT(x)           ((x) << 0)
>> +#define HIBMC_CRT_DISP_CTL_FORMAT_MASK         0x03
>> +
>> +#define HIBMC_CRT_FB_ADDRESS                   0x080204
>> +
>> +#define HIBMC_CRT_FB_WIDTH                     0x080208
>> +#define HIBMC_CRT_FB_WIDTH_WIDTH(x)            ((x) << 16)
>> +#define HIBMC_CRT_FB_WIDTH_WIDTH_MASK          0x3FFF0000
>> +#define HIBMC_CRT_FB_WIDTH_OFFS(x)             ((x) << 0)
>> +#define HIBMC_CRT_FB_WIDTH_OFFS_MASK           0x3FFF
>> +
>> +#define HIBMC_CRT_HORZ_TOTAL                   0x08020C
>> +#define HIBMC_CRT_HORZ_TOTAL_TOTAL(x)          ((x) << 16)
>> +#define HIBMC_CRT_HORZ_TOTAL_TOTAL_MASK                0xFFF0000
>> +
>> +#define HIBMC_CRT_HORZ_TOTAL_DISP_END(x)       ((x) << 0)
>> +#define HIBMC_CRT_HORZ_TOTAL_DISP_END_MASK     0xFFF
>> +
>> +#define HIBMC_CRT_HORZ_SYNC                    0x080210
>> +#define HIBMC_CRT_HORZ_SYNC_WIDTH(x)           ((x) << 16)
>> +#define HIBMC_CRT_HORZ_SYNC_WIDTH_MASK         0xFF0000
>> +
>> +#define HIBMC_CRT_HORZ_SYNC_START(x)           ((x) << 0)
>> +#define HIBMC_CRT_HORZ_SYNC_START_MASK         0xFFF
>> +
>> +#define HIBMC_CRT_VERT_TOTAL                   0x080214
>> +#define HIBMC_CRT_VERT_TOTAL_TOTAL(x)          ((x) << 16)
>> +#define HIBMC_CRT_VERT_TOTAL_TOTAL_MASK                0x7FFF0000
>> +
>> +#define HIBMC_CRT_VERT_TOTAL_DISP_END(x)       ((x) << 0)
>> +#define HIBMC_CRT_VERT_TOTAL_DISP_END_MASK     0x7FF
>> +
>> +#define HIBMC_CRT_VERT_SYNC                    0x080218
>> +#define HIBMC_CRT_VERT_SYNC_HEIGHT(x)          ((x) << 16)
>> +#define HIBMC_CRT_VERT_SYNC_HEIGHT_MASK                0x3F0000
>> +
>> +#define HIBMC_CRT_VERT_SYNC_START(x)           ((x) << 0)
>> +#define HIBMC_CRT_VERT_SYNC_START_MASK         0x7FF
>> +
>> +/* Auto Centering */
>> +#define HIBMC_CRT_AUTO_CENTERING_TL            0x080280
>> +#define HIBMC_CRT_AUTO_CENTERING_TL_TOP(x)     ((x) << 16)
>> +#define HIBMC_CRT_AUTO_CENTERING_TL_TOP_MASK   0x7FF0000
>> +
>> +#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT(x)    ((x) << 0)
>> +#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT_MASK  0x7FF
>> +
>> +#define HIBMC_CRT_AUTO_CENTERING_BR            0x080284
>> +#define HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM(x)  ((x) << 16)
>> +#define HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM_MASK        0x7FF0000
>> +
>> +#define HIBMC_CRT_AUTO_CENTERING_BR_RIGHT(x)   ((x) << 0)
>> +#define HIBMC_CRT_AUTO_CENTERING_BR_RIGHT_MASK 0x7FF
>> +
>> +/* register to control panel output */
>> +#define HIBMC_DISPLAY_CONTROL_HISILE           0x80288
>> +#define HIBMC_DISPLAY_CONTROL_FPVDDEN(x)       ((x) << 0)
>> +#define HIBMC_DISPLAY_CONTROL_PANELDATE(x)     ((x) << 1)
>> +#define HIBMC_DISPLAY_CONTROL_FPEN(x)          ((x) << 2)
>> +#define HIBMC_DISPLAY_CONTROL_VBIASEN(x)       ((x) << 3)
>> +
>> +#define HIBMC_RAW_INTERRUPT                    0x80290
>> +#define HIBMC_RAW_INTERRUPT_VBLANK(x)          ((x) << 2)
>> +#define HIBMC_RAW_INTERRUPT_VBLANK_MASK                0x4
>> +
>> +#define HIBMC_RAW_INTERRUPT_EN                 0x80298
>> +#define HIBMC_RAW_INTERRUPT_EN_VBLANK(x)       ((x) << 2)
>> +#define HIBMC_RAW_INTERRUPT_EN_VBLANK_MASK     0x4
>> +
>> +/* register and values for PLL control */
>> +#define CRT_PLL1_HS                            0x802a8
>> +#define CRT_PLL1_HS_OUTER_BYPASS(x)            ((x) << 30)
>> +#define CRT_PLL1_HS_INTER_BYPASS(x)            ((x) << 29)
>> +#define CRT_PLL1_HS_POWERON(x)                 ((x) << 24)
>> +
>> +#define CRT_PLL1_HS_25MHZ                      0x23d40f02
>> +#define CRT_PLL1_HS_40MHZ                      0x23940801
>> +#define CRT_PLL1_HS_65MHZ                      0x23940d01
>> +#define CRT_PLL1_HS_78MHZ                      0x23540F82
>> +#define CRT_PLL1_HS_74MHZ                      0x23941dc2
>> +#define CRT_PLL1_HS_80MHZ                      0x23941001
>> +#define CRT_PLL1_HS_80MHZ_1152                 0x23540fc2
>> +#define CRT_PLL1_HS_108MHZ                     0x23b41b01
>> +#define CRT_PLL1_HS_162MHZ                     0x23480681
>> +#define CRT_PLL1_HS_148MHZ                     0x23541dc2
>> +#define CRT_PLL1_HS_193MHZ                     0x234807c1
>> +
>> +#define CRT_PLL2_HS                            0x802ac
>> +#define CRT_PLL2_HS_25MHZ                      0x206B851E
>> +#define CRT_PLL2_HS_40MHZ                      0x30000000
>> +#define CRT_PLL2_HS_65MHZ                      0x40000000
>> +#define CRT_PLL2_HS_78MHZ                      0x50E147AE
>> +#define CRT_PLL2_HS_74MHZ                      0x602B6AE7
>> +#define CRT_PLL2_HS_80MHZ                      0x70000000
>> +#define CRT_PLL2_HS_108MHZ                     0x80000000
>> +#define CRT_PLL2_HS_162MHZ                     0xA0000000
>> +#define CRT_PLL2_HS_148MHZ                     0xB0CCCCCD
>> +#define CRT_PLL2_HS_193MHZ                     0xC0872B02
>> +
>> +#define HIBMC_FIELD(field, value) (field(value) & field##_MASK)
>> +#endif
>> --
>> 1.9.1
>>
> _______________________________________________
> linuxarm mailing list
> linuxarm@huawei.com
> http://rnd-openeuler.huawei.com/mailman/listinfo/linuxarm
>
> .
>

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v7 0/7] Add DRM driver for Hisilicon Hibmc
  2016-11-16 16:02     ` Sean Paul
@ 2016-11-17  4:09       ` Rongrong Zou
  -1 siblings, 0 replies; 40+ messages in thread
From: Rongrong Zou @ 2016-11-17  4:09 UTC (permalink / raw)
  To: linux-arm-kernel

? 2016/11/17 0:02, Sean Paul ??:
> On Wed, Nov 16, 2016 at 11:01 AM, Sean Paul <seanpaul@chromium.org> wrote:
>> On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
>>> This patch set adds a new drm driver for Hisilicon Hibmc. Hibmc is a
>>> BMC SoC with a display controller intergrated, usually it is used on
>>> server for Out-of-band management purpose. In this patch set, we just
>>> support basic function for Hibmc display subsystem. Hibmc display
>>> subsystem is connected to host CPU by PCIe as blow:
>>>
>>> +----------+       +----------+
>>> |          | PCIe  |  Hibmc   |
>>> |host CPU( |<----->| display  |
>>> |arm64,x86)|       |subsystem |
>>> +----------+       +----------+
>>>
>>> Hardware Detail for Hibmc display subsystem
>>> -----------
>>>
>>>    The display subsystem of Hibmc is show as bellow:
>>>    +----+      +----+      +----+     +--------+
>>>    |    |      |    |      |    |     |        |
>>>    | FB |----->| DE |----->|VDAC|---->|external|
>>>    |    |      |    |      |    |     | VGA    |
>>>    +----+      +----+      +----+     +--------+
>>>
>>>    -DE(Display Engine) is the display controller.
>>>    -VDAC(Video Digital-to-Analog converter) converts the RGB diaital data
>>>    stream from DE to VGA analog signals.
>>>
>>
>> For the whole series/driver:
>>
>> Acked-by: Sean Paul <seanpaul@chromium.org>
>>
>>
>
> Also, please send those fixups for the other ttm drivers ;)

with pleasure :)

Regards,
Rongrong.

>
>>
>>> Change History
>>> ------------
>>> Changes in v7:
>>>    -remove hibmc_drm_power.c/hibmc_drm_power.h, move the functions to
>>>     hibmc_drm_drv.c.
>>>    -remove hibmc_drm_de.h and move the struct defined in head file to
>>>     hibmc_drm_de.c.
>>>    -plane is initialized inside crtc, not in hibmc_kms_init().
>>>    -connector is initialized inside encoder, not in hibmc_kms_init().
>>>    -remove plane/crtc/encoder/connector from hibmc_drm_private struct.
>>>    -call drm_atomic_helper_suspend/resume in hibmc_pm_suspend/resume.
>>>    -remove these empty stubs because caller will do NULL check.
>>>      hibmc_plane_atomic_disable
>>>      hibmc_crtc_atomic_check
>>>      hibmc_encoder_disable
>>>      hibmc_encoder_enable
>>>      hibmc_encoder_atomic_check
>>>    -clean up in all error paths of creating driver-private framebuffer.
>>>
>>> Changes in v6:
>>>    -remove the embedded framebuffer and use a pointer of hibmc_framebuffer
>>>     instead.
>>>    -remove the deprecated drm_framebuffer_unregister_private(),
>>>     drm_framebuffer_unreference() will be called in hibmc_fbdev_destroy().
>>>    -uninstall irq in hibmc_unload().
>>>
>>> Changes in v5:
>>>    -rebase on v4.9-rc2.
>>>    -replace drm_fb_helper_set_suspend with drm_fb_helper_set_suspend_unlocked.
>>>     and remove redundant console_lock and console_unlock.
>>>
>>> Changes in v4:
>>>    -remove unused include files, and include header file when it is needed.
>>>    -remove unused FLAG in Kconfig: DRM_GEM_CMA_HELPER/DRM_KMS_CMA_HELPER.
>>>    -remove drm_helper_disable_unused_functions, since we use DRIVER_ATOMIC.
>>>
>>> Changes in v3:
>>>    -enable KMS, in v2, only fbdev is enabled.
>>>    -management video memory with ttm.
>>>    -add vblank interrupt.
>>>    -remove drm_connector_register_all() and drm_connector_unregister_all().
>>>    -I have a basic test with igt.
>>>
>>> Changes in v2:
>>>    -Remove self-defined macros for bit operations.
>>>    -Remove unused register.
>>>    -Replace those deprecated functions with new version of them.
>>>    -use drm_connector_register_all() to register connector after
>>>     drm_dev_register().
>>>
>>> The patch v2 is at
>>> https://lists.freedesktop.org/archives/dri-devel/2016-May/108661.html
>>>
>>> Rongrong Zou (7):
>>>    drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
>>>    drm/hisilicon/hibmc: Add video memory management
>>>    drm/hisilicon/hibmc: Add support for frame buffer
>>>    drm/hisilicon/hibmc: Add support for display engine
>>>    drm/hisilicon/hibmc: Add support for VDAC
>>>    drm/hisilicon/hibmc: Add support for vblank interrupt
>>>    MAINTAINERS: Update HISILICON DRM entries
>>>
>>>   MAINTAINERS                                       |   1 +
>>>   drivers/gpu/drm/hisilicon/Kconfig                 |   1 +
>>>   drivers/gpu/drm/hisilicon/Makefile                |   1 +
>>>   drivers/gpu/drm/hisilicon/hibmc/Kconfig           |   9 +
>>>   drivers/gpu/drm/hisilicon/hibmc/Makefile          |   4 +
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c    | 477 ++++++++++++++++++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   | 456 ++++++++++++++++++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   | 114 +++++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 267 +++++++++++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h  | 196 ++++++++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c  | 147 ++++++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       | 558 ++++++++++++++++++++++
>>>   12 files changed, 2231 insertions(+)
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Makefile
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>>
>>> --
>>> 1.9.1
>>>
> _______________________________________________
> linuxarm mailing list
> linuxarm at huawei.com
> http://rnd-openeuler.huawei.com/mailman/listinfo/linuxarm
>
> .
>


-- 
Regards, Rongrong

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v7 0/7] Add DRM driver for Hisilicon Hibmc
@ 2016-11-17  4:09       ` Rongrong Zou
  0 siblings, 0 replies; 40+ messages in thread
From: Rongrong Zou @ 2016-11-17  4:09 UTC (permalink / raw)
  To: Sean Paul, Rongrong Zou
  Cc: Mark Rutland, Archit, lijianhua, Benjamin Gaignard, Tomeu Vizoso,
	Jonathan Corbet, Dave Airlie, Emil Velikov, linuxarm, dri-devel,
	Xinliang Liu, james.xiong, Daniel Vetter, Daniel Stone,
	Linux ARM Kernel, shenhui

在 2016/11/17 0:02, Sean Paul 写道:
> On Wed, Nov 16, 2016 at 11:01 AM, Sean Paul <seanpaul@chromium.org> wrote:
>> On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
>>> This patch set adds a new drm driver for Hisilicon Hibmc. Hibmc is a
>>> BMC SoC with a display controller intergrated, usually it is used on
>>> server for Out-of-band management purpose. In this patch set, we just
>>> support basic function for Hibmc display subsystem. Hibmc display
>>> subsystem is connected to host CPU by PCIe as blow:
>>>
>>> +----------+       +----------+
>>> |          | PCIe  |  Hibmc   |
>>> |host CPU( |<----->| display  |
>>> |arm64,x86)|       |subsystem |
>>> +----------+       +----------+
>>>
>>> Hardware Detail for Hibmc display subsystem
>>> -----------
>>>
>>>    The display subsystem of Hibmc is show as bellow:
>>>    +----+      +----+      +----+     +--------+
>>>    |    |      |    |      |    |     |        |
>>>    | FB |----->| DE |----->|VDAC|---->|external|
>>>    |    |      |    |      |    |     | VGA    |
>>>    +----+      +----+      +----+     +--------+
>>>
>>>    -DE(Display Engine) is the display controller.
>>>    -VDAC(Video Digital-to-Analog converter) converts the RGB diaital data
>>>    stream from DE to VGA analog signals.
>>>
>>
>> For the whole series/driver:
>>
>> Acked-by: Sean Paul <seanpaul@chromium.org>
>>
>>
>
> Also, please send those fixups for the other ttm drivers ;)

with pleasure :)

Regards,
Rongrong.

>
>>
>>> Change History
>>> ------------
>>> Changes in v7:
>>>    -remove hibmc_drm_power.c/hibmc_drm_power.h, move the functions to
>>>     hibmc_drm_drv.c.
>>>    -remove hibmc_drm_de.h and move the struct defined in head file to
>>>     hibmc_drm_de.c.
>>>    -plane is initialized inside crtc, not in hibmc_kms_init().
>>>    -connector is initialized inside encoder, not in hibmc_kms_init().
>>>    -remove plane/crtc/encoder/connector from hibmc_drm_private struct.
>>>    -call drm_atomic_helper_suspend/resume in hibmc_pm_suspend/resume.
>>>    -remove these empty stubs because caller will do NULL check.
>>>      hibmc_plane_atomic_disable
>>>      hibmc_crtc_atomic_check
>>>      hibmc_encoder_disable
>>>      hibmc_encoder_enable
>>>      hibmc_encoder_atomic_check
>>>    -clean up in all error paths of creating driver-private framebuffer.
>>>
>>> Changes in v6:
>>>    -remove the embedded framebuffer and use a pointer of hibmc_framebuffer
>>>     instead.
>>>    -remove the deprecated drm_framebuffer_unregister_private(),
>>>     drm_framebuffer_unreference() will be called in hibmc_fbdev_destroy().
>>>    -uninstall irq in hibmc_unload().
>>>
>>> Changes in v5:
>>>    -rebase on v4.9-rc2.
>>>    -replace drm_fb_helper_set_suspend with drm_fb_helper_set_suspend_unlocked.
>>>     and remove redundant console_lock and console_unlock.
>>>
>>> Changes in v4:
>>>    -remove unused include files, and include header file when it is needed.
>>>    -remove unused FLAG in Kconfig: DRM_GEM_CMA_HELPER/DRM_KMS_CMA_HELPER.
>>>    -remove drm_helper_disable_unused_functions, since we use DRIVER_ATOMIC.
>>>
>>> Changes in v3:
>>>    -enable KMS, in v2, only fbdev is enabled.
>>>    -management video memory with ttm.
>>>    -add vblank interrupt.
>>>    -remove drm_connector_register_all() and drm_connector_unregister_all().
>>>    -I have a basic test with igt.
>>>
>>> Changes in v2:
>>>    -Remove self-defined macros for bit operations.
>>>    -Remove unused register.
>>>    -Replace those deprecated functions with new version of them.
>>>    -use drm_connector_register_all() to register connector after
>>>     drm_dev_register().
>>>
>>> The patch v2 is at
>>> https://lists.freedesktop.org/archives/dri-devel/2016-May/108661.html
>>>
>>> Rongrong Zou (7):
>>>    drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
>>>    drm/hisilicon/hibmc: Add video memory management
>>>    drm/hisilicon/hibmc: Add support for frame buffer
>>>    drm/hisilicon/hibmc: Add support for display engine
>>>    drm/hisilicon/hibmc: Add support for VDAC
>>>    drm/hisilicon/hibmc: Add support for vblank interrupt
>>>    MAINTAINERS: Update HISILICON DRM entries
>>>
>>>   MAINTAINERS                                       |   1 +
>>>   drivers/gpu/drm/hisilicon/Kconfig                 |   1 +
>>>   drivers/gpu/drm/hisilicon/Makefile                |   1 +
>>>   drivers/gpu/drm/hisilicon/hibmc/Kconfig           |   9 +
>>>   drivers/gpu/drm/hisilicon/hibmc/Makefile          |   4 +
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c    | 477 ++++++++++++++++++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   | 456 ++++++++++++++++++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   | 114 +++++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 267 +++++++++++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h  | 196 ++++++++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c  | 147 ++++++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       | 558 ++++++++++++++++++++++
>>>   12 files changed, 2231 insertions(+)
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Makefile
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>>
>>> --
>>> 1.9.1
>>>
> _______________________________________________
> linuxarm mailing list
> linuxarm@huawei.com
> http://rnd-openeuler.huawei.com/mailman/listinfo/linuxarm
>
> .
>


-- 
Regards, Rongrong

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH v7 0/7] Add DRM driver for Hisilicon Hibmc
  2016-11-16 13:43 ` Rongrong Zou
@ 2016-11-17  7:01   ` Xinliang Liu
  -1 siblings, 0 replies; 40+ messages in thread
From: Xinliang Liu @ 2016-11-17  7:01 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Rongrong,

Thanks for your hard work.

For this whole series patches:
Reviewed-by: Xinliang Liu <xinliang.liu@linaro.org>

Thanks,
-xinliang

On 16 November 2016 at 21:43, Rongrong Zou <zourongrong@gmail.com> wrote:
> This patch set adds a new drm driver for Hisilicon Hibmc. Hibmc is a
> BMC SoC with a display controller intergrated, usually it is used on
> server for Out-of-band management purpose. In this patch set, we just
> support basic function for Hibmc display subsystem. Hibmc display
> subsystem is connected to host CPU by PCIe as blow:
>
> +----------+       +----------+
> |          | PCIe  |  Hibmc   |
> |host CPU( |<----->| display  |
> |arm64,x86)|       |subsystem |
> +----------+       +----------+
>
> Hardware Detail for Hibmc display subsystem
> -----------
>
>   The display subsystem of Hibmc is show as bellow:
>   +----+      +----+      +----+     +--------+
>   |    |      |    |      |    |     |        |
>   | FB |----->| DE |----->|VDAC|---->|external|
>   |    |      |    |      |    |     | VGA    |
>   +----+      +----+      +----+     +--------+
>
>   -DE(Display Engine) is the display controller.
>   -VDAC(Video Digital-to-Analog converter) converts the RGB diaital data
>   stream from DE to VGA analog signals.
>
> Change History
> ------------
> Changes in v7:
>   -remove hibmc_drm_power.c/hibmc_drm_power.h, move the functions to
>    hibmc_drm_drv.c.
>   -remove hibmc_drm_de.h and move the struct defined in head file to
>    hibmc_drm_de.c.
>   -plane is initialized inside crtc, not in hibmc_kms_init().
>   -connector is initialized inside encoder, not in hibmc_kms_init().
>   -remove plane/crtc/encoder/connector from hibmc_drm_private struct.
>   -call drm_atomic_helper_suspend/resume in hibmc_pm_suspend/resume.
>   -remove these empty stubs because caller will do NULL check.
>     hibmc_plane_atomic_disable
>     hibmc_crtc_atomic_check
>     hibmc_encoder_disable
>     hibmc_encoder_enable
>     hibmc_encoder_atomic_check
>   -clean up in all error paths of creating driver-private framebuffer.
>
> Changes in v6:
>   -remove the embedded framebuffer and use a pointer of hibmc_framebuffer
>    instead.
>   -remove the deprecated drm_framebuffer_unregister_private(),
>    drm_framebuffer_unreference() will be called in hibmc_fbdev_destroy().
>   -uninstall irq in hibmc_unload().
>
> Changes in v5:
>   -rebase on v4.9-rc2.
>   -replace drm_fb_helper_set_suspend with drm_fb_helper_set_suspend_unlocked.
>    and remove redundant console_lock and console_unlock.
>
> Changes in v4:
>   -remove unused include files, and include header file when it is needed.
>   -remove unused FLAG in Kconfig: DRM_GEM_CMA_HELPER/DRM_KMS_CMA_HELPER.
>   -remove drm_helper_disable_unused_functions, since we use DRIVER_ATOMIC.
>
> Changes in v3:
>   -enable KMS, in v2, only fbdev is enabled.
>   -management video memory with ttm.
>   -add vblank interrupt.
>   -remove drm_connector_register_all() and drm_connector_unregister_all().
>   -I have a basic test with igt.
>
> Changes in v2:
>   -Remove self-defined macros for bit operations.
>   -Remove unused register.
>   -Replace those deprecated functions with new version of them.
>   -use drm_connector_register_all() to register connector after
>    drm_dev_register().
>
> The patch v2 is at
> https://lists.freedesktop.org/archives/dri-devel/2016-May/108661.html
>
> Rongrong Zou (7):
>   drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
>   drm/hisilicon/hibmc: Add video memory management
>   drm/hisilicon/hibmc: Add support for frame buffer
>   drm/hisilicon/hibmc: Add support for display engine
>   drm/hisilicon/hibmc: Add support for VDAC
>   drm/hisilicon/hibmc: Add support for vblank interrupt
>   MAINTAINERS: Update HISILICON DRM entries
>
>  MAINTAINERS                                       |   1 +
>  drivers/gpu/drm/hisilicon/Kconfig                 |   1 +
>  drivers/gpu/drm/hisilicon/Makefile                |   1 +
>  drivers/gpu/drm/hisilicon/hibmc/Kconfig           |   9 +
>  drivers/gpu/drm/hisilicon/hibmc/Makefile          |   4 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c    | 477 ++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   | 456 ++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   | 114 +++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 267 +++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h  | 196 ++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c  | 147 ++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       | 558 ++++++++++++++++++++++
>  12 files changed, 2231 insertions(+)
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Kconfig
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Makefile
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>
> --
> 1.9.1
>

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v7 0/7] Add DRM driver for Hisilicon Hibmc
@ 2016-11-17  7:01   ` Xinliang Liu
  0 siblings, 0 replies; 40+ messages in thread
From: Xinliang Liu @ 2016-11-17  7:01 UTC (permalink / raw)
  To: Rongrong Zou
  Cc: Mark Rutland, Tomeu Vizoso, seanpaul, Jonathan Corbet,
	Emil Velikov, Linuxarm, dri-devel, Hanjun Guo, james.xiong,
	lijianhua, LAKML, shenhui

Hi Rongrong,

Thanks for your hard work.

For this whole series patches:
Reviewed-by: Xinliang Liu <xinliang.liu@linaro.org>

Thanks,
-xinliang

On 16 November 2016 at 21:43, Rongrong Zou <zourongrong@gmail.com> wrote:
> This patch set adds a new drm driver for Hisilicon Hibmc. Hibmc is a
> BMC SoC with a display controller intergrated, usually it is used on
> server for Out-of-band management purpose. In this patch set, we just
> support basic function for Hibmc display subsystem. Hibmc display
> subsystem is connected to host CPU by PCIe as blow:
>
> +----------+       +----------+
> |          | PCIe  |  Hibmc   |
> |host CPU( |<----->| display  |
> |arm64,x86)|       |subsystem |
> +----------+       +----------+
>
> Hardware Detail for Hibmc display subsystem
> -----------
>
>   The display subsystem of Hibmc is show as bellow:
>   +----+      +----+      +----+     +--------+
>   |    |      |    |      |    |     |        |
>   | FB |----->| DE |----->|VDAC|---->|external|
>   |    |      |    |      |    |     | VGA    |
>   +----+      +----+      +----+     +--------+
>
>   -DE(Display Engine) is the display controller.
>   -VDAC(Video Digital-to-Analog converter) converts the RGB diaital data
>   stream from DE to VGA analog signals.
>
> Change History
> ------------
> Changes in v7:
>   -remove hibmc_drm_power.c/hibmc_drm_power.h, move the functions to
>    hibmc_drm_drv.c.
>   -remove hibmc_drm_de.h and move the struct defined in head file to
>    hibmc_drm_de.c.
>   -plane is initialized inside crtc, not in hibmc_kms_init().
>   -connector is initialized inside encoder, not in hibmc_kms_init().
>   -remove plane/crtc/encoder/connector from hibmc_drm_private struct.
>   -call drm_atomic_helper_suspend/resume in hibmc_pm_suspend/resume.
>   -remove these empty stubs because caller will do NULL check.
>     hibmc_plane_atomic_disable
>     hibmc_crtc_atomic_check
>     hibmc_encoder_disable
>     hibmc_encoder_enable
>     hibmc_encoder_atomic_check
>   -clean up in all error paths of creating driver-private framebuffer.
>
> Changes in v6:
>   -remove the embedded framebuffer and use a pointer of hibmc_framebuffer
>    instead.
>   -remove the deprecated drm_framebuffer_unregister_private(),
>    drm_framebuffer_unreference() will be called in hibmc_fbdev_destroy().
>   -uninstall irq in hibmc_unload().
>
> Changes in v5:
>   -rebase on v4.9-rc2.
>   -replace drm_fb_helper_set_suspend with drm_fb_helper_set_suspend_unlocked.
>    and remove redundant console_lock and console_unlock.
>
> Changes in v4:
>   -remove unused include files, and include header file when it is needed.
>   -remove unused FLAG in Kconfig: DRM_GEM_CMA_HELPER/DRM_KMS_CMA_HELPER.
>   -remove drm_helper_disable_unused_functions, since we use DRIVER_ATOMIC.
>
> Changes in v3:
>   -enable KMS, in v2, only fbdev is enabled.
>   -management video memory with ttm.
>   -add vblank interrupt.
>   -remove drm_connector_register_all() and drm_connector_unregister_all().
>   -I have a basic test with igt.
>
> Changes in v2:
>   -Remove self-defined macros for bit operations.
>   -Remove unused register.
>   -Replace those deprecated functions with new version of them.
>   -use drm_connector_register_all() to register connector after
>    drm_dev_register().
>
> The patch v2 is at
> https://lists.freedesktop.org/archives/dri-devel/2016-May/108661.html
>
> Rongrong Zou (7):
>   drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
>   drm/hisilicon/hibmc: Add video memory management
>   drm/hisilicon/hibmc: Add support for frame buffer
>   drm/hisilicon/hibmc: Add support for display engine
>   drm/hisilicon/hibmc: Add support for VDAC
>   drm/hisilicon/hibmc: Add support for vblank interrupt
>   MAINTAINERS: Update HISILICON DRM entries
>
>  MAINTAINERS                                       |   1 +
>  drivers/gpu/drm/hisilicon/Kconfig                 |   1 +
>  drivers/gpu/drm/hisilicon/Makefile                |   1 +
>  drivers/gpu/drm/hisilicon/hibmc/Kconfig           |   9 +
>  drivers/gpu/drm/hisilicon/hibmc/Makefile          |   4 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c    | 477 ++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   | 456 ++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   | 114 +++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 267 +++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h  | 196 ++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c  | 147 ++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       | 558 ++++++++++++++++++++++
>  12 files changed, 2231 insertions(+)
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Kconfig
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Makefile
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>
> --
> 1.9.1
>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 40+ messages in thread

end of thread, other threads:[~2016-11-17  7:01 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-11-16 13:43 [PATCH v7 0/7] Add DRM driver for Hisilicon Hibmc Rongrong Zou
2016-11-16 13:43 ` Rongrong Zou
2016-11-16 13:43 ` [PATCH v7 1/7] drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver Rongrong Zou
2016-11-16 13:43   ` Rongrong Zou
2016-11-16 15:42   ` Sean Paul
2016-11-16 15:42     ` Sean Paul
2016-11-17  4:05     ` Rongrong Zou
2016-11-17  4:05       ` Rongrong Zou
2016-11-16 13:43 ` [PATCH v7 2/7] drm/hisilicon/hibmc: Add video memory management Rongrong Zou
2016-11-16 13:43   ` Rongrong Zou
2016-11-16 15:52   ` Sean Paul
2016-11-16 15:52     ` Sean Paul
2016-11-16 13:43 ` [PATCH v7 3/7] drm/hisilicon/hibmc: Add support for frame buffer Rongrong Zou
2016-11-16 13:43   ` Rongrong Zou
2016-11-16 15:56   ` Sean Paul
2016-11-16 15:56     ` Sean Paul
2016-11-16 13:43 ` [PATCH v7 4/7] drm/hisilicon/hibmc: Add support for display engine Rongrong Zou
2016-11-16 13:43   ` Rongrong Zou
2016-11-16 15:58   ` Sean Paul
2016-11-16 15:58     ` Sean Paul
2016-11-16 13:43 ` [PATCH v7 5/7] drm/hisilicon/hibmc: Add support for VDAC Rongrong Zou
2016-11-16 13:43   ` Rongrong Zou
2016-11-16 15:59   ` Sean Paul
2016-11-16 15:59     ` Sean Paul
2016-11-16 13:43 ` [PATCH v7 6/7] drm/hisilicon/hibmc: Add support for vblank interrupt Rongrong Zou
2016-11-16 13:43   ` Rongrong Zou
2016-11-16 16:00   ` Sean Paul
2016-11-16 16:00     ` Sean Paul
2016-11-16 13:43 ` [PATCH v7 7/7] MAINTAINERS: Update HISILICON DRM entries Rongrong Zou
2016-11-16 13:43   ` Rongrong Zou
2016-11-16 16:00   ` Sean Paul
2016-11-16 16:00     ` Sean Paul
2016-11-16 16:01 ` [PATCH v7 0/7] Add DRM driver for Hisilicon Hibmc Sean Paul
2016-11-16 16:01   ` Sean Paul
2016-11-16 16:02   ` Sean Paul
2016-11-16 16:02     ` Sean Paul
2016-11-17  4:09     ` Rongrong Zou
2016-11-17  4:09       ` Rongrong Zou
2016-11-17  7:01 ` Xinliang Liu
2016-11-17  7:01   ` Xinliang Liu

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.