All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 0/9] Add DRM driver for Hisilicon Hibmc
@ 2016-10-28  7:27 ` Rongrong Zou
  0 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-10-28  7:27 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 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 (9):
  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 plane for DE
  drm/hisilicon/hibmc: Add crtc for DE
  drm/hisilicon/hibmc: Add encoder for VDAC
  drm/hisilicon/hibmc: Add connector for VDAC
  drm/hisilicon/hibmc: Add vblank interruput
  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          |   5 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c    | 488 +++++++++++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h    |  29 ++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   | 419 ++++++++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   | 117 +++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 255 ++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c |  85 ++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h |  28 ++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h  | 212 ++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c  | 165 +++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       | 562 ++++++++++++++++++++++
 15 files changed, 2377 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_de.h
 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_power.c
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h
 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] 64+ messages in thread

* [PATCH v6 0/9] Add DRM driver for Hisilicon Hibmc
@ 2016-10-28  7:27 ` Rongrong Zou
  0 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-10-28  7:27 UTC (permalink / raw)
  To: airlied, daniel, dri-devel, emil.l.velikov, tomeu.vizoso,
	benjamin.gaignard, robh, daniel, architt, corbet,
	catalin.marinas, will.deacon, 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 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 (9):
  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 plane for DE
  drm/hisilicon/hibmc: Add crtc for DE
  drm/hisilicon/hibmc: Add encoder for VDAC
  drm/hisilicon/hibmc: Add connector for VDAC
  drm/hisilicon/hibmc: Add vblank interruput
  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          |   5 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c    | 488 +++++++++++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h    |  29 ++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   | 419 ++++++++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   | 117 +++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 255 ++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c |  85 ++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h |  28 ++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h  | 212 ++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c  | 165 +++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       | 562 ++++++++++++++++++++++
 15 files changed, 2377 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_de.h
 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_power.c
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h
 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] 64+ messages in thread

* [PATCH v6 1/9] drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
  2016-10-28  7:27 ` Rongrong Zou
@ 2016-10-28  7:27   ` Rongrong Zou
  -1 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-10-28  7:27 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           |   7 +
 drivers/gpu/drm/hisilicon/hibmc/Makefile          |   5 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   | 269 ++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   |  35 +++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c |  85 +++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h |  28 +++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h  | 212 +++++++++++++++++
 9 files changed, 643 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_power.c
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.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..a9af90d
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
@@ -0,0 +1,7 @@
+config DRM_HISI_HIBMC
+	tristate "DRM Support for Hisilicon Hibmc"
+	depends on DRM && PCI
+
+	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..97cf4a0
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
@@ -0,0 +1,5 @@
+ccflags-y := -Iinclude/drm
+hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o
+
+obj-$(CONFIG_DRM_HISI_HIBMC)	+=hibmc-drm.o
+#obj-y	+= 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..4669d42
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -0,0 +1,269 @@
+/* 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/module.h>
+#include <linux/console.h>
+
+#include "hibmc_drm_drv.h"
+#include "hibmc_drm_regs.h"
+#include "hibmc_drm_power.h"
+
+static const struct file_operations hibmc_fops = {
+	.owner		= THIS_MODULE,
+	.open		= drm_open,
+	.release	= drm_release,
+	.unlocked_ioctl	= drm_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= drm_compat_ioctl,
+#endif
+	.poll		= drm_poll,
+	.read		= drm_read,
+	.llseek		= no_llseek,
+};
+
+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)
+};
+
+static int hibmc_hw_config(struct hibmc_drm_device *hidev)
+{
+	unsigned int reg;
+
+	/* On hardware reset, power mode 0 is default. */
+	hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_MODE0);
+
+	/* Enable display power gate & LOCALMEM power gate*/
+	reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
+	reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
+	reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
+	reg |= HIBMC_CURR_GATE_DISPLAY(ON);
+	reg |= HIBMC_CURR_GATE_LOCALMEM(ON);
+
+	hibmc_set_current_gate(hidev, 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(hidev->mmio + HIBMC_MISC_CTRL);
+	reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
+	reg |= HIBMC_MSCCTL_LOCALMEM_RESET(RESET);
+	writel(reg, hidev->mmio + HIBMC_MISC_CTRL);
+
+	reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
+	reg |= HIBMC_MSCCTL_LOCALMEM_RESET(NORMAL);
+
+	writel(reg, hidev->mmio + HIBMC_MISC_CTRL);
+
+	/* We can add more initialization as needed. */
+
+	return 0;
+}
+
+static int hibmc_hw_map(struct hibmc_drm_device *hidev)
+{
+	struct drm_device *dev = hidev->dev;
+	struct pci_dev *pdev = dev->pdev;
+	resource_size_t addr, size, ioaddr, iosize;
+
+	ioaddr = pci_resource_start(pdev, 1);
+	iosize = MB(2);
+
+	hidev->mmio = ioremap_nocache(ioaddr, iosize);
+
+	if (!hidev->mmio) {
+		DRM_ERROR("Cannot map mmio region\n");
+		return -ENOMEM;
+	}
+
+	addr = pci_resource_start(pdev, 0);
+	size = MB(32);
+
+	hidev->fb_map = ioremap(addr, size);
+	if (!hidev->fb_map) {
+		DRM_ERROR("Cannot map framebuffer\n");
+		return -ENOMEM;
+	}
+	hidev->fb_base = addr;
+	hidev->fb_size = size;
+
+	return 0;
+}
+
+static void hibmc_hw_fini(struct hibmc_drm_device *hidev)
+{
+	if (hidev->mmio)
+		iounmap(hidev->mmio);
+	if (hidev->fb_map)
+		iounmap(hidev->fb_map);
+}
+
+static int hibmc_hw_init(struct hibmc_drm_device *hidev)
+{
+	int ret;
+
+	ret = hibmc_hw_map(hidev);
+	if (ret)
+		return ret;
+
+	hibmc_hw_config(hidev);
+
+	return 0;
+}
+
+static int hibmc_unload(struct drm_device *dev)
+{
+	struct hibmc_drm_device *hidev = dev->dev_private;
+
+	hibmc_hw_fini(hidev);
+	dev->dev_private = NULL;
+	return 0;
+}
+
+static int hibmc_load(struct drm_device *dev, unsigned long flags)
+{
+	struct hibmc_drm_device *hidev;
+	int ret;
+
+	hidev = devm_kzalloc(dev->dev, sizeof(*hidev), GFP_KERNEL);
+	if (!hidev)
+		return -ENOMEM;
+	dev->dev_private = hidev;
+	hidev->dev = dev;
+
+	ret = hibmc_hw_init(hidev);
+	if (ret)
+		goto err;
+
+	return 0;
+
+err:
+	hibmc_unload(dev);
+	DRM_ERROR("failed to initialize drm driver.\n");
+	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)
+		return -ENOMEM;
+
+	dev->pdev = pdev;
+	pci_set_drvdata(pdev, dev);
+
+	ret = pci_enable_device(pdev);
+	if (ret)
+		goto err_free;
+
+	ret = hibmc_load(dev, 0);
+	if (ret)
+		goto err_disable;
+
+	ret = drm_dev_register(dev, 0);
+	if (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..0037341
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -0,0 +1,35 @@
+/* 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_device {
+	/* hw */
+	void __iomem   *mmio;
+	void __iomem   *fb_map;
+	unsigned long  fb_base;
+	unsigned long  fb_size;
+
+	/* drm */
+	struct drm_device  *dev;
+};
+
+#endif
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c
new file mode 100644
index 0000000..1036542
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c
@@ -0,0 +1,85 @@
+/* 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 "hibmc_drm_drv.h"
+#include "hibmc_drm_regs.h"
+
+/*
+ * It can operate in one of three modes: 0, 1 or Sleep.
+ */
+void hibmc_set_power_mode(struct hibmc_drm_device *hidev,
+			  unsigned int power_mode)
+{
+	unsigned int control_value = 0;
+	void __iomem   *mmio = hidev->mmio;
+
+	if (power_mode > HIBMC_PW_MODE_CTL_MODE_SLEEP)
+		return;
+
+	control_value = readl(mmio + HIBMC_POWER_MODE_CTRL);
+	control_value &= ~HIBMC_PW_MODE_CTL_MODE_MASK;
+
+	control_value |= HIBMC_PW_MODE_CTL_MODE(power_mode) &
+			 HIBMC_PW_MODE_CTL_MODE_MASK;
+
+    /* Set up other fields in Power Control Register */
+	if (power_mode == HIBMC_PW_MODE_CTL_MODE_SLEEP) {
+		control_value &= ~HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
+		control_value |= HIBMC_PW_MODE_CTL_OSC_INPUT(0) &
+				 HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
+	} else {
+		control_value &= ~HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
+		control_value |= HIBMC_PW_MODE_CTL_OSC_INPUT(1) &
+				 HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
+	}
+	/* Program new power mode. */
+	writel(control_value, mmio + HIBMC_POWER_MODE_CTRL);
+}
+
+static unsigned int hibmc_get_power_mode(struct hibmc_drm_device *hidev)
+{
+	void __iomem   *mmio = hidev->mmio;
+
+	return (readl(mmio + HIBMC_POWER_MODE_CTRL) &
+		HIBMC_PW_MODE_CTL_MODE_MASK) >> HIBMC_PW_MODE_CTL_MODE_SHIFT;
+}
+
+void hibmc_set_current_gate(struct hibmc_drm_device *hidev, unsigned int gate)
+{
+	unsigned int gate_reg;
+	unsigned int mode;
+	void __iomem   *mmio = hidev->mmio;
+
+	/* Get current power mode. */
+	mode = hibmc_get_power_mode(hidev);
+
+	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);
+}
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h
new file mode 100644
index 0000000..e20e1aa
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h
@@ -0,0 +1,28 @@
+/* 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_POWER_H
+#define HIBMC_DRM_POWER_H
+
+#include "hibmc_drm_drv.h"
+
+void hibmc_set_power_mode(struct hibmc_drm_device *hidev,
+			  unsigned int power_mode);
+void hibmc_set_current_gate(struct hibmc_drm_device *hidev,
+			    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..9c804ca
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
@@ -0,0 +1,212 @@
+/* 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
+
+#define OFF 0
+#define ON  1
+#define DISABLE               0
+#define ENABLE                1
+
+/* register definition */
+#define HIBMC_MISC_CTRL				0x4
+
+#define HIBMC_MSCCTL_LOCALMEM_RESET(x)		((x) << 6)
+#define HIBMC_MSCCTL_LOCALMEM_RESET_MASK	0x40
+
+#define RESET                0
+#define NORMAL               1
+
+#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 OSC					0
+#define TESTCLK					1
+
+#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 CRTSELECT_VGA                0
+#define CRTSELECT_CRT                1
+
+#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE(x)	((x) << 14)
+#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE_MASK	0x4000
+
+#define PHASE_ACTIVE_HIGH      0
+#define PHASE_ACTIVE_LOW       1
+
+#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_DISPLAY_END(x)	((x) << 0)
+#define HIBMC_CRT_HORZ_TOTAL_DISPLAY_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_DISPLAY_END(x)	((x) << 0)
+#define HIBMC_CRT_VERT_TOTAL_DISPLAY_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_MSK	0x7FF0000
+
+#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT(x)	((x) << 0)
+#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT_MSK	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 DISPLAY_CONTROL_HISILE			0x80288
+
+#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_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
+
+/* Global macros */
+#define RGB(r, g, b) \
+( \
+	(unsigned long)(((r) << 16) | ((g) << 8) | (b)) \
+)
+
+#define PADDING(align, data) (((data) + (align) - 1) & (~((align) - 1)))
+
+#define MB(x) ((x) << 20)
+
+#endif
-- 
1.9.1

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

* [PATCH v6 1/9] drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
@ 2016-10-28  7:27   ` Rongrong Zou
  0 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-10-28  7:27 UTC (permalink / raw)
  To: airlied, daniel, dri-devel, emil.l.velikov, tomeu.vizoso,
	benjamin.gaignard, robh, daniel, architt, corbet,
	catalin.marinas, will.deacon, 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           |   7 +
 drivers/gpu/drm/hisilicon/hibmc/Makefile          |   5 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   | 269 ++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   |  35 +++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c |  85 +++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h |  28 +++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h  | 212 +++++++++++++++++
 9 files changed, 643 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_power.c
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.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..a9af90d
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
@@ -0,0 +1,7 @@
+config DRM_HISI_HIBMC
+	tristate "DRM Support for Hisilicon Hibmc"
+	depends on DRM && PCI
+
+	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..97cf4a0
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
@@ -0,0 +1,5 @@
+ccflags-y := -Iinclude/drm
+hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o
+
+obj-$(CONFIG_DRM_HISI_HIBMC)	+=hibmc-drm.o
+#obj-y	+= 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..4669d42
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -0,0 +1,269 @@
+/* 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/module.h>
+#include <linux/console.h>
+
+#include "hibmc_drm_drv.h"
+#include "hibmc_drm_regs.h"
+#include "hibmc_drm_power.h"
+
+static const struct file_operations hibmc_fops = {
+	.owner		= THIS_MODULE,
+	.open		= drm_open,
+	.release	= drm_release,
+	.unlocked_ioctl	= drm_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= drm_compat_ioctl,
+#endif
+	.poll		= drm_poll,
+	.read		= drm_read,
+	.llseek		= no_llseek,
+};
+
+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)
+};
+
+static int hibmc_hw_config(struct hibmc_drm_device *hidev)
+{
+	unsigned int reg;
+
+	/* On hardware reset, power mode 0 is default. */
+	hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_MODE0);
+
+	/* Enable display power gate & LOCALMEM power gate*/
+	reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
+	reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
+	reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
+	reg |= HIBMC_CURR_GATE_DISPLAY(ON);
+	reg |= HIBMC_CURR_GATE_LOCALMEM(ON);
+
+	hibmc_set_current_gate(hidev, 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(hidev->mmio + HIBMC_MISC_CTRL);
+	reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
+	reg |= HIBMC_MSCCTL_LOCALMEM_RESET(RESET);
+	writel(reg, hidev->mmio + HIBMC_MISC_CTRL);
+
+	reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
+	reg |= HIBMC_MSCCTL_LOCALMEM_RESET(NORMAL);
+
+	writel(reg, hidev->mmio + HIBMC_MISC_CTRL);
+
+	/* We can add more initialization as needed. */
+
+	return 0;
+}
+
+static int hibmc_hw_map(struct hibmc_drm_device *hidev)
+{
+	struct drm_device *dev = hidev->dev;
+	struct pci_dev *pdev = dev->pdev;
+	resource_size_t addr, size, ioaddr, iosize;
+
+	ioaddr = pci_resource_start(pdev, 1);
+	iosize = MB(2);
+
+	hidev->mmio = ioremap_nocache(ioaddr, iosize);
+
+	if (!hidev->mmio) {
+		DRM_ERROR("Cannot map mmio region\n");
+		return -ENOMEM;
+	}
+
+	addr = pci_resource_start(pdev, 0);
+	size = MB(32);
+
+	hidev->fb_map = ioremap(addr, size);
+	if (!hidev->fb_map) {
+		DRM_ERROR("Cannot map framebuffer\n");
+		return -ENOMEM;
+	}
+	hidev->fb_base = addr;
+	hidev->fb_size = size;
+
+	return 0;
+}
+
+static void hibmc_hw_fini(struct hibmc_drm_device *hidev)
+{
+	if (hidev->mmio)
+		iounmap(hidev->mmio);
+	if (hidev->fb_map)
+		iounmap(hidev->fb_map);
+}
+
+static int hibmc_hw_init(struct hibmc_drm_device *hidev)
+{
+	int ret;
+
+	ret = hibmc_hw_map(hidev);
+	if (ret)
+		return ret;
+
+	hibmc_hw_config(hidev);
+
+	return 0;
+}
+
+static int hibmc_unload(struct drm_device *dev)
+{
+	struct hibmc_drm_device *hidev = dev->dev_private;
+
+	hibmc_hw_fini(hidev);
+	dev->dev_private = NULL;
+	return 0;
+}
+
+static int hibmc_load(struct drm_device *dev, unsigned long flags)
+{
+	struct hibmc_drm_device *hidev;
+	int ret;
+
+	hidev = devm_kzalloc(dev->dev, sizeof(*hidev), GFP_KERNEL);
+	if (!hidev)
+		return -ENOMEM;
+	dev->dev_private = hidev;
+	hidev->dev = dev;
+
+	ret = hibmc_hw_init(hidev);
+	if (ret)
+		goto err;
+
+	return 0;
+
+err:
+	hibmc_unload(dev);
+	DRM_ERROR("failed to initialize drm driver.\n");
+	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)
+		return -ENOMEM;
+
+	dev->pdev = pdev;
+	pci_set_drvdata(pdev, dev);
+
+	ret = pci_enable_device(pdev);
+	if (ret)
+		goto err_free;
+
+	ret = hibmc_load(dev, 0);
+	if (ret)
+		goto err_disable;
+
+	ret = drm_dev_register(dev, 0);
+	if (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..0037341
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -0,0 +1,35 @@
+/* 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_device {
+	/* hw */
+	void __iomem   *mmio;
+	void __iomem   *fb_map;
+	unsigned long  fb_base;
+	unsigned long  fb_size;
+
+	/* drm */
+	struct drm_device  *dev;
+};
+
+#endif
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c
new file mode 100644
index 0000000..1036542
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c
@@ -0,0 +1,85 @@
+/* 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 "hibmc_drm_drv.h"
+#include "hibmc_drm_regs.h"
+
+/*
+ * It can operate in one of three modes: 0, 1 or Sleep.
+ */
+void hibmc_set_power_mode(struct hibmc_drm_device *hidev,
+			  unsigned int power_mode)
+{
+	unsigned int control_value = 0;
+	void __iomem   *mmio = hidev->mmio;
+
+	if (power_mode > HIBMC_PW_MODE_CTL_MODE_SLEEP)
+		return;
+
+	control_value = readl(mmio + HIBMC_POWER_MODE_CTRL);
+	control_value &= ~HIBMC_PW_MODE_CTL_MODE_MASK;
+
+	control_value |= HIBMC_PW_MODE_CTL_MODE(power_mode) &
+			 HIBMC_PW_MODE_CTL_MODE_MASK;
+
+    /* Set up other fields in Power Control Register */
+	if (power_mode == HIBMC_PW_MODE_CTL_MODE_SLEEP) {
+		control_value &= ~HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
+		control_value |= HIBMC_PW_MODE_CTL_OSC_INPUT(0) &
+				 HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
+	} else {
+		control_value &= ~HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
+		control_value |= HIBMC_PW_MODE_CTL_OSC_INPUT(1) &
+				 HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
+	}
+	/* Program new power mode. */
+	writel(control_value, mmio + HIBMC_POWER_MODE_CTRL);
+}
+
+static unsigned int hibmc_get_power_mode(struct hibmc_drm_device *hidev)
+{
+	void __iomem   *mmio = hidev->mmio;
+
+	return (readl(mmio + HIBMC_POWER_MODE_CTRL) &
+		HIBMC_PW_MODE_CTL_MODE_MASK) >> HIBMC_PW_MODE_CTL_MODE_SHIFT;
+}
+
+void hibmc_set_current_gate(struct hibmc_drm_device *hidev, unsigned int gate)
+{
+	unsigned int gate_reg;
+	unsigned int mode;
+	void __iomem   *mmio = hidev->mmio;
+
+	/* Get current power mode. */
+	mode = hibmc_get_power_mode(hidev);
+
+	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);
+}
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h
new file mode 100644
index 0000000..e20e1aa
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h
@@ -0,0 +1,28 @@
+/* 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_POWER_H
+#define HIBMC_DRM_POWER_H
+
+#include "hibmc_drm_drv.h"
+
+void hibmc_set_power_mode(struct hibmc_drm_device *hidev,
+			  unsigned int power_mode);
+void hibmc_set_current_gate(struct hibmc_drm_device *hidev,
+			    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..9c804ca
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
@@ -0,0 +1,212 @@
+/* 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
+
+#define OFF 0
+#define ON  1
+#define DISABLE               0
+#define ENABLE                1
+
+/* register definition */
+#define HIBMC_MISC_CTRL				0x4
+
+#define HIBMC_MSCCTL_LOCALMEM_RESET(x)		((x) << 6)
+#define HIBMC_MSCCTL_LOCALMEM_RESET_MASK	0x40
+
+#define RESET                0
+#define NORMAL               1
+
+#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 OSC					0
+#define TESTCLK					1
+
+#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 CRTSELECT_VGA                0
+#define CRTSELECT_CRT                1
+
+#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE(x)	((x) << 14)
+#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE_MASK	0x4000
+
+#define PHASE_ACTIVE_HIGH      0
+#define PHASE_ACTIVE_LOW       1
+
+#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_DISPLAY_END(x)	((x) << 0)
+#define HIBMC_CRT_HORZ_TOTAL_DISPLAY_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_DISPLAY_END(x)	((x) << 0)
+#define HIBMC_CRT_VERT_TOTAL_DISPLAY_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_MSK	0x7FF0000
+
+#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT(x)	((x) << 0)
+#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT_MSK	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 DISPLAY_CONTROL_HISILE			0x80288
+
+#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_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
+
+/* Global macros */
+#define RGB(r, g, b) \
+( \
+	(unsigned long)(((r) << 16) | ((g) << 8) | (b)) \
+)
+
+#define PADDING(align, data) (((data) + (align) - 1) & (~((align) - 1)))
+
+#define MB(x) ((x) << 20)
+
+#endif
-- 
1.9.1

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

* [PATCH v6 2/9] drm/hisilicon/hibmc: Add video memory management
  2016-10-28  7:27 ` Rongrong Zou
@ 2016-10-28  7:27   ` Rongrong Zou
  -1 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-10-28  7:27 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/Kconfig         |   1 +
 drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  12 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |  46 +++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     | 490 ++++++++++++++++++++++++
 5 files changed, 550 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c

diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
index a9af90d..bcb8c18 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/Kconfig
+++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
@@ -1,6 +1,7 @@
 config DRM_HISI_HIBMC
 	tristate "DRM Support for Hisilicon Hibmc"
 	depends on DRM && PCI
+	select DRM_TTM
 
 	help
 	  Choose this option if you have a Hisilicon Hibmc soc chipset.
diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
index 97cf4a0..d5c40b8 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
+++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
@@ -1,5 +1,5 @@
 ccflags-y := -Iinclude/drm
-hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o
+hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o hibmc_ttm.o
 
 obj-$(CONFIG_DRM_HISI_HIBMC)	+=hibmc-drm.o
 #obj-y	+= 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 4669d42..81f4301 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -31,6 +31,7 @@
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= drm_compat_ioctl,
 #endif
+	.mmap		= hibmc_mmap,
 	.poll		= drm_poll,
 	.read		= drm_read,
 	.llseek		= no_llseek,
@@ -46,6 +47,8 @@ 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",
@@ -55,6 +58,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)
@@ -163,6 +170,7 @@ static int hibmc_unload(struct drm_device *dev)
 {
 	struct hibmc_drm_device *hidev = dev->dev_private;
 
+	hibmc_mm_fini(hidev);
 	hibmc_hw_fini(hidev);
 	dev->dev_private = NULL;
 	return 0;
@@ -183,6 +191,10 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
 	if (ret)
 		goto err;
 
+	ret = hibmc_mm_init(hidev);
+	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 0037341..db8d80e 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/ttm/ttm_bo_driver.h>
+#include <drm/drm_gem.h>
 
 struct hibmc_drm_device {
 	/* hw */
@@ -30,6 +32,50 @@ struct hibmc_drm_device {
 
 	/* drm */
 	struct drm_device  *dev;
+
+	/* ttm */
+	struct {
+		struct drm_global_reference mem_global_ref;
+		struct ttm_bo_global_ref bo_global_ref;
+		struct ttm_bo_device bdev;
+		bool initialized;
+	} ttm;
+
+	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);
+}
+
+#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
+
+int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
+		     struct drm_gem_object **obj);
+
+int hibmc_mm_init(struct hibmc_drm_device *hibmc);
+void hibmc_mm_fini(struct hibmc_drm_device *hibmc);
+int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr);
+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..0802ebd
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
@@ -0,0 +1,490 @@
+/* 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 "hibmc_drm_drv.h"
+#include <ttm/ttm_page_alloc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
+
+static inline struct hibmc_drm_device *
+hibmc_bdev(struct ttm_bo_device *bd)
+{
+	return container_of(bd, struct hibmc_drm_device, ttm.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_device *hibmc)
+{
+	struct drm_global_reference *global_ref;
+	int r;
+
+	global_ref = &hibmc->ttm.mem_global_ref;
+	global_ref->global_type = DRM_GLOBAL_TTM_MEM;
+	global_ref->size = sizeof(struct ttm_mem_global);
+	global_ref->init = &hibmc_ttm_mem_global_init;
+	global_ref->release = &hibmc_ttm_mem_global_release;
+	r = drm_global_item_ref(global_ref);
+	if (r != 0) {
+		DRM_ERROR("Failed setting up TTM memory accounting subsystem.\n"
+			 );
+		return r;
+	}
+
+	hibmc->ttm.bo_global_ref.mem_glob =
+		hibmc->ttm.mem_global_ref.object;
+	global_ref = &hibmc->ttm.bo_global_ref.ref;
+	global_ref->global_type = DRM_GLOBAL_TTM_BO;
+	global_ref->size = sizeof(struct ttm_bo_global);
+	global_ref->init = &ttm_bo_global_init;
+	global_ref->release = &ttm_bo_global_release;
+	r = drm_global_item_ref(global_ref);
+	if (r != 0) {
+		DRM_ERROR("Failed setting up TTM BO subsystem.\n");
+		drm_global_item_unref(&hibmc->ttm.mem_global_ref);
+		return r;
+	}
+	return 0;
+}
+
+static void
+hibmc_ttm_global_release(struct hibmc_drm_device *hibmc)
+{
+	if (!hibmc->ttm.mem_global_ref.release)
+		return;
+
+	drm_global_item_unref(&hibmc->ttm.bo_global_ref.ref);
+	drm_global_item_unref(&hibmc->ttm.mem_global_ref);
+	hibmc->ttm.mem_global_ref.release = NULL;
+}
+
+static void hibmc_bo_ttm_destroy(struct ttm_buffer_object *tbo)
+{
+	struct hibmc_bo *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)
+{
+	if (bo->destroy == &hibmc_bo_ttm_destroy)
+		return true;
+	return false;
+}
+
+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 c = 0;
+	u32 i;
+
+	bo->placement.placement = bo->placements;
+	bo->placement.busy_placement = bo->placements;
+	if (domain & TTM_PL_FLAG_VRAM)
+		bo->placements[c++].flags = TTM_PL_FLAG_WC |
+		TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
+	if (domain & TTM_PL_FLAG_SYSTEM)
+		bo->placements[c++].flags = TTM_PL_MASK_CACHING |
+		TTM_PL_FLAG_SYSTEM;
+	if (!c)
+		bo->placements[c++].flags = TTM_PL_MASK_CACHING |
+		TTM_PL_FLAG_SYSTEM;
+
+	bo->placement.num_placement = c;
+	bo->placement.num_busy_placement = c;
+	for (i = 0; i < c; ++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_device *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_io_mem_free(struct ttm_bo_device *bdev,
+				  struct ttm_mem_reg *mem)
+{
+}
+
+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;
+
+	tt = kzalloc(sizeof(*tt), GFP_KERNEL);
+	if (!tt)
+		return NULL;
+	tt->func = &hibmc_tt_backend_func;
+	if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) {
+		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		= &hibmc_ttm_io_mem_free,
+	.lru_tail		= &ttm_bo_default_lru_tail,
+	.swap_lru_tail		= &ttm_bo_default_swap_lru_tail,
+};
+
+int hibmc_mm_init(struct hibmc_drm_device *hibmc)
+{
+	int ret;
+	struct drm_device *dev = hibmc->dev;
+	struct ttm_bo_device *bdev = &hibmc->ttm.bdev;
+
+	ret = hibmc_ttm_global_init(hibmc);
+	if (ret)
+		return ret;
+
+	ret = ttm_bo_device_init(&hibmc->ttm.bdev,
+				 hibmc->ttm.bo_global_ref.ref.object,
+				 &hibmc_bo_driver,
+				 dev->anon_inode->i_mapping,
+				 DRM_FILE_PAGE_OFFSET,
+				 true);
+	if (ret) {
+		DRM_ERROR("Error initialising bo driver; %d\n", ret);
+		return ret;
+	}
+
+	ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
+			     hibmc->fb_size >> PAGE_SHIFT);
+	if (ret) {
+		DRM_ERROR("Failed ttm VRAM init: %d\n", ret);
+		return ret;
+	}
+
+	hibmc->mm_inited = true;
+	return 0;
+}
+
+void hibmc_mm_fini(struct hibmc_drm_device *hibmc)
+{
+	if (!hibmc->mm_inited)
+		return;
+
+	ttm_bo_device_release(&hibmc->ttm.bdev);
+	hibmc_ttm_global_release(hibmc);
+	hibmc->mm_inited = false;
+}
+
+int hibmc_bo_create(struct drm_device *dev, int size, int align,
+		    u32 flags, struct hibmc_bo **phibmcbo)
+{
+	struct hibmc_drm_device *hibmc = dev->dev_private;
+	struct hibmc_bo *hibmcbo;
+	size_t acc_size;
+	int ret;
+
+	hibmcbo = kzalloc(sizeof(*hibmcbo), GFP_KERNEL);
+	if (!hibmcbo)
+		return -ENOMEM;
+
+	ret = drm_gem_object_init(dev, &hibmcbo->gem, size);
+	if (ret) {
+		kfree(hibmcbo);
+		return ret;
+	}
+
+	hibmcbo->bo.bdev = &hibmc->ttm.bdev;
+
+	hibmc_ttm_placement(hibmcbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
+
+	acc_size = ttm_bo_dma_acc_size(&hibmc->ttm.bdev, size,
+				       sizeof(struct hibmc_bo));
+
+	ret = ttm_bo_init(&hibmc->ttm.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)
+		return ret;
+
+	*phibmcbo = hibmcbo;
+	return 0;
+}
+
+static inline u64 hibmc_bo_gpu_offset(struct hibmc_bo *bo)
+{
+	return bo->bo.offset;
+}
+
+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 = hibmc_bo_gpu_offset(bo);
+	}
+
+	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 = hibmc_bo_gpu_offset(bo);
+	return 0;
+}
+
+int hibmc_bo_push_sysram(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;
+
+	if (bo->kmap.virtual)
+		ttm_bo_kunmap(&bo->kmap);
+
+	hibmc_ttm_placement(bo, TTM_PL_FLAG_SYSTEM);
+	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("pushing to VRAM failed\n");
+		return ret;
+	}
+	return 0;
+}
+
+int hibmc_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct drm_file *file_priv;
+	struct hibmc_drm_device *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->ttm.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)
+		return -EINVAL;
+
+	ret = hibmc_bo_create(dev, size, 0, 0, &hibmcbo);
+	if (ret) {
+		if (ret != -ERESTARTSYS)
+			DRM_ERROR("failed to allocate GEM object\n");
+		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 * ((args->bpp + 7) / 8), 16);
+	args->size = args->pitch * args->height;
+
+	ret = hibmc_gem_create(dev, args->size, false,
+			       &gobj);
+	if (ret)
+		return ret;
+
+	ret = drm_gem_handle_create(file, gobj, &handle);
+	drm_gem_object_unreference_unlocked(gobj);
+	if (ret)
+		return ret;
+
+	args->handle = handle;
+	return 0;
+}
+
+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;
+}
+
+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] 64+ messages in thread

* [PATCH v6 2/9] drm/hisilicon/hibmc: Add video memory management
@ 2016-10-28  7:27   ` Rongrong Zou
  0 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-10-28  7:27 UTC (permalink / raw)
  To: airlied, daniel, dri-devel, emil.l.velikov, tomeu.vizoso,
	benjamin.gaignard, robh, daniel, architt, corbet,
	catalin.marinas, will.deacon, 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/Kconfig         |   1 +
 drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  12 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |  46 +++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     | 490 ++++++++++++++++++++++++
 5 files changed, 550 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c

diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
index a9af90d..bcb8c18 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/Kconfig
+++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
@@ -1,6 +1,7 @@
 config DRM_HISI_HIBMC
 	tristate "DRM Support for Hisilicon Hibmc"
 	depends on DRM && PCI
+	select DRM_TTM
 
 	help
 	  Choose this option if you have a Hisilicon Hibmc soc chipset.
diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
index 97cf4a0..d5c40b8 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
+++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
@@ -1,5 +1,5 @@
 ccflags-y := -Iinclude/drm
-hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o
+hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o hibmc_ttm.o
 
 obj-$(CONFIG_DRM_HISI_HIBMC)	+=hibmc-drm.o
 #obj-y	+= 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 4669d42..81f4301 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -31,6 +31,7 @@
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= drm_compat_ioctl,
 #endif
+	.mmap		= hibmc_mmap,
 	.poll		= drm_poll,
 	.read		= drm_read,
 	.llseek		= no_llseek,
@@ -46,6 +47,8 @@ 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",
@@ -55,6 +58,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)
@@ -163,6 +170,7 @@ static int hibmc_unload(struct drm_device *dev)
 {
 	struct hibmc_drm_device *hidev = dev->dev_private;
 
+	hibmc_mm_fini(hidev);
 	hibmc_hw_fini(hidev);
 	dev->dev_private = NULL;
 	return 0;
@@ -183,6 +191,10 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
 	if (ret)
 		goto err;
 
+	ret = hibmc_mm_init(hidev);
+	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 0037341..db8d80e 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/ttm/ttm_bo_driver.h>
+#include <drm/drm_gem.h>
 
 struct hibmc_drm_device {
 	/* hw */
@@ -30,6 +32,50 @@ struct hibmc_drm_device {
 
 	/* drm */
 	struct drm_device  *dev;
+
+	/* ttm */
+	struct {
+		struct drm_global_reference mem_global_ref;
+		struct ttm_bo_global_ref bo_global_ref;
+		struct ttm_bo_device bdev;
+		bool initialized;
+	} ttm;
+
+	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);
+}
+
+#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
+
+int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
+		     struct drm_gem_object **obj);
+
+int hibmc_mm_init(struct hibmc_drm_device *hibmc);
+void hibmc_mm_fini(struct hibmc_drm_device *hibmc);
+int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr);
+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..0802ebd
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
@@ -0,0 +1,490 @@
+/* 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 "hibmc_drm_drv.h"
+#include <ttm/ttm_page_alloc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
+
+static inline struct hibmc_drm_device *
+hibmc_bdev(struct ttm_bo_device *bd)
+{
+	return container_of(bd, struct hibmc_drm_device, ttm.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_device *hibmc)
+{
+	struct drm_global_reference *global_ref;
+	int r;
+
+	global_ref = &hibmc->ttm.mem_global_ref;
+	global_ref->global_type = DRM_GLOBAL_TTM_MEM;
+	global_ref->size = sizeof(struct ttm_mem_global);
+	global_ref->init = &hibmc_ttm_mem_global_init;
+	global_ref->release = &hibmc_ttm_mem_global_release;
+	r = drm_global_item_ref(global_ref);
+	if (r != 0) {
+		DRM_ERROR("Failed setting up TTM memory accounting subsystem.\n"
+			 );
+		return r;
+	}
+
+	hibmc->ttm.bo_global_ref.mem_glob =
+		hibmc->ttm.mem_global_ref.object;
+	global_ref = &hibmc->ttm.bo_global_ref.ref;
+	global_ref->global_type = DRM_GLOBAL_TTM_BO;
+	global_ref->size = sizeof(struct ttm_bo_global);
+	global_ref->init = &ttm_bo_global_init;
+	global_ref->release = &ttm_bo_global_release;
+	r = drm_global_item_ref(global_ref);
+	if (r != 0) {
+		DRM_ERROR("Failed setting up TTM BO subsystem.\n");
+		drm_global_item_unref(&hibmc->ttm.mem_global_ref);
+		return r;
+	}
+	return 0;
+}
+
+static void
+hibmc_ttm_global_release(struct hibmc_drm_device *hibmc)
+{
+	if (!hibmc->ttm.mem_global_ref.release)
+		return;
+
+	drm_global_item_unref(&hibmc->ttm.bo_global_ref.ref);
+	drm_global_item_unref(&hibmc->ttm.mem_global_ref);
+	hibmc->ttm.mem_global_ref.release = NULL;
+}
+
+static void hibmc_bo_ttm_destroy(struct ttm_buffer_object *tbo)
+{
+	struct hibmc_bo *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)
+{
+	if (bo->destroy == &hibmc_bo_ttm_destroy)
+		return true;
+	return false;
+}
+
+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 c = 0;
+	u32 i;
+
+	bo->placement.placement = bo->placements;
+	bo->placement.busy_placement = bo->placements;
+	if (domain & TTM_PL_FLAG_VRAM)
+		bo->placements[c++].flags = TTM_PL_FLAG_WC |
+		TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
+	if (domain & TTM_PL_FLAG_SYSTEM)
+		bo->placements[c++].flags = TTM_PL_MASK_CACHING |
+		TTM_PL_FLAG_SYSTEM;
+	if (!c)
+		bo->placements[c++].flags = TTM_PL_MASK_CACHING |
+		TTM_PL_FLAG_SYSTEM;
+
+	bo->placement.num_placement = c;
+	bo->placement.num_busy_placement = c;
+	for (i = 0; i < c; ++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_device *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_io_mem_free(struct ttm_bo_device *bdev,
+				  struct ttm_mem_reg *mem)
+{
+}
+
+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;
+
+	tt = kzalloc(sizeof(*tt), GFP_KERNEL);
+	if (!tt)
+		return NULL;
+	tt->func = &hibmc_tt_backend_func;
+	if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) {
+		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		= &hibmc_ttm_io_mem_free,
+	.lru_tail		= &ttm_bo_default_lru_tail,
+	.swap_lru_tail		= &ttm_bo_default_swap_lru_tail,
+};
+
+int hibmc_mm_init(struct hibmc_drm_device *hibmc)
+{
+	int ret;
+	struct drm_device *dev = hibmc->dev;
+	struct ttm_bo_device *bdev = &hibmc->ttm.bdev;
+
+	ret = hibmc_ttm_global_init(hibmc);
+	if (ret)
+		return ret;
+
+	ret = ttm_bo_device_init(&hibmc->ttm.bdev,
+				 hibmc->ttm.bo_global_ref.ref.object,
+				 &hibmc_bo_driver,
+				 dev->anon_inode->i_mapping,
+				 DRM_FILE_PAGE_OFFSET,
+				 true);
+	if (ret) {
+		DRM_ERROR("Error initialising bo driver; %d\n", ret);
+		return ret;
+	}
+
+	ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
+			     hibmc->fb_size >> PAGE_SHIFT);
+	if (ret) {
+		DRM_ERROR("Failed ttm VRAM init: %d\n", ret);
+		return ret;
+	}
+
+	hibmc->mm_inited = true;
+	return 0;
+}
+
+void hibmc_mm_fini(struct hibmc_drm_device *hibmc)
+{
+	if (!hibmc->mm_inited)
+		return;
+
+	ttm_bo_device_release(&hibmc->ttm.bdev);
+	hibmc_ttm_global_release(hibmc);
+	hibmc->mm_inited = false;
+}
+
+int hibmc_bo_create(struct drm_device *dev, int size, int align,
+		    u32 flags, struct hibmc_bo **phibmcbo)
+{
+	struct hibmc_drm_device *hibmc = dev->dev_private;
+	struct hibmc_bo *hibmcbo;
+	size_t acc_size;
+	int ret;
+
+	hibmcbo = kzalloc(sizeof(*hibmcbo), GFP_KERNEL);
+	if (!hibmcbo)
+		return -ENOMEM;
+
+	ret = drm_gem_object_init(dev, &hibmcbo->gem, size);
+	if (ret) {
+		kfree(hibmcbo);
+		return ret;
+	}
+
+	hibmcbo->bo.bdev = &hibmc->ttm.bdev;
+
+	hibmc_ttm_placement(hibmcbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
+
+	acc_size = ttm_bo_dma_acc_size(&hibmc->ttm.bdev, size,
+				       sizeof(struct hibmc_bo));
+
+	ret = ttm_bo_init(&hibmc->ttm.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)
+		return ret;
+
+	*phibmcbo = hibmcbo;
+	return 0;
+}
+
+static inline u64 hibmc_bo_gpu_offset(struct hibmc_bo *bo)
+{
+	return bo->bo.offset;
+}
+
+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 = hibmc_bo_gpu_offset(bo);
+	}
+
+	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 = hibmc_bo_gpu_offset(bo);
+	return 0;
+}
+
+int hibmc_bo_push_sysram(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;
+
+	if (bo->kmap.virtual)
+		ttm_bo_kunmap(&bo->kmap);
+
+	hibmc_ttm_placement(bo, TTM_PL_FLAG_SYSTEM);
+	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("pushing to VRAM failed\n");
+		return ret;
+	}
+	return 0;
+}
+
+int hibmc_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct drm_file *file_priv;
+	struct hibmc_drm_device *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->ttm.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)
+		return -EINVAL;
+
+	ret = hibmc_bo_create(dev, size, 0, 0, &hibmcbo);
+	if (ret) {
+		if (ret != -ERESTARTSYS)
+			DRM_ERROR("failed to allocate GEM object\n");
+		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 * ((args->bpp + 7) / 8), 16);
+	args->size = args->pitch * args->height;
+
+	ret = hibmc_gem_create(dev, args->size, false,
+			       &gobj);
+	if (ret)
+		return ret;
+
+	ret = drm_gem_handle_create(file, gobj, &handle);
+	drm_gem_object_unreference_unlocked(gobj);
+	if (ret)
+		return ret;
+
+	args->handle = handle;
+	return 0;
+}
+
+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;
+}
+
+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] 64+ messages in thread

* [PATCH v6 3/9] drm/hisilicon/hibmc: Add support for frame buffer
  2016-10-28  7:27 ` Rongrong Zou
@ 2016-10-28  7:27   ` Rongrong Zou
  -1 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-10-28  7:27 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   |  17 ++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   |  24 ++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 255 ++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       |  66 ++++++
 5 files changed, 363 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 d5c40b8..810a37e 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
+++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
@@ -1,5 +1,5 @@
 ccflags-y := -Iinclude/drm
-hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o hibmc_ttm.o
+hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
 
 obj-$(CONFIG_DRM_HISI_HIBMC)	+=hibmc-drm.o
 #obj-y	+= 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 81f4301..5ac7a7e 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -66,11 +66,23 @@ 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_device *hidev = drm_dev->dev_private;
+
+	drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 1);
+
 	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_device *hidev = drm_dev->dev_private;
+
+	drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 0);
+
 	return 0;
 }
 
@@ -170,6 +182,7 @@ static int hibmc_unload(struct drm_device *dev)
 {
 	struct hibmc_drm_device *hidev = dev->dev_private;
 
+	hibmc_fbdev_fini(hidev);
 	hibmc_mm_fini(hidev);
 	hibmc_hw_fini(hidev);
 	dev->dev_private = NULL;
@@ -195,6 +208,10 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
 	if (ret)
 		goto err;
 
+	ret = hibmc_fbdev_init(hidev);
+	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 db8d80e..a40e9a7 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -20,9 +20,22 @@
 #define HIBMC_DRM_DRV_H
 
 #include <drm/drmP.h>
+#include <drm/drm_fb_helper.h>
 #include <drm/ttm/ttm_bo_driver.h>
 #include <drm/drm_gem.h>
 
+struct hibmc_framebuffer {
+	struct drm_framebuffer fb;
+	struct drm_gem_object *obj;
+	bool is_fbdev_fb;
+};
+
+struct hibmc_fbdev {
+	struct drm_fb_helper helper;
+	struct hibmc_framebuffer *fb;
+	int size;
+};
+
 struct hibmc_drm_device {
 	/* hw */
 	void __iomem   *mmio;
@@ -41,9 +54,13 @@ struct hibmc_drm_device {
 		bool initialized;
 	} ttm;
 
+	/* 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;
@@ -65,8 +82,15 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
 
 #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
 
+int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
+void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
+
 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_device *hibmc);
 void hibmc_mm_fini(struct hibmc_drm_device *hibmc);
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..630124b
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
@@ -0,0 +1,255 @@
+/* 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_device *hidev,
+				const struct drm_mode_fb_cmd2 *mode_cmd,
+				struct drm_gem_object **gobj_p)
+{
+	struct drm_gem_object *gobj;
+	struct drm_device *dev = hidev->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_device *hidev =
+		(struct hibmc_drm_device *)helper->dev->dev_private;
+	struct fb_info *info;
+	struct hibmc_framebuffer *hibmc_fb;
+	struct drm_framebuffer *fb;
+	struct drm_mode_fb_cmd2 mode_cmd;
+	struct drm_gem_object *gobj = NULL;
+	int ret = 0;
+	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 = roundup(mode_cmd.pitches[0] * mode_cmd.height, PAGE_SIZE);
+
+	ret = hibmcfb_create_object(hidev, &mode_cmd, &gobj);
+	if (ret) {
+		DRM_ERROR("failed to create fbcon backing object %d\r\n", ret);
+		return -ENOMEM;
+	}
+
+	bo = gem_to_hibmc_bo(gobj);
+
+	ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
+	if (ret)
+		return ret;
+
+	ret = hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL);
+	if (ret) {
+		DRM_ERROR("failed to pin fbcon\n");
+		return ret;
+	}
+
+	ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
+
+	if (ret) {
+		DRM_ERROR("failed to kmap fbcon\n");
+		ttm_bo_unreserve(&bo->bo);
+		return ret;
+	}
+
+	ttm_bo_unreserve(&bo->bo);
+
+	info = drm_fb_helper_alloc_fbi(helper);
+	if (IS_ERR(info))
+		return PTR_ERR(info);
+
+	info->par = hi_fbdev;
+
+	hibmc_fb = hibmc_framebuffer_init(hidev->dev, &mode_cmd, gobj);
+	if (IS_ERR(hibmc_fb)) {
+		drm_fb_helper_release_fbi(helper);
+		return PTR_ERR(hibmc_fb);
+	}
+
+	hi_fbdev->fb = hibmc_fb;
+	hidev->fbdev->size = size;
+	fb = &hibmc_fb->fb;
+	if (!fb) {
+		DRM_INFO("fb is NULL\n");
+		return -EINVAL;
+	}
+
+	hi_fbdev->helper.fb = fb;
+
+	strcpy(info->fix.id, "hibmcdrmfb");
+
+	info->flags = FBINFO_DEFAULT;
+	info->fbops = &hibmc_drm_fb_ops;
+
+	drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
+	drm_fb_helper_fill_var(info, &hidev->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;
+}
+
+static void hibmc_fbdev_destroy(struct hibmc_fbdev *fbdev)
+{
+	struct hibmc_framebuffer *gfb = fbdev->fb;
+	struct drm_fb_helper *fbh = &fbdev->helper;
+
+	DRM_DEBUG_DRIVER("hibmc_fbdev_destroy\n");
+
+	drm_fb_helper_unregister_fbi(fbh);
+	drm_fb_helper_release_fbi(fbh);
+
+	drm_fb_helper_fini(fbh);
+
+	if (gfb)
+		drm_framebuffer_unreference(&gfb->fb);
+
+	kfree(fbdev);
+}
+
+static const struct drm_fb_helper_funcs hibmc_fbdev_helper_funcs = {
+	.fb_probe = hibmc_drm_fb_create,
+};
+
+int hibmc_fbdev_init(struct hibmc_drm_device *hidev)
+{
+	int ret;
+	struct fb_var_screeninfo *var;
+	struct fb_fix_screeninfo *fix;
+	struct hibmc_fbdev *hifbdev;
+
+	hifbdev = kzalloc(sizeof(*hifbdev), GFP_KERNEL);
+	if (!hifbdev)
+		return -ENOMEM;
+
+	hidev->fbdev = hifbdev;
+	drm_fb_helper_prepare(hidev->dev, &hifbdev->helper,
+			      &hibmc_fbdev_helper_funcs);
+
+	/* Now just one crtc and one channel */
+	ret = drm_fb_helper_init(hidev->dev,
+				 &hifbdev->helper, 1, 1);
+
+	if (ret)
+		return ret;
+
+	ret = drm_fb_helper_single_add_all_connectors(&hifbdev->helper);
+	if (ret)
+		goto fini;
+
+	ret = drm_fb_helper_initial_config(&hifbdev->helper, 16);
+	if (ret)
+		goto fini;
+
+	var = &hifbdev->helper.fbdev->var;
+	fix = &hifbdev->helper.fbdev->fix;
+
+	DRM_DEBUG("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("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_device *hidev)
+{
+	if (!hidev->fbdev)
+		return;
+
+	hibmc_fbdev_destroy(hidev->fbdev);
+	hidev->fbdev = NULL;
+}
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
index 0802ebd..9822f62 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
@@ -488,3 +488,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)
+		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] 64+ messages in thread

* [PATCH v6 3/9] drm/hisilicon/hibmc: Add support for frame buffer
@ 2016-10-28  7:27   ` Rongrong Zou
  0 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-10-28  7:27 UTC (permalink / raw)
  To: airlied, daniel, dri-devel, emil.l.velikov, tomeu.vizoso,
	benjamin.gaignard, robh, daniel, architt, corbet,
	catalin.marinas, will.deacon, 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   |  17 ++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   |  24 ++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 255 ++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       |  66 ++++++
 5 files changed, 363 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 d5c40b8..810a37e 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
+++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
@@ -1,5 +1,5 @@
 ccflags-y := -Iinclude/drm
-hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o hibmc_ttm.o
+hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
 
 obj-$(CONFIG_DRM_HISI_HIBMC)	+=hibmc-drm.o
 #obj-y	+= 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 81f4301..5ac7a7e 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -66,11 +66,23 @@ 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_device *hidev = drm_dev->dev_private;
+
+	drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 1);
+
 	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_device *hidev = drm_dev->dev_private;
+
+	drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 0);
+
 	return 0;
 }
 
@@ -170,6 +182,7 @@ static int hibmc_unload(struct drm_device *dev)
 {
 	struct hibmc_drm_device *hidev = dev->dev_private;
 
+	hibmc_fbdev_fini(hidev);
 	hibmc_mm_fini(hidev);
 	hibmc_hw_fini(hidev);
 	dev->dev_private = NULL;
@@ -195,6 +208,10 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
 	if (ret)
 		goto err;
 
+	ret = hibmc_fbdev_init(hidev);
+	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 db8d80e..a40e9a7 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -20,9 +20,22 @@
 #define HIBMC_DRM_DRV_H
 
 #include <drm/drmP.h>
+#include <drm/drm_fb_helper.h>
 #include <drm/ttm/ttm_bo_driver.h>
 #include <drm/drm_gem.h>
 
+struct hibmc_framebuffer {
+	struct drm_framebuffer fb;
+	struct drm_gem_object *obj;
+	bool is_fbdev_fb;
+};
+
+struct hibmc_fbdev {
+	struct drm_fb_helper helper;
+	struct hibmc_framebuffer *fb;
+	int size;
+};
+
 struct hibmc_drm_device {
 	/* hw */
 	void __iomem   *mmio;
@@ -41,9 +54,13 @@ struct hibmc_drm_device {
 		bool initialized;
 	} ttm;
 
+	/* 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;
@@ -65,8 +82,15 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
 
 #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
 
+int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
+void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
+
 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_device *hibmc);
 void hibmc_mm_fini(struct hibmc_drm_device *hibmc);
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..630124b
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
@@ -0,0 +1,255 @@
+/* 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_device *hidev,
+				const struct drm_mode_fb_cmd2 *mode_cmd,
+				struct drm_gem_object **gobj_p)
+{
+	struct drm_gem_object *gobj;
+	struct drm_device *dev = hidev->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_device *hidev =
+		(struct hibmc_drm_device *)helper->dev->dev_private;
+	struct fb_info *info;
+	struct hibmc_framebuffer *hibmc_fb;
+	struct drm_framebuffer *fb;
+	struct drm_mode_fb_cmd2 mode_cmd;
+	struct drm_gem_object *gobj = NULL;
+	int ret = 0;
+	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 = roundup(mode_cmd.pitches[0] * mode_cmd.height, PAGE_SIZE);
+
+	ret = hibmcfb_create_object(hidev, &mode_cmd, &gobj);
+	if (ret) {
+		DRM_ERROR("failed to create fbcon backing object %d\r\n", ret);
+		return -ENOMEM;
+	}
+
+	bo = gem_to_hibmc_bo(gobj);
+
+	ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
+	if (ret)
+		return ret;
+
+	ret = hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL);
+	if (ret) {
+		DRM_ERROR("failed to pin fbcon\n");
+		return ret;
+	}
+
+	ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
+
+	if (ret) {
+		DRM_ERROR("failed to kmap fbcon\n");
+		ttm_bo_unreserve(&bo->bo);
+		return ret;
+	}
+
+	ttm_bo_unreserve(&bo->bo);
+
+	info = drm_fb_helper_alloc_fbi(helper);
+	if (IS_ERR(info))
+		return PTR_ERR(info);
+
+	info->par = hi_fbdev;
+
+	hibmc_fb = hibmc_framebuffer_init(hidev->dev, &mode_cmd, gobj);
+	if (IS_ERR(hibmc_fb)) {
+		drm_fb_helper_release_fbi(helper);
+		return PTR_ERR(hibmc_fb);
+	}
+
+	hi_fbdev->fb = hibmc_fb;
+	hidev->fbdev->size = size;
+	fb = &hibmc_fb->fb;
+	if (!fb) {
+		DRM_INFO("fb is NULL\n");
+		return -EINVAL;
+	}
+
+	hi_fbdev->helper.fb = fb;
+
+	strcpy(info->fix.id, "hibmcdrmfb");
+
+	info->flags = FBINFO_DEFAULT;
+	info->fbops = &hibmc_drm_fb_ops;
+
+	drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
+	drm_fb_helper_fill_var(info, &hidev->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;
+}
+
+static void hibmc_fbdev_destroy(struct hibmc_fbdev *fbdev)
+{
+	struct hibmc_framebuffer *gfb = fbdev->fb;
+	struct drm_fb_helper *fbh = &fbdev->helper;
+
+	DRM_DEBUG_DRIVER("hibmc_fbdev_destroy\n");
+
+	drm_fb_helper_unregister_fbi(fbh);
+	drm_fb_helper_release_fbi(fbh);
+
+	drm_fb_helper_fini(fbh);
+
+	if (gfb)
+		drm_framebuffer_unreference(&gfb->fb);
+
+	kfree(fbdev);
+}
+
+static const struct drm_fb_helper_funcs hibmc_fbdev_helper_funcs = {
+	.fb_probe = hibmc_drm_fb_create,
+};
+
+int hibmc_fbdev_init(struct hibmc_drm_device *hidev)
+{
+	int ret;
+	struct fb_var_screeninfo *var;
+	struct fb_fix_screeninfo *fix;
+	struct hibmc_fbdev *hifbdev;
+
+	hifbdev = kzalloc(sizeof(*hifbdev), GFP_KERNEL);
+	if (!hifbdev)
+		return -ENOMEM;
+
+	hidev->fbdev = hifbdev;
+	drm_fb_helper_prepare(hidev->dev, &hifbdev->helper,
+			      &hibmc_fbdev_helper_funcs);
+
+	/* Now just one crtc and one channel */
+	ret = drm_fb_helper_init(hidev->dev,
+				 &hifbdev->helper, 1, 1);
+
+	if (ret)
+		return ret;
+
+	ret = drm_fb_helper_single_add_all_connectors(&hifbdev->helper);
+	if (ret)
+		goto fini;
+
+	ret = drm_fb_helper_initial_config(&hifbdev->helper, 16);
+	if (ret)
+		goto fini;
+
+	var = &hifbdev->helper.fbdev->var;
+	fix = &hifbdev->helper.fbdev->fix;
+
+	DRM_DEBUG("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("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_device *hidev)
+{
+	if (!hidev->fbdev)
+		return;
+
+	hibmc_fbdev_destroy(hidev->fbdev);
+	hidev->fbdev = NULL;
+}
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
index 0802ebd..9822f62 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
@@ -488,3 +488,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)
+		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] 64+ messages in thread

* [PATCH v6 4/9] drm/hisilicon/hibmc: Add plane for DE
  2016-10-28  7:27 ` Rongrong Zou
@ 2016-10-28  7:27   ` Rongrong Zou
  -1 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-10-28  7:27 UTC (permalink / raw)
  To: linux-arm-kernel

Add plane funcs and helper funcs for DE.

Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
---
 drivers/gpu/drm/hisilicon/hibmc/Kconfig         |   1 +
 drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c  | 170 ++++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h  |  29 ++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  51 ++++++-
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |   5 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     |   6 +
 7 files changed, 261 insertions(+), 3 deletions(-)
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h

diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
index bcb8c18..380622a 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/Kconfig
+++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
@@ -1,6 +1,7 @@
 config DRM_HISI_HIBMC
 	tristate "DRM Support for Hisilicon Hibmc"
 	depends on DRM && PCI
+	select DRM_KMS_HELPER
 	select DRM_TTM
 
 	help
diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
index 810a37e..72e107e 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
+++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
@@ -1,5 +1,5 @@
 ccflags-y := -Iinclude/drm
-hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
+hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
 
 obj-$(CONFIG_DRM_HISI_HIBMC)	+=hibmc-drm.o
 #obj-y	+= 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..9c1a68c
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
@@ -0,0 +1,170 @@
+/* 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"
+#include "hibmc_drm_power.h"
+
+/* ---------------------------------------------------------------------- */
+
+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_x = state->src_x >> 16;
+	u32 src_y = state->src_y >> 16;
+	u32 src_w = state->src_w >> 16;
+	u32 src_h = state->src_h >> 16;
+	int crtc_x = state->crtc_x;
+	int crtc_y = state->crtc_y;
+	u32 crtc_w = state->crtc_w;
+	u32 crtc_h = state->crtc_h;
+
+	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 != crtc_w || src_h != crtc_h) {
+		DRM_ERROR("Scale not support!!!\n");
+		return -EINVAL;
+	}
+
+	if (src_x + src_w > fb->width ||
+	    src_y + src_h > fb->height)
+		return -EINVAL;
+
+	if (crtc_x < 0 || crtc_y < 0)
+		return -EINVAL;
+
+	if (crtc_x + crtc_w > crtc_state->adjusted_mode.hdisplay ||
+	    crtc_y + crtc_h > crtc_state->adjusted_mode.vdisplay)
+		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_device *hidev =
+		(struct hibmc_drm_device *)plane->dev->dev_private;
+
+	struct hibmc_framebuffer *hibmc_fb;
+	struct hibmc_bo *bo;
+
+	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)
+		return;
+
+	hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
+	if (ret) {
+		ttm_bo_unreserve(&bo->bo);
+		return;
+	}
+
+	ttm_bo_unreserve(&bo->bo);
+
+	writel(gpu_addr, hidev->mmio + HIBMC_CRT_FB_ADDRESS);
+
+	reg = state->fb->width * (state->fb->bits_per_pixel >> 3);
+	/* 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_CRT_FB_WIDTH_WIDTH(reg) & HIBMC_CRT_FB_WIDTH_WIDTH_MASK) |
+	       (HIBMC_CRT_FB_WIDTH_OFFS(line_l) & HIBMC_CRT_FB_WIDTH_OFFS_MASK),
+	       hidev->mmio + HIBMC_CRT_FB_WIDTH);
+
+	/* SET PIXEL FORMAT */
+	reg = readl(hidev->mmio + HIBMC_CRT_DISP_CTL);
+	reg = reg & ~HIBMC_CRT_DISP_CTL_FORMAT_MASK;
+	reg = reg | (HIBMC_CRT_DISP_CTL_FORMAT(state->fb->bits_per_pixel >> 4) &
+		     HIBMC_CRT_DISP_CTL_FORMAT_MASK);
+	writel(reg, hidev->mmio + HIBMC_CRT_DISP_CTL);
+}
+
+static void hibmc_plane_atomic_disable(struct drm_plane *plane,
+				       struct drm_plane_state *old_state)
+{
+}
+
+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,
+	.atomic_disable = hibmc_plane_atomic_disable,
+};
+
+int hibmc_plane_init(struct hibmc_drm_device *hidev)
+{
+	struct drm_device *dev = hidev->dev;
+	struct drm_plane *plane = &hidev->plane;
+	int ret = 0;
+
+	/*
+	 * 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("fail to init plane!!!\n");
+		return ret;
+	}
+
+	drm_plane_helper_add(plane, &hibmc_plane_helper_funcs);
+	return 0;
+}
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
new file mode 100644
index 0000000..4ce0d7b
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
@@ -0,0 +1,29 @@
+/* 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_DE_H
+#define HIBMC_DRM_DE_H
+
+struct panel_pll {
+	unsigned long M;
+	unsigned long N;
+	unsigned long OD;
+	unsigned long POD;
+};
+
+#endif
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index 5ac7a7e..7d96583 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -18,6 +18,7 @@
 
 #include <linux/module.h>
 #include <linux/console.h>
+#include <drm/drm_crtc_helper.h>
 
 #include "hibmc_drm_drv.h"
 #include "hibmc_drm_regs.h"
@@ -47,8 +48,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",
@@ -70,6 +71,7 @@ static int hibmc_pm_suspend(struct device *dev)
 	struct drm_device *drm_dev = pci_get_drvdata(pdev);
 	struct hibmc_drm_device *hidev = drm_dev->dev_private;
 
+	drm_kms_helper_poll_disable(drm_dev);
 	drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 1);
 
 	return 0;
@@ -81,7 +83,9 @@ static int hibmc_pm_resume(struct device *dev)
 	struct drm_device *drm_dev = pci_get_drvdata(pdev);
 	struct hibmc_drm_device *hidev = drm_dev->dev_private;
 
+	drm_helper_resume_force_mode(drm_dev);
 	drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 0);
+	drm_kms_helper_poll_enable(drm_dev);
 
 	return 0;
 }
@@ -91,6 +95,41 @@ static int hibmc_pm_resume(struct device *dev)
 				hibmc_pm_resume)
 };
 
+static int hibmc_kms_init(struct hibmc_drm_device *hidev)
+{
+	int ret;
+
+	drm_mode_config_init(hidev->dev);
+	hidev->mode_config_initialized = true;
+
+	hidev->dev->mode_config.min_width = 0;
+	hidev->dev->mode_config.min_height = 0;
+	hidev->dev->mode_config.max_width = 1920;
+	hidev->dev->mode_config.max_height = 1440;
+
+	hidev->dev->mode_config.fb_base = hidev->fb_base;
+	hidev->dev->mode_config.preferred_depth = 24;
+	hidev->dev->mode_config.prefer_shadow = 0;
+
+	hidev->dev->mode_config.funcs = (void *)&hibmc_mode_funcs;
+
+	ret = hibmc_plane_init(hidev);
+	if (ret) {
+		DRM_ERROR("fail to init plane!!!\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static void hibmc_kms_fini(struct hibmc_drm_device *hidev)
+{
+	if (hidev->mode_config_initialized) {
+		drm_mode_config_cleanup(hidev->dev);
+		hidev->mode_config_initialized = false;
+	}
+}
+
 static int hibmc_hw_config(struct hibmc_drm_device *hidev)
 {
 	unsigned int reg;
@@ -183,6 +222,7 @@ static int hibmc_unload(struct drm_device *dev)
 	struct hibmc_drm_device *hidev = dev->dev_private;
 
 	hibmc_fbdev_fini(hidev);
+	hibmc_kms_fini(hidev);
 	hibmc_mm_fini(hidev);
 	hibmc_hw_fini(hidev);
 	dev->dev_private = NULL;
@@ -208,6 +248,13 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
 	if (ret)
 		goto err;
 
+	ret = hibmc_kms_init(hidev);
+	if (ret)
+		goto err;
+
+	/* reset all the states of crtc/plane/encoder/connector */
+	drm_mode_config_reset(dev);
+
 	ret = hibmc_fbdev_init(hidev);
 	if (ret)
 		goto err;
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
index a40e9a7..49e39d2 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -45,6 +45,8 @@ struct hibmc_drm_device {
 
 	/* drm */
 	struct drm_device  *dev;
+	struct drm_plane plane;
+	bool mode_config_initialized;
 
 	/* ttm */
 	struct {
@@ -82,6 +84,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
 
 #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
 
+int hibmc_plane_init(struct hibmc_drm_device *hidev);
 int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
 void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
 
@@ -102,4 +105,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 9822f62..beb4d76 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
@@ -554,3 +554,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] 64+ messages in thread

* [PATCH v6 4/9] drm/hisilicon/hibmc: Add plane for DE
@ 2016-10-28  7:27   ` Rongrong Zou
  0 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-10-28  7:27 UTC (permalink / raw)
  To: airlied, daniel, dri-devel, emil.l.velikov, tomeu.vizoso,
	benjamin.gaignard, robh, daniel, architt, corbet,
	catalin.marinas, will.deacon, mark.rutland, xinliang.liu
  Cc: linuxarm, kong.kongxinwei, james.xiong, shenhui, guohanjun,
	lijianhua, linux-arm-kernel

Add plane funcs and helper funcs for DE.

Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
---
 drivers/gpu/drm/hisilicon/hibmc/Kconfig         |   1 +
 drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c  | 170 ++++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h  |  29 ++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  51 ++++++-
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |   5 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     |   6 +
 7 files changed, 261 insertions(+), 3 deletions(-)
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h

diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
index bcb8c18..380622a 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/Kconfig
+++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
@@ -1,6 +1,7 @@
 config DRM_HISI_HIBMC
 	tristate "DRM Support for Hisilicon Hibmc"
 	depends on DRM && PCI
+	select DRM_KMS_HELPER
 	select DRM_TTM
 
 	help
diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
index 810a37e..72e107e 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
+++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
@@ -1,5 +1,5 @@
 ccflags-y := -Iinclude/drm
-hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
+hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
 
 obj-$(CONFIG_DRM_HISI_HIBMC)	+=hibmc-drm.o
 #obj-y	+= 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..9c1a68c
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
@@ -0,0 +1,170 @@
+/* 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"
+#include "hibmc_drm_power.h"
+
+/* ---------------------------------------------------------------------- */
+
+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_x = state->src_x >> 16;
+	u32 src_y = state->src_y >> 16;
+	u32 src_w = state->src_w >> 16;
+	u32 src_h = state->src_h >> 16;
+	int crtc_x = state->crtc_x;
+	int crtc_y = state->crtc_y;
+	u32 crtc_w = state->crtc_w;
+	u32 crtc_h = state->crtc_h;
+
+	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 != crtc_w || src_h != crtc_h) {
+		DRM_ERROR("Scale not support!!!\n");
+		return -EINVAL;
+	}
+
+	if (src_x + src_w > fb->width ||
+	    src_y + src_h > fb->height)
+		return -EINVAL;
+
+	if (crtc_x < 0 || crtc_y < 0)
+		return -EINVAL;
+
+	if (crtc_x + crtc_w > crtc_state->adjusted_mode.hdisplay ||
+	    crtc_y + crtc_h > crtc_state->adjusted_mode.vdisplay)
+		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_device *hidev =
+		(struct hibmc_drm_device *)plane->dev->dev_private;
+
+	struct hibmc_framebuffer *hibmc_fb;
+	struct hibmc_bo *bo;
+
+	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)
+		return;
+
+	hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
+	if (ret) {
+		ttm_bo_unreserve(&bo->bo);
+		return;
+	}
+
+	ttm_bo_unreserve(&bo->bo);
+
+	writel(gpu_addr, hidev->mmio + HIBMC_CRT_FB_ADDRESS);
+
+	reg = state->fb->width * (state->fb->bits_per_pixel >> 3);
+	/* 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_CRT_FB_WIDTH_WIDTH(reg) & HIBMC_CRT_FB_WIDTH_WIDTH_MASK) |
+	       (HIBMC_CRT_FB_WIDTH_OFFS(line_l) & HIBMC_CRT_FB_WIDTH_OFFS_MASK),
+	       hidev->mmio + HIBMC_CRT_FB_WIDTH);
+
+	/* SET PIXEL FORMAT */
+	reg = readl(hidev->mmio + HIBMC_CRT_DISP_CTL);
+	reg = reg & ~HIBMC_CRT_DISP_CTL_FORMAT_MASK;
+	reg = reg | (HIBMC_CRT_DISP_CTL_FORMAT(state->fb->bits_per_pixel >> 4) &
+		     HIBMC_CRT_DISP_CTL_FORMAT_MASK);
+	writel(reg, hidev->mmio + HIBMC_CRT_DISP_CTL);
+}
+
+static void hibmc_plane_atomic_disable(struct drm_plane *plane,
+				       struct drm_plane_state *old_state)
+{
+}
+
+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,
+	.atomic_disable = hibmc_plane_atomic_disable,
+};
+
+int hibmc_plane_init(struct hibmc_drm_device *hidev)
+{
+	struct drm_device *dev = hidev->dev;
+	struct drm_plane *plane = &hidev->plane;
+	int ret = 0;
+
+	/*
+	 * 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("fail to init plane!!!\n");
+		return ret;
+	}
+
+	drm_plane_helper_add(plane, &hibmc_plane_helper_funcs);
+	return 0;
+}
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
new file mode 100644
index 0000000..4ce0d7b
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
@@ -0,0 +1,29 @@
+/* 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_DE_H
+#define HIBMC_DRM_DE_H
+
+struct panel_pll {
+	unsigned long M;
+	unsigned long N;
+	unsigned long OD;
+	unsigned long POD;
+};
+
+#endif
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index 5ac7a7e..7d96583 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -18,6 +18,7 @@
 
 #include <linux/module.h>
 #include <linux/console.h>
+#include <drm/drm_crtc_helper.h>
 
 #include "hibmc_drm_drv.h"
 #include "hibmc_drm_regs.h"
@@ -47,8 +48,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",
@@ -70,6 +71,7 @@ static int hibmc_pm_suspend(struct device *dev)
 	struct drm_device *drm_dev = pci_get_drvdata(pdev);
 	struct hibmc_drm_device *hidev = drm_dev->dev_private;
 
+	drm_kms_helper_poll_disable(drm_dev);
 	drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 1);
 
 	return 0;
@@ -81,7 +83,9 @@ static int hibmc_pm_resume(struct device *dev)
 	struct drm_device *drm_dev = pci_get_drvdata(pdev);
 	struct hibmc_drm_device *hidev = drm_dev->dev_private;
 
+	drm_helper_resume_force_mode(drm_dev);
 	drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 0);
+	drm_kms_helper_poll_enable(drm_dev);
 
 	return 0;
 }
@@ -91,6 +95,41 @@ static int hibmc_pm_resume(struct device *dev)
 				hibmc_pm_resume)
 };
 
+static int hibmc_kms_init(struct hibmc_drm_device *hidev)
+{
+	int ret;
+
+	drm_mode_config_init(hidev->dev);
+	hidev->mode_config_initialized = true;
+
+	hidev->dev->mode_config.min_width = 0;
+	hidev->dev->mode_config.min_height = 0;
+	hidev->dev->mode_config.max_width = 1920;
+	hidev->dev->mode_config.max_height = 1440;
+
+	hidev->dev->mode_config.fb_base = hidev->fb_base;
+	hidev->dev->mode_config.preferred_depth = 24;
+	hidev->dev->mode_config.prefer_shadow = 0;
+
+	hidev->dev->mode_config.funcs = (void *)&hibmc_mode_funcs;
+
+	ret = hibmc_plane_init(hidev);
+	if (ret) {
+		DRM_ERROR("fail to init plane!!!\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static void hibmc_kms_fini(struct hibmc_drm_device *hidev)
+{
+	if (hidev->mode_config_initialized) {
+		drm_mode_config_cleanup(hidev->dev);
+		hidev->mode_config_initialized = false;
+	}
+}
+
 static int hibmc_hw_config(struct hibmc_drm_device *hidev)
 {
 	unsigned int reg;
@@ -183,6 +222,7 @@ static int hibmc_unload(struct drm_device *dev)
 	struct hibmc_drm_device *hidev = dev->dev_private;
 
 	hibmc_fbdev_fini(hidev);
+	hibmc_kms_fini(hidev);
 	hibmc_mm_fini(hidev);
 	hibmc_hw_fini(hidev);
 	dev->dev_private = NULL;
@@ -208,6 +248,13 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
 	if (ret)
 		goto err;
 
+	ret = hibmc_kms_init(hidev);
+	if (ret)
+		goto err;
+
+	/* reset all the states of crtc/plane/encoder/connector */
+	drm_mode_config_reset(dev);
+
 	ret = hibmc_fbdev_init(hidev);
 	if (ret)
 		goto err;
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
index a40e9a7..49e39d2 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -45,6 +45,8 @@ struct hibmc_drm_device {
 
 	/* drm */
 	struct drm_device  *dev;
+	struct drm_plane plane;
+	bool mode_config_initialized;
 
 	/* ttm */
 	struct {
@@ -82,6 +84,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
 
 #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
 
+int hibmc_plane_init(struct hibmc_drm_device *hidev);
 int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
 void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
 
@@ -102,4 +105,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 9822f62..beb4d76 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
@@ -554,3 +554,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] 64+ messages in thread

* [PATCH v6 5/9] drm/hisilicon/hibmc: Add crtc for DE
  2016-10-28  7:27 ` Rongrong Zou
@ 2016-10-28  7:27   ` Rongrong Zou
  -1 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-10-28  7:27 UTC (permalink / raw)
  To: linux-arm-kernel

Add crtc funcs and helper funcs for DE.

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

diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
index 9c1a68c..9b5d0d0 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
@@ -23,6 +23,7 @@
 
 #include "hibmc_drm_drv.h"
 #include "hibmc_drm_regs.h"
+#include "hibmc_drm_de.h"
 #include "hibmc_drm_power.h"
 
 /* ---------------------------------------------------------------------- */
@@ -168,3 +169,320 @@ int hibmc_plane_init(struct hibmc_drm_device *hidev)
 	drm_plane_helper_add(plane, &hibmc_plane_helper_funcs);
 	return 0;
 }
+
+static void hibmc_crtc_enable(struct drm_crtc *crtc)
+{
+	unsigned int reg;
+	/* power mode 0 is default. */
+	struct hibmc_drm_device *hidev = crtc->dev->dev_private;
+
+	hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_MODE0);
+
+	/* Enable display power gate & LOCALMEM power gate*/
+	reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
+	reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
+	reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
+	reg |= HIBMC_CURR_GATE_LOCALMEM(ON);
+	reg |= HIBMC_CURR_GATE_DISPLAY(ON);
+	hibmc_set_current_gate(hidev, reg);
+	drm_crtc_vblank_on(crtc);
+}
+
+static void hibmc_crtc_disable(struct drm_crtc *crtc)
+{
+	unsigned int reg;
+	struct hibmc_drm_device *hidev = crtc->dev->dev_private;
+
+	drm_crtc_vblank_off(crtc);
+
+	hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_SLEEP);
+
+	/* Enable display power gate & LOCALMEM power gate*/
+	reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
+	reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
+	reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
+	reg |= HIBMC_CURR_GATE_LOCALMEM(OFF);
+	reg |= HIBMC_CURR_GATE_DISPLAY(OFF);
+	hibmc_set_current_gate(hidev, reg);
+}
+
+static int hibmc_crtc_atomic_check(struct drm_crtc *crtc,
+				   struct drm_crtc_state *state)
+{
+	return 0;
+}
+
+static unsigned int format_pll_reg(void)
+{
+	unsigned int pllreg = 0;
+	struct 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_PLL_CTRL_BYPASS(OFF) & HIBMC_PLL_CTRL_BYPASS_MASK;
+	pllreg |= HIBMC_PLL_CTRL_POWER(ON) & HIBMC_PLL_CTRL_POWER_MASK;
+	pllreg |= HIBMC_PLL_CTRL_INPUT(OSC) & HIBMC_PLL_CTRL_INPUT_MASK;
+	pllreg |= HIBMC_PLL_CTRL_POD(pll.POD) & HIBMC_PLL_CTRL_POD_MASK;
+	pllreg |= HIBMC_PLL_CTRL_OD(pll.OD) & HIBMC_PLL_CTRL_OD_MASK;
+	pllreg |= HIBMC_PLL_CTRL_N(pll.N) & HIBMC_PLL_CTRL_N_MASK;
+	pllreg |= HIBMC_PLL_CTRL_M(pll.M) & HIBMC_PLL_CTRL_M_MASK;
+
+	return pllreg;
+}
+
+static void set_vclock_hisilicon(struct drm_device *dev, unsigned long pll)
+{
+	unsigned long tmp0, tmp1;
+	struct hibmc_drm_device *hidev = dev->dev_private;
+
+	/* 1. outer_bypass_n=0 */
+	tmp0 = readl(hidev->mmio + CRT_PLL1_HS);
+	tmp0 &= 0xBFFFFFFF;
+	writel(tmp0, hidev->mmio + CRT_PLL1_HS);
+
+	/* 2. pll_pd=1?inter_bypass=1 */
+	writel(0x21000000, hidev->mmio + CRT_PLL1_HS);
+
+	/* 3. config pll */
+	writel(pll, hidev->mmio + CRT_PLL1_HS);
+
+	/* 4. delay  */
+	mdelay(1);
+
+	/* 5. pll_pd =0 */
+	tmp1 = pll & ~0x01000000;
+	writel(tmp1, hidev->mmio + CRT_PLL1_HS);
+
+	/* 6. delay  */
+	mdelay(1);
+
+	/* 7. inter_bypass=0 */
+	tmp1 &= ~0x20000000;
+	writel(tmp1, hidev->mmio + CRT_PLL1_HS);
+
+	/* 8. delay  */
+	mdelay(1);
+
+	/* 9. outer_bypass_n=1 */
+	tmp1 |= 0x40000000;
+	writel(tmp1, hidev->mmio + CRT_PLL1_HS);
+}
+
+/* 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;
+	unsigned long pll1; /* bit[31:0] of PLL */
+	unsigned long pll2; /* bit[63:32] of PLL */
+	struct hibmc_drm_device *hidev = dev->dev_private;
+
+	x = mode->hdisplay;
+	y = mode->vdisplay;
+
+	/* Hisilicon has to set up a new register for PLL control
+	 *(CRT_PLL1_HS & CRT_PLL2_HS).
+	 */
+	if (x == 800 && y == 600) {
+		pll1 = CRT_PLL1_HS_40MHZ;
+		pll2 = CRT_PLL2_HS_40MHZ;
+	} else if (x == 1024 && y == 768) {
+		pll1 = CRT_PLL1_HS_65MHZ;
+		pll2 = CRT_PLL2_HS_65MHZ;
+	} else if (x == 1152 && y == 864) {
+		pll1 = CRT_PLL1_HS_80MHZ_1152;
+		pll2 = CRT_PLL2_HS_80MHZ;
+	} else if (x == 1280 && y == 768) {
+		pll1 = CRT_PLL1_HS_80MHZ;
+		pll2 = CRT_PLL2_HS_80MHZ;
+	} else if (x == 1280 && y == 720) {
+		pll1 = CRT_PLL1_HS_74MHZ;
+		pll2 = CRT_PLL2_HS_74MHZ;
+	} else if (x == 1280 && y == 960) {
+		pll1 = CRT_PLL1_HS_108MHZ;
+		pll2 = CRT_PLL2_HS_108MHZ;
+	} else if (x == 1280 && y == 1024) {
+		pll1 = CRT_PLL1_HS_108MHZ;
+		pll2 = CRT_PLL2_HS_108MHZ;
+	} else if (x == 1600 && y == 1200) {
+		pll1 = CRT_PLL1_HS_162MHZ;
+		pll2 = CRT_PLL2_HS_162MHZ;
+	} else if (x == 1920 && y == 1080) {
+		pll1 = CRT_PLL1_HS_148MHZ;
+		pll2 = CRT_PLL2_HS_148MHZ;
+	} else if (x == 1920 && y == 1200) {
+		pll1 = CRT_PLL1_HS_193MHZ;
+		pll2 = CRT_PLL2_HS_193MHZ;
+	} else /* default to VGA clock */ {
+		pll1 = CRT_PLL1_HS_25MHZ;
+		pll2 = CRT_PLL2_HS_25MHZ;
+	}
+
+	writel(pll2, hidev->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_CRT_AUTO_CENTERING_TL_TOP(0) &
+		HIBMC_CRT_AUTO_CENTERING_TL_TOP_MSK) |
+	       (HIBMC_CRT_AUTO_CENTERING_TL_LEFT(0) &
+		HIBMC_CRT_AUTO_CENTERING_TL_LEFT_MSK),
+	       hidev->mmio + HIBMC_CRT_AUTO_CENTERING_TL);
+
+	writel((HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM(y - 1) &
+		HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM_MASK) |
+	       (HIBMC_CRT_AUTO_CENTERING_BR_RIGHT(x - 1) &
+		HIBMC_CRT_AUTO_CENTERING_BR_RIGHT_MASK),
+		hidev->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(CRTSELECT_CRT);
+
+	/*ctrl = FIELD_SET(ctrl, HIBMC_CRT_DISP_CTL, CRTSELECT, CRT);*/
+
+	/* Set bit 14 of display controller */
+	/*ctrl &= FIELD_CLEAR(HIBMC_CRT_DISP_CTL, CLOCK_PHASE);*/
+
+	/* clock_phase_polarity is 0 */
+	ctrl |= HIBMC_CRT_DISP_CTL_CLOCK_PHASE(PHASE_ACTIVE_HIGH);
+	/*ctrl = FIELD_SET(ctrl, HIBMC_CRT_DISP_CTL,*/
+	/*CLOCK_PHASE, ACTIVE_HIGH);*/
+
+	writel(ctrl, hidev->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_device *hidev = dev->dev_private;
+
+	writel(format_pll_reg(), hidev->mmio + HIBMC_CRT_PLL_CTRL);
+	writel((HIBMC_CRT_HORZ_TOTAL_TOTAL(mode->htotal - 1) &
+		HIBMC_CRT_HORZ_TOTAL_TOTAL_MASK) |
+		(HIBMC_CRT_HORZ_TOTAL_DISPLAY_END(mode->hdisplay - 1) &
+		HIBMC_CRT_HORZ_TOTAL_DISPLAY_END_MASK),
+		hidev->mmio + HIBMC_CRT_HORZ_TOTAL);
+
+	writel((HIBMC_CRT_HORZ_SYNC_WIDTH(mode->hsync_end - mode->hsync_start)
+		& HIBMC_CRT_HORZ_SYNC_WIDTH_MASK) |
+		(HIBMC_CRT_HORZ_SYNC_START(mode->hsync_start - 1)
+		& HIBMC_CRT_HORZ_SYNC_START_MASK),
+		hidev->mmio + HIBMC_CRT_HORZ_SYNC);
+
+	writel((HIBMC_CRT_VERT_TOTAL_TOTAL(mode->vtotal - 1) &
+		HIBMC_CRT_VERT_TOTAL_TOTAL_MASK) |
+		(HIBMC_CRT_VERT_TOTAL_DISPLAY_END(mode->vdisplay - 1) &
+		HIBMC_CRT_VERT_TOTAL_DISPLAY_END_MASK),
+		hidev->mmio + HIBMC_CRT_VERT_TOTAL);
+
+	writel((HIBMC_CRT_VERT_SYNC_HEIGHT(mode->vsync_end - mode->vsync_start)
+		& HIBMC_CRT_VERT_SYNC_HEIGHT_MASK) |
+	       (HIBMC_CRT_VERT_SYNC_START(mode->vsync_start - 1) &
+		HIBMC_CRT_VERT_SYNC_START_MASK),
+		hidev->mmio + HIBMC_CRT_VERT_SYNC);
+
+	val = HIBMC_CRT_DISP_CTL_VSYNC_PHASE(0) &
+	      HIBMC_CRT_DISP_CTL_VSYNC_PHASE_MASK;
+	val |= HIBMC_CRT_DISP_CTL_HSYNC_PHASE(0) &
+	       HIBMC_CRT_DISP_CTL_HSYNC_PHASE_MASK;
+	val |= HIBMC_CRT_DISP_CTL_TIMING(ENABLE);
+	val |= HIBMC_CRT_DISP_CTL_PLANE(ENABLE);
+
+	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_device *hidev = dev->dev_private;
+
+	hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_MODE0);
+
+	/* Enable display power gate & LOCALMEM power gate*/
+	reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
+	reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
+	reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
+	reg |= HIBMC_CURR_GATE_DISPLAY(ON);
+	reg |= HIBMC_CURR_GATE_LOCALMEM(ON);
+	hibmc_set_current_gate(hidev, 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);
+}
+
+/* These provide the minimum set of functions required to handle a CRTC */
+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_check	= hibmc_crtc_atomic_check,
+	.atomic_begin	= hibmc_crtc_atomic_begin,
+	.atomic_flush	= hibmc_crtc_atomic_flush,
+};
+
+int hibmc_crtc_init(struct hibmc_drm_device *hidev)
+{
+	struct drm_device *dev = hidev->dev;
+	struct drm_crtc *crtc = &hidev->crtc;
+	struct drm_plane *plane = &hidev->plane;
+	int ret;
+
+	ret = drm_crtc_init_with_planes(dev, crtc, plane,
+					NULL, &hibmc_crtc_funcs, NULL);
+	if (ret) {
+		DRM_ERROR("failed to init crtc.\n");
+		return ret;
+	}
+
+	drm_mode_crtc_set_gamma_size(crtc, 256);
+	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 7d96583..303cd36 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -119,6 +119,12 @@ static int hibmc_kms_init(struct hibmc_drm_device *hidev)
 		return ret;
 	}
 
+	ret = hibmc_crtc_init(hidev);
+	if (ret) {
+		DRM_ERROR("failed to init crtc.\n");
+		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 49e39d2..5731ec2 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -46,6 +46,7 @@ struct hibmc_drm_device {
 	/* drm */
 	struct drm_device  *dev;
 	struct drm_plane plane;
+	struct drm_crtc crtc;
 	bool mode_config_initialized;
 
 	/* ttm */
@@ -85,6 +86,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
 #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
 
 int hibmc_plane_init(struct hibmc_drm_device *hidev);
+int hibmc_crtc_init(struct hibmc_drm_device *hidev);
 int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
 void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
 
-- 
1.9.1

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

* [PATCH v6 5/9] drm/hisilicon/hibmc: Add crtc for DE
@ 2016-10-28  7:27   ` Rongrong Zou
  0 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-10-28  7:27 UTC (permalink / raw)
  To: airlied, daniel, dri-devel, emil.l.velikov, tomeu.vizoso,
	benjamin.gaignard, robh, daniel, architt, corbet,
	catalin.marinas, will.deacon, mark.rutland, xinliang.liu
  Cc: linuxarm, kong.kongxinwei, james.xiong, shenhui, guohanjun,
	lijianhua, linux-arm-kernel

Add crtc funcs and helper funcs for DE.

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

diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
index 9c1a68c..9b5d0d0 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
@@ -23,6 +23,7 @@
 
 #include "hibmc_drm_drv.h"
 #include "hibmc_drm_regs.h"
+#include "hibmc_drm_de.h"
 #include "hibmc_drm_power.h"
 
 /* ---------------------------------------------------------------------- */
@@ -168,3 +169,320 @@ int hibmc_plane_init(struct hibmc_drm_device *hidev)
 	drm_plane_helper_add(plane, &hibmc_plane_helper_funcs);
 	return 0;
 }
+
+static void hibmc_crtc_enable(struct drm_crtc *crtc)
+{
+	unsigned int reg;
+	/* power mode 0 is default. */
+	struct hibmc_drm_device *hidev = crtc->dev->dev_private;
+
+	hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_MODE0);
+
+	/* Enable display power gate & LOCALMEM power gate*/
+	reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
+	reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
+	reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
+	reg |= HIBMC_CURR_GATE_LOCALMEM(ON);
+	reg |= HIBMC_CURR_GATE_DISPLAY(ON);
+	hibmc_set_current_gate(hidev, reg);
+	drm_crtc_vblank_on(crtc);
+}
+
+static void hibmc_crtc_disable(struct drm_crtc *crtc)
+{
+	unsigned int reg;
+	struct hibmc_drm_device *hidev = crtc->dev->dev_private;
+
+	drm_crtc_vblank_off(crtc);
+
+	hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_SLEEP);
+
+	/* Enable display power gate & LOCALMEM power gate*/
+	reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
+	reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
+	reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
+	reg |= HIBMC_CURR_GATE_LOCALMEM(OFF);
+	reg |= HIBMC_CURR_GATE_DISPLAY(OFF);
+	hibmc_set_current_gate(hidev, reg);
+}
+
+static int hibmc_crtc_atomic_check(struct drm_crtc *crtc,
+				   struct drm_crtc_state *state)
+{
+	return 0;
+}
+
+static unsigned int format_pll_reg(void)
+{
+	unsigned int pllreg = 0;
+	struct 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_PLL_CTRL_BYPASS(OFF) & HIBMC_PLL_CTRL_BYPASS_MASK;
+	pllreg |= HIBMC_PLL_CTRL_POWER(ON) & HIBMC_PLL_CTRL_POWER_MASK;
+	pllreg |= HIBMC_PLL_CTRL_INPUT(OSC) & HIBMC_PLL_CTRL_INPUT_MASK;
+	pllreg |= HIBMC_PLL_CTRL_POD(pll.POD) & HIBMC_PLL_CTRL_POD_MASK;
+	pllreg |= HIBMC_PLL_CTRL_OD(pll.OD) & HIBMC_PLL_CTRL_OD_MASK;
+	pllreg |= HIBMC_PLL_CTRL_N(pll.N) & HIBMC_PLL_CTRL_N_MASK;
+	pllreg |= HIBMC_PLL_CTRL_M(pll.M) & HIBMC_PLL_CTRL_M_MASK;
+
+	return pllreg;
+}
+
+static void set_vclock_hisilicon(struct drm_device *dev, unsigned long pll)
+{
+	unsigned long tmp0, tmp1;
+	struct hibmc_drm_device *hidev = dev->dev_private;
+
+	/* 1. outer_bypass_n=0 */
+	tmp0 = readl(hidev->mmio + CRT_PLL1_HS);
+	tmp0 &= 0xBFFFFFFF;
+	writel(tmp0, hidev->mmio + CRT_PLL1_HS);
+
+	/* 2. pll_pd=1?inter_bypass=1 */
+	writel(0x21000000, hidev->mmio + CRT_PLL1_HS);
+
+	/* 3. config pll */
+	writel(pll, hidev->mmio + CRT_PLL1_HS);
+
+	/* 4. delay  */
+	mdelay(1);
+
+	/* 5. pll_pd =0 */
+	tmp1 = pll & ~0x01000000;
+	writel(tmp1, hidev->mmio + CRT_PLL1_HS);
+
+	/* 6. delay  */
+	mdelay(1);
+
+	/* 7. inter_bypass=0 */
+	tmp1 &= ~0x20000000;
+	writel(tmp1, hidev->mmio + CRT_PLL1_HS);
+
+	/* 8. delay  */
+	mdelay(1);
+
+	/* 9. outer_bypass_n=1 */
+	tmp1 |= 0x40000000;
+	writel(tmp1, hidev->mmio + CRT_PLL1_HS);
+}
+
+/* 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;
+	unsigned long pll1; /* bit[31:0] of PLL */
+	unsigned long pll2; /* bit[63:32] of PLL */
+	struct hibmc_drm_device *hidev = dev->dev_private;
+
+	x = mode->hdisplay;
+	y = mode->vdisplay;
+
+	/* Hisilicon has to set up a new register for PLL control
+	 *(CRT_PLL1_HS & CRT_PLL2_HS).
+	 */
+	if (x == 800 && y == 600) {
+		pll1 = CRT_PLL1_HS_40MHZ;
+		pll2 = CRT_PLL2_HS_40MHZ;
+	} else if (x == 1024 && y == 768) {
+		pll1 = CRT_PLL1_HS_65MHZ;
+		pll2 = CRT_PLL2_HS_65MHZ;
+	} else if (x == 1152 && y == 864) {
+		pll1 = CRT_PLL1_HS_80MHZ_1152;
+		pll2 = CRT_PLL2_HS_80MHZ;
+	} else if (x == 1280 && y == 768) {
+		pll1 = CRT_PLL1_HS_80MHZ;
+		pll2 = CRT_PLL2_HS_80MHZ;
+	} else if (x == 1280 && y == 720) {
+		pll1 = CRT_PLL1_HS_74MHZ;
+		pll2 = CRT_PLL2_HS_74MHZ;
+	} else if (x == 1280 && y == 960) {
+		pll1 = CRT_PLL1_HS_108MHZ;
+		pll2 = CRT_PLL2_HS_108MHZ;
+	} else if (x == 1280 && y == 1024) {
+		pll1 = CRT_PLL1_HS_108MHZ;
+		pll2 = CRT_PLL2_HS_108MHZ;
+	} else if (x == 1600 && y == 1200) {
+		pll1 = CRT_PLL1_HS_162MHZ;
+		pll2 = CRT_PLL2_HS_162MHZ;
+	} else if (x == 1920 && y == 1080) {
+		pll1 = CRT_PLL1_HS_148MHZ;
+		pll2 = CRT_PLL2_HS_148MHZ;
+	} else if (x == 1920 && y == 1200) {
+		pll1 = CRT_PLL1_HS_193MHZ;
+		pll2 = CRT_PLL2_HS_193MHZ;
+	} else /* default to VGA clock */ {
+		pll1 = CRT_PLL1_HS_25MHZ;
+		pll2 = CRT_PLL2_HS_25MHZ;
+	}
+
+	writel(pll2, hidev->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_CRT_AUTO_CENTERING_TL_TOP(0) &
+		HIBMC_CRT_AUTO_CENTERING_TL_TOP_MSK) |
+	       (HIBMC_CRT_AUTO_CENTERING_TL_LEFT(0) &
+		HIBMC_CRT_AUTO_CENTERING_TL_LEFT_MSK),
+	       hidev->mmio + HIBMC_CRT_AUTO_CENTERING_TL);
+
+	writel((HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM(y - 1) &
+		HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM_MASK) |
+	       (HIBMC_CRT_AUTO_CENTERING_BR_RIGHT(x - 1) &
+		HIBMC_CRT_AUTO_CENTERING_BR_RIGHT_MASK),
+		hidev->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(CRTSELECT_CRT);
+
+	/*ctrl = FIELD_SET(ctrl, HIBMC_CRT_DISP_CTL, CRTSELECT, CRT);*/
+
+	/* Set bit 14 of display controller */
+	/*ctrl &= FIELD_CLEAR(HIBMC_CRT_DISP_CTL, CLOCK_PHASE);*/
+
+	/* clock_phase_polarity is 0 */
+	ctrl |= HIBMC_CRT_DISP_CTL_CLOCK_PHASE(PHASE_ACTIVE_HIGH);
+	/*ctrl = FIELD_SET(ctrl, HIBMC_CRT_DISP_CTL,*/
+	/*CLOCK_PHASE, ACTIVE_HIGH);*/
+
+	writel(ctrl, hidev->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_device *hidev = dev->dev_private;
+
+	writel(format_pll_reg(), hidev->mmio + HIBMC_CRT_PLL_CTRL);
+	writel((HIBMC_CRT_HORZ_TOTAL_TOTAL(mode->htotal - 1) &
+		HIBMC_CRT_HORZ_TOTAL_TOTAL_MASK) |
+		(HIBMC_CRT_HORZ_TOTAL_DISPLAY_END(mode->hdisplay - 1) &
+		HIBMC_CRT_HORZ_TOTAL_DISPLAY_END_MASK),
+		hidev->mmio + HIBMC_CRT_HORZ_TOTAL);
+
+	writel((HIBMC_CRT_HORZ_SYNC_WIDTH(mode->hsync_end - mode->hsync_start)
+		& HIBMC_CRT_HORZ_SYNC_WIDTH_MASK) |
+		(HIBMC_CRT_HORZ_SYNC_START(mode->hsync_start - 1)
+		& HIBMC_CRT_HORZ_SYNC_START_MASK),
+		hidev->mmio + HIBMC_CRT_HORZ_SYNC);
+
+	writel((HIBMC_CRT_VERT_TOTAL_TOTAL(mode->vtotal - 1) &
+		HIBMC_CRT_VERT_TOTAL_TOTAL_MASK) |
+		(HIBMC_CRT_VERT_TOTAL_DISPLAY_END(mode->vdisplay - 1) &
+		HIBMC_CRT_VERT_TOTAL_DISPLAY_END_MASK),
+		hidev->mmio + HIBMC_CRT_VERT_TOTAL);
+
+	writel((HIBMC_CRT_VERT_SYNC_HEIGHT(mode->vsync_end - mode->vsync_start)
+		& HIBMC_CRT_VERT_SYNC_HEIGHT_MASK) |
+	       (HIBMC_CRT_VERT_SYNC_START(mode->vsync_start - 1) &
+		HIBMC_CRT_VERT_SYNC_START_MASK),
+		hidev->mmio + HIBMC_CRT_VERT_SYNC);
+
+	val = HIBMC_CRT_DISP_CTL_VSYNC_PHASE(0) &
+	      HIBMC_CRT_DISP_CTL_VSYNC_PHASE_MASK;
+	val |= HIBMC_CRT_DISP_CTL_HSYNC_PHASE(0) &
+	       HIBMC_CRT_DISP_CTL_HSYNC_PHASE_MASK;
+	val |= HIBMC_CRT_DISP_CTL_TIMING(ENABLE);
+	val |= HIBMC_CRT_DISP_CTL_PLANE(ENABLE);
+
+	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_device *hidev = dev->dev_private;
+
+	hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_MODE0);
+
+	/* Enable display power gate & LOCALMEM power gate*/
+	reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
+	reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
+	reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
+	reg |= HIBMC_CURR_GATE_DISPLAY(ON);
+	reg |= HIBMC_CURR_GATE_LOCALMEM(ON);
+	hibmc_set_current_gate(hidev, 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);
+}
+
+/* These provide the minimum set of functions required to handle a CRTC */
+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_check	= hibmc_crtc_atomic_check,
+	.atomic_begin	= hibmc_crtc_atomic_begin,
+	.atomic_flush	= hibmc_crtc_atomic_flush,
+};
+
+int hibmc_crtc_init(struct hibmc_drm_device *hidev)
+{
+	struct drm_device *dev = hidev->dev;
+	struct drm_crtc *crtc = &hidev->crtc;
+	struct drm_plane *plane = &hidev->plane;
+	int ret;
+
+	ret = drm_crtc_init_with_planes(dev, crtc, plane,
+					NULL, &hibmc_crtc_funcs, NULL);
+	if (ret) {
+		DRM_ERROR("failed to init crtc.\n");
+		return ret;
+	}
+
+	drm_mode_crtc_set_gamma_size(crtc, 256);
+	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 7d96583..303cd36 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -119,6 +119,12 @@ static int hibmc_kms_init(struct hibmc_drm_device *hidev)
 		return ret;
 	}
 
+	ret = hibmc_crtc_init(hidev);
+	if (ret) {
+		DRM_ERROR("failed to init crtc.\n");
+		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 49e39d2..5731ec2 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -46,6 +46,7 @@ struct hibmc_drm_device {
 	/* drm */
 	struct drm_device  *dev;
 	struct drm_plane plane;
+	struct drm_crtc crtc;
 	bool mode_config_initialized;
 
 	/* ttm */
@@ -85,6 +86,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
 #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
 
 int hibmc_plane_init(struct hibmc_drm_device *hidev);
+int hibmc_crtc_init(struct hibmc_drm_device *hidev);
 int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
 void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
 
-- 
1.9.1

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

* [PATCH v6 6/9] drm/hisilicon/hibmc: Add encoder for VDAC
  2016-10-28  7:27 ` Rongrong Zou
@ 2016-10-28  7:27   ` Rongrong Zou
  -1 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-10-28  7:27 UTC (permalink / raw)
  To: linux-arm-kernel

Add encoder funcs and helpers for VDAC.

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  |  2 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c | 89 ++++++++++++++++++++++++
 4 files changed, 98 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 72e107e..e04f114 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
+++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
@@ -1,5 +1,5 @@
 ccflags-y := -Iinclude/drm
-hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
+hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
 
 obj-$(CONFIG_DRM_HISI_HIBMC)	+=hibmc-drm.o
 #obj-y	+= 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 303cd36..ba191e1 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -125,6 +125,12 @@ static int hibmc_kms_init(struct hibmc_drm_device *hidev)
 		return ret;
 	}
 
+	ret = hibmc_encoder_init(hidev);
+	if (ret) {
+		DRM_ERROR("failed to init encoder\n");
+		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 5731ec2..401cea4 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -47,6 +47,7 @@ struct hibmc_drm_device {
 	struct drm_device  *dev;
 	struct drm_plane plane;
 	struct drm_crtc crtc;
+	struct drm_encoder encoder;
 	bool mode_config_initialized;
 
 	/* ttm */
@@ -87,6 +88,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
 
 int hibmc_plane_init(struct hibmc_drm_device *hidev);
 int hibmc_crtc_init(struct hibmc_drm_device *hidev);
+int hibmc_encoder_init(struct hibmc_drm_device *hidev);
 int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
 void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
 
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..953f659
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
@@ -0,0 +1,89 @@
+/* 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 defx = 800;
+static int defy = 600;
+
+module_param(defx, int, 0444);
+module_param(defy, int, 0444);
+MODULE_PARM_DESC(defx, "default x resolution");
+MODULE_PARM_DESC(defy, "default y resolution");
+
+static void hibmc_encoder_disable(struct drm_encoder *encoder)
+{
+}
+
+static void hibmc_encoder_enable(struct drm_encoder *encoder)
+{
+}
+
+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_device *hidev = dev->dev_private;
+
+	/* just open DISPLAY_CONTROL_HISILE register bit 3:0*/
+	reg = readl(hidev->mmio + DISPLAY_CONTROL_HISILE);
+	reg |= 0xf;
+	writel(reg, hidev->mmio + DISPLAY_CONTROL_HISILE);
+}
+
+static int hibmc_encoder_atomic_check(struct drm_encoder *encoder,
+				      struct drm_crtc_state *crtc_state,
+				      struct drm_connector_state *conn_state)
+{
+	return 0;
+}
+
+static const struct drm_encoder_helper_funcs hibmc_encoder_helper_funcs = {
+	.mode_set = hibmc_encoder_mode_set,
+	.disable = hibmc_encoder_disable,
+	.enable = hibmc_encoder_enable,
+	.atomic_check = hibmc_encoder_atomic_check,
+};
+
+static const struct drm_encoder_funcs hibmc_encoder_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+int hibmc_encoder_init(struct hibmc_drm_device *hidev)
+{
+	struct drm_device *dev = hidev->dev;
+	struct drm_encoder *encoder = &hidev->encoder;
+	int ret;
+
+	encoder->possible_crtcs = 0x1;
+	ret = drm_encoder_init(dev, encoder, &hibmc_encoder_encoder_funcs,
+			       DRM_MODE_ENCODER_DAC, NULL);
+	if (ret) {
+		DRM_ERROR("failed to init encoder\n");
+		return ret;
+	}
+
+	drm_encoder_helper_add(encoder, &hibmc_encoder_helper_funcs);
+	return 0;
+}
-- 
1.9.1

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

* [PATCH v6 6/9] drm/hisilicon/hibmc: Add encoder for VDAC
@ 2016-10-28  7:27   ` Rongrong Zou
  0 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-10-28  7:27 UTC (permalink / raw)
  To: airlied, daniel, dri-devel, emil.l.velikov, tomeu.vizoso,
	benjamin.gaignard, robh, daniel, architt, corbet,
	catalin.marinas, will.deacon, mark.rutland, xinliang.liu
  Cc: linuxarm, kong.kongxinwei, james.xiong, shenhui, guohanjun,
	lijianhua, linux-arm-kernel

Add encoder funcs and helpers for VDAC.

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  |  2 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c | 89 ++++++++++++++++++++++++
 4 files changed, 98 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 72e107e..e04f114 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
+++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
@@ -1,5 +1,5 @@
 ccflags-y := -Iinclude/drm
-hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
+hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
 
 obj-$(CONFIG_DRM_HISI_HIBMC)	+=hibmc-drm.o
 #obj-y	+= 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 303cd36..ba191e1 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -125,6 +125,12 @@ static int hibmc_kms_init(struct hibmc_drm_device *hidev)
 		return ret;
 	}
 
+	ret = hibmc_encoder_init(hidev);
+	if (ret) {
+		DRM_ERROR("failed to init encoder\n");
+		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 5731ec2..401cea4 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -47,6 +47,7 @@ struct hibmc_drm_device {
 	struct drm_device  *dev;
 	struct drm_plane plane;
 	struct drm_crtc crtc;
+	struct drm_encoder encoder;
 	bool mode_config_initialized;
 
 	/* ttm */
@@ -87,6 +88,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
 
 int hibmc_plane_init(struct hibmc_drm_device *hidev);
 int hibmc_crtc_init(struct hibmc_drm_device *hidev);
+int hibmc_encoder_init(struct hibmc_drm_device *hidev);
 int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
 void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
 
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..953f659
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
@@ -0,0 +1,89 @@
+/* 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 defx = 800;
+static int defy = 600;
+
+module_param(defx, int, 0444);
+module_param(defy, int, 0444);
+MODULE_PARM_DESC(defx, "default x resolution");
+MODULE_PARM_DESC(defy, "default y resolution");
+
+static void hibmc_encoder_disable(struct drm_encoder *encoder)
+{
+}
+
+static void hibmc_encoder_enable(struct drm_encoder *encoder)
+{
+}
+
+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_device *hidev = dev->dev_private;
+
+	/* just open DISPLAY_CONTROL_HISILE register bit 3:0*/
+	reg = readl(hidev->mmio + DISPLAY_CONTROL_HISILE);
+	reg |= 0xf;
+	writel(reg, hidev->mmio + DISPLAY_CONTROL_HISILE);
+}
+
+static int hibmc_encoder_atomic_check(struct drm_encoder *encoder,
+				      struct drm_crtc_state *crtc_state,
+				      struct drm_connector_state *conn_state)
+{
+	return 0;
+}
+
+static const struct drm_encoder_helper_funcs hibmc_encoder_helper_funcs = {
+	.mode_set = hibmc_encoder_mode_set,
+	.disable = hibmc_encoder_disable,
+	.enable = hibmc_encoder_enable,
+	.atomic_check = hibmc_encoder_atomic_check,
+};
+
+static const struct drm_encoder_funcs hibmc_encoder_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+int hibmc_encoder_init(struct hibmc_drm_device *hidev)
+{
+	struct drm_device *dev = hidev->dev;
+	struct drm_encoder *encoder = &hidev->encoder;
+	int ret;
+
+	encoder->possible_crtcs = 0x1;
+	ret = drm_encoder_init(dev, encoder, &hibmc_encoder_encoder_funcs,
+			       DRM_MODE_ENCODER_DAC, NULL);
+	if (ret) {
+		DRM_ERROR("failed to init encoder\n");
+		return ret;
+	}
+
+	drm_encoder_helper_add(encoder, &hibmc_encoder_helper_funcs);
+	return 0;
+}
-- 
1.9.1

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

* [PATCH v6 7/9] drm/hisilicon/hibmc: Add connector for VDAC
  2016-10-28  7:27 ` Rongrong Zou
@ 2016-10-28  7:28   ` Rongrong Zou
  -1 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-10-28  7:28 UTC (permalink / raw)
  To: linux-arm-kernel

Add connector funcs and helper funcs for VDAC.

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

diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index ba191e1..4253603 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -131,6 +131,14 @@ static int hibmc_kms_init(struct hibmc_drm_device *hidev)
 		return ret;
 	}
 
+	ret = hibmc_connector_init(hidev);
+	if (ret) {
+		DRM_ERROR("failed to init connector\n");
+		return ret;
+	}
+
+	drm_mode_connector_attach_encoder(&hidev->connector,
+					  &hidev->encoder);
 	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 401cea4..450247d 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -48,6 +48,7 @@ struct hibmc_drm_device {
 	struct drm_plane plane;
 	struct drm_crtc crtc;
 	struct drm_encoder encoder;
+	struct drm_connector connector;
 	bool mode_config_initialized;
 
 	/* ttm */
@@ -89,6 +90,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
 int hibmc_plane_init(struct hibmc_drm_device *hidev);
 int hibmc_crtc_init(struct hibmc_drm_device *hidev);
 int hibmc_encoder_init(struct hibmc_drm_device *hidev);
+int hibmc_connector_init(struct hibmc_drm_device *hidev);
 int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
 void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
 
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
index 953f659..ebefcd1 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
@@ -87,3 +87,79 @@ int hibmc_encoder_init(struct hibmc_drm_device *hidev)
 	drm_encoder_helper_add(encoder, &hibmc_encoder_helper_funcs);
 	return 0;
 }
+
+static int hibmc_connector_get_modes(struct drm_connector *connector)
+{
+	int count;
+
+	count = drm_add_modes_noedid(connector, 800, 600);
+	drm_set_preferred_mode(connector, defx, defy);
+	return count;
+}
+
+static int hibmc_connector_mode_valid(struct drm_connector *connector,
+				      struct drm_display_mode *mode)
+{
+	struct hibmc_drm_device *hiprivate =
+	 container_of(connector, struct hibmc_drm_device, connector);
+	unsigned long size = mode->hdisplay * mode->vdisplay * 4;
+
+	if (size * 2 > hiprivate->fb_size)
+		return MODE_BAD;
+
+	return MODE_OK;
+}
+
+static struct drm_encoder *
+hibmc_connector_best_encoder(struct drm_connector *connector)
+{
+	int enc_id = connector->encoder_ids[0];
+
+	/* pick the encoder ids */
+	if (enc_id)
+		return drm_encoder_find(connector->dev, enc_id);
+
+	return NULL;
+}
+
+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_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_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,
+};
+
+int hibmc_connector_init(struct hibmc_drm_device *hidev)
+{
+	struct drm_device *dev = hidev->dev;
+	struct drm_connector *connector = &hidev->connector;
+	int ret;
+
+	ret = drm_connector_init(dev, connector,
+				 &hibmc_connector_connector_funcs,
+				 DRM_MODE_CONNECTOR_VGA);
+	if (ret) {
+		DRM_ERROR("failed to init connector\n");
+		return ret;
+	}
+	drm_connector_helper_add(connector,
+				 &hibmc_connector_connector_helper_funcs);
+
+	return 0;
+}
-- 
1.9.1

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

* [PATCH v6 7/9] drm/hisilicon/hibmc: Add connector for VDAC
@ 2016-10-28  7:28   ` Rongrong Zou
  0 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-10-28  7:28 UTC (permalink / raw)
  To: airlied, daniel, dri-devel, emil.l.velikov, tomeu.vizoso,
	benjamin.gaignard, robh, daniel, architt, corbet,
	catalin.marinas, will.deacon, mark.rutland, xinliang.liu
  Cc: linuxarm, kong.kongxinwei, james.xiong, shenhui, guohanjun,
	lijianhua, linux-arm-kernel

Add connector funcs and helper funcs for VDAC.

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

diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index ba191e1..4253603 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -131,6 +131,14 @@ static int hibmc_kms_init(struct hibmc_drm_device *hidev)
 		return ret;
 	}
 
+	ret = hibmc_connector_init(hidev);
+	if (ret) {
+		DRM_ERROR("failed to init connector\n");
+		return ret;
+	}
+
+	drm_mode_connector_attach_encoder(&hidev->connector,
+					  &hidev->encoder);
 	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 401cea4..450247d 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -48,6 +48,7 @@ struct hibmc_drm_device {
 	struct drm_plane plane;
 	struct drm_crtc crtc;
 	struct drm_encoder encoder;
+	struct drm_connector connector;
 	bool mode_config_initialized;
 
 	/* ttm */
@@ -89,6 +90,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
 int hibmc_plane_init(struct hibmc_drm_device *hidev);
 int hibmc_crtc_init(struct hibmc_drm_device *hidev);
 int hibmc_encoder_init(struct hibmc_drm_device *hidev);
+int hibmc_connector_init(struct hibmc_drm_device *hidev);
 int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
 void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
 
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
index 953f659..ebefcd1 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
@@ -87,3 +87,79 @@ int hibmc_encoder_init(struct hibmc_drm_device *hidev)
 	drm_encoder_helper_add(encoder, &hibmc_encoder_helper_funcs);
 	return 0;
 }
+
+static int hibmc_connector_get_modes(struct drm_connector *connector)
+{
+	int count;
+
+	count = drm_add_modes_noedid(connector, 800, 600);
+	drm_set_preferred_mode(connector, defx, defy);
+	return count;
+}
+
+static int hibmc_connector_mode_valid(struct drm_connector *connector,
+				      struct drm_display_mode *mode)
+{
+	struct hibmc_drm_device *hiprivate =
+	 container_of(connector, struct hibmc_drm_device, connector);
+	unsigned long size = mode->hdisplay * mode->vdisplay * 4;
+
+	if (size * 2 > hiprivate->fb_size)
+		return MODE_BAD;
+
+	return MODE_OK;
+}
+
+static struct drm_encoder *
+hibmc_connector_best_encoder(struct drm_connector *connector)
+{
+	int enc_id = connector->encoder_ids[0];
+
+	/* pick the encoder ids */
+	if (enc_id)
+		return drm_encoder_find(connector->dev, enc_id);
+
+	return NULL;
+}
+
+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_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_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,
+};
+
+int hibmc_connector_init(struct hibmc_drm_device *hidev)
+{
+	struct drm_device *dev = hidev->dev;
+	struct drm_connector *connector = &hidev->connector;
+	int ret;
+
+	ret = drm_connector_init(dev, connector,
+				 &hibmc_connector_connector_funcs,
+				 DRM_MODE_CONNECTOR_VGA);
+	if (ret) {
+		DRM_ERROR("failed to init connector\n");
+		return ret;
+	}
+	drm_connector_helper_add(connector,
+				 &hibmc_connector_connector_helper_funcs);
+
+	return 0;
+}
-- 
1.9.1

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

* [PATCH v6 8/9] drm/hisilicon/hibmc: Add vblank interruput
  2016-10-28  7:27 ` Rongrong Zou
@ 2016-10-28  7:28   ` Rongrong Zou
  -1 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-10-28  7:28 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 4253603..b668e3e 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -40,16 +40,46 @@
 
 static int hibmc_enable_vblank(struct drm_device *dev, unsigned int pipe)
 {
+	struct hibmc_drm_device *hidev =
+		(struct hibmc_drm_device *)dev->dev_private;
+
+	writel(HIBMC_RAW_INTERRUPT_EN_VBLANK(1),
+	       hidev->mmio + HIBMC_RAW_INTERRUPT_EN);
+
 	return 0;
 }
 
 static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
 {
+	struct hibmc_drm_device *hidev =
+		(struct hibmc_drm_device *)dev->dev_private;
+
+	writel(HIBMC_RAW_INTERRUPT_EN_VBLANK(0),
+	       hidev->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_device *hidev =
+		(struct hibmc_drm_device *)dev->dev_private;
+	struct drm_crtc *crtc = &hidev->crtc;
+	u32 status;
+
+	status = readl(hidev->mmio + HIBMC_RAW_INTERRUPT);
+
+	if (status & HIBMC_RAW_INTERRUPT_VBLANK(1)) {
+		writel(HIBMC_RAW_INTERRUPT_VBLANK(1),
+		       hidev->mmio + HIBMC_RAW_INTERRUPT);
+		drm_crtc_handle_vblank(crtc);
+	}
+
+	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",
@@ -63,6 +93,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)
@@ -242,6 +273,13 @@ static int hibmc_unload(struct drm_device *dev)
 	struct hibmc_drm_device *hidev = dev->dev_private;
 
 	hibmc_fbdev_fini(hidev);
+
+	if (dev->irq_enabled)
+		drm_irq_uninstall(dev);
+	if (hidev->msi_enabled)
+		pci_disable_msi(dev->pdev);
+	drm_vblank_cleanup(dev);
+
 	hibmc_kms_fini(hidev);
 	hibmc_mm_fini(hidev);
 	hibmc_hw_fini(hidev);
@@ -272,6 +310,22 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
 	if (ret)
 		goto err;
 
+	ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
+	if (ret) {
+		DRM_ERROR("failed to initialize vblank.\n");
+		goto err;
+	}
+
+	hidev->msi_enabled = 0;
+	if (pci_enable_msi(dev->pdev)) {
+		DRM_ERROR("Enabling MSI failed!\n");
+	} else {
+		hidev->msi_enabled = 1;
+		ret = drm_irq_install(dev, dev->pdev->irq);
+		if (ret)
+			DRM_ERROR("install irq failed , ret = %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 450247d..f1706fb 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_device {
 	void __iomem   *fb_map;
 	unsigned long  fb_base;
 	unsigned long  fb_size;
+	int msi_enabled;
 
 	/* drm */
 	struct drm_device  *dev;
-- 
1.9.1

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

* [PATCH v6 8/9] drm/hisilicon/hibmc: Add vblank interruput
@ 2016-10-28  7:28   ` Rongrong Zou
  0 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-10-28  7:28 UTC (permalink / raw)
  To: airlied, daniel, dri-devel, emil.l.velikov, tomeu.vizoso,
	benjamin.gaignard, robh, daniel, architt, corbet,
	catalin.marinas, will.deacon, 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 4253603..b668e3e 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -40,16 +40,46 @@
 
 static int hibmc_enable_vblank(struct drm_device *dev, unsigned int pipe)
 {
+	struct hibmc_drm_device *hidev =
+		(struct hibmc_drm_device *)dev->dev_private;
+
+	writel(HIBMC_RAW_INTERRUPT_EN_VBLANK(1),
+	       hidev->mmio + HIBMC_RAW_INTERRUPT_EN);
+
 	return 0;
 }
 
 static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
 {
+	struct hibmc_drm_device *hidev =
+		(struct hibmc_drm_device *)dev->dev_private;
+
+	writel(HIBMC_RAW_INTERRUPT_EN_VBLANK(0),
+	       hidev->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_device *hidev =
+		(struct hibmc_drm_device *)dev->dev_private;
+	struct drm_crtc *crtc = &hidev->crtc;
+	u32 status;
+
+	status = readl(hidev->mmio + HIBMC_RAW_INTERRUPT);
+
+	if (status & HIBMC_RAW_INTERRUPT_VBLANK(1)) {
+		writel(HIBMC_RAW_INTERRUPT_VBLANK(1),
+		       hidev->mmio + HIBMC_RAW_INTERRUPT);
+		drm_crtc_handle_vblank(crtc);
+	}
+
+	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",
@@ -63,6 +93,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)
@@ -242,6 +273,13 @@ static int hibmc_unload(struct drm_device *dev)
 	struct hibmc_drm_device *hidev = dev->dev_private;
 
 	hibmc_fbdev_fini(hidev);
+
+	if (dev->irq_enabled)
+		drm_irq_uninstall(dev);
+	if (hidev->msi_enabled)
+		pci_disable_msi(dev->pdev);
+	drm_vblank_cleanup(dev);
+
 	hibmc_kms_fini(hidev);
 	hibmc_mm_fini(hidev);
 	hibmc_hw_fini(hidev);
@@ -272,6 +310,22 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
 	if (ret)
 		goto err;
 
+	ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
+	if (ret) {
+		DRM_ERROR("failed to initialize vblank.\n");
+		goto err;
+	}
+
+	hidev->msi_enabled = 0;
+	if (pci_enable_msi(dev->pdev)) {
+		DRM_ERROR("Enabling MSI failed!\n");
+	} else {
+		hidev->msi_enabled = 1;
+		ret = drm_irq_install(dev, dev->pdev->irq);
+		if (ret)
+			DRM_ERROR("install irq failed , ret = %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 450247d..f1706fb 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_device {
 	void __iomem   *fb_map;
 	unsigned long  fb_base;
 	unsigned long  fb_size;
+	int msi_enabled;
 
 	/* drm */
 	struct drm_device  *dev;
-- 
1.9.1

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

* [PATCH v6 9/9] MAINTAINERS: Update HISILICON DRM entries
  2016-10-28  7:27 ` Rongrong Zou
@ 2016-10-28  7:28   ` Rongrong Zou
  -1 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-10-28  7:28 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 c447953..cc5ee3a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4117,6 +4117,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] 64+ messages in thread

* [PATCH v6 9/9] MAINTAINERS: Update HISILICON DRM entries
@ 2016-10-28  7:28   ` Rongrong Zou
  0 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-10-28  7:28 UTC (permalink / raw)
  To: airlied, daniel, dri-devel, emil.l.velikov, tomeu.vizoso,
	benjamin.gaignard, robh, daniel, architt, corbet,
	catalin.marinas, will.deacon, 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 c447953..cc5ee3a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4117,6 +4117,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] 64+ messages in thread

* [PATCH v6 1/9] drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
  2016-10-28  7:27   ` Rongrong Zou
@ 2016-11-10 17:35     ` Sean Paul
  -1 siblings, 0 replies; 64+ messages in thread
From: Sean Paul @ 2016-11-10 17:35 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Oct 28, 2016 at 3:27 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>
> ---
>  drivers/gpu/drm/hisilicon/Kconfig                 |   1 +
>  drivers/gpu/drm/hisilicon/Makefile                |   1 +
>  drivers/gpu/drm/hisilicon/hibmc/Kconfig           |   7 +
>  drivers/gpu/drm/hisilicon/hibmc/Makefile          |   5 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   | 269 ++++++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   |  35 +++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c |  85 +++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h |  28 +++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h  | 212 +++++++++++++++++
>  9 files changed, 643 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_power.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.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..a9af90d
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
> @@ -0,0 +1,7 @@
> +config DRM_HISI_HIBMC
> +       tristate "DRM Support for Hisilicon Hibmc"
> +       depends on DRM && PCI
> +
> +       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..97cf4a0
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> @@ -0,0 +1,5 @@
> +ccflags-y := -Iinclude/drm
> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o
> +
> +obj-$(CONFIG_DRM_HISI_HIBMC)   +=hibmc-drm.o

nit: Improper spacing here

> +#obj-y += 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..4669d42
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -0,0 +1,269 @@
> +/* 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/module.h>
> +#include <linux/console.h>
> +
> +#include "hibmc_drm_drv.h"
> +#include "hibmc_drm_regs.h"
> +#include "hibmc_drm_power.h"

nit: Alphabetize headers

> +
> +static const struct file_operations hibmc_fops = {
> +       .owner          = THIS_MODULE,
> +       .open           = drm_open,
> +       .release        = drm_release,
> +       .unlocked_ioctl = drm_ioctl,
> +#ifdef CONFIG_COMPAT

drm_compat_ioctl is now initialized to NULL, so you can remove the #ifdef

> +       .compat_ioctl   = drm_compat_ioctl,
> +#endif
> +       .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)
> +};
> +
> +static int hibmc_hw_config(struct hibmc_drm_device *hidev)
> +{
> +       unsigned int reg;
> +
> +       /* On hardware reset, power mode 0 is default. */
> +       hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_MODE0);
> +
> +       /* Enable display power gate & LOCALMEM power gate*/
> +       reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
> +       reg |= HIBMC_CURR_GATE_DISPLAY(ON);
> +       reg |= HIBMC_CURR_GATE_LOCALMEM(ON);
> +
> +       hibmc_set_current_gate(hidev, 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(hidev->mmio + HIBMC_MISC_CTRL);
> +       reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
> +       reg |= HIBMC_MSCCTL_LOCALMEM_RESET(RESET);
> +       writel(reg, hidev->mmio + HIBMC_MISC_CTRL);
> +
> +       reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
> +       reg |= HIBMC_MSCCTL_LOCALMEM_RESET(NORMAL);
> +
> +       writel(reg, hidev->mmio + HIBMC_MISC_CTRL);
> +
> +       /* We can add more initialization as needed. */
> +
> +       return 0;

Consider using void return type here to simplify error checking in the
caller, especially since it looks like you aren't checking the return
code, anyways :)

> +}
> +
> +static int hibmc_hw_map(struct hibmc_drm_device *hidev)
> +{
> +       struct drm_device *dev = hidev->dev;
> +       struct pci_dev *pdev = dev->pdev;
> +       resource_size_t addr, size, ioaddr, iosize;
> +
> +       ioaddr = pci_resource_start(pdev, 1);
> +       iosize = MB(2);
> +
> +       hidev->mmio = ioremap_nocache(ioaddr, iosize);

Use devm_ioremap_nocache to avoid managing the resource directly

> +

nit: extra space

> +       if (!hidev->mmio) {
> +               DRM_ERROR("Cannot map mmio region\n");
> +               return -ENOMEM;
> +       }
> +
> +       addr = pci_resource_start(pdev, 0);
> +       size = MB(32);

Pull size and iosize out into #defines with descriptive names

> +
> +       hidev->fb_map = ioremap(addr, size);

Use devm_ioremap to avoid managing the resource directly.

> +       if (!hidev->fb_map) {
> +               DRM_ERROR("Cannot map framebuffer\n");
> +               return -ENOMEM;
> +       }
> +       hidev->fb_base = addr;
> +       hidev->fb_size = size;
> +
> +       return 0;
> +}
> +
> +static void hibmc_hw_fini(struct hibmc_drm_device *hidev)
> +{
> +       if (hidev->mmio)
> +               iounmap(hidev->mmio);
> +       if (hidev->fb_map)
> +               iounmap(hidev->fb_map);
> +}

You don't need this function if you use the devm variants above

> +
> +static int hibmc_hw_init(struct hibmc_drm_device *hidev)
> +{
> +       int ret;
> +
> +       ret = hibmc_hw_map(hidev);
> +       if (ret)
> +               return ret;
> +
> +       hibmc_hw_config(hidev);
> +
> +       return 0;
> +}
> +
> +static int hibmc_unload(struct drm_device *dev)
> +{
> +       struct hibmc_drm_device *hidev = dev->dev_private;
> +
> +       hibmc_hw_fini(hidev);
> +       dev->dev_private = NULL;
> +       return 0;
> +}
> +
> +static int hibmc_load(struct drm_device *dev, unsigned long flags)

flags isn't used anywhere?

> +{
> +       struct hibmc_drm_device *hidev;
> +       int ret;
> +
> +       hidev = devm_kzalloc(dev->dev, sizeof(*hidev), GFP_KERNEL);
> +       if (!hidev)

Print error here?

> +               return -ENOMEM;
> +       dev->dev_private = hidev;
> +       hidev->dev = dev;
> +
> +       ret = hibmc_hw_init(hidev);
> +       if (ret)
> +               goto err;
> +
> +       return 0;
> +
> +err:
> +       hibmc_unload(dev);
> +       DRM_ERROR("failed to initialize drm driver.\n");

Print the return value

> +       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)

Print error here

> +               return -ENOMEM;
> +
> +       dev->pdev = pdev;
> +       pci_set_drvdata(pdev, dev);
> +
> +       ret = pci_enable_device(pdev);
> +       if (ret)

and here, and in other failure paths

> +               goto err_free;
> +
> +       ret = hibmc_load(dev, 0);
> +       if (ret)
> +               goto err_disable;
> +
> +       ret = drm_dev_register(dev, 0);
> +       if (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..0037341
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -0,0 +1,35 @@
> +/* 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_device {

nit: Calling this hibmc_drm_priv would probably make things easier to
read. When I read hibmc_drm_device, it makes me think that it's an
extension of drm_device, which this isn't.


> +       /* hw */
> +       void __iomem   *mmio;
> +       void __iomem   *fb_map;
> +       unsigned long  fb_base;
> +       unsigned long  fb_size;
> +
> +       /* drm */
> +       struct drm_device  *dev;
> +};
> +
> +#endif
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c
> new file mode 100644
> index 0000000..1036542
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c

I don't think you need a new file for these functions. Just stash them
in hibmc_drm_drv.c

> @@ -0,0 +1,85 @@
> +/* 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 "hibmc_drm_drv.h"
> +#include "hibmc_drm_regs.h"
> +
> +/*
> + * It can operate in one of three modes: 0, 1 or Sleep.
> + */
> +void hibmc_set_power_mode(struct hibmc_drm_device *hidev,
> +                         unsigned int power_mode)
> +{
> +       unsigned int control_value = 0;
> +       void __iomem   *mmio = hidev->mmio;
> +
> +       if (power_mode > HIBMC_PW_MODE_CTL_MODE_SLEEP)
> +               return;
> +
> +       control_value = readl(mmio + HIBMC_POWER_MODE_CTRL);
> +       control_value &= ~HIBMC_PW_MODE_CTL_MODE_MASK;
> +
> +       control_value |= HIBMC_PW_MODE_CTL_MODE(power_mode) &
> +                        HIBMC_PW_MODE_CTL_MODE_MASK;
> +
> +    /* Set up other fields in Power Control Register */
> +       if (power_mode == HIBMC_PW_MODE_CTL_MODE_SLEEP) {
> +               control_value &= ~HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;

You do this in both branches of the conditional

> +               control_value |= HIBMC_PW_MODE_CTL_OSC_INPUT(0) &
> +                                HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
> +       } else {
> +               control_value &= ~HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
> +               control_value |= HIBMC_PW_MODE_CTL_OSC_INPUT(1) &
> +                                HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
> +       }

I think you could simplify this by adding a new local.

unsigned int input = 1;

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_PW_MODE_CTL_MODE(power_mode) &
                 HIBMC_PW_MODE_CTL_MODE_MASK;
control_value |= HIBMC_PW_MODE_CTL_OSC_INPUT(input) &
                 HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;


> +       /* Program new power mode. */
> +       writel(control_value, mmio + HIBMC_POWER_MODE_CTRL);
> +}
> +
> +static unsigned int hibmc_get_power_mode(struct hibmc_drm_device *hidev)
> +{
> +       void __iomem   *mmio = hidev->mmio;
> +
> +       return (readl(mmio + HIBMC_POWER_MODE_CTRL) &
> +               HIBMC_PW_MODE_CTL_MODE_MASK) >> HIBMC_PW_MODE_CTL_MODE_SHIFT;

nit: You're doing a lot of work in the return statement here.

> +}
> +
> +void hibmc_set_current_gate(struct hibmc_drm_device *hidev, unsigned int gate)
> +{
> +       unsigned int gate_reg;
> +       unsigned int mode;
> +       void __iomem   *mmio = hidev->mmio;
> +
> +       /* Get current power mode. */

nit: try to avoid comments that don't add value

> +       mode = hibmc_get_power_mode(hidev);
> +
> +       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);
> +}
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h
> new file mode 100644
> index 0000000..e20e1aa
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h
> @@ -0,0 +1,28 @@
> +/* 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_POWER_H
> +#define HIBMC_DRM_POWER_H
> +
> +#include "hibmc_drm_drv.h"
> +
> +void hibmc_set_power_mode(struct hibmc_drm_device *hidev,
> +                         unsigned int power_mode);
> +void hibmc_set_current_gate(struct hibmc_drm_device *hidev,
> +                           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..9c804ca
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
> @@ -0,0 +1,212 @@
> +/* 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
> +
> +#define OFF 0
> +#define ON  1
> +#define DISABLE               0
> +#define ENABLE                1

These are not good names. I think you can probably hardcode the 0's
and 1's in the code instead of these. However, if you want to use
them, at least add a HIBMC_ prefix

> +
> +/* register definition */
> +#define HIBMC_MISC_CTRL                                0x4
> +
> +#define HIBMC_MSCCTL_LOCALMEM_RESET(x)         ((x) << 6)
> +#define HIBMC_MSCCTL_LOCALMEM_RESET_MASK       0x40
> +
> +#define RESET                0
> +#define NORMAL               1

Same naming nit here. Add a prefix

> +
> +#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 OSC                                    0

Naming

> +#define TESTCLK                                        1

This doesn't seem to be used?

> +
> +#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 CRTSELECT_VGA                0
> +#define CRTSELECT_CRT                1
> +
> +#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE(x)      ((x) << 14)
> +#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE_MASK    0x4000
> +
> +#define PHASE_ACTIVE_HIGH      0
> +#define PHASE_ACTIVE_LOW       1
> +
> +#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_DISPLAY_END(x)    ((x) << 0)
> +#define HIBMC_CRT_HORZ_TOTAL_DISPLAY_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_DISPLAY_END(x)    ((x) << 0)
> +#define HIBMC_CRT_VERT_TOTAL_DISPLAY_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_MSK    0x7FF0000
> +
> +#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT(x)    ((x) << 0)
> +#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT_MSK   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 DISPLAY_CONTROL_HISILE                 0x80288
> +
> +#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_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
> +
> +/* Global macros */
> +#define RGB(r, g, b) \

Not used anywhere?

> +( \
> +       (unsigned long)(((r) << 16) | ((g) << 8) | (b)) \
> +)
> +
> +#define PADDING(align, data) (((data) + (align) - 1) & (~((align) - 1)))
> +

This is only used in hibmc_drm_de.c, move it in there. It might also
be nice to make it a type-checked function while you're at it.


> +#define MB(x) ((x) << 20)
> +

This is only used in 2 places, I think you can just hardcode the value
in their respective #defines

> +#endif
> --
> 1.9.1
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v6 1/9] drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
@ 2016-11-10 17:35     ` Sean Paul
  0 siblings, 0 replies; 64+ messages in thread
From: Sean Paul @ 2016-11-10 17:35 UTC (permalink / raw)
  To: Rongrong Zou
  Cc: Mark Rutland, shenhui, Tomeu Vizoso, Jonathan Corbet,
	catalin.marinas, Emil Velikov, linuxarm, dri-devel, guohanjun,
	Will Deacon, lijianhua, Linux ARM Kernel, james.xiong

On Fri, Oct 28, 2016 at 3:27 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>
> ---
>  drivers/gpu/drm/hisilicon/Kconfig                 |   1 +
>  drivers/gpu/drm/hisilicon/Makefile                |   1 +
>  drivers/gpu/drm/hisilicon/hibmc/Kconfig           |   7 +
>  drivers/gpu/drm/hisilicon/hibmc/Makefile          |   5 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   | 269 ++++++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   |  35 +++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c |  85 +++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h |  28 +++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h  | 212 +++++++++++++++++
>  9 files changed, 643 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_power.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.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..a9af90d
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
> @@ -0,0 +1,7 @@
> +config DRM_HISI_HIBMC
> +       tristate "DRM Support for Hisilicon Hibmc"
> +       depends on DRM && PCI
> +
> +       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..97cf4a0
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> @@ -0,0 +1,5 @@
> +ccflags-y := -Iinclude/drm
> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o
> +
> +obj-$(CONFIG_DRM_HISI_HIBMC)   +=hibmc-drm.o

nit: Improper spacing here

> +#obj-y += 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..4669d42
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -0,0 +1,269 @@
> +/* 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/module.h>
> +#include <linux/console.h>
> +
> +#include "hibmc_drm_drv.h"
> +#include "hibmc_drm_regs.h"
> +#include "hibmc_drm_power.h"

nit: Alphabetize headers

> +
> +static const struct file_operations hibmc_fops = {
> +       .owner          = THIS_MODULE,
> +       .open           = drm_open,
> +       .release        = drm_release,
> +       .unlocked_ioctl = drm_ioctl,
> +#ifdef CONFIG_COMPAT

drm_compat_ioctl is now initialized to NULL, so you can remove the #ifdef

> +       .compat_ioctl   = drm_compat_ioctl,
> +#endif
> +       .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)
> +};
> +
> +static int hibmc_hw_config(struct hibmc_drm_device *hidev)
> +{
> +       unsigned int reg;
> +
> +       /* On hardware reset, power mode 0 is default. */
> +       hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_MODE0);
> +
> +       /* Enable display power gate & LOCALMEM power gate*/
> +       reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
> +       reg |= HIBMC_CURR_GATE_DISPLAY(ON);
> +       reg |= HIBMC_CURR_GATE_LOCALMEM(ON);
> +
> +       hibmc_set_current_gate(hidev, 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(hidev->mmio + HIBMC_MISC_CTRL);
> +       reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
> +       reg |= HIBMC_MSCCTL_LOCALMEM_RESET(RESET);
> +       writel(reg, hidev->mmio + HIBMC_MISC_CTRL);
> +
> +       reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
> +       reg |= HIBMC_MSCCTL_LOCALMEM_RESET(NORMAL);
> +
> +       writel(reg, hidev->mmio + HIBMC_MISC_CTRL);
> +
> +       /* We can add more initialization as needed. */
> +
> +       return 0;

Consider using void return type here to simplify error checking in the
caller, especially since it looks like you aren't checking the return
code, anyways :)

> +}
> +
> +static int hibmc_hw_map(struct hibmc_drm_device *hidev)
> +{
> +       struct drm_device *dev = hidev->dev;
> +       struct pci_dev *pdev = dev->pdev;
> +       resource_size_t addr, size, ioaddr, iosize;
> +
> +       ioaddr = pci_resource_start(pdev, 1);
> +       iosize = MB(2);
> +
> +       hidev->mmio = ioremap_nocache(ioaddr, iosize);

Use devm_ioremap_nocache to avoid managing the resource directly

> +

nit: extra space

> +       if (!hidev->mmio) {
> +               DRM_ERROR("Cannot map mmio region\n");
> +               return -ENOMEM;
> +       }
> +
> +       addr = pci_resource_start(pdev, 0);
> +       size = MB(32);

Pull size and iosize out into #defines with descriptive names

> +
> +       hidev->fb_map = ioremap(addr, size);

Use devm_ioremap to avoid managing the resource directly.

> +       if (!hidev->fb_map) {
> +               DRM_ERROR("Cannot map framebuffer\n");
> +               return -ENOMEM;
> +       }
> +       hidev->fb_base = addr;
> +       hidev->fb_size = size;
> +
> +       return 0;
> +}
> +
> +static void hibmc_hw_fini(struct hibmc_drm_device *hidev)
> +{
> +       if (hidev->mmio)
> +               iounmap(hidev->mmio);
> +       if (hidev->fb_map)
> +               iounmap(hidev->fb_map);
> +}

You don't need this function if you use the devm variants above

> +
> +static int hibmc_hw_init(struct hibmc_drm_device *hidev)
> +{
> +       int ret;
> +
> +       ret = hibmc_hw_map(hidev);
> +       if (ret)
> +               return ret;
> +
> +       hibmc_hw_config(hidev);
> +
> +       return 0;
> +}
> +
> +static int hibmc_unload(struct drm_device *dev)
> +{
> +       struct hibmc_drm_device *hidev = dev->dev_private;
> +
> +       hibmc_hw_fini(hidev);
> +       dev->dev_private = NULL;
> +       return 0;
> +}
> +
> +static int hibmc_load(struct drm_device *dev, unsigned long flags)

flags isn't used anywhere?

> +{
> +       struct hibmc_drm_device *hidev;
> +       int ret;
> +
> +       hidev = devm_kzalloc(dev->dev, sizeof(*hidev), GFP_KERNEL);
> +       if (!hidev)

Print error here?

> +               return -ENOMEM;
> +       dev->dev_private = hidev;
> +       hidev->dev = dev;
> +
> +       ret = hibmc_hw_init(hidev);
> +       if (ret)
> +               goto err;
> +
> +       return 0;
> +
> +err:
> +       hibmc_unload(dev);
> +       DRM_ERROR("failed to initialize drm driver.\n");

Print the return value

> +       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)

Print error here

> +               return -ENOMEM;
> +
> +       dev->pdev = pdev;
> +       pci_set_drvdata(pdev, dev);
> +
> +       ret = pci_enable_device(pdev);
> +       if (ret)

and here, and in other failure paths

> +               goto err_free;
> +
> +       ret = hibmc_load(dev, 0);
> +       if (ret)
> +               goto err_disable;
> +
> +       ret = drm_dev_register(dev, 0);
> +       if (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..0037341
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -0,0 +1,35 @@
> +/* 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_device {

nit: Calling this hibmc_drm_priv would probably make things easier to
read. When I read hibmc_drm_device, it makes me think that it's an
extension of drm_device, which this isn't.


> +       /* hw */
> +       void __iomem   *mmio;
> +       void __iomem   *fb_map;
> +       unsigned long  fb_base;
> +       unsigned long  fb_size;
> +
> +       /* drm */
> +       struct drm_device  *dev;
> +};
> +
> +#endif
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c
> new file mode 100644
> index 0000000..1036542
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c

I don't think you need a new file for these functions. Just stash them
in hibmc_drm_drv.c

> @@ -0,0 +1,85 @@
> +/* 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 "hibmc_drm_drv.h"
> +#include "hibmc_drm_regs.h"
> +
> +/*
> + * It can operate in one of three modes: 0, 1 or Sleep.
> + */
> +void hibmc_set_power_mode(struct hibmc_drm_device *hidev,
> +                         unsigned int power_mode)
> +{
> +       unsigned int control_value = 0;
> +       void __iomem   *mmio = hidev->mmio;
> +
> +       if (power_mode > HIBMC_PW_MODE_CTL_MODE_SLEEP)
> +               return;
> +
> +       control_value = readl(mmio + HIBMC_POWER_MODE_CTRL);
> +       control_value &= ~HIBMC_PW_MODE_CTL_MODE_MASK;
> +
> +       control_value |= HIBMC_PW_MODE_CTL_MODE(power_mode) &
> +                        HIBMC_PW_MODE_CTL_MODE_MASK;
> +
> +    /* Set up other fields in Power Control Register */
> +       if (power_mode == HIBMC_PW_MODE_CTL_MODE_SLEEP) {
> +               control_value &= ~HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;

You do this in both branches of the conditional

> +               control_value |= HIBMC_PW_MODE_CTL_OSC_INPUT(0) &
> +                                HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
> +       } else {
> +               control_value &= ~HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
> +               control_value |= HIBMC_PW_MODE_CTL_OSC_INPUT(1) &
> +                                HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
> +       }

I think you could simplify this by adding a new local.

unsigned int input = 1;

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_PW_MODE_CTL_MODE(power_mode) &
                 HIBMC_PW_MODE_CTL_MODE_MASK;
control_value |= HIBMC_PW_MODE_CTL_OSC_INPUT(input) &
                 HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;


> +       /* Program new power mode. */
> +       writel(control_value, mmio + HIBMC_POWER_MODE_CTRL);
> +}
> +
> +static unsigned int hibmc_get_power_mode(struct hibmc_drm_device *hidev)
> +{
> +       void __iomem   *mmio = hidev->mmio;
> +
> +       return (readl(mmio + HIBMC_POWER_MODE_CTRL) &
> +               HIBMC_PW_MODE_CTL_MODE_MASK) >> HIBMC_PW_MODE_CTL_MODE_SHIFT;

nit: You're doing a lot of work in the return statement here.

> +}
> +
> +void hibmc_set_current_gate(struct hibmc_drm_device *hidev, unsigned int gate)
> +{
> +       unsigned int gate_reg;
> +       unsigned int mode;
> +       void __iomem   *mmio = hidev->mmio;
> +
> +       /* Get current power mode. */

nit: try to avoid comments that don't add value

> +       mode = hibmc_get_power_mode(hidev);
> +
> +       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);
> +}
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h
> new file mode 100644
> index 0000000..e20e1aa
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h
> @@ -0,0 +1,28 @@
> +/* 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_POWER_H
> +#define HIBMC_DRM_POWER_H
> +
> +#include "hibmc_drm_drv.h"
> +
> +void hibmc_set_power_mode(struct hibmc_drm_device *hidev,
> +                         unsigned int power_mode);
> +void hibmc_set_current_gate(struct hibmc_drm_device *hidev,
> +                           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..9c804ca
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
> @@ -0,0 +1,212 @@
> +/* 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
> +
> +#define OFF 0
> +#define ON  1
> +#define DISABLE               0
> +#define ENABLE                1

These are not good names. I think you can probably hardcode the 0's
and 1's in the code instead of these. However, if you want to use
them, at least add a HIBMC_ prefix

> +
> +/* register definition */
> +#define HIBMC_MISC_CTRL                                0x4
> +
> +#define HIBMC_MSCCTL_LOCALMEM_RESET(x)         ((x) << 6)
> +#define HIBMC_MSCCTL_LOCALMEM_RESET_MASK       0x40
> +
> +#define RESET                0
> +#define NORMAL               1

Same naming nit here. Add a prefix

> +
> +#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 OSC                                    0

Naming

> +#define TESTCLK                                        1

This doesn't seem to be used?

> +
> +#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 CRTSELECT_VGA                0
> +#define CRTSELECT_CRT                1
> +
> +#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE(x)      ((x) << 14)
> +#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE_MASK    0x4000
> +
> +#define PHASE_ACTIVE_HIGH      0
> +#define PHASE_ACTIVE_LOW       1
> +
> +#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_DISPLAY_END(x)    ((x) << 0)
> +#define HIBMC_CRT_HORZ_TOTAL_DISPLAY_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_DISPLAY_END(x)    ((x) << 0)
> +#define HIBMC_CRT_VERT_TOTAL_DISPLAY_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_MSK    0x7FF0000
> +
> +#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT(x)    ((x) << 0)
> +#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT_MSK   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 DISPLAY_CONTROL_HISILE                 0x80288
> +
> +#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_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
> +
> +/* Global macros */
> +#define RGB(r, g, b) \

Not used anywhere?

> +( \
> +       (unsigned long)(((r) << 16) | ((g) << 8) | (b)) \
> +)
> +
> +#define PADDING(align, data) (((data) + (align) - 1) & (~((align) - 1)))
> +

This is only used in hibmc_drm_de.c, move it in there. It might also
be nice to make it a type-checked function while you're at it.


> +#define MB(x) ((x) << 20)
> +

This is only used in 2 places, I think you can just hardcode the value
in their respective #defines

> +#endif
> --
> 1.9.1
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v6 2/9] drm/hisilicon/hibmc: Add video memory management
  2016-10-28  7:27   ` Rongrong Zou
@ 2016-11-10 17:35     ` Sean Paul
  -1 siblings, 0 replies; 64+ messages in thread
From: Sean Paul @ 2016-11-10 17:35 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Oct 28, 2016 at 3:27 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>
> ---
>  drivers/gpu/drm/hisilicon/hibmc/Kconfig         |   1 +
>  drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  12 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |  46 +++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     | 490 ++++++++++++++++++++++++
>  5 files changed, 550 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
> index a9af90d..bcb8c18 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/Kconfig
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
> @@ -1,6 +1,7 @@
>  config DRM_HISI_HIBMC
>         tristate "DRM Support for Hisilicon Hibmc"
>         depends on DRM && PCI
> +       select DRM_TTM
>
>         help
>           Choose this option if you have a Hisilicon Hibmc soc chipset.
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> index 97cf4a0..d5c40b8 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> @@ -1,5 +1,5 @@
>  ccflags-y := -Iinclude/drm
> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o
> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o hibmc_ttm.o
>
>  obj-$(CONFIG_DRM_HISI_HIBMC)   +=hibmc-drm.o
>  #obj-y += 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 4669d42..81f4301 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -31,6 +31,7 @@
>  #ifdef CONFIG_COMPAT
>         .compat_ioctl   = drm_compat_ioctl,
>  #endif
> +       .mmap           = hibmc_mmap,
>         .poll           = drm_poll,
>         .read           = drm_read,
>         .llseek         = no_llseek,
> @@ -46,6 +47,8 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>  }
>
>  static struct drm_driver hibmc_driver = {
> +       .driver_features        = DRIVER_GEM,
> +

nit: extra space

>         .fops                   = &hibmc_fops,
>         .name                   = "hibmc",
>         .date                   = "20160828",
> @@ -55,6 +58,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)
> @@ -163,6 +170,7 @@ static int hibmc_unload(struct drm_device *dev)
>  {
>         struct hibmc_drm_device *hidev = dev->dev_private;
>
> +       hibmc_mm_fini(hidev);
>         hibmc_hw_fini(hidev);
>         dev->dev_private = NULL;
>         return 0;
> @@ -183,6 +191,10 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
>         if (ret)
>                 goto err;
>
> +       ret = hibmc_mm_init(hidev);
> +       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 0037341..db8d80e 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/ttm/ttm_bo_driver.h>
> +#include <drm/drm_gem.h>

nit: alphabetize

>
>  struct hibmc_drm_device {
>         /* hw */
> @@ -30,6 +32,50 @@ struct hibmc_drm_device {
>
>         /* drm */
>         struct drm_device  *dev;
> +
> +       /* ttm */
> +       struct {
> +               struct drm_global_reference mem_global_ref;
> +               struct ttm_bo_global_ref bo_global_ref;
> +               struct ttm_bo_device bdev;
> +               bool initialized;
> +       } ttm;

I don't think you gain anything other than keystrokes from the substruct

> +
> +       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);
> +}
> +
> +#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)

Hide this in ttm.c

> +
> +int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
> +                    struct drm_gem_object **obj);
> +
> +int hibmc_mm_init(struct hibmc_drm_device *hibmc);
> +void hibmc_mm_fini(struct hibmc_drm_device *hibmc);
> +int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr);
> +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..0802ebd
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> @@ -0,0 +1,490 @@
> +/* 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 "hibmc_drm_drv.h"
> +#include <ttm/ttm_page_alloc.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_atomic_helper.h>
> +
> +static inline struct hibmc_drm_device *
> +hibmc_bdev(struct ttm_bo_device *bd)
> +{
> +       return container_of(bd, struct hibmc_drm_device, ttm.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_device *hibmc)
> +{
> +       struct drm_global_reference *global_ref;
> +       int r;

nit: try not to use one character variable names unless it's for the
purpose of a loop (ie: i,j). You also use ret elsewhere in the driver,
so it'd be nice to remain consistent

> +
> +       global_ref = &hibmc->ttm.mem_global_ref;

I think using the global_ref local obfuscates what you're doing here.
It saves you 6 characters while typing, but adds a layer of
indirection for all future readers.

> +       global_ref->global_type = DRM_GLOBAL_TTM_MEM;
> +       global_ref->size = sizeof(struct ttm_mem_global);
> +       global_ref->init = &hibmc_ttm_mem_global_init;
> +       global_ref->release = &hibmc_ttm_mem_global_release;
> +       r = drm_global_item_ref(global_ref);
> +       if (r != 0) {

nit: if (r)

> +               DRM_ERROR("Failed setting up TTM memory accounting subsystem.\n"
> +                        );

Breaking up the line for one character is probably not worthwhile, and
you should really print the error. How about:

DRM_ERROR("Could not get ref on ttm global ret=%d.\n", ret);


> +               return r;
> +       }
> +
> +       hibmc->ttm.bo_global_ref.mem_glob =
> +               hibmc->ttm.mem_global_ref.object;
> +       global_ref = &hibmc->ttm.bo_global_ref.ref;
> +       global_ref->global_type = DRM_GLOBAL_TTM_BO;
> +       global_ref->size = sizeof(struct ttm_bo_global);
> +       global_ref->init = &ttm_bo_global_init;
> +       global_ref->release = &ttm_bo_global_release;
> +       r = drm_global_item_ref(global_ref);
> +       if (r != 0) {
> +               DRM_ERROR("Failed setting up TTM BO subsystem.\n");
> +               drm_global_item_unref(&hibmc->ttm.mem_global_ref);
> +               return r;
> +       }
> +       return 0;
> +}
> +
> +static void
> +hibmc_ttm_global_release(struct hibmc_drm_device *hibmc)
> +{
> +       if (!hibmc->ttm.mem_global_ref.release)

Are you actually hitting this condition? This seems like it's papering
over something else.

> +               return;
> +
> +       drm_global_item_unref(&hibmc->ttm.bo_global_ref.ref);
> +       drm_global_item_unref(&hibmc->ttm.mem_global_ref);
> +       hibmc->ttm.mem_global_ref.release = NULL;
> +}
> +
> +static void hibmc_bo_ttm_destroy(struct ttm_buffer_object *tbo)
> +{
> +       struct hibmc_bo *bo;
> +
> +       bo = container_of(tbo, struct hibmc_bo, bo);

nit: No need to split this into a separate line.

> +
> +       drm_gem_object_release(&bo->gem);
> +       kfree(bo);
> +}
> +
> +static bool hibmc_ttm_bo_is_hibmc_bo(struct ttm_buffer_object *bo)
> +{
> +       if (bo->destroy == &hibmc_bo_ttm_destroy)
> +               return true;
> +       return false;

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 c = 0;

Can you please use a more descriptive name than 'c'?

> +       u32 i;
> +
> +       bo->placement.placement = bo->placements;
> +       bo->placement.busy_placement = bo->placements;
> +       if (domain & TTM_PL_FLAG_VRAM)
> +               bo->placements[c++].flags = TTM_PL_FLAG_WC |
> +               TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;

nit: you're alignment is off here and below

> +       if (domain & TTM_PL_FLAG_SYSTEM)
> +               bo->placements[c++].flags = TTM_PL_MASK_CACHING |
> +               TTM_PL_FLAG_SYSTEM;
> +       if (!c)
> +               bo->placements[c++].flags = TTM_PL_MASK_CACHING |
> +               TTM_PL_FLAG_SYSTEM;
> +
> +       bo->placement.num_placement = c;
> +       bo->placement.num_busy_placement = c;
> +       for (i = 0; i < c; ++i) {

nit: we tend towards post-increment in kernel

> +               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_device *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_io_mem_free(struct ttm_bo_device *bdev,
> +                                 struct ttm_mem_reg *mem)
> +{
> +}

No need to stub this, the caller does a NULL-check before invoking

> +
> +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;
> +
> +       tt = kzalloc(sizeof(*tt), GFP_KERNEL);
> +       if (!tt)

Print error

> +               return NULL;
> +       tt->func = &hibmc_tt_backend_func;
> +       if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) {

Here too?

> +               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            = &hibmc_ttm_io_mem_free,
> +       .lru_tail               = &ttm_bo_default_lru_tail,
> +       .swap_lru_tail          = &ttm_bo_default_swap_lru_tail,
> +};
> +
> +int hibmc_mm_init(struct hibmc_drm_device *hibmc)
> +{
> +       int ret;
> +       struct drm_device *dev = hibmc->dev;
> +       struct ttm_bo_device *bdev = &hibmc->ttm.bdev;
> +
> +       ret = hibmc_ttm_global_init(hibmc);
> +       if (ret)
> +               return ret;
> +
> +       ret = ttm_bo_device_init(&hibmc->ttm.bdev,
> +                                hibmc->ttm.bo_global_ref.ref.object,
> +                                &hibmc_bo_driver,
> +                                dev->anon_inode->i_mapping,
> +                                DRM_FILE_PAGE_OFFSET,
> +                                true);
> +       if (ret) {

Call hibmc_ttm_global_release here?

> +               DRM_ERROR("Error initialising bo driver; %d\n", ret);
> +               return ret;
> +       }
> +
> +       ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
> +                            hibmc->fb_size >> PAGE_SHIFT);
> +       if (ret) {

Clean up here as well?

> +               DRM_ERROR("Failed ttm VRAM init: %d\n", ret);
> +               return ret;
> +       }
> +
> +       hibmc->mm_inited = true;
> +       return 0;
> +}
> +
> +void hibmc_mm_fini(struct hibmc_drm_device *hibmc)
> +{
> +       if (!hibmc->mm_inited)
> +               return;
> +
> +       ttm_bo_device_release(&hibmc->ttm.bdev);
> +       hibmc_ttm_global_release(hibmc);
> +       hibmc->mm_inited = false;
> +}
> +
> +int hibmc_bo_create(struct drm_device *dev, int size, int align,
> +                   u32 flags, struct hibmc_bo **phibmcbo)
> +{
> +       struct hibmc_drm_device *hibmc = dev->dev_private;
> +       struct hibmc_bo *hibmcbo;
> +       size_t acc_size;
> +       int ret;
> +
> +       hibmcbo = kzalloc(sizeof(*hibmcbo), GFP_KERNEL);
> +       if (!hibmcbo)
> +               return -ENOMEM;
> +
> +       ret = drm_gem_object_init(dev, &hibmcbo->gem, size);
> +       if (ret) {
> +               kfree(hibmcbo);
> +               return ret;
> +       }
> +
> +       hibmcbo->bo.bdev = &hibmc->ttm.bdev;
> +
> +       hibmc_ttm_placement(hibmcbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
> +
> +       acc_size = ttm_bo_dma_acc_size(&hibmc->ttm.bdev, size,
> +                                      sizeof(struct hibmc_bo));
> +
> +       ret = ttm_bo_init(&hibmc->ttm.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)

Missing hibmcbo clean up here

> +               return ret;
> +
> +       *phibmcbo = hibmcbo;
> +       return 0;
> +}
> +
> +static inline u64 hibmc_bo_gpu_offset(struct hibmc_bo *bo)
> +{
> +       return bo->bo.offset;
> +}

I don't think this function provides any value

> +
> +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 = hibmc_bo_gpu_offset(bo);

Are you missing a return here?

> +       }
> +
> +       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 = hibmc_bo_gpu_offset(bo);
> +       return 0;
> +}
> +
> +int hibmc_bo_push_sysram(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;
> +
> +       if (bo->kmap.virtual)

ttm_bo_kunmap already does this check so you don't have to

> +               ttm_bo_kunmap(&bo->kmap);
> +
> +       hibmc_ttm_placement(bo, TTM_PL_FLAG_SYSTEM);
> +       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("pushing to VRAM failed\n");

Print ret

> +               return ret;
> +       }
> +       return 0;
> +}
> +
> +int hibmc_mmap(struct file *filp, struct vm_area_struct *vma)
> +{
> +       struct drm_file *file_priv;
> +       struct hibmc_drm_device *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->ttm.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)

Print error

> +               return -EINVAL;
> +
> +       ret = hibmc_bo_create(dev, size, 0, 0, &hibmcbo);
> +       if (ret) {
> +               if (ret != -ERESTARTSYS)
> +                       DRM_ERROR("failed to allocate GEM object\n");

Print 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 * ((args->bpp + 7) / 8), 16);

What's up with the bpp + 7 here? Perhaps you're looking for DIV_ROUND_UP?


> +       args->size = args->pitch * args->height;
> +
> +       ret = hibmc_gem_create(dev, args->size, false,
> +                              &gobj);
> +       if (ret)
> +               return ret;
> +
> +       ret = drm_gem_handle_create(file, gobj, &handle);
> +       drm_gem_object_unreference_unlocked(gobj);
> +       if (ret)

Print error here

> +               return ret;
> +
> +       args->handle = handle;
> +       return 0;
> +}
> +
> +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;
> +}
> +
> +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
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v6 2/9] drm/hisilicon/hibmc: Add video memory management
@ 2016-11-10 17:35     ` Sean Paul
  0 siblings, 0 replies; 64+ messages in thread
From: Sean Paul @ 2016-11-10 17:35 UTC (permalink / raw)
  To: Rongrong Zou
  Cc: Mark Rutland, shenhui, Tomeu Vizoso, Jonathan Corbet,
	catalin.marinas, Emil Velikov, linuxarm, dri-devel, guohanjun,
	Will Deacon, lijianhua, Linux ARM Kernel, james.xiong

On Fri, Oct 28, 2016 at 3:27 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>
> ---
>  drivers/gpu/drm/hisilicon/hibmc/Kconfig         |   1 +
>  drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  12 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |  46 +++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     | 490 ++++++++++++++++++++++++
>  5 files changed, 550 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
> index a9af90d..bcb8c18 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/Kconfig
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
> @@ -1,6 +1,7 @@
>  config DRM_HISI_HIBMC
>         tristate "DRM Support for Hisilicon Hibmc"
>         depends on DRM && PCI
> +       select DRM_TTM
>
>         help
>           Choose this option if you have a Hisilicon Hibmc soc chipset.
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> index 97cf4a0..d5c40b8 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> @@ -1,5 +1,5 @@
>  ccflags-y := -Iinclude/drm
> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o
> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o hibmc_ttm.o
>
>  obj-$(CONFIG_DRM_HISI_HIBMC)   +=hibmc-drm.o
>  #obj-y += 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 4669d42..81f4301 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -31,6 +31,7 @@
>  #ifdef CONFIG_COMPAT
>         .compat_ioctl   = drm_compat_ioctl,
>  #endif
> +       .mmap           = hibmc_mmap,
>         .poll           = drm_poll,
>         .read           = drm_read,
>         .llseek         = no_llseek,
> @@ -46,6 +47,8 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>  }
>
>  static struct drm_driver hibmc_driver = {
> +       .driver_features        = DRIVER_GEM,
> +

nit: extra space

>         .fops                   = &hibmc_fops,
>         .name                   = "hibmc",
>         .date                   = "20160828",
> @@ -55,6 +58,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)
> @@ -163,6 +170,7 @@ static int hibmc_unload(struct drm_device *dev)
>  {
>         struct hibmc_drm_device *hidev = dev->dev_private;
>
> +       hibmc_mm_fini(hidev);
>         hibmc_hw_fini(hidev);
>         dev->dev_private = NULL;
>         return 0;
> @@ -183,6 +191,10 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
>         if (ret)
>                 goto err;
>
> +       ret = hibmc_mm_init(hidev);
> +       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 0037341..db8d80e 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/ttm/ttm_bo_driver.h>
> +#include <drm/drm_gem.h>

nit: alphabetize

>
>  struct hibmc_drm_device {
>         /* hw */
> @@ -30,6 +32,50 @@ struct hibmc_drm_device {
>
>         /* drm */
>         struct drm_device  *dev;
> +
> +       /* ttm */
> +       struct {
> +               struct drm_global_reference mem_global_ref;
> +               struct ttm_bo_global_ref bo_global_ref;
> +               struct ttm_bo_device bdev;
> +               bool initialized;
> +       } ttm;

I don't think you gain anything other than keystrokes from the substruct

> +
> +       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);
> +}
> +
> +#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)

Hide this in ttm.c

> +
> +int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
> +                    struct drm_gem_object **obj);
> +
> +int hibmc_mm_init(struct hibmc_drm_device *hibmc);
> +void hibmc_mm_fini(struct hibmc_drm_device *hibmc);
> +int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr);
> +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..0802ebd
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> @@ -0,0 +1,490 @@
> +/* 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 "hibmc_drm_drv.h"
> +#include <ttm/ttm_page_alloc.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_atomic_helper.h>
> +
> +static inline struct hibmc_drm_device *
> +hibmc_bdev(struct ttm_bo_device *bd)
> +{
> +       return container_of(bd, struct hibmc_drm_device, ttm.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_device *hibmc)
> +{
> +       struct drm_global_reference *global_ref;
> +       int r;

nit: try not to use one character variable names unless it's for the
purpose of a loop (ie: i,j). You also use ret elsewhere in the driver,
so it'd be nice to remain consistent

> +
> +       global_ref = &hibmc->ttm.mem_global_ref;

I think using the global_ref local obfuscates what you're doing here.
It saves you 6 characters while typing, but adds a layer of
indirection for all future readers.

> +       global_ref->global_type = DRM_GLOBAL_TTM_MEM;
> +       global_ref->size = sizeof(struct ttm_mem_global);
> +       global_ref->init = &hibmc_ttm_mem_global_init;
> +       global_ref->release = &hibmc_ttm_mem_global_release;
> +       r = drm_global_item_ref(global_ref);
> +       if (r != 0) {

nit: if (r)

> +               DRM_ERROR("Failed setting up TTM memory accounting subsystem.\n"
> +                        );

Breaking up the line for one character is probably not worthwhile, and
you should really print the error. How about:

DRM_ERROR("Could not get ref on ttm global ret=%d.\n", ret);


> +               return r;
> +       }
> +
> +       hibmc->ttm.bo_global_ref.mem_glob =
> +               hibmc->ttm.mem_global_ref.object;
> +       global_ref = &hibmc->ttm.bo_global_ref.ref;
> +       global_ref->global_type = DRM_GLOBAL_TTM_BO;
> +       global_ref->size = sizeof(struct ttm_bo_global);
> +       global_ref->init = &ttm_bo_global_init;
> +       global_ref->release = &ttm_bo_global_release;
> +       r = drm_global_item_ref(global_ref);
> +       if (r != 0) {
> +               DRM_ERROR("Failed setting up TTM BO subsystem.\n");
> +               drm_global_item_unref(&hibmc->ttm.mem_global_ref);
> +               return r;
> +       }
> +       return 0;
> +}
> +
> +static void
> +hibmc_ttm_global_release(struct hibmc_drm_device *hibmc)
> +{
> +       if (!hibmc->ttm.mem_global_ref.release)

Are you actually hitting this condition? This seems like it's papering
over something else.

> +               return;
> +
> +       drm_global_item_unref(&hibmc->ttm.bo_global_ref.ref);
> +       drm_global_item_unref(&hibmc->ttm.mem_global_ref);
> +       hibmc->ttm.mem_global_ref.release = NULL;
> +}
> +
> +static void hibmc_bo_ttm_destroy(struct ttm_buffer_object *tbo)
> +{
> +       struct hibmc_bo *bo;
> +
> +       bo = container_of(tbo, struct hibmc_bo, bo);

nit: No need to split this into a separate line.

> +
> +       drm_gem_object_release(&bo->gem);
> +       kfree(bo);
> +}
> +
> +static bool hibmc_ttm_bo_is_hibmc_bo(struct ttm_buffer_object *bo)
> +{
> +       if (bo->destroy == &hibmc_bo_ttm_destroy)
> +               return true;
> +       return false;

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 c = 0;

Can you please use a more descriptive name than 'c'?

> +       u32 i;
> +
> +       bo->placement.placement = bo->placements;
> +       bo->placement.busy_placement = bo->placements;
> +       if (domain & TTM_PL_FLAG_VRAM)
> +               bo->placements[c++].flags = TTM_PL_FLAG_WC |
> +               TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;

nit: you're alignment is off here and below

> +       if (domain & TTM_PL_FLAG_SYSTEM)
> +               bo->placements[c++].flags = TTM_PL_MASK_CACHING |
> +               TTM_PL_FLAG_SYSTEM;
> +       if (!c)
> +               bo->placements[c++].flags = TTM_PL_MASK_CACHING |
> +               TTM_PL_FLAG_SYSTEM;
> +
> +       bo->placement.num_placement = c;
> +       bo->placement.num_busy_placement = c;
> +       for (i = 0; i < c; ++i) {

nit: we tend towards post-increment in kernel

> +               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_device *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_io_mem_free(struct ttm_bo_device *bdev,
> +                                 struct ttm_mem_reg *mem)
> +{
> +}

No need to stub this, the caller does a NULL-check before invoking

> +
> +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;
> +
> +       tt = kzalloc(sizeof(*tt), GFP_KERNEL);
> +       if (!tt)

Print error

> +               return NULL;
> +       tt->func = &hibmc_tt_backend_func;
> +       if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) {

Here too?

> +               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            = &hibmc_ttm_io_mem_free,
> +       .lru_tail               = &ttm_bo_default_lru_tail,
> +       .swap_lru_tail          = &ttm_bo_default_swap_lru_tail,
> +};
> +
> +int hibmc_mm_init(struct hibmc_drm_device *hibmc)
> +{
> +       int ret;
> +       struct drm_device *dev = hibmc->dev;
> +       struct ttm_bo_device *bdev = &hibmc->ttm.bdev;
> +
> +       ret = hibmc_ttm_global_init(hibmc);
> +       if (ret)
> +               return ret;
> +
> +       ret = ttm_bo_device_init(&hibmc->ttm.bdev,
> +                                hibmc->ttm.bo_global_ref.ref.object,
> +                                &hibmc_bo_driver,
> +                                dev->anon_inode->i_mapping,
> +                                DRM_FILE_PAGE_OFFSET,
> +                                true);
> +       if (ret) {

Call hibmc_ttm_global_release here?

> +               DRM_ERROR("Error initialising bo driver; %d\n", ret);
> +               return ret;
> +       }
> +
> +       ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
> +                            hibmc->fb_size >> PAGE_SHIFT);
> +       if (ret) {

Clean up here as well?

> +               DRM_ERROR("Failed ttm VRAM init: %d\n", ret);
> +               return ret;
> +       }
> +
> +       hibmc->mm_inited = true;
> +       return 0;
> +}
> +
> +void hibmc_mm_fini(struct hibmc_drm_device *hibmc)
> +{
> +       if (!hibmc->mm_inited)
> +               return;
> +
> +       ttm_bo_device_release(&hibmc->ttm.bdev);
> +       hibmc_ttm_global_release(hibmc);
> +       hibmc->mm_inited = false;
> +}
> +
> +int hibmc_bo_create(struct drm_device *dev, int size, int align,
> +                   u32 flags, struct hibmc_bo **phibmcbo)
> +{
> +       struct hibmc_drm_device *hibmc = dev->dev_private;
> +       struct hibmc_bo *hibmcbo;
> +       size_t acc_size;
> +       int ret;
> +
> +       hibmcbo = kzalloc(sizeof(*hibmcbo), GFP_KERNEL);
> +       if (!hibmcbo)
> +               return -ENOMEM;
> +
> +       ret = drm_gem_object_init(dev, &hibmcbo->gem, size);
> +       if (ret) {
> +               kfree(hibmcbo);
> +               return ret;
> +       }
> +
> +       hibmcbo->bo.bdev = &hibmc->ttm.bdev;
> +
> +       hibmc_ttm_placement(hibmcbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
> +
> +       acc_size = ttm_bo_dma_acc_size(&hibmc->ttm.bdev, size,
> +                                      sizeof(struct hibmc_bo));
> +
> +       ret = ttm_bo_init(&hibmc->ttm.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)

Missing hibmcbo clean up here

> +               return ret;
> +
> +       *phibmcbo = hibmcbo;
> +       return 0;
> +}
> +
> +static inline u64 hibmc_bo_gpu_offset(struct hibmc_bo *bo)
> +{
> +       return bo->bo.offset;
> +}

I don't think this function provides any value

> +
> +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 = hibmc_bo_gpu_offset(bo);

Are you missing a return here?

> +       }
> +
> +       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 = hibmc_bo_gpu_offset(bo);
> +       return 0;
> +}
> +
> +int hibmc_bo_push_sysram(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;
> +
> +       if (bo->kmap.virtual)

ttm_bo_kunmap already does this check so you don't have to

> +               ttm_bo_kunmap(&bo->kmap);
> +
> +       hibmc_ttm_placement(bo, TTM_PL_FLAG_SYSTEM);
> +       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("pushing to VRAM failed\n");

Print ret

> +               return ret;
> +       }
> +       return 0;
> +}
> +
> +int hibmc_mmap(struct file *filp, struct vm_area_struct *vma)
> +{
> +       struct drm_file *file_priv;
> +       struct hibmc_drm_device *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->ttm.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)

Print error

> +               return -EINVAL;
> +
> +       ret = hibmc_bo_create(dev, size, 0, 0, &hibmcbo);
> +       if (ret) {
> +               if (ret != -ERESTARTSYS)
> +                       DRM_ERROR("failed to allocate GEM object\n");

Print 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 * ((args->bpp + 7) / 8), 16);

What's up with the bpp + 7 here? Perhaps you're looking for DIV_ROUND_UP?


> +       args->size = args->pitch * args->height;
> +
> +       ret = hibmc_gem_create(dev, args->size, false,
> +                              &gobj);
> +       if (ret)
> +               return ret;
> +
> +       ret = drm_gem_handle_create(file, gobj, &handle);
> +       drm_gem_object_unreference_unlocked(gobj);
> +       if (ret)

Print error here

> +               return ret;
> +
> +       args->handle = handle;
> +       return 0;
> +}
> +
> +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;
> +}
> +
> +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
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v6 3/9] drm/hisilicon/hibmc: Add support for frame buffer
  2016-10-28  7:27   ` Rongrong Zou
@ 2016-11-10 18:30     ` Sean Paul
  -1 siblings, 0 replies; 64+ messages in thread
From: Sean Paul @ 2016-11-10 18:30 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Oct 28, 2016 at 3:27 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> 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   |  17 ++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   |  24 ++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 255 ++++++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       |  66 ++++++
>  5 files changed, 363 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 d5c40b8..810a37e 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> @@ -1,5 +1,5 @@
>  ccflags-y := -Iinclude/drm
> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o hibmc_ttm.o
> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
>
>  obj-$(CONFIG_DRM_HISI_HIBMC)   +=hibmc-drm.o
>  #obj-y += 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 81f4301..5ac7a7e 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -66,11 +66,23 @@ 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_device *hidev = drm_dev->dev_private;
> +
> +       drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 1);
> +

We have atomic helpers for suspend/resume now. Please use those.

>         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_device *hidev = drm_dev->dev_private;
> +
> +       drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 0);
> +
>         return 0;
>  }
>
> @@ -170,6 +182,7 @@ static int hibmc_unload(struct drm_device *dev)
>  {
>         struct hibmc_drm_device *hidev = dev->dev_private;
>
> +       hibmc_fbdev_fini(hidev);
>         hibmc_mm_fini(hidev);
>         hibmc_hw_fini(hidev);
>         dev->dev_private = NULL;
> @@ -195,6 +208,10 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
>         if (ret)
>                 goto err;
>
> +       ret = hibmc_fbdev_init(hidev);
> +       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 db8d80e..a40e9a7 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -20,9 +20,22 @@
>  #define HIBMC_DRM_DRV_H
>
>  #include <drm/drmP.h>
> +#include <drm/drm_fb_helper.h>
>  #include <drm/ttm/ttm_bo_driver.h>
>  #include <drm/drm_gem.h>
>
> +struct hibmc_framebuffer {
> +       struct drm_framebuffer fb;
> +       struct drm_gem_object *obj;
> +       bool is_fbdev_fb;
> +};
> +
> +struct hibmc_fbdev {
> +       struct drm_fb_helper helper;
> +       struct hibmc_framebuffer *fb;
> +       int size;
> +};
> +
>  struct hibmc_drm_device {
>         /* hw */
>         void __iomem   *mmio;
> @@ -41,9 +54,13 @@ struct hibmc_drm_device {
>                 bool initialized;
>         } ttm;
>
> +       /* 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;
> @@ -65,8 +82,15 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
>
>  #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
>
> +int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
> +void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
> +
>  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_device *hibmc);
>  void hibmc_mm_fini(struct hibmc_drm_device *hibmc);
> 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..630124b
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
> @@ -0,0 +1,255 @@
> +/* 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"
> +
> +/* ---------------------------------------------------------------------- */

Please remove

> +
> +static int hibmcfb_create_object(
> +                               struct hibmc_drm_device *hidev,
> +                               const struct drm_mode_fb_cmd2 *mode_cmd,
> +                               struct drm_gem_object **gobj_p)
> +{
> +       struct drm_gem_object *gobj;
> +       struct drm_device *dev = hidev->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_device *hidev =
> +               (struct hibmc_drm_device *)helper->dev->dev_private;
> +       struct fb_info *info;
> +       struct hibmc_framebuffer *hibmc_fb;
> +       struct drm_framebuffer *fb;
> +       struct drm_mode_fb_cmd2 mode_cmd;
> +       struct drm_gem_object *gobj = NULL;
> +       int ret = 0;
> +       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 = roundup(mode_cmd.pitches[0] * mode_cmd.height, PAGE_SIZE);

It's somewhat curious that you used ALIGN in the previous patch and
roundup here. But anyways, I think PAGE_ALIGN would be the most
appropriate thing to do here.

> +
> +       ret = hibmcfb_create_object(hidev, &mode_cmd, &gobj);
> +       if (ret) {
> +               DRM_ERROR("failed to create fbcon backing object %d\r\n",
ret);

\r, yikes!!!

> +               return -ENOMEM;
> +       }
> +
> +       bo = gem_to_hibmc_bo(gobj);
> +
> +       ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
> +       if (ret)

Print error here?

How about cleaning up gobj?

> +               return ret;
> +
> +       ret = hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL);
> +       if (ret) {
> +               DRM_ERROR("failed to pin fbcon\n");

Print ret

ttm_bo_unreserve? It seems like you're missing clean-up in all of the
error paths in this function. Can you please make sure everything is
tidied up?

> +               return ret;
> +       }
> +
> +       ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
> +

nit: extra space

> +       if (ret) {
> +               DRM_ERROR("failed to kmap fbcon\n");

Print ret

> +               ttm_bo_unreserve(&bo->bo);
> +               return ret;
> +       }
> +
> +       ttm_bo_unreserve(&bo->bo);

Move this between ttm_bo_kmap and if (ret), then remove it from inside
the conditional.

> +
> +       info = drm_fb_helper_alloc_fbi(helper);
> +       if (IS_ERR(info))

Print error

> +               return PTR_ERR(info);
> +
> +       info->par = hi_fbdev;
> +
> +       hibmc_fb = hibmc_framebuffer_init(hidev->dev, &mode_cmd, gobj);
> +       if (IS_ERR(hibmc_fb)) {
> +               drm_fb_helper_release_fbi(helper);
> +               return PTR_ERR(hibmc_fb);
> +       }
> +
> +       hi_fbdev->fb = hibmc_fb;
> +       hidev->fbdev->size = size;
> +       fb = &hibmc_fb->fb;

The fb variable isn't necessary, and really, the hibmc_fb doesn't
really help either, it just masks what's actually happening IMO.

> +       if (!fb) {
> +               DRM_INFO("fb is NULL\n");
> +               return -EINVAL;
> +       }
> +
> +       hi_fbdev->helper.fb = fb;
> +
> +       strcpy(info->fix.id, "hibmcdrmfb");
> +
> +       info->flags = FBINFO_DEFAULT;
> +       info->fbops = &hibmc_drm_fb_ops;
> +
> +       drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
> +       drm_fb_helper_fill_var(info, &hidev->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;
> +}
> +
> +static void hibmc_fbdev_destroy(struct hibmc_fbdev *fbdev)
> +{
> +       struct hibmc_framebuffer *gfb = fbdev->fb;
> +       struct drm_fb_helper *fbh = &fbdev->helper;
> +
> +       DRM_DEBUG_DRIVER("hibmc_fbdev_destroy\n");

Not useful

> +
> +       drm_fb_helper_unregister_fbi(fbh);
> +       drm_fb_helper_release_fbi(fbh);
> +
> +       drm_fb_helper_fini(fbh);
> +
> +       if (gfb)
> +               drm_framebuffer_unreference(&gfb->fb);
> +
> +       kfree(fbdev);
> +}
> +
> +static const struct drm_fb_helper_funcs hibmc_fbdev_helper_funcs = {
> +       .fb_probe = hibmc_drm_fb_create,
> +};
> +
> +int hibmc_fbdev_init(struct hibmc_drm_device *hidev)
> +{
> +       int ret;
> +       struct fb_var_screeninfo *var;
> +       struct fb_fix_screeninfo *fix;
> +       struct hibmc_fbdev *hifbdev;
> +
> +       hifbdev = kzalloc(sizeof(*hifbdev), GFP_KERNEL);

devm_kzalloc?

> +       if (!hifbdev)
> +               return -ENOMEM;
> +
> +       hidev->fbdev = hifbdev;
> +       drm_fb_helper_prepare(hidev->dev, &hifbdev->helper,
> +                             &hibmc_fbdev_helper_funcs);
> +
> +       /* Now just one crtc and one channel */
> +       ret = drm_fb_helper_init(hidev->dev,
> +                                &hifbdev->helper, 1, 1);
> +

nit: extra line

> +       if (ret)
> +               return ret;
> +
> +       ret = drm_fb_helper_single_add_all_connectors(&hifbdev->helper);
> +       if (ret)
> +               goto fini;
> +
> +       ret = drm_fb_helper_initial_config(&hifbdev->helper, 16);
> +       if (ret)
> +               goto fini;
> +
> +       var = &hifbdev->helper.fbdev->var;
> +       fix = &hifbdev->helper.fbdev->fix;
> +
> +       DRM_DEBUG("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("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);

You've been using DRM_DEBUG_DRIVER elsewhere, you should probably use
it here, too.

> +
> +       return 0;
> +
> +fini:
> +       drm_fb_helper_fini(&hifbdev->helper);
> +       return ret;
> +}
> +
> +void hibmc_fbdev_fini(struct hibmc_drm_device *hidev)
> +{
> +       if (!hidev->fbdev)
> +               return;
> +
> +       hibmc_fbdev_destroy(hidev->fbdev);
> +       hidev->fbdev = NULL;
> +}
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> index 0802ebd..9822f62 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> @@ -488,3 +488,69 @@ int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
>         drm_gem_object_unreference_unlocked(obj);
>         return 0;
>  }
> +
> +/* ---------------------------------------------------------------------- */
> +

Please remove

> +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)

Print error

> +               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
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v6 3/9] drm/hisilicon/hibmc: Add support for frame buffer
@ 2016-11-10 18:30     ` Sean Paul
  0 siblings, 0 replies; 64+ messages in thread
From: Sean Paul @ 2016-11-10 18:30 UTC (permalink / raw)
  To: Rongrong Zou
  Cc: Mark Rutland, shenhui, Tomeu Vizoso, Jonathan Corbet,
	catalin.marinas, Emil Velikov, linuxarm, dri-devel, guohanjun,
	Will Deacon, lijianhua, Linux ARM Kernel, james.xiong

On Fri, Oct 28, 2016 at 3:27 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> 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   |  17 ++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   |  24 ++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 255 ++++++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       |  66 ++++++
>  5 files changed, 363 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 d5c40b8..810a37e 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> @@ -1,5 +1,5 @@
>  ccflags-y := -Iinclude/drm
> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o hibmc_ttm.o
> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
>
>  obj-$(CONFIG_DRM_HISI_HIBMC)   +=hibmc-drm.o
>  #obj-y += 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 81f4301..5ac7a7e 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -66,11 +66,23 @@ 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_device *hidev = drm_dev->dev_private;
> +
> +       drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 1);
> +

We have atomic helpers for suspend/resume now. Please use those.

>         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_device *hidev = drm_dev->dev_private;
> +
> +       drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 0);
> +
>         return 0;
>  }
>
> @@ -170,6 +182,7 @@ static int hibmc_unload(struct drm_device *dev)
>  {
>         struct hibmc_drm_device *hidev = dev->dev_private;
>
> +       hibmc_fbdev_fini(hidev);
>         hibmc_mm_fini(hidev);
>         hibmc_hw_fini(hidev);
>         dev->dev_private = NULL;
> @@ -195,6 +208,10 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
>         if (ret)
>                 goto err;
>
> +       ret = hibmc_fbdev_init(hidev);
> +       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 db8d80e..a40e9a7 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -20,9 +20,22 @@
>  #define HIBMC_DRM_DRV_H
>
>  #include <drm/drmP.h>
> +#include <drm/drm_fb_helper.h>
>  #include <drm/ttm/ttm_bo_driver.h>
>  #include <drm/drm_gem.h>
>
> +struct hibmc_framebuffer {
> +       struct drm_framebuffer fb;
> +       struct drm_gem_object *obj;
> +       bool is_fbdev_fb;
> +};
> +
> +struct hibmc_fbdev {
> +       struct drm_fb_helper helper;
> +       struct hibmc_framebuffer *fb;
> +       int size;
> +};
> +
>  struct hibmc_drm_device {
>         /* hw */
>         void __iomem   *mmio;
> @@ -41,9 +54,13 @@ struct hibmc_drm_device {
>                 bool initialized;
>         } ttm;
>
> +       /* 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;
> @@ -65,8 +82,15 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
>
>  #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
>
> +int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
> +void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
> +
>  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_device *hibmc);
>  void hibmc_mm_fini(struct hibmc_drm_device *hibmc);
> 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..630124b
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
> @@ -0,0 +1,255 @@
> +/* 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"
> +
> +/* ---------------------------------------------------------------------- */

Please remove

> +
> +static int hibmcfb_create_object(
> +                               struct hibmc_drm_device *hidev,
> +                               const struct drm_mode_fb_cmd2 *mode_cmd,
> +                               struct drm_gem_object **gobj_p)
> +{
> +       struct drm_gem_object *gobj;
> +       struct drm_device *dev = hidev->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_device *hidev =
> +               (struct hibmc_drm_device *)helper->dev->dev_private;
> +       struct fb_info *info;
> +       struct hibmc_framebuffer *hibmc_fb;
> +       struct drm_framebuffer *fb;
> +       struct drm_mode_fb_cmd2 mode_cmd;
> +       struct drm_gem_object *gobj = NULL;
> +       int ret = 0;
> +       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 = roundup(mode_cmd.pitches[0] * mode_cmd.height, PAGE_SIZE);

It's somewhat curious that you used ALIGN in the previous patch and
roundup here. But anyways, I think PAGE_ALIGN would be the most
appropriate thing to do here.

> +
> +       ret = hibmcfb_create_object(hidev, &mode_cmd, &gobj);
> +       if (ret) {
> +               DRM_ERROR("failed to create fbcon backing object %d\r\n",
ret);

\r, yikes!!!

> +               return -ENOMEM;
> +       }
> +
> +       bo = gem_to_hibmc_bo(gobj);
> +
> +       ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
> +       if (ret)

Print error here?

How about cleaning up gobj?

> +               return ret;
> +
> +       ret = hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL);
> +       if (ret) {
> +               DRM_ERROR("failed to pin fbcon\n");

Print ret

ttm_bo_unreserve? It seems like you're missing clean-up in all of the
error paths in this function. Can you please make sure everything is
tidied up?

> +               return ret;
> +       }
> +
> +       ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
> +

nit: extra space

> +       if (ret) {
> +               DRM_ERROR("failed to kmap fbcon\n");

Print ret

> +               ttm_bo_unreserve(&bo->bo);
> +               return ret;
> +       }
> +
> +       ttm_bo_unreserve(&bo->bo);

Move this between ttm_bo_kmap and if (ret), then remove it from inside
the conditional.

> +
> +       info = drm_fb_helper_alloc_fbi(helper);
> +       if (IS_ERR(info))

Print error

> +               return PTR_ERR(info);
> +
> +       info->par = hi_fbdev;
> +
> +       hibmc_fb = hibmc_framebuffer_init(hidev->dev, &mode_cmd, gobj);
> +       if (IS_ERR(hibmc_fb)) {
> +               drm_fb_helper_release_fbi(helper);
> +               return PTR_ERR(hibmc_fb);
> +       }
> +
> +       hi_fbdev->fb = hibmc_fb;
> +       hidev->fbdev->size = size;
> +       fb = &hibmc_fb->fb;

The fb variable isn't necessary, and really, the hibmc_fb doesn't
really help either, it just masks what's actually happening IMO.

> +       if (!fb) {
> +               DRM_INFO("fb is NULL\n");
> +               return -EINVAL;
> +       }
> +
> +       hi_fbdev->helper.fb = fb;
> +
> +       strcpy(info->fix.id, "hibmcdrmfb");
> +
> +       info->flags = FBINFO_DEFAULT;
> +       info->fbops = &hibmc_drm_fb_ops;
> +
> +       drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
> +       drm_fb_helper_fill_var(info, &hidev->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;
> +}
> +
> +static void hibmc_fbdev_destroy(struct hibmc_fbdev *fbdev)
> +{
> +       struct hibmc_framebuffer *gfb = fbdev->fb;
> +       struct drm_fb_helper *fbh = &fbdev->helper;
> +
> +       DRM_DEBUG_DRIVER("hibmc_fbdev_destroy\n");

Not useful

> +
> +       drm_fb_helper_unregister_fbi(fbh);
> +       drm_fb_helper_release_fbi(fbh);
> +
> +       drm_fb_helper_fini(fbh);
> +
> +       if (gfb)
> +               drm_framebuffer_unreference(&gfb->fb);
> +
> +       kfree(fbdev);
> +}
> +
> +static const struct drm_fb_helper_funcs hibmc_fbdev_helper_funcs = {
> +       .fb_probe = hibmc_drm_fb_create,
> +};
> +
> +int hibmc_fbdev_init(struct hibmc_drm_device *hidev)
> +{
> +       int ret;
> +       struct fb_var_screeninfo *var;
> +       struct fb_fix_screeninfo *fix;
> +       struct hibmc_fbdev *hifbdev;
> +
> +       hifbdev = kzalloc(sizeof(*hifbdev), GFP_KERNEL);

devm_kzalloc?

> +       if (!hifbdev)
> +               return -ENOMEM;
> +
> +       hidev->fbdev = hifbdev;
> +       drm_fb_helper_prepare(hidev->dev, &hifbdev->helper,
> +                             &hibmc_fbdev_helper_funcs);
> +
> +       /* Now just one crtc and one channel */
> +       ret = drm_fb_helper_init(hidev->dev,
> +                                &hifbdev->helper, 1, 1);
> +

nit: extra line

> +       if (ret)
> +               return ret;
> +
> +       ret = drm_fb_helper_single_add_all_connectors(&hifbdev->helper);
> +       if (ret)
> +               goto fini;
> +
> +       ret = drm_fb_helper_initial_config(&hifbdev->helper, 16);
> +       if (ret)
> +               goto fini;
> +
> +       var = &hifbdev->helper.fbdev->var;
> +       fix = &hifbdev->helper.fbdev->fix;
> +
> +       DRM_DEBUG("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("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);

You've been using DRM_DEBUG_DRIVER elsewhere, you should probably use
it here, too.

> +
> +       return 0;
> +
> +fini:
> +       drm_fb_helper_fini(&hifbdev->helper);
> +       return ret;
> +}
> +
> +void hibmc_fbdev_fini(struct hibmc_drm_device *hidev)
> +{
> +       if (!hidev->fbdev)
> +               return;
> +
> +       hibmc_fbdev_destroy(hidev->fbdev);
> +       hidev->fbdev = NULL;
> +}
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> index 0802ebd..9822f62 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> @@ -488,3 +488,69 @@ int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
>         drm_gem_object_unreference_unlocked(obj);
>         return 0;
>  }
> +
> +/* ---------------------------------------------------------------------- */
> +

Please remove

> +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)

Print error

> +               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
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v6 4/9] drm/hisilicon/hibmc: Add plane for DE
  2016-10-28  7:27   ` Rongrong Zou
@ 2016-11-10 21:53     ` Sean Paul
  -1 siblings, 0 replies; 64+ messages in thread
From: Sean Paul @ 2016-11-10 21:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Oct 28, 2016 at 3:27 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Add plane funcs and helper funcs for DE.
>
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
> ---
>  drivers/gpu/drm/hisilicon/hibmc/Kconfig         |   1 +
>  drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c  | 170 ++++++++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h  |  29 ++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  51 ++++++-
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |   5 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     |   6 +
>  7 files changed, 261 insertions(+), 3 deletions(-)
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
> index bcb8c18..380622a 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/Kconfig
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
> @@ -1,6 +1,7 @@
>  config DRM_HISI_HIBMC
>         tristate "DRM Support for Hisilicon Hibmc"
>         depends on DRM && PCI
> +       select DRM_KMS_HELPER
>         select DRM_TTM
>
>         help
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> index 810a37e..72e107e 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> @@ -1,5 +1,5 @@
>  ccflags-y := -Iinclude/drm
> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
>
>  obj-$(CONFIG_DRM_HISI_HIBMC)   +=hibmc-drm.o
>  #obj-y += 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..9c1a68c
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
> @@ -0,0 +1,170 @@
> +/* 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"
> +#include "hibmc_drm_power.h"
> +
> +/* ---------------------------------------------------------------------- */

Remove

> +
> +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_x = state->src_x >> 16;
> +       u32 src_y = state->src_y >> 16;
> +       u32 src_w = state->src_w >> 16;
> +       u32 src_h = state->src_h >> 16;
> +       int crtc_x = state->crtc_x;
> +       int crtc_y = state->crtc_y;
> +       u32 crtc_w = state->crtc_w;
> +       u32 crtc_h = state->crtc_h;

I don't think you gain anything with the crtc_* vars

> +
> +       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 != crtc_w || src_h != crtc_h) {
> +               DRM_ERROR("Scale not support!!!\n");

I like the enthusiasm, but I think DRM_DEBUG_ATOMIC would be better

> +               return -EINVAL;
> +       }
> +
> +       if (src_x + src_w > fb->width ||
> +           src_y + src_h > fb->height)

These should be already covered in drm_atomic_plane_check

> +               return -EINVAL;
> +
> +       if (crtc_x < 0 || crtc_y < 0)

Print DRM_DEBUG_ATOMIC message here

> +               return -EINVAL;
> +
> +       if (crtc_x + crtc_w > crtc_state->adjusted_mode.hdisplay ||
> +           crtc_y + crtc_h > crtc_state->adjusted_mode.vdisplay)

DRM_DEBUG_ATOMIC here too

> +               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_device *hidev =
> +               (struct hibmc_drm_device *)plane->dev->dev_private;
> +

nit: extra line

> +       struct hibmc_framebuffer *hibmc_fb;
> +       struct hibmc_bo *bo;
> +
> +       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)

Print error

> +               return;
> +
> +       hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);

Check return value

> +       if (ret) {
> +               ttm_bo_unreserve(&bo->bo);
> +               return;
> +       }
> +
> +       ttm_bo_unreserve(&bo->bo);

Move this up before the conditional so you don't have to call it in
both branches

> +
> +       writel(gpu_addr, hidev->mmio + HIBMC_CRT_FB_ADDRESS);
> +
> +       reg = state->fb->width * (state->fb->bits_per_pixel >> 3);
> +       /* now line_pad is 16 */
> +       reg = PADDING(16, reg);
> +
> +       line_l = state->fb->width * state->fb->bits_per_pixel / 8;

above, you >> 3. here you / 8, pick one?

> +       line_l = PADDING(16, line_l);
> +       writel((HIBMC_CRT_FB_WIDTH_WIDTH(reg) & HIBMC_CRT_FB_WIDTH_WIDTH_MASK) |
> +              (HIBMC_CRT_FB_WIDTH_OFFS(line_l) & HIBMC_CRT_FB_WIDTH_OFFS_MASK),
> +              hidev->mmio + HIBMC_CRT_FB_WIDTH);
> +
> +       /* SET PIXEL FORMAT */
> +       reg = readl(hidev->mmio + HIBMC_CRT_DISP_CTL);
> +       reg = reg & ~HIBMC_CRT_DISP_CTL_FORMAT_MASK;
> +       reg = reg | (HIBMC_CRT_DISP_CTL_FORMAT(state->fb->bits_per_pixel >> 4) &
> +                    HIBMC_CRT_DISP_CTL_FORMAT_MASK);
> +       writel(reg, hidev->mmio + HIBMC_CRT_DISP_CTL);
> +}
> +
> +static void hibmc_plane_atomic_disable(struct drm_plane *plane,
> +                                      struct drm_plane_state *old_state)
> +{
> +}

The caller checks for NULL, no need to stub

> +
> +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,
> +       .atomic_disable = hibmc_plane_atomic_disable,
> +};
> +
> +int hibmc_plane_init(struct hibmc_drm_device *hidev)
> +{
> +       struct drm_device *dev = hidev->dev;
> +       struct drm_plane *plane = &hidev->plane;
> +       int ret = 0;
> +
> +       /*
> +        * 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("fail to init plane!!!\n");
> +               return ret;
> +       }
> +
> +       drm_plane_helper_add(plane, &hibmc_plane_helper_funcs);
> +       return 0;
> +}
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
> new file mode 100644
> index 0000000..4ce0d7b
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
> @@ -0,0 +1,29 @@
> +/* 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_DE_H
> +#define HIBMC_DRM_DE_H
> +
> +struct panel_pll {
> +       unsigned long M;
> +       unsigned long N;
> +       unsigned long OD;
> +       unsigned long POD;
> +};
> +
> +#endif
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> index 5ac7a7e..7d96583 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -18,6 +18,7 @@
>
>  #include <linux/module.h>
>  #include <linux/console.h>
> +#include <drm/drm_crtc_helper.h>
>
>  #include "hibmc_drm_drv.h"
>  #include "hibmc_drm_regs.h"
> @@ -47,8 +48,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",
> @@ -70,6 +71,7 @@ static int hibmc_pm_suspend(struct device *dev)
>         struct drm_device *drm_dev = pci_get_drvdata(pdev);
>         struct hibmc_drm_device *hidev = drm_dev->dev_private;
>
> +       drm_kms_helper_poll_disable(drm_dev);
>         drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 1);
>
>         return 0;
> @@ -81,7 +83,9 @@ static int hibmc_pm_resume(struct device *dev)
>         struct drm_device *drm_dev = pci_get_drvdata(pdev);
>         struct hibmc_drm_device *hidev = drm_dev->dev_private;
>
> +       drm_helper_resume_force_mode(drm_dev);
>         drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 0);
> +       drm_kms_helper_poll_enable(drm_dev);
>
>         return 0;
>  }
> @@ -91,6 +95,41 @@ static int hibmc_pm_resume(struct device *dev)
>                                 hibmc_pm_resume)
>  };
>
> +static int hibmc_kms_init(struct hibmc_drm_device *hidev)
> +{
> +       int ret;
> +
> +       drm_mode_config_init(hidev->dev);
> +       hidev->mode_config_initialized = true;
> +
> +       hidev->dev->mode_config.min_width = 0;
> +       hidev->dev->mode_config.min_height = 0;
> +       hidev->dev->mode_config.max_width = 1920;
> +       hidev->dev->mode_config.max_height = 1440;
> +
> +       hidev->dev->mode_config.fb_base = hidev->fb_base;
> +       hidev->dev->mode_config.preferred_depth = 24;
> +       hidev->dev->mode_config.prefer_shadow = 0;
> +
> +       hidev->dev->mode_config.funcs = (void *)&hibmc_mode_funcs;
> +
> +       ret = hibmc_plane_init(hidev);
> +       if (ret) {
> +               DRM_ERROR("fail to init plane!!!\n");
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +static void hibmc_kms_fini(struct hibmc_drm_device *hidev)
> +{
> +       if (hidev->mode_config_initialized) {
> +               drm_mode_config_cleanup(hidev->dev);
> +               hidev->mode_config_initialized = false;
> +       }
> +}
> +
>  static int hibmc_hw_config(struct hibmc_drm_device *hidev)
>  {
>         unsigned int reg;
> @@ -183,6 +222,7 @@ static int hibmc_unload(struct drm_device *dev)
>         struct hibmc_drm_device *hidev = dev->dev_private;
>
>         hibmc_fbdev_fini(hidev);
> +       hibmc_kms_fini(hidev);
>         hibmc_mm_fini(hidev);
>         hibmc_hw_fini(hidev);
>         dev->dev_private = NULL;
> @@ -208,6 +248,13 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
>         if (ret)
>                 goto err;
>
> +       ret = hibmc_kms_init(hidev);
> +       if (ret)
> +               goto err;
> +
> +       /* reset all the states of crtc/plane/encoder/connector */
> +       drm_mode_config_reset(dev);
> +
>         ret = hibmc_fbdev_init(hidev);
>         if (ret)
>                 goto err;
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> index a40e9a7..49e39d2 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -45,6 +45,8 @@ struct hibmc_drm_device {
>
>         /* drm */
>         struct drm_device  *dev;
> +       struct drm_plane plane;
> +       bool mode_config_initialized;
>
>         /* ttm */
>         struct {
> @@ -82,6 +84,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
>
>  #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
>
> +int hibmc_plane_init(struct hibmc_drm_device *hidev);
>  int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
>  void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
>
> @@ -102,4 +105,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 9822f62..beb4d76 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> @@ -554,3 +554,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
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v6 4/9] drm/hisilicon/hibmc: Add plane for DE
@ 2016-11-10 21:53     ` Sean Paul
  0 siblings, 0 replies; 64+ messages in thread
From: Sean Paul @ 2016-11-10 21:53 UTC (permalink / raw)
  To: Rongrong Zou
  Cc: Mark Rutland, shenhui, Tomeu Vizoso, Jonathan Corbet,
	catalin.marinas, Emil Velikov, linuxarm, dri-devel, guohanjun,
	Will Deacon, lijianhua, Linux ARM Kernel, james.xiong

On Fri, Oct 28, 2016 at 3:27 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Add plane funcs and helper funcs for DE.
>
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
> ---
>  drivers/gpu/drm/hisilicon/hibmc/Kconfig         |   1 +
>  drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c  | 170 ++++++++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h  |  29 ++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  51 ++++++-
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |   5 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     |   6 +
>  7 files changed, 261 insertions(+), 3 deletions(-)
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
> index bcb8c18..380622a 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/Kconfig
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
> @@ -1,6 +1,7 @@
>  config DRM_HISI_HIBMC
>         tristate "DRM Support for Hisilicon Hibmc"
>         depends on DRM && PCI
> +       select DRM_KMS_HELPER
>         select DRM_TTM
>
>         help
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> index 810a37e..72e107e 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> @@ -1,5 +1,5 @@
>  ccflags-y := -Iinclude/drm
> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
>
>  obj-$(CONFIG_DRM_HISI_HIBMC)   +=hibmc-drm.o
>  #obj-y += 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..9c1a68c
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
> @@ -0,0 +1,170 @@
> +/* 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"
> +#include "hibmc_drm_power.h"
> +
> +/* ---------------------------------------------------------------------- */

Remove

> +
> +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_x = state->src_x >> 16;
> +       u32 src_y = state->src_y >> 16;
> +       u32 src_w = state->src_w >> 16;
> +       u32 src_h = state->src_h >> 16;
> +       int crtc_x = state->crtc_x;
> +       int crtc_y = state->crtc_y;
> +       u32 crtc_w = state->crtc_w;
> +       u32 crtc_h = state->crtc_h;

I don't think you gain anything with the crtc_* vars

> +
> +       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 != crtc_w || src_h != crtc_h) {
> +               DRM_ERROR("Scale not support!!!\n");

I like the enthusiasm, but I think DRM_DEBUG_ATOMIC would be better

> +               return -EINVAL;
> +       }
> +
> +       if (src_x + src_w > fb->width ||
> +           src_y + src_h > fb->height)

These should be already covered in drm_atomic_plane_check

> +               return -EINVAL;
> +
> +       if (crtc_x < 0 || crtc_y < 0)

Print DRM_DEBUG_ATOMIC message here

> +               return -EINVAL;
> +
> +       if (crtc_x + crtc_w > crtc_state->adjusted_mode.hdisplay ||
> +           crtc_y + crtc_h > crtc_state->adjusted_mode.vdisplay)

DRM_DEBUG_ATOMIC here too

> +               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_device *hidev =
> +               (struct hibmc_drm_device *)plane->dev->dev_private;
> +

nit: extra line

> +       struct hibmc_framebuffer *hibmc_fb;
> +       struct hibmc_bo *bo;
> +
> +       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)

Print error

> +               return;
> +
> +       hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);

Check return value

> +       if (ret) {
> +               ttm_bo_unreserve(&bo->bo);
> +               return;
> +       }
> +
> +       ttm_bo_unreserve(&bo->bo);

Move this up before the conditional so you don't have to call it in
both branches

> +
> +       writel(gpu_addr, hidev->mmio + HIBMC_CRT_FB_ADDRESS);
> +
> +       reg = state->fb->width * (state->fb->bits_per_pixel >> 3);
> +       /* now line_pad is 16 */
> +       reg = PADDING(16, reg);
> +
> +       line_l = state->fb->width * state->fb->bits_per_pixel / 8;

above, you >> 3. here you / 8, pick one?

> +       line_l = PADDING(16, line_l);
> +       writel((HIBMC_CRT_FB_WIDTH_WIDTH(reg) & HIBMC_CRT_FB_WIDTH_WIDTH_MASK) |
> +              (HIBMC_CRT_FB_WIDTH_OFFS(line_l) & HIBMC_CRT_FB_WIDTH_OFFS_MASK),
> +              hidev->mmio + HIBMC_CRT_FB_WIDTH);
> +
> +       /* SET PIXEL FORMAT */
> +       reg = readl(hidev->mmio + HIBMC_CRT_DISP_CTL);
> +       reg = reg & ~HIBMC_CRT_DISP_CTL_FORMAT_MASK;
> +       reg = reg | (HIBMC_CRT_DISP_CTL_FORMAT(state->fb->bits_per_pixel >> 4) &
> +                    HIBMC_CRT_DISP_CTL_FORMAT_MASK);
> +       writel(reg, hidev->mmio + HIBMC_CRT_DISP_CTL);
> +}
> +
> +static void hibmc_plane_atomic_disable(struct drm_plane *plane,
> +                                      struct drm_plane_state *old_state)
> +{
> +}

The caller checks for NULL, no need to stub

> +
> +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,
> +       .atomic_disable = hibmc_plane_atomic_disable,
> +};
> +
> +int hibmc_plane_init(struct hibmc_drm_device *hidev)
> +{
> +       struct drm_device *dev = hidev->dev;
> +       struct drm_plane *plane = &hidev->plane;
> +       int ret = 0;
> +
> +       /*
> +        * 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("fail to init plane!!!\n");
> +               return ret;
> +       }
> +
> +       drm_plane_helper_add(plane, &hibmc_plane_helper_funcs);
> +       return 0;
> +}
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
> new file mode 100644
> index 0000000..4ce0d7b
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
> @@ -0,0 +1,29 @@
> +/* 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_DE_H
> +#define HIBMC_DRM_DE_H
> +
> +struct panel_pll {
> +       unsigned long M;
> +       unsigned long N;
> +       unsigned long OD;
> +       unsigned long POD;
> +};
> +
> +#endif
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> index 5ac7a7e..7d96583 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -18,6 +18,7 @@
>
>  #include <linux/module.h>
>  #include <linux/console.h>
> +#include <drm/drm_crtc_helper.h>
>
>  #include "hibmc_drm_drv.h"
>  #include "hibmc_drm_regs.h"
> @@ -47,8 +48,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",
> @@ -70,6 +71,7 @@ static int hibmc_pm_suspend(struct device *dev)
>         struct drm_device *drm_dev = pci_get_drvdata(pdev);
>         struct hibmc_drm_device *hidev = drm_dev->dev_private;
>
> +       drm_kms_helper_poll_disable(drm_dev);
>         drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 1);
>
>         return 0;
> @@ -81,7 +83,9 @@ static int hibmc_pm_resume(struct device *dev)
>         struct drm_device *drm_dev = pci_get_drvdata(pdev);
>         struct hibmc_drm_device *hidev = drm_dev->dev_private;
>
> +       drm_helper_resume_force_mode(drm_dev);
>         drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 0);
> +       drm_kms_helper_poll_enable(drm_dev);
>
>         return 0;
>  }
> @@ -91,6 +95,41 @@ static int hibmc_pm_resume(struct device *dev)
>                                 hibmc_pm_resume)
>  };
>
> +static int hibmc_kms_init(struct hibmc_drm_device *hidev)
> +{
> +       int ret;
> +
> +       drm_mode_config_init(hidev->dev);
> +       hidev->mode_config_initialized = true;
> +
> +       hidev->dev->mode_config.min_width = 0;
> +       hidev->dev->mode_config.min_height = 0;
> +       hidev->dev->mode_config.max_width = 1920;
> +       hidev->dev->mode_config.max_height = 1440;
> +
> +       hidev->dev->mode_config.fb_base = hidev->fb_base;
> +       hidev->dev->mode_config.preferred_depth = 24;
> +       hidev->dev->mode_config.prefer_shadow = 0;
> +
> +       hidev->dev->mode_config.funcs = (void *)&hibmc_mode_funcs;
> +
> +       ret = hibmc_plane_init(hidev);
> +       if (ret) {
> +               DRM_ERROR("fail to init plane!!!\n");
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +static void hibmc_kms_fini(struct hibmc_drm_device *hidev)
> +{
> +       if (hidev->mode_config_initialized) {
> +               drm_mode_config_cleanup(hidev->dev);
> +               hidev->mode_config_initialized = false;
> +       }
> +}
> +
>  static int hibmc_hw_config(struct hibmc_drm_device *hidev)
>  {
>         unsigned int reg;
> @@ -183,6 +222,7 @@ static int hibmc_unload(struct drm_device *dev)
>         struct hibmc_drm_device *hidev = dev->dev_private;
>
>         hibmc_fbdev_fini(hidev);
> +       hibmc_kms_fini(hidev);
>         hibmc_mm_fini(hidev);
>         hibmc_hw_fini(hidev);
>         dev->dev_private = NULL;
> @@ -208,6 +248,13 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
>         if (ret)
>                 goto err;
>
> +       ret = hibmc_kms_init(hidev);
> +       if (ret)
> +               goto err;
> +
> +       /* reset all the states of crtc/plane/encoder/connector */
> +       drm_mode_config_reset(dev);
> +
>         ret = hibmc_fbdev_init(hidev);
>         if (ret)
>                 goto err;
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> index a40e9a7..49e39d2 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -45,6 +45,8 @@ struct hibmc_drm_device {
>
>         /* drm */
>         struct drm_device  *dev;
> +       struct drm_plane plane;
> +       bool mode_config_initialized;
>
>         /* ttm */
>         struct {
> @@ -82,6 +84,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
>
>  #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
>
> +int hibmc_plane_init(struct hibmc_drm_device *hidev);
>  int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
>  void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
>
> @@ -102,4 +105,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 9822f62..beb4d76 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
> @@ -554,3 +554,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
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v6 5/9] drm/hisilicon/hibmc: Add crtc for DE
  2016-10-28  7:27   ` Rongrong Zou
@ 2016-11-10 22:14     ` Sean Paul
  -1 siblings, 0 replies; 64+ messages in thread
From: Sean Paul @ 2016-11-10 22:14 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Oct 28, 2016 at 3:27 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Add crtc funcs and helper funcs for DE.
>
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
> ---
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c  | 318 ++++++++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |   6 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |   2 +
>  3 files changed, 326 insertions(+)
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
> index 9c1a68c..9b5d0d0 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
> @@ -23,6 +23,7 @@
>
>  #include "hibmc_drm_drv.h"
>  #include "hibmc_drm_regs.h"
> +#include "hibmc_drm_de.h"
>  #include "hibmc_drm_power.h"

nit: alphabetize

>
>  /* ---------------------------------------------------------------------- */

Remove

> @@ -168,3 +169,320 @@ int hibmc_plane_init(struct hibmc_drm_device *hidev)
>         drm_plane_helper_add(plane, &hibmc_plane_helper_funcs);
>         return 0;
>  }
> +
> +static void hibmc_crtc_enable(struct drm_crtc *crtc)
> +{
> +       unsigned int reg;
> +       /* power mode 0 is default. */

This comment seems to be in the wrong place

> +       struct hibmc_drm_device *hidev = crtc->dev->dev_private;
> +
> +       hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_MODE0);
> +
> +       /* Enable display power gate & LOCALMEM power gate*/
> +       reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
> +       reg |= HIBMC_CURR_GATE_LOCALMEM(ON);
> +       reg |= HIBMC_CURR_GATE_DISPLAY(ON);
> +       hibmc_set_current_gate(hidev, reg);
> +       drm_crtc_vblank_on(crtc);
> +}
> +
> +static void hibmc_crtc_disable(struct drm_crtc *crtc)
> +{
> +       unsigned int reg;
> +       struct hibmc_drm_device *hidev = crtc->dev->dev_private;
> +
> +       drm_crtc_vblank_off(crtc);
> +
> +       hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_SLEEP);
> +
> +       /* Enable display power gate & LOCALMEM power gate*/
> +       reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
> +       reg |= HIBMC_CURR_GATE_LOCALMEM(OFF);
> +       reg |= HIBMC_CURR_GATE_DISPLAY(OFF);
> +       hibmc_set_current_gate(hidev, reg);
> +}
> +
> +static int hibmc_crtc_atomic_check(struct drm_crtc *crtc,
> +                                  struct drm_crtc_state *state)
> +{
> +       return 0;
> +}

Caller NULL-checks, no need for stub

> +
> +static unsigned int format_pll_reg(void)
> +{
> +       unsigned int pllreg = 0;
> +       struct 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_PLL_CTRL_BYPASS(OFF) & HIBMC_PLL_CTRL_BYPASS_MASK;
> +       pllreg |= HIBMC_PLL_CTRL_POWER(ON) & HIBMC_PLL_CTRL_POWER_MASK;
> +       pllreg |= HIBMC_PLL_CTRL_INPUT(OSC) & HIBMC_PLL_CTRL_INPUT_MASK;
> +       pllreg |= HIBMC_PLL_CTRL_POD(pll.POD) & HIBMC_PLL_CTRL_POD_MASK;
> +       pllreg |= HIBMC_PLL_CTRL_OD(pll.OD) & HIBMC_PLL_CTRL_OD_MASK;
> +       pllreg |= HIBMC_PLL_CTRL_N(pll.N) & HIBMC_PLL_CTRL_N_MASK;
> +       pllreg |= HIBMC_PLL_CTRL_M(pll.M) & HIBMC_PLL_CTRL_M_MASK;
> +
> +       return pllreg;
> +}
> +
> +static void set_vclock_hisilicon(struct drm_device *dev, unsigned long pll)
> +{
> +       unsigned long tmp0, tmp1;
> +       struct hibmc_drm_device *hidev = dev->dev_private;
> +
> +       /* 1. outer_bypass_n=0 */
> +       tmp0 = readl(hidev->mmio + CRT_PLL1_HS);
> +       tmp0 &= 0xBFFFFFFF;
> +       writel(tmp0, hidev->mmio + CRT_PLL1_HS);
> +
> +       /* 2. pll_pd=1?inter_bypass=1 */
> +       writel(0x21000000, hidev->mmio + CRT_PLL1_HS);
> +
> +       /* 3. config pll */
> +       writel(pll, hidev->mmio + CRT_PLL1_HS);
> +
> +       /* 4. delay  */
> +       mdelay(1);

These should be usleep_range() see
https://www.kernel.org/doc/Documentation/timers/timers-howto.txt

> +
> +       /* 5. pll_pd =0 */
> +       tmp1 = pll & ~0x01000000;
> +       writel(tmp1, hidev->mmio + CRT_PLL1_HS);
> +
> +       /* 6. delay  */
> +       mdelay(1);
> +
> +       /* 7. inter_bypass=0 */
> +       tmp1 &= ~0x20000000;
> +       writel(tmp1, hidev->mmio + CRT_PLL1_HS);
> +
> +       /* 8. delay  */
> +       mdelay(1);
> +
> +       /* 9. outer_bypass_n=1 */
> +       tmp1 |= 0x40000000;
> +       writel(tmp1, hidev->mmio + CRT_PLL1_HS);

This function is a whole lot of magic. Any chance you can pull the
values out into #defines?

> +}
> +
> +/* This function takes care the extra registers and bit fields required to

nit: multi-line comments have a leading /* line with the comment
starting on the following line

applies below as well


> + *setup a mode in board.

nit: space between * and comment, ie: * setup a mode in board

applies to the rest of the comment too


> + *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;
> +       unsigned long pll1; /* bit[31:0] of PLL */
> +       unsigned long pll2; /* bit[63:32] of PLL */
> +       struct hibmc_drm_device *hidev = dev->dev_private;
> +
> +       x = mode->hdisplay;
> +       y = mode->vdisplay;
> +
> +       /* Hisilicon has to set up a new register for PLL control
> +        *(CRT_PLL1_HS & CRT_PLL2_HS).
> +        */
> +       if (x == 800 && y == 600) {
> +               pll1 = CRT_PLL1_HS_40MHZ;
> +               pll2 = CRT_PLL2_HS_40MHZ;
> +       } else if (x == 1024 && y == 768) {
> +               pll1 = CRT_PLL1_HS_65MHZ;
> +               pll2 = CRT_PLL2_HS_65MHZ;
> +       } else if (x == 1152 && y == 864) {
> +               pll1 = CRT_PLL1_HS_80MHZ_1152;
> +               pll2 = CRT_PLL2_HS_80MHZ;
> +       } else if (x == 1280 && y == 768) {
> +               pll1 = CRT_PLL1_HS_80MHZ;
> +               pll2 = CRT_PLL2_HS_80MHZ;
> +       } else if (x == 1280 && y == 720) {
> +               pll1 = CRT_PLL1_HS_74MHZ;
> +               pll2 = CRT_PLL2_HS_74MHZ;
> +       } else if (x == 1280 && y == 960) {
> +               pll1 = CRT_PLL1_HS_108MHZ;
> +               pll2 = CRT_PLL2_HS_108MHZ;
> +       } else if (x == 1280 && y == 1024) {
> +               pll1 = CRT_PLL1_HS_108MHZ;
> +               pll2 = CRT_PLL2_HS_108MHZ;
> +       } else if (x == 1600 && y == 1200) {
> +               pll1 = CRT_PLL1_HS_162MHZ;
> +               pll2 = CRT_PLL2_HS_162MHZ;
> +       } else if (x == 1920 && y == 1080) {
> +               pll1 = CRT_PLL1_HS_148MHZ;
> +               pll2 = CRT_PLL2_HS_148MHZ;
> +       } else if (x == 1920 && y == 1200) {
> +               pll1 = CRT_PLL1_HS_193MHZ;
> +               pll2 = CRT_PLL2_HS_193MHZ;
> +       } else /* default to VGA clock */ {
> +               pll1 = CRT_PLL1_HS_25MHZ;
> +               pll2 = CRT_PLL2_HS_25MHZ;
> +       }

This seems like something that should be checked in atomic_check so
you can be sure the mode is supported.

It would also be nice to pull this out into a separate function (and a
lookup table if you're feeling adventurous)

> +
> +       writel(pll2, hidev->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_CRT_AUTO_CENTERING_TL_TOP(0) &
> +               HIBMC_CRT_AUTO_CENTERING_TL_TOP_MSK) |
> +              (HIBMC_CRT_AUTO_CENTERING_TL_LEFT(0) &
> +               HIBMC_CRT_AUTO_CENTERING_TL_LEFT_MSK),
> +              hidev->mmio + HIBMC_CRT_AUTO_CENTERING_TL);
> +
> +       writel((HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM(y - 1) &
> +               HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM_MASK) |
> +              (HIBMC_CRT_AUTO_CENTERING_BR_RIGHT(x - 1) &
> +               HIBMC_CRT_AUTO_CENTERING_BR_RIGHT_MASK),
> +               hidev->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(CRTSELECT_CRT);
> +
> +       /*ctrl = FIELD_SET(ctrl, HIBMC_CRT_DISP_CTL, CRTSELECT, CRT);*/

What's the deal with this commented code?

> +
> +       /* Set bit 14 of display controller */
> +       /*ctrl &= FIELD_CLEAR(HIBMC_CRT_DISP_CTL, CLOCK_PHASE);*/
> +
> +       /* clock_phase_polarity is 0 */
> +       ctrl |= HIBMC_CRT_DISP_CTL_CLOCK_PHASE(PHASE_ACTIVE_HIGH);
> +       /*ctrl = FIELD_SET(ctrl, HIBMC_CRT_DISP_CTL,*/
> +       /*CLOCK_PHASE, ACTIVE_HIGH);*/

Here too...

> +
> +       writel(ctrl, hidev->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_device *hidev = dev->dev_private;
> +
> +       writel(format_pll_reg(), hidev->mmio + HIBMC_CRT_PLL_CTRL);
> +       writel((HIBMC_CRT_HORZ_TOTAL_TOTAL(mode->htotal - 1) &
> +               HIBMC_CRT_HORZ_TOTAL_TOTAL_MASK) |
> +               (HIBMC_CRT_HORZ_TOTAL_DISPLAY_END(mode->hdisplay - 1) &
> +               HIBMC_CRT_HORZ_TOTAL_DISPLAY_END_MASK),

You could probably macroize this code to make it more readable

> +               hidev->mmio + HIBMC_CRT_HORZ_TOTAL);
> +
> +       writel((HIBMC_CRT_HORZ_SYNC_WIDTH(mode->hsync_end - mode->hsync_start)
> +               & HIBMC_CRT_HORZ_SYNC_WIDTH_MASK) |
> +               (HIBMC_CRT_HORZ_SYNC_START(mode->hsync_start - 1)
> +               & HIBMC_CRT_HORZ_SYNC_START_MASK),
> +               hidev->mmio + HIBMC_CRT_HORZ_SYNC);
> +
> +       writel((HIBMC_CRT_VERT_TOTAL_TOTAL(mode->vtotal - 1) &
> +               HIBMC_CRT_VERT_TOTAL_TOTAL_MASK) |
> +               (HIBMC_CRT_VERT_TOTAL_DISPLAY_END(mode->vdisplay - 1) &
> +               HIBMC_CRT_VERT_TOTAL_DISPLAY_END_MASK),
> +               hidev->mmio + HIBMC_CRT_VERT_TOTAL);
> +
> +       writel((HIBMC_CRT_VERT_SYNC_HEIGHT(mode->vsync_end - mode->vsync_start)
> +               & HIBMC_CRT_VERT_SYNC_HEIGHT_MASK) |
> +              (HIBMC_CRT_VERT_SYNC_START(mode->vsync_start - 1) &
> +               HIBMC_CRT_VERT_SYNC_START_MASK),
> +               hidev->mmio + HIBMC_CRT_VERT_SYNC);
> +
> +       val = HIBMC_CRT_DISP_CTL_VSYNC_PHASE(0) &
> +             HIBMC_CRT_DISP_CTL_VSYNC_PHASE_MASK;
> +       val |= HIBMC_CRT_DISP_CTL_HSYNC_PHASE(0) &
> +              HIBMC_CRT_DISP_CTL_HSYNC_PHASE_MASK;
> +       val |= HIBMC_CRT_DISP_CTL_TIMING(ENABLE);
> +       val |= HIBMC_CRT_DISP_CTL_PLANE(ENABLE);
> +
> +       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_device *hidev = dev->dev_private;
> +
> +       hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_MODE0);
> +
> +       /* Enable display power gate & LOCALMEM power gate*/
> +       reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
> +       reg |= HIBMC_CURR_GATE_DISPLAY(ON);
> +       reg |= HIBMC_CURR_GATE_LOCALMEM(ON);
> +       hibmc_set_current_gate(hidev, 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);
> +}
> +
> +/* These provide the minimum set of functions required to handle a CRTC */

nit: don't need this comment

> +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_check   = hibmc_crtc_atomic_check,
> +       .atomic_begin   = hibmc_crtc_atomic_begin,
> +       .atomic_flush   = hibmc_crtc_atomic_flush,
> +};
> +
> +int hibmc_crtc_init(struct hibmc_drm_device *hidev)
> +{
> +       struct drm_device *dev = hidev->dev;
> +       struct drm_crtc *crtc = &hidev->crtc;
> +       struct drm_plane *plane = &hidev->plane;
> +       int ret;
> +
> +       ret = drm_crtc_init_with_planes(dev, crtc, plane,
> +                                       NULL, &hibmc_crtc_funcs, NULL);
> +       if (ret) {
> +               DRM_ERROR("failed to init crtc.\n");

print return code

> +               return ret;
> +       }
> +
> +       drm_mode_crtc_set_gamma_size(crtc, 256);

check return code

> +       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 7d96583..303cd36 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -119,6 +119,12 @@ static int hibmc_kms_init(struct hibmc_drm_device *hidev)
>                 return ret;
>         }
>
> +       ret = hibmc_crtc_init(hidev);
> +       if (ret) {
> +               DRM_ERROR("failed to init crtc.\n");
> +               return ret;
> +       }

Typically the plane is initialized internally in the crtc driver. I
think this is a good design pattern, and you should probably use it.

So how about squashing this down with the plane patch and keeping the
plane inside hibmc_drm_de.c?

> +
>         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 49e39d2..5731ec2 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -46,6 +46,7 @@ struct hibmc_drm_device {
>         /* drm */
>         struct drm_device  *dev;
>         struct drm_plane plane;

I don't think you should be keeping track of plane here. plane is only
used in the crtc init, which should be addressed by the previous
comment.


> +       struct drm_crtc crtc;

crtc is only used in the irq handler, so you could remove this here
and just call drm_handle_vblank(dev, 0) in the handler.


>         bool mode_config_initialized;
>
>         /* ttm */
> @@ -85,6 +86,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
>  #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
>
>  int hibmc_plane_init(struct hibmc_drm_device *hidev);
> +int hibmc_crtc_init(struct hibmc_drm_device *hidev);
>  int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
>  void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
>
> --
> 1.9.1
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v6 5/9] drm/hisilicon/hibmc: Add crtc for DE
@ 2016-11-10 22:14     ` Sean Paul
  0 siblings, 0 replies; 64+ messages in thread
From: Sean Paul @ 2016-11-10 22:14 UTC (permalink / raw)
  To: Rongrong Zou
  Cc: Mark Rutland, shenhui, Tomeu Vizoso, Jonathan Corbet,
	catalin.marinas, Emil Velikov, linuxarm, dri-devel, guohanjun,
	Will Deacon, lijianhua, Linux ARM Kernel, james.xiong

On Fri, Oct 28, 2016 at 3:27 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Add crtc funcs and helper funcs for DE.
>
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
> ---
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c  | 318 ++++++++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |   6 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |   2 +
>  3 files changed, 326 insertions(+)
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
> index 9c1a68c..9b5d0d0 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
> @@ -23,6 +23,7 @@
>
>  #include "hibmc_drm_drv.h"
>  #include "hibmc_drm_regs.h"
> +#include "hibmc_drm_de.h"
>  #include "hibmc_drm_power.h"

nit: alphabetize

>
>  /* ---------------------------------------------------------------------- */

Remove

> @@ -168,3 +169,320 @@ int hibmc_plane_init(struct hibmc_drm_device *hidev)
>         drm_plane_helper_add(plane, &hibmc_plane_helper_funcs);
>         return 0;
>  }
> +
> +static void hibmc_crtc_enable(struct drm_crtc *crtc)
> +{
> +       unsigned int reg;
> +       /* power mode 0 is default. */

This comment seems to be in the wrong place

> +       struct hibmc_drm_device *hidev = crtc->dev->dev_private;
> +
> +       hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_MODE0);
> +
> +       /* Enable display power gate & LOCALMEM power gate*/
> +       reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
> +       reg |= HIBMC_CURR_GATE_LOCALMEM(ON);
> +       reg |= HIBMC_CURR_GATE_DISPLAY(ON);
> +       hibmc_set_current_gate(hidev, reg);
> +       drm_crtc_vblank_on(crtc);
> +}
> +
> +static void hibmc_crtc_disable(struct drm_crtc *crtc)
> +{
> +       unsigned int reg;
> +       struct hibmc_drm_device *hidev = crtc->dev->dev_private;
> +
> +       drm_crtc_vblank_off(crtc);
> +
> +       hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_SLEEP);
> +
> +       /* Enable display power gate & LOCALMEM power gate*/
> +       reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
> +       reg |= HIBMC_CURR_GATE_LOCALMEM(OFF);
> +       reg |= HIBMC_CURR_GATE_DISPLAY(OFF);
> +       hibmc_set_current_gate(hidev, reg);
> +}
> +
> +static int hibmc_crtc_atomic_check(struct drm_crtc *crtc,
> +                                  struct drm_crtc_state *state)
> +{
> +       return 0;
> +}

Caller NULL-checks, no need for stub

> +
> +static unsigned int format_pll_reg(void)
> +{
> +       unsigned int pllreg = 0;
> +       struct 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_PLL_CTRL_BYPASS(OFF) & HIBMC_PLL_CTRL_BYPASS_MASK;
> +       pllreg |= HIBMC_PLL_CTRL_POWER(ON) & HIBMC_PLL_CTRL_POWER_MASK;
> +       pllreg |= HIBMC_PLL_CTRL_INPUT(OSC) & HIBMC_PLL_CTRL_INPUT_MASK;
> +       pllreg |= HIBMC_PLL_CTRL_POD(pll.POD) & HIBMC_PLL_CTRL_POD_MASK;
> +       pllreg |= HIBMC_PLL_CTRL_OD(pll.OD) & HIBMC_PLL_CTRL_OD_MASK;
> +       pllreg |= HIBMC_PLL_CTRL_N(pll.N) & HIBMC_PLL_CTRL_N_MASK;
> +       pllreg |= HIBMC_PLL_CTRL_M(pll.M) & HIBMC_PLL_CTRL_M_MASK;
> +
> +       return pllreg;
> +}
> +
> +static void set_vclock_hisilicon(struct drm_device *dev, unsigned long pll)
> +{
> +       unsigned long tmp0, tmp1;
> +       struct hibmc_drm_device *hidev = dev->dev_private;
> +
> +       /* 1. outer_bypass_n=0 */
> +       tmp0 = readl(hidev->mmio + CRT_PLL1_HS);
> +       tmp0 &= 0xBFFFFFFF;
> +       writel(tmp0, hidev->mmio + CRT_PLL1_HS);
> +
> +       /* 2. pll_pd=1?inter_bypass=1 */
> +       writel(0x21000000, hidev->mmio + CRT_PLL1_HS);
> +
> +       /* 3. config pll */
> +       writel(pll, hidev->mmio + CRT_PLL1_HS);
> +
> +       /* 4. delay  */
> +       mdelay(1);

These should be usleep_range() see
https://www.kernel.org/doc/Documentation/timers/timers-howto.txt

> +
> +       /* 5. pll_pd =0 */
> +       tmp1 = pll & ~0x01000000;
> +       writel(tmp1, hidev->mmio + CRT_PLL1_HS);
> +
> +       /* 6. delay  */
> +       mdelay(1);
> +
> +       /* 7. inter_bypass=0 */
> +       tmp1 &= ~0x20000000;
> +       writel(tmp1, hidev->mmio + CRT_PLL1_HS);
> +
> +       /* 8. delay  */
> +       mdelay(1);
> +
> +       /* 9. outer_bypass_n=1 */
> +       tmp1 |= 0x40000000;
> +       writel(tmp1, hidev->mmio + CRT_PLL1_HS);

This function is a whole lot of magic. Any chance you can pull the
values out into #defines?

> +}
> +
> +/* This function takes care the extra registers and bit fields required to

nit: multi-line comments have a leading /* line with the comment
starting on the following line

applies below as well


> + *setup a mode in board.

nit: space between * and comment, ie: * setup a mode in board

applies to the rest of the comment too


> + *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;
> +       unsigned long pll1; /* bit[31:0] of PLL */
> +       unsigned long pll2; /* bit[63:32] of PLL */
> +       struct hibmc_drm_device *hidev = dev->dev_private;
> +
> +       x = mode->hdisplay;
> +       y = mode->vdisplay;
> +
> +       /* Hisilicon has to set up a new register for PLL control
> +        *(CRT_PLL1_HS & CRT_PLL2_HS).
> +        */
> +       if (x == 800 && y == 600) {
> +               pll1 = CRT_PLL1_HS_40MHZ;
> +               pll2 = CRT_PLL2_HS_40MHZ;
> +       } else if (x == 1024 && y == 768) {
> +               pll1 = CRT_PLL1_HS_65MHZ;
> +               pll2 = CRT_PLL2_HS_65MHZ;
> +       } else if (x == 1152 && y == 864) {
> +               pll1 = CRT_PLL1_HS_80MHZ_1152;
> +               pll2 = CRT_PLL2_HS_80MHZ;
> +       } else if (x == 1280 && y == 768) {
> +               pll1 = CRT_PLL1_HS_80MHZ;
> +               pll2 = CRT_PLL2_HS_80MHZ;
> +       } else if (x == 1280 && y == 720) {
> +               pll1 = CRT_PLL1_HS_74MHZ;
> +               pll2 = CRT_PLL2_HS_74MHZ;
> +       } else if (x == 1280 && y == 960) {
> +               pll1 = CRT_PLL1_HS_108MHZ;
> +               pll2 = CRT_PLL2_HS_108MHZ;
> +       } else if (x == 1280 && y == 1024) {
> +               pll1 = CRT_PLL1_HS_108MHZ;
> +               pll2 = CRT_PLL2_HS_108MHZ;
> +       } else if (x == 1600 && y == 1200) {
> +               pll1 = CRT_PLL1_HS_162MHZ;
> +               pll2 = CRT_PLL2_HS_162MHZ;
> +       } else if (x == 1920 && y == 1080) {
> +               pll1 = CRT_PLL1_HS_148MHZ;
> +               pll2 = CRT_PLL2_HS_148MHZ;
> +       } else if (x == 1920 && y == 1200) {
> +               pll1 = CRT_PLL1_HS_193MHZ;
> +               pll2 = CRT_PLL2_HS_193MHZ;
> +       } else /* default to VGA clock */ {
> +               pll1 = CRT_PLL1_HS_25MHZ;
> +               pll2 = CRT_PLL2_HS_25MHZ;
> +       }

This seems like something that should be checked in atomic_check so
you can be sure the mode is supported.

It would also be nice to pull this out into a separate function (and a
lookup table if you're feeling adventurous)

> +
> +       writel(pll2, hidev->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_CRT_AUTO_CENTERING_TL_TOP(0) &
> +               HIBMC_CRT_AUTO_CENTERING_TL_TOP_MSK) |
> +              (HIBMC_CRT_AUTO_CENTERING_TL_LEFT(0) &
> +               HIBMC_CRT_AUTO_CENTERING_TL_LEFT_MSK),
> +              hidev->mmio + HIBMC_CRT_AUTO_CENTERING_TL);
> +
> +       writel((HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM(y - 1) &
> +               HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM_MASK) |
> +              (HIBMC_CRT_AUTO_CENTERING_BR_RIGHT(x - 1) &
> +               HIBMC_CRT_AUTO_CENTERING_BR_RIGHT_MASK),
> +               hidev->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(CRTSELECT_CRT);
> +
> +       /*ctrl = FIELD_SET(ctrl, HIBMC_CRT_DISP_CTL, CRTSELECT, CRT);*/

What's the deal with this commented code?

> +
> +       /* Set bit 14 of display controller */
> +       /*ctrl &= FIELD_CLEAR(HIBMC_CRT_DISP_CTL, CLOCK_PHASE);*/
> +
> +       /* clock_phase_polarity is 0 */
> +       ctrl |= HIBMC_CRT_DISP_CTL_CLOCK_PHASE(PHASE_ACTIVE_HIGH);
> +       /*ctrl = FIELD_SET(ctrl, HIBMC_CRT_DISP_CTL,*/
> +       /*CLOCK_PHASE, ACTIVE_HIGH);*/

Here too...

> +
> +       writel(ctrl, hidev->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_device *hidev = dev->dev_private;
> +
> +       writel(format_pll_reg(), hidev->mmio + HIBMC_CRT_PLL_CTRL);
> +       writel((HIBMC_CRT_HORZ_TOTAL_TOTAL(mode->htotal - 1) &
> +               HIBMC_CRT_HORZ_TOTAL_TOTAL_MASK) |
> +               (HIBMC_CRT_HORZ_TOTAL_DISPLAY_END(mode->hdisplay - 1) &
> +               HIBMC_CRT_HORZ_TOTAL_DISPLAY_END_MASK),

You could probably macroize this code to make it more readable

> +               hidev->mmio + HIBMC_CRT_HORZ_TOTAL);
> +
> +       writel((HIBMC_CRT_HORZ_SYNC_WIDTH(mode->hsync_end - mode->hsync_start)
> +               & HIBMC_CRT_HORZ_SYNC_WIDTH_MASK) |
> +               (HIBMC_CRT_HORZ_SYNC_START(mode->hsync_start - 1)
> +               & HIBMC_CRT_HORZ_SYNC_START_MASK),
> +               hidev->mmio + HIBMC_CRT_HORZ_SYNC);
> +
> +       writel((HIBMC_CRT_VERT_TOTAL_TOTAL(mode->vtotal - 1) &
> +               HIBMC_CRT_VERT_TOTAL_TOTAL_MASK) |
> +               (HIBMC_CRT_VERT_TOTAL_DISPLAY_END(mode->vdisplay - 1) &
> +               HIBMC_CRT_VERT_TOTAL_DISPLAY_END_MASK),
> +               hidev->mmio + HIBMC_CRT_VERT_TOTAL);
> +
> +       writel((HIBMC_CRT_VERT_SYNC_HEIGHT(mode->vsync_end - mode->vsync_start)
> +               & HIBMC_CRT_VERT_SYNC_HEIGHT_MASK) |
> +              (HIBMC_CRT_VERT_SYNC_START(mode->vsync_start - 1) &
> +               HIBMC_CRT_VERT_SYNC_START_MASK),
> +               hidev->mmio + HIBMC_CRT_VERT_SYNC);
> +
> +       val = HIBMC_CRT_DISP_CTL_VSYNC_PHASE(0) &
> +             HIBMC_CRT_DISP_CTL_VSYNC_PHASE_MASK;
> +       val |= HIBMC_CRT_DISP_CTL_HSYNC_PHASE(0) &
> +              HIBMC_CRT_DISP_CTL_HSYNC_PHASE_MASK;
> +       val |= HIBMC_CRT_DISP_CTL_TIMING(ENABLE);
> +       val |= HIBMC_CRT_DISP_CTL_PLANE(ENABLE);
> +
> +       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_device *hidev = dev->dev_private;
> +
> +       hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_MODE0);
> +
> +       /* Enable display power gate & LOCALMEM power gate*/
> +       reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
> +       reg |= HIBMC_CURR_GATE_DISPLAY(ON);
> +       reg |= HIBMC_CURR_GATE_LOCALMEM(ON);
> +       hibmc_set_current_gate(hidev, 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);
> +}
> +
> +/* These provide the minimum set of functions required to handle a CRTC */

nit: don't need this comment

> +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_check   = hibmc_crtc_atomic_check,
> +       .atomic_begin   = hibmc_crtc_atomic_begin,
> +       .atomic_flush   = hibmc_crtc_atomic_flush,
> +};
> +
> +int hibmc_crtc_init(struct hibmc_drm_device *hidev)
> +{
> +       struct drm_device *dev = hidev->dev;
> +       struct drm_crtc *crtc = &hidev->crtc;
> +       struct drm_plane *plane = &hidev->plane;
> +       int ret;
> +
> +       ret = drm_crtc_init_with_planes(dev, crtc, plane,
> +                                       NULL, &hibmc_crtc_funcs, NULL);
> +       if (ret) {
> +               DRM_ERROR("failed to init crtc.\n");

print return code

> +               return ret;
> +       }
> +
> +       drm_mode_crtc_set_gamma_size(crtc, 256);

check return code

> +       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 7d96583..303cd36 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -119,6 +119,12 @@ static int hibmc_kms_init(struct hibmc_drm_device *hidev)
>                 return ret;
>         }
>
> +       ret = hibmc_crtc_init(hidev);
> +       if (ret) {
> +               DRM_ERROR("failed to init crtc.\n");
> +               return ret;
> +       }

Typically the plane is initialized internally in the crtc driver. I
think this is a good design pattern, and you should probably use it.

So how about squashing this down with the plane patch and keeping the
plane inside hibmc_drm_de.c?

> +
>         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 49e39d2..5731ec2 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -46,6 +46,7 @@ struct hibmc_drm_device {
>         /* drm */
>         struct drm_device  *dev;
>         struct drm_plane plane;

I don't think you should be keeping track of plane here. plane is only
used in the crtc init, which should be addressed by the previous
comment.


> +       struct drm_crtc crtc;

crtc is only used in the irq handler, so you could remove this here
and just call drm_handle_vblank(dev, 0) in the handler.


>         bool mode_config_initialized;
>
>         /* ttm */
> @@ -85,6 +86,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
>  #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
>
>  int hibmc_plane_init(struct hibmc_drm_device *hidev);
> +int hibmc_crtc_init(struct hibmc_drm_device *hidev);
>  int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
>  void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
>
> --
> 1.9.1
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v6 6/9] drm/hisilicon/hibmc: Add encoder for VDAC
  2016-10-28  7:27   ` Rongrong Zou
@ 2016-11-10 22:20     ` Sean Paul
  -1 siblings, 0 replies; 64+ messages in thread
From: Sean Paul @ 2016-11-10 22:20 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Oct 28, 2016 at 3:27 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Add encoder funcs and helpers for VDAC.
>
> 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  |  2 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c | 89 ++++++++++++++++++++++++
>  4 files changed, 98 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 72e107e..e04f114 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> @@ -1,5 +1,5 @@
>  ccflags-y := -Iinclude/drm
> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
>
>  obj-$(CONFIG_DRM_HISI_HIBMC)   +=hibmc-drm.o
>  #obj-y += 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 303cd36..ba191e1 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -125,6 +125,12 @@ static int hibmc_kms_init(struct hibmc_drm_device *hidev)
>                 return ret;
>         }
>
> +       ret = hibmc_encoder_init(hidev);
> +       if (ret) {
> +               DRM_ERROR("failed to init encoder\n");
> +               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 5731ec2..401cea4 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -47,6 +47,7 @@ struct hibmc_drm_device {
>         struct drm_device  *dev;
>         struct drm_plane plane;
>         struct drm_crtc crtc;
> +       struct drm_encoder encoder;

Same comment here, you don't need to keep track of this

>         bool mode_config_initialized;
>
>         /* ttm */
> @@ -87,6 +88,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
>
>  int hibmc_plane_init(struct hibmc_drm_device *hidev);
>  int hibmc_crtc_init(struct hibmc_drm_device *hidev);
> +int hibmc_encoder_init(struct hibmc_drm_device *hidev);
>  int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
>  void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
>
> 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..953f659
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
> @@ -0,0 +1,89 @@
> +/* 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 defx = 800;
> +static int defy = 600;
> +
> +module_param(defx, int, 0444);
> +module_param(defy, int, 0444);
> +MODULE_PARM_DESC(defx, "default x resolution");
> +MODULE_PARM_DESC(defy, "default y resolution");

Not used, and I'm not sure these are a good idea

> +
> +static void hibmc_encoder_disable(struct drm_encoder *encoder)
> +{
> +}
> +
> +static void hibmc_encoder_enable(struct drm_encoder *encoder)
> +{
> +}

Null-checked, no need to stub

> +
> +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_device *hidev = dev->dev_private;
> +
> +       /* just open DISPLAY_CONTROL_HISILE register bit 3:0*/
> +       reg = readl(hidev->mmio + DISPLAY_CONTROL_HISILE);
> +       reg |= 0xf;

Can you just pull this into a #define instead of explaining in the comment?

> +       writel(reg, hidev->mmio + DISPLAY_CONTROL_HISILE);
> +}
> +
> +static int hibmc_encoder_atomic_check(struct drm_encoder *encoder,
> +                                     struct drm_crtc_state *crtc_state,
> +                                     struct drm_connector_state *conn_state)
> +{
> +       return 0;
> +}

null-checked, remove stub

> +
> +static const struct drm_encoder_helper_funcs hibmc_encoder_helper_funcs = {
> +       .mode_set = hibmc_encoder_mode_set,
> +       .disable = hibmc_encoder_disable,
> +       .enable = hibmc_encoder_enable,
> +       .atomic_check = hibmc_encoder_atomic_check,
> +};
> +
> +static const struct drm_encoder_funcs hibmc_encoder_encoder_funcs = {
> +       .destroy = drm_encoder_cleanup,
> +};
> +
> +int hibmc_encoder_init(struct hibmc_drm_device *hidev)
> +{
> +       struct drm_device *dev = hidev->dev;
> +       struct drm_encoder *encoder = &hidev->encoder;
> +       int ret;
> +
> +       encoder->possible_crtcs = 0x1;
> +       ret = drm_encoder_init(dev, encoder, &hibmc_encoder_encoder_funcs,
> +                              DRM_MODE_ENCODER_DAC, NULL);
> +       if (ret) {
> +               DRM_ERROR("failed to init encoder\n");

print ret

> +               return ret;
> +       }
> +
> +       drm_encoder_helper_add(encoder, &hibmc_encoder_helper_funcs);
> +       return 0;
> +}
> --
> 1.9.1
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v6 6/9] drm/hisilicon/hibmc: Add encoder for VDAC
@ 2016-11-10 22:20     ` Sean Paul
  0 siblings, 0 replies; 64+ messages in thread
From: Sean Paul @ 2016-11-10 22:20 UTC (permalink / raw)
  To: Rongrong Zou
  Cc: Mark Rutland, shenhui, Tomeu Vizoso, Jonathan Corbet,
	catalin.marinas, Emil Velikov, linuxarm, dri-devel, guohanjun,
	Will Deacon, lijianhua, Linux ARM Kernel, james.xiong

On Fri, Oct 28, 2016 at 3:27 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Add encoder funcs and helpers for VDAC.
>
> 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  |  2 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c | 89 ++++++++++++++++++++++++
>  4 files changed, 98 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 72e107e..e04f114 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
> @@ -1,5 +1,5 @@
>  ccflags-y := -Iinclude/drm
> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
>
>  obj-$(CONFIG_DRM_HISI_HIBMC)   +=hibmc-drm.o
>  #obj-y += 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 303cd36..ba191e1 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -125,6 +125,12 @@ static int hibmc_kms_init(struct hibmc_drm_device *hidev)
>                 return ret;
>         }
>
> +       ret = hibmc_encoder_init(hidev);
> +       if (ret) {
> +               DRM_ERROR("failed to init encoder\n");
> +               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 5731ec2..401cea4 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -47,6 +47,7 @@ struct hibmc_drm_device {
>         struct drm_device  *dev;
>         struct drm_plane plane;
>         struct drm_crtc crtc;
> +       struct drm_encoder encoder;

Same comment here, you don't need to keep track of this

>         bool mode_config_initialized;
>
>         /* ttm */
> @@ -87,6 +88,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
>
>  int hibmc_plane_init(struct hibmc_drm_device *hidev);
>  int hibmc_crtc_init(struct hibmc_drm_device *hidev);
> +int hibmc_encoder_init(struct hibmc_drm_device *hidev);
>  int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
>  void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
>
> 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..953f659
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
> @@ -0,0 +1,89 @@
> +/* 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 defx = 800;
> +static int defy = 600;
> +
> +module_param(defx, int, 0444);
> +module_param(defy, int, 0444);
> +MODULE_PARM_DESC(defx, "default x resolution");
> +MODULE_PARM_DESC(defy, "default y resolution");

Not used, and I'm not sure these are a good idea

> +
> +static void hibmc_encoder_disable(struct drm_encoder *encoder)
> +{
> +}
> +
> +static void hibmc_encoder_enable(struct drm_encoder *encoder)
> +{
> +}

Null-checked, no need to stub

> +
> +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_device *hidev = dev->dev_private;
> +
> +       /* just open DISPLAY_CONTROL_HISILE register bit 3:0*/
> +       reg = readl(hidev->mmio + DISPLAY_CONTROL_HISILE);
> +       reg |= 0xf;

Can you just pull this into a #define instead of explaining in the comment?

> +       writel(reg, hidev->mmio + DISPLAY_CONTROL_HISILE);
> +}
> +
> +static int hibmc_encoder_atomic_check(struct drm_encoder *encoder,
> +                                     struct drm_crtc_state *crtc_state,
> +                                     struct drm_connector_state *conn_state)
> +{
> +       return 0;
> +}

null-checked, remove stub

> +
> +static const struct drm_encoder_helper_funcs hibmc_encoder_helper_funcs = {
> +       .mode_set = hibmc_encoder_mode_set,
> +       .disable = hibmc_encoder_disable,
> +       .enable = hibmc_encoder_enable,
> +       .atomic_check = hibmc_encoder_atomic_check,
> +};
> +
> +static const struct drm_encoder_funcs hibmc_encoder_encoder_funcs = {
> +       .destroy = drm_encoder_cleanup,
> +};
> +
> +int hibmc_encoder_init(struct hibmc_drm_device *hidev)
> +{
> +       struct drm_device *dev = hidev->dev;
> +       struct drm_encoder *encoder = &hidev->encoder;
> +       int ret;
> +
> +       encoder->possible_crtcs = 0x1;
> +       ret = drm_encoder_init(dev, encoder, &hibmc_encoder_encoder_funcs,
> +                              DRM_MODE_ENCODER_DAC, NULL);
> +       if (ret) {
> +               DRM_ERROR("failed to init encoder\n");

print ret

> +               return ret;
> +       }
> +
> +       drm_encoder_helper_add(encoder, &hibmc_encoder_helper_funcs);
> +       return 0;
> +}
> --
> 1.9.1
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v6 7/9] drm/hisilicon/hibmc: Add connector for VDAC
  2016-10-28  7:28   ` Rongrong Zou
@ 2016-11-11  1:45     ` Sean Paul
  -1 siblings, 0 replies; 64+ messages in thread
From: Sean Paul @ 2016-11-11  1:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Oct 28, 2016 at 3:28 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Add connector funcs and helper funcs for VDAC.
>
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
> ---
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c  |  8 +++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h  |  2 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c | 76 ++++++++++++++++++++++++
>  3 files changed, 86 insertions(+)
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> index ba191e1..4253603 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -131,6 +131,14 @@ static int hibmc_kms_init(struct hibmc_drm_device *hidev)
>                 return ret;
>         }
>
> +       ret = hibmc_connector_init(hidev);
> +       if (ret) {
> +               DRM_ERROR("failed to init connector\n");
> +               return ret;
> +       }
> +
> +       drm_mode_connector_attach_encoder(&hidev->connector,
> +                                         &hidev->encoder);

The connector should be initialized in the vdac driver with the
encoder, not in the drv file (same as plane/crtc)

>         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 401cea4..450247d 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -48,6 +48,7 @@ struct hibmc_drm_device {
>         struct drm_plane plane;
>         struct drm_crtc crtc;
>         struct drm_encoder encoder;
> +       struct drm_connector connector;

No need to keep track here

>         bool mode_config_initialized;
>
>         /* ttm */
> @@ -89,6 +90,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
>  int hibmc_plane_init(struct hibmc_drm_device *hidev);
>  int hibmc_crtc_init(struct hibmc_drm_device *hidev);
>  int hibmc_encoder_init(struct hibmc_drm_device *hidev);
> +int hibmc_connector_init(struct hibmc_drm_device *hidev);
>  int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
>  void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
> index 953f659..ebefcd1 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
> @@ -87,3 +87,79 @@ int hibmc_encoder_init(struct hibmc_drm_device *hidev)
>         drm_encoder_helper_add(encoder, &hibmc_encoder_helper_funcs);
>         return 0;
>  }
> +
> +static int hibmc_connector_get_modes(struct drm_connector *connector)
> +{
> +       int count;
> +
> +       count = drm_add_modes_noedid(connector, 800, 600);
> +       drm_set_preferred_mode(connector, defx, defy);

So you have defx/defy as module parameters, but then hardcode the
800x600 mode. If defx/defy is anything other than 800/600, this won't
work. I think you should just remove the defx/defy module params and
rely on userspace adding modes as appropriate.

> +       return count;
> +}
> +
> +static int hibmc_connector_mode_valid(struct drm_connector *connector,
> +                                     struct drm_display_mode *mode)
> +{
> +       struct hibmc_drm_device *hiprivate =
> +        container_of(connector, struct hibmc_drm_device, connector);
> +       unsigned long size = mode->hdisplay * mode->vdisplay * 4;

Why * 4 here and why * 2 below? You support formats less than 32 bpp,
so the * 4 isn't necessarily correct for all formats. Is the * 2 to
account for front & back buffer?


> +
> +       if (size * 2 > hiprivate->fb_size)
> +               return MODE_BAD;
> +
> +       return MODE_OK;
> +}
> +
> +static struct drm_encoder *
> +hibmc_connector_best_encoder(struct drm_connector *connector)
> +{
> +       int enc_id = connector->encoder_ids[0];
> +
> +       /* pick the encoder ids */
> +       if (enc_id)
> +               return drm_encoder_find(connector->dev, enc_id);

Can't you just do return drm_encoder_find(connector->dev,
connector->encoder_ids[0]); ?

ie: won't drm_encoder_find do the right thing if you pass in id == 0?

> +
> +       return NULL;
> +}
> +
> +static enum drm_connector_status hibmc_connector_detect(struct drm_connector
> +                                                *connector, bool force)
> +{
> +       return connector_status_connected;

Perhaps this should be connector_status_unknown, since you don't
necessarily know it's connected.

> +}
> +
> +static const struct drm_connector_helper_funcs
> +       hibmc_connector_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_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,
> +};
> +
> +int hibmc_connector_init(struct hibmc_drm_device *hidev)
> +{
> +       struct drm_device *dev = hidev->dev;
> +       struct drm_connector *connector = &hidev->connector;
> +       int ret;
> +
> +       ret = drm_connector_init(dev, connector,
> +                                &hibmc_connector_connector_funcs,
> +                                DRM_MODE_CONNECTOR_VGA);
> +       if (ret) {
> +               DRM_ERROR("failed to init connector\n");
> +               return ret;
> +       }
> +       drm_connector_helper_add(connector,
> +                                &hibmc_connector_connector_helper_funcs);
> +
> +       return 0;
> +}
> --
> 1.9.1
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v6 7/9] drm/hisilicon/hibmc: Add connector for VDAC
@ 2016-11-11  1:45     ` Sean Paul
  0 siblings, 0 replies; 64+ messages in thread
From: Sean Paul @ 2016-11-11  1:45 UTC (permalink / raw)
  To: Rongrong Zou
  Cc: Mark Rutland, shenhui, Tomeu Vizoso, Jonathan Corbet,
	catalin.marinas, Emil Velikov, linuxarm, dri-devel, guohanjun,
	Will Deacon, lijianhua, Linux ARM Kernel, james.xiong

On Fri, Oct 28, 2016 at 3:28 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Add connector funcs and helper funcs for VDAC.
>
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
> ---
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c  |  8 +++
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h  |  2 +
>  drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c | 76 ++++++++++++++++++++++++
>  3 files changed, 86 insertions(+)
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> index ba191e1..4253603 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -131,6 +131,14 @@ static int hibmc_kms_init(struct hibmc_drm_device *hidev)
>                 return ret;
>         }
>
> +       ret = hibmc_connector_init(hidev);
> +       if (ret) {
> +               DRM_ERROR("failed to init connector\n");
> +               return ret;
> +       }
> +
> +       drm_mode_connector_attach_encoder(&hidev->connector,
> +                                         &hidev->encoder);

The connector should be initialized in the vdac driver with the
encoder, not in the drv file (same as plane/crtc)

>         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 401cea4..450247d 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
> @@ -48,6 +48,7 @@ struct hibmc_drm_device {
>         struct drm_plane plane;
>         struct drm_crtc crtc;
>         struct drm_encoder encoder;
> +       struct drm_connector connector;

No need to keep track here

>         bool mode_config_initialized;
>
>         /* ttm */
> @@ -89,6 +90,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
>  int hibmc_plane_init(struct hibmc_drm_device *hidev);
>  int hibmc_crtc_init(struct hibmc_drm_device *hidev);
>  int hibmc_encoder_init(struct hibmc_drm_device *hidev);
> +int hibmc_connector_init(struct hibmc_drm_device *hidev);
>  int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
>  void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
>
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
> index 953f659..ebefcd1 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
> @@ -87,3 +87,79 @@ int hibmc_encoder_init(struct hibmc_drm_device *hidev)
>         drm_encoder_helper_add(encoder, &hibmc_encoder_helper_funcs);
>         return 0;
>  }
> +
> +static int hibmc_connector_get_modes(struct drm_connector *connector)
> +{
> +       int count;
> +
> +       count = drm_add_modes_noedid(connector, 800, 600);
> +       drm_set_preferred_mode(connector, defx, defy);

So you have defx/defy as module parameters, but then hardcode the
800x600 mode. If defx/defy is anything other than 800/600, this won't
work. I think you should just remove the defx/defy module params and
rely on userspace adding modes as appropriate.

> +       return count;
> +}
> +
> +static int hibmc_connector_mode_valid(struct drm_connector *connector,
> +                                     struct drm_display_mode *mode)
> +{
> +       struct hibmc_drm_device *hiprivate =
> +        container_of(connector, struct hibmc_drm_device, connector);
> +       unsigned long size = mode->hdisplay * mode->vdisplay * 4;

Why * 4 here and why * 2 below? You support formats less than 32 bpp,
so the * 4 isn't necessarily correct for all formats. Is the * 2 to
account for front & back buffer?


> +
> +       if (size * 2 > hiprivate->fb_size)
> +               return MODE_BAD;
> +
> +       return MODE_OK;
> +}
> +
> +static struct drm_encoder *
> +hibmc_connector_best_encoder(struct drm_connector *connector)
> +{
> +       int enc_id = connector->encoder_ids[0];
> +
> +       /* pick the encoder ids */
> +       if (enc_id)
> +               return drm_encoder_find(connector->dev, enc_id);

Can't you just do return drm_encoder_find(connector->dev,
connector->encoder_ids[0]); ?

ie: won't drm_encoder_find do the right thing if you pass in id == 0?

> +
> +       return NULL;
> +}
> +
> +static enum drm_connector_status hibmc_connector_detect(struct drm_connector
> +                                                *connector, bool force)
> +{
> +       return connector_status_connected;

Perhaps this should be connector_status_unknown, since you don't
necessarily know it's connected.

> +}
> +
> +static const struct drm_connector_helper_funcs
> +       hibmc_connector_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_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,
> +};
> +
> +int hibmc_connector_init(struct hibmc_drm_device *hidev)
> +{
> +       struct drm_device *dev = hidev->dev;
> +       struct drm_connector *connector = &hidev->connector;
> +       int ret;
> +
> +       ret = drm_connector_init(dev, connector,
> +                                &hibmc_connector_connector_funcs,
> +                                DRM_MODE_CONNECTOR_VGA);
> +       if (ret) {
> +               DRM_ERROR("failed to init connector\n");
> +               return ret;
> +       }
> +       drm_connector_helper_add(connector,
> +                                &hibmc_connector_connector_helper_funcs);
> +
> +       return 0;
> +}
> --
> 1.9.1
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v6 8/9] drm/hisilicon/hibmc: Add vblank interruput
  2016-10-28  7:28   ` Rongrong Zou
@ 2016-11-11  1:49     ` Sean Paul
  -1 siblings, 0 replies; 64+ messages in thread
From: Sean Paul @ 2016-11-11  1:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Oct 28, 2016 at 3:28 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> 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 4253603..b668e3e 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -40,16 +40,46 @@
>
>  static int hibmc_enable_vblank(struct drm_device *dev, unsigned int pipe)
>  {
> +       struct hibmc_drm_device *hidev =
> +               (struct hibmc_drm_device *)dev->dev_private;
> +
> +       writel(HIBMC_RAW_INTERRUPT_EN_VBLANK(1),
> +              hidev->mmio + HIBMC_RAW_INTERRUPT_EN);
> +
>         return 0;
>  }
>
>  static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>  {
> +       struct hibmc_drm_device *hidev =
> +               (struct hibmc_drm_device *)dev->dev_private;
> +
> +       writel(HIBMC_RAW_INTERRUPT_EN_VBLANK(0),
> +              hidev->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_device *hidev =
> +               (struct hibmc_drm_device *)dev->dev_private;
> +       struct drm_crtc *crtc = &hidev->crtc;
> +       u32 status;
> +
> +       status = readl(hidev->mmio + HIBMC_RAW_INTERRUPT);
> +
> +       if (status & HIBMC_RAW_INTERRUPT_VBLANK(1)) {
> +               writel(HIBMC_RAW_INTERRUPT_VBLANK(1),
> +                      hidev->mmio + HIBMC_RAW_INTERRUPT);
> +               drm_crtc_handle_vblank(crtc);
> +       }
> +
> +       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",
> @@ -63,6 +93,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)
> @@ -242,6 +273,13 @@ static int hibmc_unload(struct drm_device *dev)
>         struct hibmc_drm_device *hidev = dev->dev_private;
>
>         hibmc_fbdev_fini(hidev);
> +
> +       if (dev->irq_enabled)
> +               drm_irq_uninstall(dev);
> +       if (hidev->msi_enabled)
> +               pci_disable_msi(dev->pdev);
> +       drm_vblank_cleanup(dev);
> +
>         hibmc_kms_fini(hidev);
>         hibmc_mm_fini(hidev);
>         hibmc_hw_fini(hidev);
> @@ -272,6 +310,22 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
>         if (ret)
>                 goto err;
>
> +       ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
> +       if (ret) {
> +               DRM_ERROR("failed to initialize vblank.\n");
> +               goto err;
> +       }
> +
> +       hidev->msi_enabled = 0;
> +       if (pci_enable_msi(dev->pdev)) {

It would be useful to check and print the return value of this.

> +               DRM_ERROR("Enabling MSI failed!\n");
> +       } else {
> +               hidev->msi_enabled = 1;
> +               ret = drm_irq_install(dev, dev->pdev->irq);
> +               if (ret)
> +                       DRM_ERROR("install irq failed , ret = %d\n", ret);

DRM_WARN might be more appropriate, given that this isn't considered fatal.

> +       }
> +
>         /* 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 450247d..f1706fb 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_device {
>         void __iomem   *fb_map;
>         unsigned long  fb_base;
>         unsigned long  fb_size;
> +       int msi_enabled;

Why not bool?

>
>         /* drm */
>         struct drm_device  *dev;
> --
> 1.9.1
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v6 8/9] drm/hisilicon/hibmc: Add vblank interruput
@ 2016-11-11  1:49     ` Sean Paul
  0 siblings, 0 replies; 64+ messages in thread
From: Sean Paul @ 2016-11-11  1:49 UTC (permalink / raw)
  To: Rongrong Zou
  Cc: Mark Rutland, shenhui, Tomeu Vizoso, Jonathan Corbet,
	catalin.marinas, Emil Velikov, linuxarm, dri-devel, guohanjun,
	Will Deacon, lijianhua, Linux ARM Kernel, james.xiong

On Fri, Oct 28, 2016 at 3:28 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> 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 4253603..b668e3e 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
> @@ -40,16 +40,46 @@
>
>  static int hibmc_enable_vblank(struct drm_device *dev, unsigned int pipe)
>  {
> +       struct hibmc_drm_device *hidev =
> +               (struct hibmc_drm_device *)dev->dev_private;
> +
> +       writel(HIBMC_RAW_INTERRUPT_EN_VBLANK(1),
> +              hidev->mmio + HIBMC_RAW_INTERRUPT_EN);
> +
>         return 0;
>  }
>
>  static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>  {
> +       struct hibmc_drm_device *hidev =
> +               (struct hibmc_drm_device *)dev->dev_private;
> +
> +       writel(HIBMC_RAW_INTERRUPT_EN_VBLANK(0),
> +              hidev->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_device *hidev =
> +               (struct hibmc_drm_device *)dev->dev_private;
> +       struct drm_crtc *crtc = &hidev->crtc;
> +       u32 status;
> +
> +       status = readl(hidev->mmio + HIBMC_RAW_INTERRUPT);
> +
> +       if (status & HIBMC_RAW_INTERRUPT_VBLANK(1)) {
> +               writel(HIBMC_RAW_INTERRUPT_VBLANK(1),
> +                      hidev->mmio + HIBMC_RAW_INTERRUPT);
> +               drm_crtc_handle_vblank(crtc);
> +       }
> +
> +       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",
> @@ -63,6 +93,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)
> @@ -242,6 +273,13 @@ static int hibmc_unload(struct drm_device *dev)
>         struct hibmc_drm_device *hidev = dev->dev_private;
>
>         hibmc_fbdev_fini(hidev);
> +
> +       if (dev->irq_enabled)
> +               drm_irq_uninstall(dev);
> +       if (hidev->msi_enabled)
> +               pci_disable_msi(dev->pdev);
> +       drm_vblank_cleanup(dev);
> +
>         hibmc_kms_fini(hidev);
>         hibmc_mm_fini(hidev);
>         hibmc_hw_fini(hidev);
> @@ -272,6 +310,22 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
>         if (ret)
>                 goto err;
>
> +       ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
> +       if (ret) {
> +               DRM_ERROR("failed to initialize vblank.\n");
> +               goto err;
> +       }
> +
> +       hidev->msi_enabled = 0;
> +       if (pci_enable_msi(dev->pdev)) {

It would be useful to check and print the return value of this.

> +               DRM_ERROR("Enabling MSI failed!\n");
> +       } else {
> +               hidev->msi_enabled = 1;
> +               ret = drm_irq_install(dev, dev->pdev->irq);
> +               if (ret)
> +                       DRM_ERROR("install irq failed , ret = %d\n", ret);

DRM_WARN might be more appropriate, given that this isn't considered fatal.

> +       }
> +
>         /* 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 450247d..f1706fb 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_device {
>         void __iomem   *fb_map;
>         unsigned long  fb_base;
>         unsigned long  fb_size;
> +       int msi_enabled;

Why not bool?

>
>         /* drm */
>         struct drm_device  *dev;
> --
> 1.9.1
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v6 9/9] MAINTAINERS: Update HISILICON DRM entries
  2016-10-28  7:28   ` Rongrong Zou
@ 2016-11-11  1:50     ` Sean Paul
  -1 siblings, 0 replies; 64+ messages in thread
From: Sean Paul @ 2016-11-11  1:50 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Oct 28, 2016 at 3:28 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>

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

> ---
>  MAINTAINERS | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index c447953..cc5ee3a 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -4117,6 +4117,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
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v6 9/9] MAINTAINERS: Update HISILICON DRM entries
@ 2016-11-11  1:50     ` Sean Paul
  0 siblings, 0 replies; 64+ messages in thread
From: Sean Paul @ 2016-11-11  1:50 UTC (permalink / raw)
  To: Rongrong Zou
  Cc: Mark Rutland, shenhui, Tomeu Vizoso, Jonathan Corbet,
	catalin.marinas, Emil Velikov, linuxarm, dri-devel, guohanjun,
	Will Deacon, lijianhua, Linux ARM Kernel, james.xiong

On Fri, Oct 28, 2016 at 3:28 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>

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

> ---
>  MAINTAINERS | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index c447953..cc5ee3a 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -4117,6 +4117,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
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v6 1/9] drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
  2016-11-10 17:35     ` Sean Paul
@ 2016-11-11  3:10       ` Rongrong Zou
  -1 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-11-11  3:10 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Sean,

Thanks for reviewing! All comments is helpful.

? 2016/11/11 1:35, Sean Paul ??:
> On Fri, Oct 28, 2016 at 3:27 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>
>> ---
>>   drivers/gpu/drm/hisilicon/Kconfig                 |   1 +
>>   drivers/gpu/drm/hisilicon/Makefile                |   1 +
>>   drivers/gpu/drm/hisilicon/hibmc/Kconfig           |   7 +
>>   drivers/gpu/drm/hisilicon/hibmc/Makefile          |   5 +
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   | 269 ++++++++++++++++++++++
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   |  35 +++
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c |  85 +++++++
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h |  28 +++
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h  | 212 +++++++++++++++++
>>   9 files changed, 643 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_power.c
>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.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..a9af90d
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>> @@ -0,0 +1,7 @@
>> +config DRM_HISI_HIBMC
>> +       tristate "DRM Support for Hisilicon Hibmc"
>> +       depends on DRM && PCI
>> +
>> +       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..97cf4a0
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>> @@ -0,0 +1,5 @@
>> +ccflags-y := -Iinclude/drm
>> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o
>> +
>> +obj-$(CONFIG_DRM_HISI_HIBMC)   +=hibmc-drm.o
>
> nit: Improper spacing here

seems a space was missed, thanks.

>
>> +#obj-y += 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..4669d42
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> @@ -0,0 +1,269 @@
>> +/* 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/module.h>
>> +#include <linux/console.h>
>> +
>> +#include "hibmc_drm_drv.h"
>> +#include "hibmc_drm_regs.h"
>> +#include "hibmc_drm_power.h"
>
> nit: Alphabetize headers

agreed, thanks.

>
>> +
>> +static const struct file_operations hibmc_fops = {
>> +       .owner          = THIS_MODULE,
>> +       .open           = drm_open,
>> +       .release        = drm_release,
>> +       .unlocked_ioctl = drm_ioctl,
>> +#ifdef CONFIG_COMPAT
>
> drm_compat_ioctl is now initialized to NULL, so you can remove the #ifdef
>
understood, will remove it next version.

>> +       .compat_ioctl   = drm_compat_ioctl,
>> +#endif
>> +       .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)
>> +};
>> +
>> +static int hibmc_hw_config(struct hibmc_drm_device *hidev)
>> +{
>> +       unsigned int reg;
>> +
>> +       /* On hardware reset, power mode 0 is default. */
>> +       hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_MODE0);
>> +
>> +       /* Enable display power gate & LOCALMEM power gate*/
>> +       reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
>> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
>> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
>> +       reg |= HIBMC_CURR_GATE_DISPLAY(ON);
>> +       reg |= HIBMC_CURR_GATE_LOCALMEM(ON);
>> +
>> +       hibmc_set_current_gate(hidev, 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(hidev->mmio + HIBMC_MISC_CTRL);
>> +       reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
>> +       reg |= HIBMC_MSCCTL_LOCALMEM_RESET(RESET);
>> +       writel(reg, hidev->mmio + HIBMC_MISC_CTRL);
>> +
>> +       reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
>> +       reg |= HIBMC_MSCCTL_LOCALMEM_RESET(NORMAL);
>> +
>> +       writel(reg, hidev->mmio + HIBMC_MISC_CTRL);
>> +
>> +       /* We can add more initialization as needed. */
>> +
>> +       return 0;
>
> Consider using void return type here to simplify error checking in the
> caller, especially since it looks like you aren't checking the return
> code, anyways :)

Yes, you are right. i did not check the return value, so void type
is better, thanks.

>
>> +}
>> +
>> +static int hibmc_hw_map(struct hibmc_drm_device *hidev)
>> +{
>> +       struct drm_device *dev = hidev->dev;
>> +       struct pci_dev *pdev = dev->pdev;
>> +       resource_size_t addr, size, ioaddr, iosize;
>> +
>> +       ioaddr = pci_resource_start(pdev, 1);
>> +       iosize = MB(2);
>> +
>> +       hidev->mmio = ioremap_nocache(ioaddr, iosize);
>
> Use devm_ioremap_nocache to avoid managing the resource directly

agreed, thanks

>
>> +
>
> nit: extra space
>
>> +       if (!hidev->mmio) {
>> +               DRM_ERROR("Cannot map mmio region\n");
>> +               return -ENOMEM;
>> +       }
>> +
>> +       addr = pci_resource_start(pdev, 0);
>> +       size = MB(32);
>
> Pull size and iosize out into #defines with descriptive names

agreed, thanks

>
>> +
>> +       hidev->fb_map = ioremap(addr, size);
>
> Use devm_ioremap to avoid managing the resource directly.

agreed, thanks

>
>> +       if (!hidev->fb_map) {
>> +               DRM_ERROR("Cannot map framebuffer\n");
>> +               return -ENOMEM;
>> +       }
>> +       hidev->fb_base = addr;
>> +       hidev->fb_size = size;
>> +
>> +       return 0;
>> +}
>> +
>> +static void hibmc_hw_fini(struct hibmc_drm_device *hidev)
>> +{
>> +       if (hidev->mmio)
>> +               iounmap(hidev->mmio);
>> +       if (hidev->fb_map)
>> +               iounmap(hidev->fb_map);
>> +}
>
> You don't need this function if you use the devm variants above

yes, it seems more simple :)

>
>> +
>> +static int hibmc_hw_init(struct hibmc_drm_device *hidev)
>> +{
>> +       int ret;
>> +
>> +       ret = hibmc_hw_map(hidev);
>> +       if (ret)
>> +               return ret;
>> +
>> +       hibmc_hw_config(hidev);
>> +
>> +       return 0;
>> +}
>> +
>> +static int hibmc_unload(struct drm_device *dev)
>> +{
>> +       struct hibmc_drm_device *hidev = dev->dev_private;
>> +
>> +       hibmc_hw_fini(hidev);
>> +       dev->dev_private = NULL;
>> +       return 0;
>> +}
>> +
>> +static int hibmc_load(struct drm_device *dev, unsigned long flags)
>
> flags isn't used anywhere?

Initially, hibmc_load is assigned to ".load", so second parameter is reserved.
In fact it is not used.

>
>> +{
>> +       struct hibmc_drm_device *hidev;
>> +       int ret;
>> +
>> +       hidev = devm_kzalloc(dev->dev, sizeof(*hidev), GFP_KERNEL);
>> +       if (!hidev)
>
> Print error here?

applied, thanks.

>
>> +               return -ENOMEM;
>> +       dev->dev_private = hidev;
>> +       hidev->dev = dev;
>> +
>> +       ret = hibmc_hw_init(hidev);
>> +       if (ret)
>> +               goto err;
>> +
>> +       return 0;
>> +
>> +err:
>> +       hibmc_unload(dev);
>> +       DRM_ERROR("failed to initialize drm driver.\n");
>
> Print the return value

ditto

>
>> +       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)
>
> Print error here

ditto

>
>> +               return -ENOMEM;
>> +
>> +       dev->pdev = pdev;
>> +       pci_set_drvdata(pdev, dev);
>> +
>> +       ret = pci_enable_device(pdev);
>> +       if (ret)
>
> and here, and in other failure paths

ditto

>
>> +               goto err_free;
>> +
>> +       ret = hibmc_load(dev, 0);
>> +       if (ret)
>> +               goto err_disable;
>> +
>> +       ret = drm_dev_register(dev, 0);
>> +       if (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..0037341
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> @@ -0,0 +1,35 @@
>> +/* 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_device {
>
> nit: Calling this hibmc_drm_priv would probably make things easier to
> read. When I read hibmc_drm_device, it makes me think that it's an
> extension of drm_device, which this isn't.

okay, will replace hibmc_drm_device with hibmc_drm_priv, thanks.

>
>
>> +       /* hw */
>> +       void __iomem   *mmio;
>> +       void __iomem   *fb_map;
>> +       unsigned long  fb_base;
>> +       unsigned long  fb_size;
>> +
>> +       /* drm */
>> +       struct drm_device  *dev;
>> +};
>> +
>> +#endif
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c
>> new file mode 100644
>> index 0000000..1036542
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c
>
> I don't think you need a new file for these functions. Just stash them
> in hibmc_drm_drv.c

okay, thanks.

>
>> @@ -0,0 +1,85 @@
>> +/* 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 "hibmc_drm_drv.h"
>> +#include "hibmc_drm_regs.h"
>> +
>> +/*
>> + * It can operate in one of three modes: 0, 1 or Sleep.
>> + */
>> +void hibmc_set_power_mode(struct hibmc_drm_device *hidev,
>> +                         unsigned int power_mode)
>> +{
>> +       unsigned int control_value = 0;
>> +       void __iomem   *mmio = hidev->mmio;
>> +
>> +       if (power_mode > HIBMC_PW_MODE_CTL_MODE_SLEEP)
>> +               return;
>> +
>> +       control_value = readl(mmio + HIBMC_POWER_MODE_CTRL);
>> +       control_value &= ~HIBMC_PW_MODE_CTL_MODE_MASK;
>> +
>> +       control_value |= HIBMC_PW_MODE_CTL_MODE(power_mode) &
>> +                        HIBMC_PW_MODE_CTL_MODE_MASK;
>> +
>> +    /* Set up other fields in Power Control Register */
>> +       if (power_mode == HIBMC_PW_MODE_CTL_MODE_SLEEP) {
>> +               control_value &= ~HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
>
> You do this in both branches of the conditional

sounds good to me, thanks :)

>
>> +               control_value |= HIBMC_PW_MODE_CTL_OSC_INPUT(0) &
>> +                                HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
>> +       } else {
>> +               control_value &= ~HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
>> +               control_value |= HIBMC_PW_MODE_CTL_OSC_INPUT(1) &
>> +                                HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
>> +       }
>
> I think you could simplify this by adding a new local.
>
> unsigned int input = 1;
>
> 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_PW_MODE_CTL_MODE(power_mode) &
>                   HIBMC_PW_MODE_CTL_MODE_MASK;
> control_value |= HIBMC_PW_MODE_CTL_OSC_INPUT(input) &
>                   HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;

agreed.

>
>
>> +       /* Program new power mode. */
>> +       writel(control_value, mmio + HIBMC_POWER_MODE_CTRL);
>> +}
>> +
>> +static unsigned int hibmc_get_power_mode(struct hibmc_drm_device *hidev)
>> +{
>> +       void __iomem   *mmio = hidev->mmio;
>> +
>> +       return (readl(mmio + HIBMC_POWER_MODE_CTRL) &
>> +               HIBMC_PW_MODE_CTL_MODE_MASK) >> HIBMC_PW_MODE_CTL_MODE_SHIFT;
>
> nit: You're doing a lot of work in the return statement here.

so i need to define an extra variable.

>
>> +}
>> +
>> +void hibmc_set_current_gate(struct hibmc_drm_device *hidev, unsigned int gate)
>> +{
>> +       unsigned int gate_reg;
>> +       unsigned int mode;
>> +       void __iomem   *mmio = hidev->mmio;
>> +
>> +       /* Get current power mode. */
>
> nit: try to avoid comments that don't add value

okay, thanks.

>
>> +       mode = hibmc_get_power_mode(hidev);
>> +
>> +       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);
>> +}
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h
>> new file mode 100644
>> index 0000000..e20e1aa
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h
>> @@ -0,0 +1,28 @@
>> +/* 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_POWER_H
>> +#define HIBMC_DRM_POWER_H
>> +
>> +#include "hibmc_drm_drv.h"
>> +
>> +void hibmc_set_power_mode(struct hibmc_drm_device *hidev,
>> +                         unsigned int power_mode);
>> +void hibmc_set_current_gate(struct hibmc_drm_device *hidev,
>> +                           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..9c804ca
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>> @@ -0,0 +1,212 @@
>> +/* 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
>> +
>> +#define OFF 0
>> +#define ON  1
>> +#define DISABLE               0
>> +#define ENABLE                1
>
> These are not good names. I think you can probably hardcode the 0's
> and 1's in the code instead of these. However, if you want to use
> them, at least add a HIBMC_ prefix

I like hardcode here, thanks.

>
>> +
>> +/* register definition */
>> +#define HIBMC_MISC_CTRL                                0x4
>> +
>> +#define HIBMC_MSCCTL_LOCALMEM_RESET(x)         ((x) << 6)
>> +#define HIBMC_MSCCTL_LOCALMEM_RESET_MASK       0x40
>> +
>> +#define RESET                0
>> +#define NORMAL               1
>
> Same naming nit here. Add a prefix

ditto.

>
>> +
>> +#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 OSC                                    0
>
> Naming

ditto.

>
>> +#define TESTCLK                                        1
>
> This doesn't seem to be used?

will remove it in next version.

>
>> +
>> +#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 CRTSELECT_VGA                0
>> +#define CRTSELECT_CRT                1
>> +
>> +#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE(x)      ((x) << 14)
>> +#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE_MASK    0x4000
>> +
>> +#define PHASE_ACTIVE_HIGH      0
>> +#define PHASE_ACTIVE_LOW       1
>> +
>> +#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_DISPLAY_END(x)    ((x) << 0)
>> +#define HIBMC_CRT_HORZ_TOTAL_DISPLAY_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_DISPLAY_END(x)    ((x) << 0)
>> +#define HIBMC_CRT_VERT_TOTAL_DISPLAY_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_MSK    0x7FF0000
>> +
>> +#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT(x)    ((x) << 0)
>> +#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT_MSK   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 DISPLAY_CONTROL_HISILE                 0x80288
>> +
>> +#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_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
>> +
>> +/* Global macros */
>> +#define RGB(r, g, b) \
>
> Not used anywhere?

will remove it in next version.

>
>> +( \
>> +       (unsigned long)(((r) << 16) | ((g) << 8) | (b)) \
>> +)
>> +
>> +#define PADDING(align, data) (((data) + (align) - 1) & (~((align) - 1)))
>> +
>
> This is only used in hibmc_drm_de.c, move it in there. It might also
> be nice to make it a type-checked function while you're at it.

agreed, thanks.

>
>
>> +#define MB(x) ((x) << 20)
>> +
>
> This is only used in 2 places, I think you can just hardcode the value
> in their respective #defines

agreed, thanks.

Regards,
Rongrong.

>
>> +#endif
>> --
>> 1.9.1
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> _______________________________________________
> linuxarm mailing list
> linuxarm at huawei.com
> http://rnd-openeuler.huawei.com/mailman/listinfo/linuxarm
>
> .
>

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

* Re: [PATCH v6 1/9] drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
@ 2016-11-11  3:10       ` Rongrong Zou
  0 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-11-11  3:10 UTC (permalink / raw)
  To: Sean Paul, Rongrong Zou
  Cc: Mark Rutland, Archit, shenhui, Tomeu Vizoso, Jonathan Corbet,
	Dave Airlie, catalin.marinas, Emil Velikov, linuxarm, dri-devel,
	xinliang.liu, james.xiong, daniel, Daniel Vetter, Will Deacon,
	lijianhua, Linux ARM Kernel, Benjamin Gaignard

Hi Sean,

Thanks for reviewing! All comments is helpful.

在 2016/11/11 1:35, Sean Paul 写道:
> On Fri, Oct 28, 2016 at 3:27 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>
>> ---
>>   drivers/gpu/drm/hisilicon/Kconfig                 |   1 +
>>   drivers/gpu/drm/hisilicon/Makefile                |   1 +
>>   drivers/gpu/drm/hisilicon/hibmc/Kconfig           |   7 +
>>   drivers/gpu/drm/hisilicon/hibmc/Makefile          |   5 +
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   | 269 ++++++++++++++++++++++
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   |  35 +++
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c |  85 +++++++
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h |  28 +++
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h  | 212 +++++++++++++++++
>>   9 files changed, 643 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_power.c
>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.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..a9af90d
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>> @@ -0,0 +1,7 @@
>> +config DRM_HISI_HIBMC
>> +       tristate "DRM Support for Hisilicon Hibmc"
>> +       depends on DRM && PCI
>> +
>> +       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..97cf4a0
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>> @@ -0,0 +1,5 @@
>> +ccflags-y := -Iinclude/drm
>> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o
>> +
>> +obj-$(CONFIG_DRM_HISI_HIBMC)   +=hibmc-drm.o
>
> nit: Improper spacing here

seems a space was missed, thanks.

>
>> +#obj-y += 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..4669d42
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> @@ -0,0 +1,269 @@
>> +/* 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/module.h>
>> +#include <linux/console.h>
>> +
>> +#include "hibmc_drm_drv.h"
>> +#include "hibmc_drm_regs.h"
>> +#include "hibmc_drm_power.h"
>
> nit: Alphabetize headers

agreed, thanks.

>
>> +
>> +static const struct file_operations hibmc_fops = {
>> +       .owner          = THIS_MODULE,
>> +       .open           = drm_open,
>> +       .release        = drm_release,
>> +       .unlocked_ioctl = drm_ioctl,
>> +#ifdef CONFIG_COMPAT
>
> drm_compat_ioctl is now initialized to NULL, so you can remove the #ifdef
>
understood, will remove it next version.

>> +       .compat_ioctl   = drm_compat_ioctl,
>> +#endif
>> +       .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)
>> +};
>> +
>> +static int hibmc_hw_config(struct hibmc_drm_device *hidev)
>> +{
>> +       unsigned int reg;
>> +
>> +       /* On hardware reset, power mode 0 is default. */
>> +       hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_MODE0);
>> +
>> +       /* Enable display power gate & LOCALMEM power gate*/
>> +       reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
>> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
>> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
>> +       reg |= HIBMC_CURR_GATE_DISPLAY(ON);
>> +       reg |= HIBMC_CURR_GATE_LOCALMEM(ON);
>> +
>> +       hibmc_set_current_gate(hidev, 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(hidev->mmio + HIBMC_MISC_CTRL);
>> +       reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
>> +       reg |= HIBMC_MSCCTL_LOCALMEM_RESET(RESET);
>> +       writel(reg, hidev->mmio + HIBMC_MISC_CTRL);
>> +
>> +       reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
>> +       reg |= HIBMC_MSCCTL_LOCALMEM_RESET(NORMAL);
>> +
>> +       writel(reg, hidev->mmio + HIBMC_MISC_CTRL);
>> +
>> +       /* We can add more initialization as needed. */
>> +
>> +       return 0;
>
> Consider using void return type here to simplify error checking in the
> caller, especially since it looks like you aren't checking the return
> code, anyways :)

Yes, you are right. i did not check the return value, so void type
is better, thanks.

>
>> +}
>> +
>> +static int hibmc_hw_map(struct hibmc_drm_device *hidev)
>> +{
>> +       struct drm_device *dev = hidev->dev;
>> +       struct pci_dev *pdev = dev->pdev;
>> +       resource_size_t addr, size, ioaddr, iosize;
>> +
>> +       ioaddr = pci_resource_start(pdev, 1);
>> +       iosize = MB(2);
>> +
>> +       hidev->mmio = ioremap_nocache(ioaddr, iosize);
>
> Use devm_ioremap_nocache to avoid managing the resource directly

agreed, thanks

>
>> +
>
> nit: extra space
>
>> +       if (!hidev->mmio) {
>> +               DRM_ERROR("Cannot map mmio region\n");
>> +               return -ENOMEM;
>> +       }
>> +
>> +       addr = pci_resource_start(pdev, 0);
>> +       size = MB(32);
>
> Pull size and iosize out into #defines with descriptive names

agreed, thanks

>
>> +
>> +       hidev->fb_map = ioremap(addr, size);
>
> Use devm_ioremap to avoid managing the resource directly.

agreed, thanks

>
>> +       if (!hidev->fb_map) {
>> +               DRM_ERROR("Cannot map framebuffer\n");
>> +               return -ENOMEM;
>> +       }
>> +       hidev->fb_base = addr;
>> +       hidev->fb_size = size;
>> +
>> +       return 0;
>> +}
>> +
>> +static void hibmc_hw_fini(struct hibmc_drm_device *hidev)
>> +{
>> +       if (hidev->mmio)
>> +               iounmap(hidev->mmio);
>> +       if (hidev->fb_map)
>> +               iounmap(hidev->fb_map);
>> +}
>
> You don't need this function if you use the devm variants above

yes, it seems more simple :)

>
>> +
>> +static int hibmc_hw_init(struct hibmc_drm_device *hidev)
>> +{
>> +       int ret;
>> +
>> +       ret = hibmc_hw_map(hidev);
>> +       if (ret)
>> +               return ret;
>> +
>> +       hibmc_hw_config(hidev);
>> +
>> +       return 0;
>> +}
>> +
>> +static int hibmc_unload(struct drm_device *dev)
>> +{
>> +       struct hibmc_drm_device *hidev = dev->dev_private;
>> +
>> +       hibmc_hw_fini(hidev);
>> +       dev->dev_private = NULL;
>> +       return 0;
>> +}
>> +
>> +static int hibmc_load(struct drm_device *dev, unsigned long flags)
>
> flags isn't used anywhere?

Initially, hibmc_load is assigned to ".load", so second parameter is reserved.
In fact it is not used.

>
>> +{
>> +       struct hibmc_drm_device *hidev;
>> +       int ret;
>> +
>> +       hidev = devm_kzalloc(dev->dev, sizeof(*hidev), GFP_KERNEL);
>> +       if (!hidev)
>
> Print error here?

applied, thanks.

>
>> +               return -ENOMEM;
>> +       dev->dev_private = hidev;
>> +       hidev->dev = dev;
>> +
>> +       ret = hibmc_hw_init(hidev);
>> +       if (ret)
>> +               goto err;
>> +
>> +       return 0;
>> +
>> +err:
>> +       hibmc_unload(dev);
>> +       DRM_ERROR("failed to initialize drm driver.\n");
>
> Print the return value

ditto

>
>> +       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)
>
> Print error here

ditto

>
>> +               return -ENOMEM;
>> +
>> +       dev->pdev = pdev;
>> +       pci_set_drvdata(pdev, dev);
>> +
>> +       ret = pci_enable_device(pdev);
>> +       if (ret)
>
> and here, and in other failure paths

ditto

>
>> +               goto err_free;
>> +
>> +       ret = hibmc_load(dev, 0);
>> +       if (ret)
>> +               goto err_disable;
>> +
>> +       ret = drm_dev_register(dev, 0);
>> +       if (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..0037341
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> @@ -0,0 +1,35 @@
>> +/* 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_device {
>
> nit: Calling this hibmc_drm_priv would probably make things easier to
> read. When I read hibmc_drm_device, it makes me think that it's an
> extension of drm_device, which this isn't.

okay, will replace hibmc_drm_device with hibmc_drm_priv, thanks.

>
>
>> +       /* hw */
>> +       void __iomem   *mmio;
>> +       void __iomem   *fb_map;
>> +       unsigned long  fb_base;
>> +       unsigned long  fb_size;
>> +
>> +       /* drm */
>> +       struct drm_device  *dev;
>> +};
>> +
>> +#endif
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c
>> new file mode 100644
>> index 0000000..1036542
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c
>
> I don't think you need a new file for these functions. Just stash them
> in hibmc_drm_drv.c

okay, thanks.

>
>> @@ -0,0 +1,85 @@
>> +/* 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 "hibmc_drm_drv.h"
>> +#include "hibmc_drm_regs.h"
>> +
>> +/*
>> + * It can operate in one of three modes: 0, 1 or Sleep.
>> + */
>> +void hibmc_set_power_mode(struct hibmc_drm_device *hidev,
>> +                         unsigned int power_mode)
>> +{
>> +       unsigned int control_value = 0;
>> +       void __iomem   *mmio = hidev->mmio;
>> +
>> +       if (power_mode > HIBMC_PW_MODE_CTL_MODE_SLEEP)
>> +               return;
>> +
>> +       control_value = readl(mmio + HIBMC_POWER_MODE_CTRL);
>> +       control_value &= ~HIBMC_PW_MODE_CTL_MODE_MASK;
>> +
>> +       control_value |= HIBMC_PW_MODE_CTL_MODE(power_mode) &
>> +                        HIBMC_PW_MODE_CTL_MODE_MASK;
>> +
>> +    /* Set up other fields in Power Control Register */
>> +       if (power_mode == HIBMC_PW_MODE_CTL_MODE_SLEEP) {
>> +               control_value &= ~HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
>
> You do this in both branches of the conditional

sounds good to me, thanks :)

>
>> +               control_value |= HIBMC_PW_MODE_CTL_OSC_INPUT(0) &
>> +                                HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
>> +       } else {
>> +               control_value &= ~HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
>> +               control_value |= HIBMC_PW_MODE_CTL_OSC_INPUT(1) &
>> +                                HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
>> +       }
>
> I think you could simplify this by adding a new local.
>
> unsigned int input = 1;
>
> 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_PW_MODE_CTL_MODE(power_mode) &
>                   HIBMC_PW_MODE_CTL_MODE_MASK;
> control_value |= HIBMC_PW_MODE_CTL_OSC_INPUT(input) &
>                   HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;

agreed.

>
>
>> +       /* Program new power mode. */
>> +       writel(control_value, mmio + HIBMC_POWER_MODE_CTRL);
>> +}
>> +
>> +static unsigned int hibmc_get_power_mode(struct hibmc_drm_device *hidev)
>> +{
>> +       void __iomem   *mmio = hidev->mmio;
>> +
>> +       return (readl(mmio + HIBMC_POWER_MODE_CTRL) &
>> +               HIBMC_PW_MODE_CTL_MODE_MASK) >> HIBMC_PW_MODE_CTL_MODE_SHIFT;
>
> nit: You're doing a lot of work in the return statement here.

so i need to define an extra variable.

>
>> +}
>> +
>> +void hibmc_set_current_gate(struct hibmc_drm_device *hidev, unsigned int gate)
>> +{
>> +       unsigned int gate_reg;
>> +       unsigned int mode;
>> +       void __iomem   *mmio = hidev->mmio;
>> +
>> +       /* Get current power mode. */
>
> nit: try to avoid comments that don't add value

okay, thanks.

>
>> +       mode = hibmc_get_power_mode(hidev);
>> +
>> +       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);
>> +}
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h
>> new file mode 100644
>> index 0000000..e20e1aa
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h
>> @@ -0,0 +1,28 @@
>> +/* 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_POWER_H
>> +#define HIBMC_DRM_POWER_H
>> +
>> +#include "hibmc_drm_drv.h"
>> +
>> +void hibmc_set_power_mode(struct hibmc_drm_device *hidev,
>> +                         unsigned int power_mode);
>> +void hibmc_set_current_gate(struct hibmc_drm_device *hidev,
>> +                           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..9c804ca
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>> @@ -0,0 +1,212 @@
>> +/* 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
>> +
>> +#define OFF 0
>> +#define ON  1
>> +#define DISABLE               0
>> +#define ENABLE                1
>
> These are not good names. I think you can probably hardcode the 0's
> and 1's in the code instead of these. However, if you want to use
> them, at least add a HIBMC_ prefix

I like hardcode here, thanks.

>
>> +
>> +/* register definition */
>> +#define HIBMC_MISC_CTRL                                0x4
>> +
>> +#define HIBMC_MSCCTL_LOCALMEM_RESET(x)         ((x) << 6)
>> +#define HIBMC_MSCCTL_LOCALMEM_RESET_MASK       0x40
>> +
>> +#define RESET                0
>> +#define NORMAL               1
>
> Same naming nit here. Add a prefix

ditto.

>
>> +
>> +#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 OSC                                    0
>
> Naming

ditto.

>
>> +#define TESTCLK                                        1
>
> This doesn't seem to be used?

will remove it in next version.

>
>> +
>> +#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 CRTSELECT_VGA                0
>> +#define CRTSELECT_CRT                1
>> +
>> +#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE(x)      ((x) << 14)
>> +#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE_MASK    0x4000
>> +
>> +#define PHASE_ACTIVE_HIGH      0
>> +#define PHASE_ACTIVE_LOW       1
>> +
>> +#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_DISPLAY_END(x)    ((x) << 0)
>> +#define HIBMC_CRT_HORZ_TOTAL_DISPLAY_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_DISPLAY_END(x)    ((x) << 0)
>> +#define HIBMC_CRT_VERT_TOTAL_DISPLAY_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_MSK    0x7FF0000
>> +
>> +#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT(x)    ((x) << 0)
>> +#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT_MSK   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 DISPLAY_CONTROL_HISILE                 0x80288
>> +
>> +#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_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
>> +
>> +/* Global macros */
>> +#define RGB(r, g, b) \
>
> Not used anywhere?

will remove it in next version.

>
>> +( \
>> +       (unsigned long)(((r) << 16) | ((g) << 8) | (b)) \
>> +)
>> +
>> +#define PADDING(align, data) (((data) + (align) - 1) & (~((align) - 1)))
>> +
>
> This is only used in hibmc_drm_de.c, move it in there. It might also
> be nice to make it a type-checked function while you're at it.

agreed, thanks.

>
>
>> +#define MB(x) ((x) << 20)
>> +
>
> This is only used in 2 places, I think you can just hardcode the value
> in their respective #defines

agreed, thanks.

Regards,
Rongrong.

>
>> +#endif
>> --
>> 1.9.1
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> _______________________________________________
> 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] 64+ messages in thread

* [PATCH v6 2/9] drm/hisilicon/hibmc: Add video memory management
  2016-11-10 17:35     ` Sean Paul
@ 2016-11-11 11:16       ` Rongrong Zou
  -1 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-11-11 11:16 UTC (permalink / raw)
  To: linux-arm-kernel

? 2016/11/11 1:35, Sean Paul ??:
> On Fri, Oct 28, 2016 at 3:27 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>
>> ---
>>   drivers/gpu/drm/hisilicon/hibmc/Kconfig         |   1 +
>>   drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  12 +
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |  46 +++
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     | 490 ++++++++++++++++++++++++
>>   5 files changed, 550 insertions(+), 1 deletion(-)
>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>> index a9af90d..bcb8c18 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>> @@ -1,6 +1,7 @@
>>   config DRM_HISI_HIBMC
>>          tristate "DRM Support for Hisilicon Hibmc"
>>          depends on DRM && PCI
>> +       select DRM_TTM
>>
>>          help
>>            Choose this option if you have a Hisilicon Hibmc soc chipset.
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>> index 97cf4a0..d5c40b8 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>> @@ -1,5 +1,5 @@
>>   ccflags-y := -Iinclude/drm
>> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o
>> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o hibmc_ttm.o
>>
>>   obj-$(CONFIG_DRM_HISI_HIBMC)   +=hibmc-drm.o
>>   #obj-y += 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 4669d42..81f4301 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> @@ -31,6 +31,7 @@
>>   #ifdef CONFIG_COMPAT
>>          .compat_ioctl   = drm_compat_ioctl,
>>   #endif
>> +       .mmap           = hibmc_mmap,
>>          .poll           = drm_poll,
>>          .read           = drm_read,
>>          .llseek         = no_llseek,
>> @@ -46,6 +47,8 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>>   }
>>
>>   static struct drm_driver hibmc_driver = {
>> +       .driver_features        = DRIVER_GEM,
>> +
>
> nit: extra space
>
>>          .fops                   = &hibmc_fops,
>>          .name                   = "hibmc",
>>          .date                   = "20160828",
>> @@ -55,6 +58,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)
>> @@ -163,6 +170,7 @@ static int hibmc_unload(struct drm_device *dev)
>>   {
>>          struct hibmc_drm_device *hidev = dev->dev_private;
>>
>> +       hibmc_mm_fini(hidev);
>>          hibmc_hw_fini(hidev);
>>          dev->dev_private = NULL;
>>          return 0;
>> @@ -183,6 +191,10 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
>>          if (ret)
>>                  goto err;
>>
>> +       ret = hibmc_mm_init(hidev);
>> +       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 0037341..db8d80e 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/ttm/ttm_bo_driver.h>
>> +#include <drm/drm_gem.h>
>
> nit: alphabetize

will fix it, thanks.

>
>>
>>   struct hibmc_drm_device {
>>          /* hw */
>> @@ -30,6 +32,50 @@ struct hibmc_drm_device {
>>
>>          /* drm */
>>          struct drm_device  *dev;
>> +
>> +       /* ttm */
>> +       struct {
>> +               struct drm_global_reference mem_global_ref;
>> +               struct ttm_bo_global_ref bo_global_ref;
>> +               struct ttm_bo_device bdev;
>> +               bool initialized;
>> +       } ttm;
>
> I don't think you gain anything other than keystrokes from the substruct

I'm sorry i didn't catch you, i looked at the all drivers used ttm such
as ast/bochs/cirrus/mgag200/qxl/virtio_gpu, they all embedded the ttm substruct
into the driver-private struct.

so do you mean
struct hibmc_drm_device {
	/* hw */
	void __iomem   *mmio;
	void __iomem   *fb_map;
	unsigned long  fb_base;
	unsigned long  fb_size;

	/* drm */
	struct drm_device  *dev;
	struct drm_plane plane;
	struct drm_crtc crtc;
	struct drm_encoder encoder;
	struct drm_connector connector;
	bool mode_config_initialized;

	/* 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);
>> +}
>> +
>> +#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
>
> Hide this in ttm.c

ok, will do that.
thanks for pointing it out.

>
>> +
>> +int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
>> +                    struct drm_gem_object **obj);
>> +
>> +int hibmc_mm_init(struct hibmc_drm_device *hibmc);
>> +void hibmc_mm_fini(struct hibmc_drm_device *hibmc);
>> +int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr);
>> +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..0802ebd
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>> @@ -0,0 +1,490 @@
>> +/* 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 "hibmc_drm_drv.h"
>> +#include <ttm/ttm_page_alloc.h>
>> +#include <drm/drm_crtc_helper.h>
>> +#include <drm/drm_atomic_helper.h>
>> +
>> +static inline struct hibmc_drm_device *
>> +hibmc_bdev(struct ttm_bo_device *bd)
>> +{
>> +       return container_of(bd, struct hibmc_drm_device, ttm.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_device *hibmc)
>> +{
>> +       struct drm_global_reference *global_ref;
>> +       int r;
>
> nit: try not to use one character variable names unless it's for the
> purpose of a loop (ie: i,j). You also use ret elsewhere in the driver,
> so it'd be nice to remain consistent

the whole file is delivered from bochs ttm, i didn't modify anything except
some checkpatch warnings and the 'hibmc_' prefix. Unfortunately, some
problems were delivered too.

>
>> +
>> +       global_ref = &hibmc->ttm.mem_global_ref;
>
> I think using the global_ref local obfuscates what you're doing here.
> It saves you 6 characters while typing, but adds a layer of
> indirection for all future readers.
>
>> +       global_ref->global_type = DRM_GLOBAL_TTM_MEM;
>> +       global_ref->size = sizeof(struct ttm_mem_global);
>> +       global_ref->init = &hibmc_ttm_mem_global_init;
>> +       global_ref->release = &hibmc_ttm_mem_global_release;
>> +       r = drm_global_item_ref(global_ref);
>> +       if (r != 0) {
>
> nit: if (r)

will fix it,
thanks.
BTW, i wonder why checkpatch.pl didn't report it.


>
>> +               DRM_ERROR("Failed setting up TTM memory accounting subsystem.\n"
>> +                        );
>
> Breaking up the line for one character is probably not worthwhile, and
> you should really print the error. How about:
>
> DRM_ERROR("Could not get ref on ttm global ret=%d.\n", ret);

i like your solution, thanks.

>
>
>> +               return r;
>> +       }
>> +
>> +       hibmc->ttm.bo_global_ref.mem_glob =
>> +               hibmc->ttm.mem_global_ref.object;
>> +       global_ref = &hibmc->ttm.bo_global_ref.ref;
>> +       global_ref->global_type = DRM_GLOBAL_TTM_BO;
>> +       global_ref->size = sizeof(struct ttm_bo_global);
>> +       global_ref->init = &ttm_bo_global_init;
>> +       global_ref->release = &ttm_bo_global_release;
>> +       r = drm_global_item_ref(global_ref);
>> +       if (r != 0) {
>> +               DRM_ERROR("Failed setting up TTM BO subsystem.\n");
>> +               drm_global_item_unref(&hibmc->ttm.mem_global_ref);
>> +               return r;
>> +       }
>> +       return 0;
>> +}
>> +
>> +static void
>> +hibmc_ttm_global_release(struct hibmc_drm_device *hibmc)
>> +{
>> +       if (!hibmc->ttm.mem_global_ref.release)
>
> Are you actually hitting this condition? This seems like it's papering
> over something else.

it was also delivered from others, i looked at the xxx_ttm_global_init
function, 'mem_global_ref.release' is assigned unconditionally, so i
think this condition never be hit, it may be hit when release twice,
but this won't take place in my driver.

>
>> +               return;
>> +
>> +       drm_global_item_unref(&hibmc->ttm.bo_global_ref.ref);
>> +       drm_global_item_unref(&hibmc->ttm.mem_global_ref);
>> +       hibmc->ttm.mem_global_ref.release = NULL;
>> +}
>> +
>> +static void hibmc_bo_ttm_destroy(struct ttm_buffer_object *tbo)
>> +{
>> +       struct hibmc_bo *bo;
>> +
>> +       bo = container_of(tbo, struct hibmc_bo, bo);
>
> nit: No need to split this into a separate line.

agreed, thanks.

>
>> +
>> +       drm_gem_object_release(&bo->gem);
>> +       kfree(bo);
>> +}
>> +
>> +static bool hibmc_ttm_bo_is_hibmc_bo(struct ttm_buffer_object *bo)
>> +{
>> +       if (bo->destroy == &hibmc_bo_ttm_destroy)
>> +               return true;
>> +       return false;
>
> return bo->destroy == &hibmc_bo_ttm_destroy;

looks better to me.

>
>> +}
>> +
>> +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 c = 0;
>
> Can you please use a more descriptive name than 'c'?

ok, will do that.

>
>> +       u32 i;
>> +
>> +       bo->placement.placement = bo->placements;
>> +       bo->placement.busy_placement = bo->placements;
>> +       if (domain & TTM_PL_FLAG_VRAM)
>> +               bo->placements[c++].flags = TTM_PL_FLAG_WC |
>> +               TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
>
> nit: you're alignment is off here and below

is it correct?

	if (domain & TTM_PL_FLAG_VRAM)
		bo->placements[c++].flags = TTM_PL_FLAG_WC |
			TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
	if (domain & TTM_PL_FLAG_SYSTEM)
		bo->placements[c++].flags = TTM_PL_MASK_CACHING |
			TTM_PL_FLAG_SYSTEM;
	if (!c)
		bo->placements[c++].flags = TTM_PL_MASK_CACHING |
			TTM_PL_FLAG_SYSTEM;

>
>> +       if (domain & TTM_PL_FLAG_SYSTEM)
>> +               bo->placements[c++].flags = TTM_PL_MASK_CACHING |
>> +               TTM_PL_FLAG_SYSTEM;
>> +       if (!c)
>> +               bo->placements[c++].flags = TTM_PL_MASK_CACHING |
>> +               TTM_PL_FLAG_SYSTEM;
>> +
>> +       bo->placement.num_placement = c;
>> +       bo->placement.num_busy_placement = c;
>> +       for (i = 0; i < c; ++i) {
>
> nit: we tend towards post-increment in kernel

agreed, thanks.

>
>> +               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_device *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_io_mem_free(struct ttm_bo_device *bdev,
>> +                                 struct ttm_mem_reg *mem)
>> +{
>> +}
>
> No need to stub this, the caller does a NULL-check before invoking

will delete it, thanks.

>
>> +
>> +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;
>> +
>> +       tt = kzalloc(sizeof(*tt), GFP_KERNEL);
>> +       if (!tt)
>
> Print error

ok, will do that, thanks.

>
>> +               return NULL;
>> +       tt->func = &hibmc_tt_backend_func;
>> +       if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) {
>
> Here too?

ditto

>
>> +               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            = &hibmc_ttm_io_mem_free,
>> +       .lru_tail               = &ttm_bo_default_lru_tail,
>> +       .swap_lru_tail          = &ttm_bo_default_swap_lru_tail,
>> +};
>> +
>> +int hibmc_mm_init(struct hibmc_drm_device *hibmc)
>> +{
>> +       int ret;
>> +       struct drm_device *dev = hibmc->dev;
>> +       struct ttm_bo_device *bdev = &hibmc->ttm.bdev;
>> +
>> +       ret = hibmc_ttm_global_init(hibmc);
>> +       if (ret)
>> +               return ret;
>> +
>> +       ret = ttm_bo_device_init(&hibmc->ttm.bdev,
>> +                                hibmc->ttm.bo_global_ref.ref.object,
>> +                                &hibmc_bo_driver,
>> +                                dev->anon_inode->i_mapping,
>> +                                DRM_FILE_PAGE_OFFSET,
>> +                                true);
>> +       if (ret) {
>
> Call hibmc_ttm_global_release here?

agreed, thanks for pointing it out.

>
>> +               DRM_ERROR("Error initialising bo driver; %d\n", ret);
>> +               return ret;
>> +       }
>> +
>> +       ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
>> +                            hibmc->fb_size >> PAGE_SHIFT);
>> +       if (ret) {
>
> Clean up here as well?

ditto

>
>> +               DRM_ERROR("Failed ttm VRAM init: %d\n", ret);
>> +               return ret;
>> +       }
>> +
>> +       hibmc->mm_inited = true;
>> +       return 0;
>> +}
>> +
>> +void hibmc_mm_fini(struct hibmc_drm_device *hibmc)
>> +{
>> +       if (!hibmc->mm_inited)
>> +               return;
>> +
>> +       ttm_bo_device_release(&hibmc->ttm.bdev);
>> +       hibmc_ttm_global_release(hibmc);
>> +       hibmc->mm_inited = false;
>> +}
>> +
>> +int hibmc_bo_create(struct drm_device *dev, int size, int align,
>> +                   u32 flags, struct hibmc_bo **phibmcbo)
>> +{
>> +       struct hibmc_drm_device *hibmc = dev->dev_private;
>> +       struct hibmc_bo *hibmcbo;
>> +       size_t acc_size;
>> +       int ret;
>> +
>> +       hibmcbo = kzalloc(sizeof(*hibmcbo), GFP_KERNEL);
>> +       if (!hibmcbo)
>> +               return -ENOMEM;
>> +
>> +       ret = drm_gem_object_init(dev, &hibmcbo->gem, size);
>> +       if (ret) {
>> +               kfree(hibmcbo);
>> +               return ret;
>> +       }
>> +
>> +       hibmcbo->bo.bdev = &hibmc->ttm.bdev;
>> +
>> +       hibmc_ttm_placement(hibmcbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
>> +
>> +       acc_size = ttm_bo_dma_acc_size(&hibmc->ttm.bdev, size,
>> +                                      sizeof(struct hibmc_bo));
>> +
>> +       ret = ttm_bo_init(&hibmc->ttm.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)
>
> Missing hibmcbo clean up here

i looked at all other ttm drivers and all of them return directly when ttm_bo_init
failed, however, i think it is better to clean up here, should i call
hibmc_bo_unref(&hibmc_bo) here ?

>
>> +               return ret;
>> +
>> +       *phibmcbo = hibmcbo;
>> +       return 0;
>> +}
>> +
>> +static inline u64 hibmc_bo_gpu_offset(struct hibmc_bo *bo)
>> +{
>> +       return bo->bo.offset;
>> +}
>
> I don't think this function provides any value

do you nean i use bo->bo.offset instead of calling hibmc_bo_gpu_offset()?

>
>> +
>> +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 = hibmc_bo_gpu_offset(bo);
>
> Are you missing a return here?

Thanks for pointing it out!

>
>> +       }
>> +
>> +       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 = hibmc_bo_gpu_offset(bo);
>> +       return 0;
>> +}
>> +
>> +int hibmc_bo_push_sysram(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;
>> +
>> +       if (bo->kmap.virtual)
>
> ttm_bo_kunmap already does this check so you don't have to

agreed. will remove this condition.

>
>> +               ttm_bo_kunmap(&bo->kmap);
>> +
>> +       hibmc_ttm_placement(bo, TTM_PL_FLAG_SYSTEM);
>> +       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("pushing to VRAM failed\n");
>
> Print ret

ok, thanks.

>
>> +               return ret;
>> +       }
>> +       return 0;
>> +}
>> +
>> +int hibmc_mmap(struct file *filp, struct vm_area_struct *vma)
>> +{
>> +       struct drm_file *file_priv;
>> +       struct hibmc_drm_device *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->ttm.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)
>
> Print error

ditto

>
>> +               return -EINVAL;
>> +
>> +       ret = hibmc_bo_create(dev, size, 0, 0, &hibmcbo);
>> +       if (ret) {
>> +               if (ret != -ERESTARTSYS)
>> +                       DRM_ERROR("failed to allocate GEM object\n");
>
> Print ret

ditto

>
>> +               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 * ((args->bpp + 7) / 8), 16);
>
> What's up with the bpp + 7 here? Perhaps you're looking for DIV_ROUND_UP?

Yes, that sounds sane.

>
>
>> +       args->size = args->pitch * args->height;
>> +
>> +       ret = hibmc_gem_create(dev, args->size, false,
>> +                              &gobj);
>> +       if (ret)
>> +               return ret;
>> +
>> +       ret = drm_gem_handle_create(file, gobj, &handle);
>> +       drm_gem_object_unreference_unlocked(gobj);
>> +       if (ret)
>
> Print error here

agreed.

>
>> +               return ret;
>> +
>> +       args->handle = handle;
>> +       return 0;
>> +}
>> +
>> +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;
>> +}
>> +
>> +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;
>> +}

Regards,
Rongrong.

>> --
>> 1.9.1
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> _______________________________________________
> linuxarm mailing list
> linuxarm at huawei.com
> http://rnd-openeuler.huawei.com/mailman/listinfo/linuxarm
>
> .
>

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

* Re: [PATCH v6 2/9] drm/hisilicon/hibmc: Add video memory management
@ 2016-11-11 11:16       ` Rongrong Zou
  0 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-11-11 11:16 UTC (permalink / raw)
  To: Sean Paul, Rongrong Zou
  Cc: Mark Rutland, Archit, shenhui, Tomeu Vizoso, Jonathan Corbet,
	Dave Airlie, catalin.marinas, Emil Velikov, linuxarm, dri-devel,
	xinliang.liu, james.xiong, daniel, Daniel Vetter, Will Deacon,
	lijianhua, Linux ARM Kernel, Benjamin Gaignard

在 2016/11/11 1:35, Sean Paul 写道:
> On Fri, Oct 28, 2016 at 3:27 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>
>> ---
>>   drivers/gpu/drm/hisilicon/hibmc/Kconfig         |   1 +
>>   drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  12 +
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |  46 +++
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     | 490 ++++++++++++++++++++++++
>>   5 files changed, 550 insertions(+), 1 deletion(-)
>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>> index a9af90d..bcb8c18 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>> @@ -1,6 +1,7 @@
>>   config DRM_HISI_HIBMC
>>          tristate "DRM Support for Hisilicon Hibmc"
>>          depends on DRM && PCI
>> +       select DRM_TTM
>>
>>          help
>>            Choose this option if you have a Hisilicon Hibmc soc chipset.
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>> index 97cf4a0..d5c40b8 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>> @@ -1,5 +1,5 @@
>>   ccflags-y := -Iinclude/drm
>> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o
>> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o hibmc_ttm.o
>>
>>   obj-$(CONFIG_DRM_HISI_HIBMC)   +=hibmc-drm.o
>>   #obj-y += 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 4669d42..81f4301 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> @@ -31,6 +31,7 @@
>>   #ifdef CONFIG_COMPAT
>>          .compat_ioctl   = drm_compat_ioctl,
>>   #endif
>> +       .mmap           = hibmc_mmap,
>>          .poll           = drm_poll,
>>          .read           = drm_read,
>>          .llseek         = no_llseek,
>> @@ -46,6 +47,8 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>>   }
>>
>>   static struct drm_driver hibmc_driver = {
>> +       .driver_features        = DRIVER_GEM,
>> +
>
> nit: extra space
>
>>          .fops                   = &hibmc_fops,
>>          .name                   = "hibmc",
>>          .date                   = "20160828",
>> @@ -55,6 +58,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)
>> @@ -163,6 +170,7 @@ static int hibmc_unload(struct drm_device *dev)
>>   {
>>          struct hibmc_drm_device *hidev = dev->dev_private;
>>
>> +       hibmc_mm_fini(hidev);
>>          hibmc_hw_fini(hidev);
>>          dev->dev_private = NULL;
>>          return 0;
>> @@ -183,6 +191,10 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
>>          if (ret)
>>                  goto err;
>>
>> +       ret = hibmc_mm_init(hidev);
>> +       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 0037341..db8d80e 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/ttm/ttm_bo_driver.h>
>> +#include <drm/drm_gem.h>
>
> nit: alphabetize

will fix it, thanks.

>
>>
>>   struct hibmc_drm_device {
>>          /* hw */
>> @@ -30,6 +32,50 @@ struct hibmc_drm_device {
>>
>>          /* drm */
>>          struct drm_device  *dev;
>> +
>> +       /* ttm */
>> +       struct {
>> +               struct drm_global_reference mem_global_ref;
>> +               struct ttm_bo_global_ref bo_global_ref;
>> +               struct ttm_bo_device bdev;
>> +               bool initialized;
>> +       } ttm;
>
> I don't think you gain anything other than keystrokes from the substruct

I'm sorry i didn't catch you, i looked at the all drivers used ttm such
as ast/bochs/cirrus/mgag200/qxl/virtio_gpu, they all embedded the ttm substruct
into the driver-private struct.

so do you mean
struct hibmc_drm_device {
	/* hw */
	void __iomem   *mmio;
	void __iomem   *fb_map;
	unsigned long  fb_base;
	unsigned long  fb_size;

	/* drm */
	struct drm_device  *dev;
	struct drm_plane plane;
	struct drm_crtc crtc;
	struct drm_encoder encoder;
	struct drm_connector connector;
	bool mode_config_initialized;

	/* 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);
>> +}
>> +
>> +#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
>
> Hide this in ttm.c

ok, will do that.
thanks for pointing it out.

>
>> +
>> +int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
>> +                    struct drm_gem_object **obj);
>> +
>> +int hibmc_mm_init(struct hibmc_drm_device *hibmc);
>> +void hibmc_mm_fini(struct hibmc_drm_device *hibmc);
>> +int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr);
>> +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..0802ebd
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>> @@ -0,0 +1,490 @@
>> +/* 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 "hibmc_drm_drv.h"
>> +#include <ttm/ttm_page_alloc.h>
>> +#include <drm/drm_crtc_helper.h>
>> +#include <drm/drm_atomic_helper.h>
>> +
>> +static inline struct hibmc_drm_device *
>> +hibmc_bdev(struct ttm_bo_device *bd)
>> +{
>> +       return container_of(bd, struct hibmc_drm_device, ttm.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_device *hibmc)
>> +{
>> +       struct drm_global_reference *global_ref;
>> +       int r;
>
> nit: try not to use one character variable names unless it's for the
> purpose of a loop (ie: i,j). You also use ret elsewhere in the driver,
> so it'd be nice to remain consistent

the whole file is delivered from bochs ttm, i didn't modify anything except
some checkpatch warnings and the 'hibmc_' prefix. Unfortunately, some
problems were delivered too.

>
>> +
>> +       global_ref = &hibmc->ttm.mem_global_ref;
>
> I think using the global_ref local obfuscates what you're doing here.
> It saves you 6 characters while typing, but adds a layer of
> indirection for all future readers.
>
>> +       global_ref->global_type = DRM_GLOBAL_TTM_MEM;
>> +       global_ref->size = sizeof(struct ttm_mem_global);
>> +       global_ref->init = &hibmc_ttm_mem_global_init;
>> +       global_ref->release = &hibmc_ttm_mem_global_release;
>> +       r = drm_global_item_ref(global_ref);
>> +       if (r != 0) {
>
> nit: if (r)

will fix it,
thanks.
BTW, i wonder why checkpatch.pl didn't report it.


>
>> +               DRM_ERROR("Failed setting up TTM memory accounting subsystem.\n"
>> +                        );
>
> Breaking up the line for one character is probably not worthwhile, and
> you should really print the error. How about:
>
> DRM_ERROR("Could not get ref on ttm global ret=%d.\n", ret);

i like your solution, thanks.

>
>
>> +               return r;
>> +       }
>> +
>> +       hibmc->ttm.bo_global_ref.mem_glob =
>> +               hibmc->ttm.mem_global_ref.object;
>> +       global_ref = &hibmc->ttm.bo_global_ref.ref;
>> +       global_ref->global_type = DRM_GLOBAL_TTM_BO;
>> +       global_ref->size = sizeof(struct ttm_bo_global);
>> +       global_ref->init = &ttm_bo_global_init;
>> +       global_ref->release = &ttm_bo_global_release;
>> +       r = drm_global_item_ref(global_ref);
>> +       if (r != 0) {
>> +               DRM_ERROR("Failed setting up TTM BO subsystem.\n");
>> +               drm_global_item_unref(&hibmc->ttm.mem_global_ref);
>> +               return r;
>> +       }
>> +       return 0;
>> +}
>> +
>> +static void
>> +hibmc_ttm_global_release(struct hibmc_drm_device *hibmc)
>> +{
>> +       if (!hibmc->ttm.mem_global_ref.release)
>
> Are you actually hitting this condition? This seems like it's papering
> over something else.

it was also delivered from others, i looked at the xxx_ttm_global_init
function, 'mem_global_ref.release' is assigned unconditionally, so i
think this condition never be hit, it may be hit when release twice,
but this won't take place in my driver.

>
>> +               return;
>> +
>> +       drm_global_item_unref(&hibmc->ttm.bo_global_ref.ref);
>> +       drm_global_item_unref(&hibmc->ttm.mem_global_ref);
>> +       hibmc->ttm.mem_global_ref.release = NULL;
>> +}
>> +
>> +static void hibmc_bo_ttm_destroy(struct ttm_buffer_object *tbo)
>> +{
>> +       struct hibmc_bo *bo;
>> +
>> +       bo = container_of(tbo, struct hibmc_bo, bo);
>
> nit: No need to split this into a separate line.

agreed, thanks.

>
>> +
>> +       drm_gem_object_release(&bo->gem);
>> +       kfree(bo);
>> +}
>> +
>> +static bool hibmc_ttm_bo_is_hibmc_bo(struct ttm_buffer_object *bo)
>> +{
>> +       if (bo->destroy == &hibmc_bo_ttm_destroy)
>> +               return true;
>> +       return false;
>
> return bo->destroy == &hibmc_bo_ttm_destroy;

looks better to me.

>
>> +}
>> +
>> +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 c = 0;
>
> Can you please use a more descriptive name than 'c'?

ok, will do that.

>
>> +       u32 i;
>> +
>> +       bo->placement.placement = bo->placements;
>> +       bo->placement.busy_placement = bo->placements;
>> +       if (domain & TTM_PL_FLAG_VRAM)
>> +               bo->placements[c++].flags = TTM_PL_FLAG_WC |
>> +               TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
>
> nit: you're alignment is off here and below

is it correct?

	if (domain & TTM_PL_FLAG_VRAM)
		bo->placements[c++].flags = TTM_PL_FLAG_WC |
			TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
	if (domain & TTM_PL_FLAG_SYSTEM)
		bo->placements[c++].flags = TTM_PL_MASK_CACHING |
			TTM_PL_FLAG_SYSTEM;
	if (!c)
		bo->placements[c++].flags = TTM_PL_MASK_CACHING |
			TTM_PL_FLAG_SYSTEM;

>
>> +       if (domain & TTM_PL_FLAG_SYSTEM)
>> +               bo->placements[c++].flags = TTM_PL_MASK_CACHING |
>> +               TTM_PL_FLAG_SYSTEM;
>> +       if (!c)
>> +               bo->placements[c++].flags = TTM_PL_MASK_CACHING |
>> +               TTM_PL_FLAG_SYSTEM;
>> +
>> +       bo->placement.num_placement = c;
>> +       bo->placement.num_busy_placement = c;
>> +       for (i = 0; i < c; ++i) {
>
> nit: we tend towards post-increment in kernel

agreed, thanks.

>
>> +               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_device *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_io_mem_free(struct ttm_bo_device *bdev,
>> +                                 struct ttm_mem_reg *mem)
>> +{
>> +}
>
> No need to stub this, the caller does a NULL-check before invoking

will delete it, thanks.

>
>> +
>> +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;
>> +
>> +       tt = kzalloc(sizeof(*tt), GFP_KERNEL);
>> +       if (!tt)
>
> Print error

ok, will do that, thanks.

>
>> +               return NULL;
>> +       tt->func = &hibmc_tt_backend_func;
>> +       if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) {
>
> Here too?

ditto

>
>> +               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            = &hibmc_ttm_io_mem_free,
>> +       .lru_tail               = &ttm_bo_default_lru_tail,
>> +       .swap_lru_tail          = &ttm_bo_default_swap_lru_tail,
>> +};
>> +
>> +int hibmc_mm_init(struct hibmc_drm_device *hibmc)
>> +{
>> +       int ret;
>> +       struct drm_device *dev = hibmc->dev;
>> +       struct ttm_bo_device *bdev = &hibmc->ttm.bdev;
>> +
>> +       ret = hibmc_ttm_global_init(hibmc);
>> +       if (ret)
>> +               return ret;
>> +
>> +       ret = ttm_bo_device_init(&hibmc->ttm.bdev,
>> +                                hibmc->ttm.bo_global_ref.ref.object,
>> +                                &hibmc_bo_driver,
>> +                                dev->anon_inode->i_mapping,
>> +                                DRM_FILE_PAGE_OFFSET,
>> +                                true);
>> +       if (ret) {
>
> Call hibmc_ttm_global_release here?

agreed, thanks for pointing it out.

>
>> +               DRM_ERROR("Error initialising bo driver; %d\n", ret);
>> +               return ret;
>> +       }
>> +
>> +       ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
>> +                            hibmc->fb_size >> PAGE_SHIFT);
>> +       if (ret) {
>
> Clean up here as well?

ditto

>
>> +               DRM_ERROR("Failed ttm VRAM init: %d\n", ret);
>> +               return ret;
>> +       }
>> +
>> +       hibmc->mm_inited = true;
>> +       return 0;
>> +}
>> +
>> +void hibmc_mm_fini(struct hibmc_drm_device *hibmc)
>> +{
>> +       if (!hibmc->mm_inited)
>> +               return;
>> +
>> +       ttm_bo_device_release(&hibmc->ttm.bdev);
>> +       hibmc_ttm_global_release(hibmc);
>> +       hibmc->mm_inited = false;
>> +}
>> +
>> +int hibmc_bo_create(struct drm_device *dev, int size, int align,
>> +                   u32 flags, struct hibmc_bo **phibmcbo)
>> +{
>> +       struct hibmc_drm_device *hibmc = dev->dev_private;
>> +       struct hibmc_bo *hibmcbo;
>> +       size_t acc_size;
>> +       int ret;
>> +
>> +       hibmcbo = kzalloc(sizeof(*hibmcbo), GFP_KERNEL);
>> +       if (!hibmcbo)
>> +               return -ENOMEM;
>> +
>> +       ret = drm_gem_object_init(dev, &hibmcbo->gem, size);
>> +       if (ret) {
>> +               kfree(hibmcbo);
>> +               return ret;
>> +       }
>> +
>> +       hibmcbo->bo.bdev = &hibmc->ttm.bdev;
>> +
>> +       hibmc_ttm_placement(hibmcbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
>> +
>> +       acc_size = ttm_bo_dma_acc_size(&hibmc->ttm.bdev, size,
>> +                                      sizeof(struct hibmc_bo));
>> +
>> +       ret = ttm_bo_init(&hibmc->ttm.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)
>
> Missing hibmcbo clean up here

i looked at all other ttm drivers and all of them return directly when ttm_bo_init
failed, however, i think it is better to clean up here, should i call
hibmc_bo_unref(&hibmc_bo) here ?

>
>> +               return ret;
>> +
>> +       *phibmcbo = hibmcbo;
>> +       return 0;
>> +}
>> +
>> +static inline u64 hibmc_bo_gpu_offset(struct hibmc_bo *bo)
>> +{
>> +       return bo->bo.offset;
>> +}
>
> I don't think this function provides any value

do you nean i use bo->bo.offset instead of calling hibmc_bo_gpu_offset()?

>
>> +
>> +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 = hibmc_bo_gpu_offset(bo);
>
> Are you missing a return here?

Thanks for pointing it out!

>
>> +       }
>> +
>> +       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 = hibmc_bo_gpu_offset(bo);
>> +       return 0;
>> +}
>> +
>> +int hibmc_bo_push_sysram(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;
>> +
>> +       if (bo->kmap.virtual)
>
> ttm_bo_kunmap already does this check so you don't have to

agreed. will remove this condition.

>
>> +               ttm_bo_kunmap(&bo->kmap);
>> +
>> +       hibmc_ttm_placement(bo, TTM_PL_FLAG_SYSTEM);
>> +       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("pushing to VRAM failed\n");
>
> Print ret

ok, thanks.

>
>> +               return ret;
>> +       }
>> +       return 0;
>> +}
>> +
>> +int hibmc_mmap(struct file *filp, struct vm_area_struct *vma)
>> +{
>> +       struct drm_file *file_priv;
>> +       struct hibmc_drm_device *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->ttm.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)
>
> Print error

ditto

>
>> +               return -EINVAL;
>> +
>> +       ret = hibmc_bo_create(dev, size, 0, 0, &hibmcbo);
>> +       if (ret) {
>> +               if (ret != -ERESTARTSYS)
>> +                       DRM_ERROR("failed to allocate GEM object\n");
>
> Print ret

ditto

>
>> +               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 * ((args->bpp + 7) / 8), 16);
>
> What's up with the bpp + 7 here? Perhaps you're looking for DIV_ROUND_UP?

Yes, that sounds sane.

>
>
>> +       args->size = args->pitch * args->height;
>> +
>> +       ret = hibmc_gem_create(dev, args->size, false,
>> +                              &gobj);
>> +       if (ret)
>> +               return ret;
>> +
>> +       ret = drm_gem_handle_create(file, gobj, &handle);
>> +       drm_gem_object_unreference_unlocked(gobj);
>> +       if (ret)
>
> Print error here

agreed.

>
>> +               return ret;
>> +
>> +       args->handle = handle;
>> +       return 0;
>> +}
>> +
>> +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;
>> +}
>> +
>> +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;
>> +}

Regards,
Rongrong.

>> --
>> 1.9.1
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> _______________________________________________
> 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] 64+ messages in thread

* [PATCH v6 3/9] drm/hisilicon/hibmc: Add support for frame buffer
  2016-11-10 18:30     ` Sean Paul
@ 2016-11-11 13:16       ` Rongrong Zou
  -1 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-11-11 13:16 UTC (permalink / raw)
  To: linux-arm-kernel

? 2016/11/11 2:30, Sean Paul ??:
> On Fri, Oct 28, 2016 at 3:27 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
>> 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   |  17 ++
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   |  24 ++
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 255 ++++++++++++++++++++++
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       |  66 ++++++
>>   5 files changed, 363 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 d5c40b8..810a37e 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>> @@ -1,5 +1,5 @@
>>   ccflags-y := -Iinclude/drm
>> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o hibmc_ttm.o
>> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
>>
>>   obj-$(CONFIG_DRM_HISI_HIBMC)   +=hibmc-drm.o
>>   #obj-y += 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 81f4301..5ac7a7e 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> @@ -66,11 +66,23 @@ 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_device *hidev = drm_dev->dev_private;
>> +
>> +       drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 1);
>> +
>
> We have atomic helpers for suspend/resume now. Please use those.

drm_atomic_helper_suspend/resume()?

>
>>          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_device *hidev = drm_dev->dev_private;
>> +
>> +       drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 0);
>> +
>>          return 0;
>>   }
>>
>> @@ -170,6 +182,7 @@ static int hibmc_unload(struct drm_device *dev)
>>   {
>>          struct hibmc_drm_device *hidev = dev->dev_private;
>>
>> +       hibmc_fbdev_fini(hidev);
>>          hibmc_mm_fini(hidev);
>>          hibmc_hw_fini(hidev);
>>          dev->dev_private = NULL;
>> @@ -195,6 +208,10 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
>>          if (ret)
>>                  goto err;
>>
>> +       ret = hibmc_fbdev_init(hidev);
>> +       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 db8d80e..a40e9a7 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> @@ -20,9 +20,22 @@
>>   #define HIBMC_DRM_DRV_H
>>
>>   #include <drm/drmP.h>
>> +#include <drm/drm_fb_helper.h>
>>   #include <drm/ttm/ttm_bo_driver.h>
>>   #include <drm/drm_gem.h>
>>
>> +struct hibmc_framebuffer {
>> +       struct drm_framebuffer fb;
>> +       struct drm_gem_object *obj;
>> +       bool is_fbdev_fb;
>> +};
>> +
>> +struct hibmc_fbdev {
>> +       struct drm_fb_helper helper;
>> +       struct hibmc_framebuffer *fb;
>> +       int size;
>> +};
>> +
>>   struct hibmc_drm_device {
>>          /* hw */
>>          void __iomem   *mmio;
>> @@ -41,9 +54,13 @@ struct hibmc_drm_device {
>>                  bool initialized;
>>          } ttm;
>>
>> +       /* 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;
>> @@ -65,8 +82,15 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
>>
>>   #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
>>
>> +int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
>> +void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
>> +
>>   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_device *hibmc);
>>   void hibmc_mm_fini(struct hibmc_drm_device *hibmc);
>> 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..630124b
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
>> @@ -0,0 +1,255 @@
>> +/* 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"
>> +
>> +/* ---------------------------------------------------------------------- */
>
> Please remove

will do that, thanks.

>
>> +
>> +static int hibmcfb_create_object(
>> +                               struct hibmc_drm_device *hidev,
>> +                               const struct drm_mode_fb_cmd2 *mode_cmd,
>> +                               struct drm_gem_object **gobj_p)
>> +{
>> +       struct drm_gem_object *gobj;
>> +       struct drm_device *dev = hidev->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_device *hidev =
>> +               (struct hibmc_drm_device *)helper->dev->dev_private;
>> +       struct fb_info *info;
>> +       struct hibmc_framebuffer *hibmc_fb;
>> +       struct drm_framebuffer *fb;
>> +       struct drm_mode_fb_cmd2 mode_cmd;
>> +       struct drm_gem_object *gobj = NULL;
>> +       int ret = 0;
>> +       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 = roundup(mode_cmd.pitches[0] * mode_cmd.height, PAGE_SIZE);
>
> It's somewhat curious that you used ALIGN in the previous patch and
> roundup here. But anyways, I think PAGE_ALIGN would be the most
> appropriate thing to do here.

agreed, thanks.

>
>> +
>> +       ret = hibmcfb_create_object(hidev, &mode_cmd, &gobj);
>> +       if (ret) {
>> +               DRM_ERROR("failed to create fbcon backing object %d\r\n",
> ret);
>
> \r, yikes!!!

will delete it, thanks.

>
>> +               return -ENOMEM;
>> +       }
>> +
>> +       bo = gem_to_hibmc_bo(gobj);
>> +
>> +       ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
>> +       if (ret)
>
> Print error here?

will do.

>
> How about cleaning up gobj?

you are right,

>
>> +               return ret;
>> +
>> +       ret = hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL);
>> +       if (ret) {
>> +               DRM_ERROR("failed to pin fbcon\n");
>
> Print ret
>
> ttm_bo_unreserve? It seems like you're missing clean-up in all of the
> error paths in this function. Can you please make sure everything is
> tidied up?

ok, thanks.

>
>> +               return ret;
>> +       }
>> +
>> +       ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
>> +
>
> nit: extra space

do you mean extra line?

>
>> +       if (ret) {
>> +               DRM_ERROR("failed to kmap fbcon\n");
>
> Print ret

ok, thanks.

>
>> +               ttm_bo_unreserve(&bo->bo);
>> +               return ret;
>> +       }
>> +
>> +       ttm_bo_unreserve(&bo->bo);
>
> Move this between ttm_bo_kmap and if (ret), then remove it from inside
> the conditional.

This is fine with me, thanks.

>
>> +
>> +       info = drm_fb_helper_alloc_fbi(helper);
>> +       if (IS_ERR(info))
>
> Print error

ok, thanks.

>
>> +               return PTR_ERR(info);
>> +
>> +       info->par = hi_fbdev;
>> +
>> +       hibmc_fb = hibmc_framebuffer_init(hidev->dev, &mode_cmd, gobj);
>> +       if (IS_ERR(hibmc_fb)) {
>> +               drm_fb_helper_release_fbi(helper);
>> +               return PTR_ERR(hibmc_fb);
>> +       }
>> +
>> +       hi_fbdev->fb = hibmc_fb;
>> +       hidev->fbdev->size = size;
>> +       fb = &hibmc_fb->fb;
>
> The fb variable isn't necessary, and really, the hibmc_fb doesn't
> really help either, it just masks what's actually happening IMO.

i will clean the two variables.

>
>> +       if (!fb) {
>> +               DRM_INFO("fb is NULL\n");
>> +               return -EINVAL;
>> +       }
>> +
>> +       hi_fbdev->helper.fb = fb;
>> +
>> +       strcpy(info->fix.id, "hibmcdrmfb");
>> +
>> +       info->flags = FBINFO_DEFAULT;
>> +       info->fbops = &hibmc_drm_fb_ops;
>> +
>> +       drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
>> +       drm_fb_helper_fill_var(info, &hidev->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;
>> +}
>> +
>> +static void hibmc_fbdev_destroy(struct hibmc_fbdev *fbdev)
>> +{
>> +       struct hibmc_framebuffer *gfb = fbdev->fb;
>> +       struct drm_fb_helper *fbh = &fbdev->helper;
>> +
>> +       DRM_DEBUG_DRIVER("hibmc_fbdev_destroy\n");
>
> Not useful

ok, will remove.

>
>> +
>> +       drm_fb_helper_unregister_fbi(fbh);
>> +       drm_fb_helper_release_fbi(fbh);
>> +
>> +       drm_fb_helper_fini(fbh);
>> +
>> +       if (gfb)
>> +               drm_framebuffer_unreference(&gfb->fb);
>> +
>> +       kfree(fbdev);
>> +}
>> +
>> +static const struct drm_fb_helper_funcs hibmc_fbdev_helper_funcs = {
>> +       .fb_probe = hibmc_drm_fb_create,
>> +};
>> +
>> +int hibmc_fbdev_init(struct hibmc_drm_device *hidev)
>> +{
>> +       int ret;
>> +       struct fb_var_screeninfo *var;
>> +       struct fb_fix_screeninfo *fix;
>> +       struct hibmc_fbdev *hifbdev;
>> +
>> +       hifbdev = kzalloc(sizeof(*hifbdev), GFP_KERNEL);
>
> devm_kzalloc?

sounds good, so there need no kfree at hibmc_fbdev_destroy(),
thanks.

>
>> +       if (!hifbdev)
>> +               return -ENOMEM;
>> +
>> +       hidev->fbdev = hifbdev;
>> +       drm_fb_helper_prepare(hidev->dev, &hifbdev->helper,
>> +                             &hibmc_fbdev_helper_funcs);
>> +
>> +       /* Now just one crtc and one channel */
>> +       ret = drm_fb_helper_init(hidev->dev,
>> +                                &hifbdev->helper, 1, 1);
>> +
>
> nit: extra line

ok, thanks.

>
>> +       if (ret)
>> +               return ret;
>> +
>> +       ret = drm_fb_helper_single_add_all_connectors(&hifbdev->helper);
>> +       if (ret)
>> +               goto fini;
>> +
>> +       ret = drm_fb_helper_initial_config(&hifbdev->helper, 16);
>> +       if (ret)
>> +               goto fini;
>> +
>> +       var = &hifbdev->helper.fbdev->var;
>> +       fix = &hifbdev->helper.fbdev->fix;
>> +
>> +       DRM_DEBUG("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("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);
>
> You've been using DRM_DEBUG_DRIVER elsewhere, you should probably use
> it here, too.

ok, thanks.

>
>> +
>> +       return 0;
>> +
>> +fini:
>> +       drm_fb_helper_fini(&hifbdev->helper);
>> +       return ret;
>> +}
>> +
>> +void hibmc_fbdev_fini(struct hibmc_drm_device *hidev)
>> +{
>> +       if (!hidev->fbdev)
>> +               return;
>> +
>> +       hibmc_fbdev_destroy(hidev->fbdev);
>> +       hidev->fbdev = NULL;
>> +}
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>> index 0802ebd..9822f62 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>> @@ -488,3 +488,69 @@ int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
>>          drm_gem_object_unreference_unlocked(obj);
>>          return 0;
>>   }
>> +
>> +/* ---------------------------------------------------------------------- */
>> +
>
> Please remove

will do.

>
>> +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)
>
> Print error

ok, thanks.

Regards,
Rongrong.

>
>> +               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
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> _______________________________________________
> linuxarm mailing list
> linuxarm at huawei.com
> http://rnd-openeuler.huawei.com/mailman/listinfo/linuxarm
>
> .
>

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

* Re: [PATCH v6 3/9] drm/hisilicon/hibmc: Add support for frame buffer
@ 2016-11-11 13:16       ` Rongrong Zou
  0 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-11-11 13:16 UTC (permalink / raw)
  To: Sean Paul, Rongrong Zou
  Cc: Mark Rutland, Archit, shenhui, Tomeu Vizoso, Jonathan Corbet,
	Dave Airlie, catalin.marinas, Emil Velikov, linuxarm, dri-devel,
	xinliang.liu, james.xiong, daniel, Daniel Vetter, Will Deacon,
	lijianhua, Linux ARM Kernel, Benjamin Gaignard

在 2016/11/11 2:30, Sean Paul 写道:
> On Fri, Oct 28, 2016 at 3:27 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
>> 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   |  17 ++
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   |  24 ++
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 255 ++++++++++++++++++++++
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       |  66 ++++++
>>   5 files changed, 363 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 d5c40b8..810a37e 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>> @@ -1,5 +1,5 @@
>>   ccflags-y := -Iinclude/drm
>> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o hibmc_ttm.o
>> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
>>
>>   obj-$(CONFIG_DRM_HISI_HIBMC)   +=hibmc-drm.o
>>   #obj-y += 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 81f4301..5ac7a7e 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> @@ -66,11 +66,23 @@ 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_device *hidev = drm_dev->dev_private;
>> +
>> +       drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 1);
>> +
>
> We have atomic helpers for suspend/resume now. Please use those.

drm_atomic_helper_suspend/resume()?

>
>>          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_device *hidev = drm_dev->dev_private;
>> +
>> +       drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 0);
>> +
>>          return 0;
>>   }
>>
>> @@ -170,6 +182,7 @@ static int hibmc_unload(struct drm_device *dev)
>>   {
>>          struct hibmc_drm_device *hidev = dev->dev_private;
>>
>> +       hibmc_fbdev_fini(hidev);
>>          hibmc_mm_fini(hidev);
>>          hibmc_hw_fini(hidev);
>>          dev->dev_private = NULL;
>> @@ -195,6 +208,10 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
>>          if (ret)
>>                  goto err;
>>
>> +       ret = hibmc_fbdev_init(hidev);
>> +       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 db8d80e..a40e9a7 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> @@ -20,9 +20,22 @@
>>   #define HIBMC_DRM_DRV_H
>>
>>   #include <drm/drmP.h>
>> +#include <drm/drm_fb_helper.h>
>>   #include <drm/ttm/ttm_bo_driver.h>
>>   #include <drm/drm_gem.h>
>>
>> +struct hibmc_framebuffer {
>> +       struct drm_framebuffer fb;
>> +       struct drm_gem_object *obj;
>> +       bool is_fbdev_fb;
>> +};
>> +
>> +struct hibmc_fbdev {
>> +       struct drm_fb_helper helper;
>> +       struct hibmc_framebuffer *fb;
>> +       int size;
>> +};
>> +
>>   struct hibmc_drm_device {
>>          /* hw */
>>          void __iomem   *mmio;
>> @@ -41,9 +54,13 @@ struct hibmc_drm_device {
>>                  bool initialized;
>>          } ttm;
>>
>> +       /* 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;
>> @@ -65,8 +82,15 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
>>
>>   #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
>>
>> +int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
>> +void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
>> +
>>   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_device *hibmc);
>>   void hibmc_mm_fini(struct hibmc_drm_device *hibmc);
>> 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..630124b
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
>> @@ -0,0 +1,255 @@
>> +/* 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"
>> +
>> +/* ---------------------------------------------------------------------- */
>
> Please remove

will do that, thanks.

>
>> +
>> +static int hibmcfb_create_object(
>> +                               struct hibmc_drm_device *hidev,
>> +                               const struct drm_mode_fb_cmd2 *mode_cmd,
>> +                               struct drm_gem_object **gobj_p)
>> +{
>> +       struct drm_gem_object *gobj;
>> +       struct drm_device *dev = hidev->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_device *hidev =
>> +               (struct hibmc_drm_device *)helper->dev->dev_private;
>> +       struct fb_info *info;
>> +       struct hibmc_framebuffer *hibmc_fb;
>> +       struct drm_framebuffer *fb;
>> +       struct drm_mode_fb_cmd2 mode_cmd;
>> +       struct drm_gem_object *gobj = NULL;
>> +       int ret = 0;
>> +       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 = roundup(mode_cmd.pitches[0] * mode_cmd.height, PAGE_SIZE);
>
> It's somewhat curious that you used ALIGN in the previous patch and
> roundup here. But anyways, I think PAGE_ALIGN would be the most
> appropriate thing to do here.

agreed, thanks.

>
>> +
>> +       ret = hibmcfb_create_object(hidev, &mode_cmd, &gobj);
>> +       if (ret) {
>> +               DRM_ERROR("failed to create fbcon backing object %d\r\n",
> ret);
>
> \r, yikes!!!

will delete it, thanks.

>
>> +               return -ENOMEM;
>> +       }
>> +
>> +       bo = gem_to_hibmc_bo(gobj);
>> +
>> +       ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
>> +       if (ret)
>
> Print error here?

will do.

>
> How about cleaning up gobj?

you are right,

>
>> +               return ret;
>> +
>> +       ret = hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL);
>> +       if (ret) {
>> +               DRM_ERROR("failed to pin fbcon\n");
>
> Print ret
>
> ttm_bo_unreserve? It seems like you're missing clean-up in all of the
> error paths in this function. Can you please make sure everything is
> tidied up?

ok, thanks.

>
>> +               return ret;
>> +       }
>> +
>> +       ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
>> +
>
> nit: extra space

do you mean extra line?

>
>> +       if (ret) {
>> +               DRM_ERROR("failed to kmap fbcon\n");
>
> Print ret

ok, thanks.

>
>> +               ttm_bo_unreserve(&bo->bo);
>> +               return ret;
>> +       }
>> +
>> +       ttm_bo_unreserve(&bo->bo);
>
> Move this between ttm_bo_kmap and if (ret), then remove it from inside
> the conditional.

This is fine with me, thanks.

>
>> +
>> +       info = drm_fb_helper_alloc_fbi(helper);
>> +       if (IS_ERR(info))
>
> Print error

ok, thanks.

>
>> +               return PTR_ERR(info);
>> +
>> +       info->par = hi_fbdev;
>> +
>> +       hibmc_fb = hibmc_framebuffer_init(hidev->dev, &mode_cmd, gobj);
>> +       if (IS_ERR(hibmc_fb)) {
>> +               drm_fb_helper_release_fbi(helper);
>> +               return PTR_ERR(hibmc_fb);
>> +       }
>> +
>> +       hi_fbdev->fb = hibmc_fb;
>> +       hidev->fbdev->size = size;
>> +       fb = &hibmc_fb->fb;
>
> The fb variable isn't necessary, and really, the hibmc_fb doesn't
> really help either, it just masks what's actually happening IMO.

i will clean the two variables.

>
>> +       if (!fb) {
>> +               DRM_INFO("fb is NULL\n");
>> +               return -EINVAL;
>> +       }
>> +
>> +       hi_fbdev->helper.fb = fb;
>> +
>> +       strcpy(info->fix.id, "hibmcdrmfb");
>> +
>> +       info->flags = FBINFO_DEFAULT;
>> +       info->fbops = &hibmc_drm_fb_ops;
>> +
>> +       drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
>> +       drm_fb_helper_fill_var(info, &hidev->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;
>> +}
>> +
>> +static void hibmc_fbdev_destroy(struct hibmc_fbdev *fbdev)
>> +{
>> +       struct hibmc_framebuffer *gfb = fbdev->fb;
>> +       struct drm_fb_helper *fbh = &fbdev->helper;
>> +
>> +       DRM_DEBUG_DRIVER("hibmc_fbdev_destroy\n");
>
> Not useful

ok, will remove.

>
>> +
>> +       drm_fb_helper_unregister_fbi(fbh);
>> +       drm_fb_helper_release_fbi(fbh);
>> +
>> +       drm_fb_helper_fini(fbh);
>> +
>> +       if (gfb)
>> +               drm_framebuffer_unreference(&gfb->fb);
>> +
>> +       kfree(fbdev);
>> +}
>> +
>> +static const struct drm_fb_helper_funcs hibmc_fbdev_helper_funcs = {
>> +       .fb_probe = hibmc_drm_fb_create,
>> +};
>> +
>> +int hibmc_fbdev_init(struct hibmc_drm_device *hidev)
>> +{
>> +       int ret;
>> +       struct fb_var_screeninfo *var;
>> +       struct fb_fix_screeninfo *fix;
>> +       struct hibmc_fbdev *hifbdev;
>> +
>> +       hifbdev = kzalloc(sizeof(*hifbdev), GFP_KERNEL);
>
> devm_kzalloc?

sounds good, so there need no kfree at hibmc_fbdev_destroy(),
thanks.

>
>> +       if (!hifbdev)
>> +               return -ENOMEM;
>> +
>> +       hidev->fbdev = hifbdev;
>> +       drm_fb_helper_prepare(hidev->dev, &hifbdev->helper,
>> +                             &hibmc_fbdev_helper_funcs);
>> +
>> +       /* Now just one crtc and one channel */
>> +       ret = drm_fb_helper_init(hidev->dev,
>> +                                &hifbdev->helper, 1, 1);
>> +
>
> nit: extra line

ok, thanks.

>
>> +       if (ret)
>> +               return ret;
>> +
>> +       ret = drm_fb_helper_single_add_all_connectors(&hifbdev->helper);
>> +       if (ret)
>> +               goto fini;
>> +
>> +       ret = drm_fb_helper_initial_config(&hifbdev->helper, 16);
>> +       if (ret)
>> +               goto fini;
>> +
>> +       var = &hifbdev->helper.fbdev->var;
>> +       fix = &hifbdev->helper.fbdev->fix;
>> +
>> +       DRM_DEBUG("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("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);
>
> You've been using DRM_DEBUG_DRIVER elsewhere, you should probably use
> it here, too.

ok, thanks.

>
>> +
>> +       return 0;
>> +
>> +fini:
>> +       drm_fb_helper_fini(&hifbdev->helper);
>> +       return ret;
>> +}
>> +
>> +void hibmc_fbdev_fini(struct hibmc_drm_device *hidev)
>> +{
>> +       if (!hidev->fbdev)
>> +               return;
>> +
>> +       hibmc_fbdev_destroy(hidev->fbdev);
>> +       hidev->fbdev = NULL;
>> +}
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>> index 0802ebd..9822f62 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>> @@ -488,3 +488,69 @@ int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
>>          drm_gem_object_unreference_unlocked(obj);
>>          return 0;
>>   }
>> +
>> +/* ---------------------------------------------------------------------- */
>> +
>
> Please remove

will do.

>
>> +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)
>
> Print error

ok, thanks.

Regards,
Rongrong.

>
>> +               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
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> _______________________________________________
> 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] 64+ messages in thread

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

On Fri, Nov 11, 2016 at 6:16 AM, Rongrong Zou <zourongrong@huawei.com> wrote:
> ? 2016/11/11 1:35, Sean Paul ??:
>>
>> On Fri, Oct 28, 2016 at 3:27 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>
>>> ---
>>>   drivers/gpu/drm/hisilicon/hibmc/Kconfig         |   1 +
>>>   drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  12 +
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |  46 +++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     | 490
>>> ++++++++++++++++++++++++
>>>   5 files changed, 550 insertions(+), 1 deletion(-)
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>>
>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>> b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>> index a9af90d..bcb8c18 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>> @@ -1,6 +1,7 @@
>>>   config DRM_HISI_HIBMC
>>>          tristate "DRM Support for Hisilicon Hibmc"
>>>          depends on DRM && PCI
>>> +       select DRM_TTM
>>>
>>>          help
>>>            Choose this option if you have a Hisilicon Hibmc soc chipset.
>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>> b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>> index 97cf4a0..d5c40b8 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>> @@ -1,5 +1,5 @@
>>>   ccflags-y := -Iinclude/drm
>>> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o
>>> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o hibmc_ttm.o
>>>
>>>   obj-$(CONFIG_DRM_HISI_HIBMC)   +=hibmc-drm.o
>>>   #obj-y += 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 4669d42..81f4301 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>> @@ -31,6 +31,7 @@
>>>   #ifdef CONFIG_COMPAT
>>>          .compat_ioctl   = drm_compat_ioctl,
>>>   #endif
>>> +       .mmap           = hibmc_mmap,
>>>          .poll           = drm_poll,
>>>          .read           = drm_read,
>>>          .llseek         = no_llseek,
>>> @@ -46,6 +47,8 @@ static void hibmc_disable_vblank(struct drm_device
>>> *dev, unsigned int pipe)
>>>   }
>>>
>>>   static struct drm_driver hibmc_driver = {
>>> +       .driver_features        = DRIVER_GEM,
>>> +
>>
>>
>> nit: extra space
>>
>>>          .fops                   = &hibmc_fops,
>>>          .name                   = "hibmc",
>>>          .date                   = "20160828",
>>> @@ -55,6 +58,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)
>>> @@ -163,6 +170,7 @@ static int hibmc_unload(struct drm_device *dev)
>>>   {
>>>          struct hibmc_drm_device *hidev = dev->dev_private;
>>>
>>> +       hibmc_mm_fini(hidev);
>>>          hibmc_hw_fini(hidev);
>>>          dev->dev_private = NULL;
>>>          return 0;
>>> @@ -183,6 +191,10 @@ static int hibmc_load(struct drm_device *dev,
>>> unsigned long flags)
>>>          if (ret)
>>>                  goto err;
>>>
>>> +       ret = hibmc_mm_init(hidev);
>>> +       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 0037341..db8d80e 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/ttm/ttm_bo_driver.h>
>>> +#include <drm/drm_gem.h>
>>
>>
>> nit: alphabetize
>
>
> will fix it, thanks.
>
>>
>>>
>>>   struct hibmc_drm_device {
>>>          /* hw */
>>> @@ -30,6 +32,50 @@ struct hibmc_drm_device {
>>>
>>>          /* drm */
>>>          struct drm_device  *dev;
>>> +
>>> +       /* ttm */
>>> +       struct {
>>> +               struct drm_global_reference mem_global_ref;
>>> +               struct ttm_bo_global_ref bo_global_ref;
>>> +               struct ttm_bo_device bdev;
>>> +               bool initialized;
>>> +       } ttm;
>>
>>
>> I don't think you gain anything other than keystrokes from the substruct
>
>
> I'm sorry i didn't catch you, i looked at the all drivers used ttm such
> as ast/bochs/cirrus/mgag200/qxl/virtio_gpu, they all embedded the ttm
> substruct
> into the driver-private struct.
>
> so do you mean
> struct hibmc_drm_device {
>         /* hw */
>         void __iomem   *mmio;
>         void __iomem   *fb_map;
>         unsigned long  fb_base;
>         unsigned long  fb_size;
>
>         /* drm */
>         struct drm_device  *dev;
>         struct drm_plane plane;
>         struct drm_crtc crtc;
>         struct drm_encoder encoder;
>         struct drm_connector connector;
>         bool mode_config_initialized;
>
>         /* ttm */
>         struct drm_global_reference mem_global_ref;
>         struct ttm_bo_global_ref bo_global_ref;
>         struct ttm_bo_device bdev;
>         bool initialized;
>         ...
>         };
> ?

Yeah, that's what I was thinking

>
>>
>>> +
>>> +       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);
>>> +}
>>> +
>>> +#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
>>
>>
>> Hide this in ttm.c
>
>
> ok, will do that.
> thanks for pointing it out.
>
>
>>
>>> +
>>> +int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
>>> +                    struct drm_gem_object **obj);
>>> +
>>> +int hibmc_mm_init(struct hibmc_drm_device *hibmc);
>>> +void hibmc_mm_fini(struct hibmc_drm_device *hibmc);
>>> +int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr);
>>> +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..0802ebd
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>> @@ -0,0 +1,490 @@
>>> +/* 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 "hibmc_drm_drv.h"
>>> +#include <ttm/ttm_page_alloc.h>
>>> +#include <drm/drm_crtc_helper.h>
>>> +#include <drm/drm_atomic_helper.h>
>>> +
>>> +static inline struct hibmc_drm_device *
>>> +hibmc_bdev(struct ttm_bo_device *bd)
>>> +{
>>> +       return container_of(bd, struct hibmc_drm_device, ttm.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_device *hibmc)
>>> +{
>>> +       struct drm_global_reference *global_ref;
>>> +       int r;
>>
>>
>> nit: try not to use one character variable names unless it's for the
>> purpose of a loop (ie: i,j). You also use ret elsewhere in the driver,
>> so it'd be nice to remain consistent
>
>
> the whole file is delivered from bochs ttm, i didn't modify anything except
> some checkpatch warnings and the 'hibmc_' prefix. Unfortunately, some
> problems were delivered too.

Yeah, seems like it. Perhaps you can post patches to fix these issues
in the other drivers too :)

>
>>
>>> +
>>> +       global_ref = &hibmc->ttm.mem_global_ref;
>>
>>
>> I think using the global_ref local obfuscates what you're doing here.
>> It saves you 6 characters while typing, but adds a layer of
>> indirection for all future readers.
>>
>>> +       global_ref->global_type = DRM_GLOBAL_TTM_MEM;
>>> +       global_ref->size = sizeof(struct ttm_mem_global);
>>> +       global_ref->init = &hibmc_ttm_mem_global_init;
>>> +       global_ref->release = &hibmc_ttm_mem_global_release;
>>> +       r = drm_global_item_ref(global_ref);
>>> +       if (r != 0) {
>>
>>
>> nit: if (r)
>
>
> will fix it,
> thanks.
> BTW, i wonder why checkpatch.pl didn't report it.
>
>
>>
>>> +               DRM_ERROR("Failed setting up TTM memory accounting
>>> subsystem.\n"
>>> +                        );
>>
>>
>> Breaking up the line for one character is probably not worthwhile, and
>> you should really print the error. How about:
>>
>> DRM_ERROR("Could not get ref on ttm global ret=%d.\n", ret);
>
>
> i like your solution, thanks.
>
>
>>
>>
>>> +               return r;
>>> +       }
>>> +
>>> +       hibmc->ttm.bo_global_ref.mem_glob =
>>> +               hibmc->ttm.mem_global_ref.object;
>>> +       global_ref = &hibmc->ttm.bo_global_ref.ref;
>>> +       global_ref->global_type = DRM_GLOBAL_TTM_BO;
>>> +       global_ref->size = sizeof(struct ttm_bo_global);
>>> +       global_ref->init = &ttm_bo_global_init;
>>> +       global_ref->release = &ttm_bo_global_release;
>>> +       r = drm_global_item_ref(global_ref);
>>> +       if (r != 0) {
>>> +               DRM_ERROR("Failed setting up TTM BO subsystem.\n");
>>> +               drm_global_item_unref(&hibmc->ttm.mem_global_ref);
>>> +               return r;
>>> +       }
>>> +       return 0;
>>> +}
>>> +
>>> +static void
>>> +hibmc_ttm_global_release(struct hibmc_drm_device *hibmc)
>>> +{
>>> +       if (!hibmc->ttm.mem_global_ref.release)
>>
>>
>> Are you actually hitting this condition? This seems like it's papering
>> over something else.
>
>
> it was also delivered from others, i looked at the xxx_ttm_global_init
> function, 'mem_global_ref.release' is assigned unconditionally, so i
> think this condition never be hit, it may be hit when release twice,
> but this won't take place in my driver.
>

Yeah, that's what I was hoping for. So perhaps we can remove this?

>>
>>> +               return;
>>> +
>>> +       drm_global_item_unref(&hibmc->ttm.bo_global_ref.ref);
>>> +       drm_global_item_unref(&hibmc->ttm.mem_global_ref);
>>> +       hibmc->ttm.mem_global_ref.release = NULL;
>>> +}
>>> +
>>> +static void hibmc_bo_ttm_destroy(struct ttm_buffer_object *tbo)
>>> +{
>>> +       struct hibmc_bo *bo;
>>> +
>>> +       bo = container_of(tbo, struct hibmc_bo, bo);
>>
>>
>> nit: No need to split this into a separate line.
>
>
> agreed, thanks.
>
>>
>>> +
>>> +       drm_gem_object_release(&bo->gem);
>>> +       kfree(bo);
>>> +}
>>> +
>>> +static bool hibmc_ttm_bo_is_hibmc_bo(struct ttm_buffer_object *bo)
>>> +{
>>> +       if (bo->destroy == &hibmc_bo_ttm_destroy)
>>> +               return true;
>>> +       return false;
>>
>>
>> return bo->destroy == &hibmc_bo_ttm_destroy;
>
>
> looks better to me.
>
>
>>
>>> +}
>>> +
>>> +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 c = 0;
>>
>>
>> Can you please use a more descriptive name than 'c'?
>
>
> ok, will do that.
>
>>
>>> +       u32 i;
>>> +
>>> +       bo->placement.placement = bo->placements;
>>> +       bo->placement.busy_placement = bo->placements;
>>> +       if (domain & TTM_PL_FLAG_VRAM)
>>> +               bo->placements[c++].flags = TTM_PL_FLAG_WC |
>>> +               TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
>>
>>
>> nit: you're alignment is off here and below
>
>
> is it correct?
>
>         if (domain & TTM_PL_FLAG_VRAM)
>                 bo->placements[c++].flags = TTM_PL_FLAG_WC |
>                         TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
>         if (domain & TTM_PL_FLAG_SYSTEM)
>                 bo->placements[c++].flags = TTM_PL_MASK_CACHING |
>                         TTM_PL_FLAG_SYSTEM;
>         if (!c)
>                 bo->placements[c++].flags = TTM_PL_MASK_CACHING |
>                         TTM_PL_FLAG_SYSTEM;
>

Pretty much anything other than lining them up one under the other is better

>>
>>> +       if (domain & TTM_PL_FLAG_SYSTEM)
>>> +               bo->placements[c++].flags = TTM_PL_MASK_CACHING |
>>> +               TTM_PL_FLAG_SYSTEM;
>>> +       if (!c)
>>> +               bo->placements[c++].flags = TTM_PL_MASK_CACHING |
>>> +               TTM_PL_FLAG_SYSTEM;
>>> +
>>> +       bo->placement.num_placement = c;
>>> +       bo->placement.num_busy_placement = c;
>>> +       for (i = 0; i < c; ++i) {
>>
>>
>> nit: we tend towards post-increment in kernel
>
>
> agreed, thanks.
>
>
>>
>>> +               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_device *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_io_mem_free(struct ttm_bo_device *bdev,
>>> +                                 struct ttm_mem_reg *mem)
>>> +{
>>> +}
>>
>>
>> No need to stub this, the caller does a NULL-check before invoking
>
>
> will delete it, thanks.
>
>>
>>> +
>>> +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;
>>> +
>>> +       tt = kzalloc(sizeof(*tt), GFP_KERNEL);
>>> +       if (!tt)
>>
>>
>> Print error
>
>
> ok, will do that, thanks.
>
>>
>>> +               return NULL;
>>> +       tt->func = &hibmc_tt_backend_func;
>>> +       if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) {
>>
>>
>> Here too?
>
>
> ditto
>
>
>>
>>> +               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            = &hibmc_ttm_io_mem_free,
>>> +       .lru_tail               = &ttm_bo_default_lru_tail,
>>> +       .swap_lru_tail          = &ttm_bo_default_swap_lru_tail,
>>> +};
>>> +
>>> +int hibmc_mm_init(struct hibmc_drm_device *hibmc)
>>> +{
>>> +       int ret;
>>> +       struct drm_device *dev = hibmc->dev;
>>> +       struct ttm_bo_device *bdev = &hibmc->ttm.bdev;
>>> +
>>> +       ret = hibmc_ttm_global_init(hibmc);
>>> +       if (ret)
>>> +               return ret;
>>> +
>>> +       ret = ttm_bo_device_init(&hibmc->ttm.bdev,
>>> +                                hibmc->ttm.bo_global_ref.ref.object,
>>> +                                &hibmc_bo_driver,
>>> +                                dev->anon_inode->i_mapping,
>>> +                                DRM_FILE_PAGE_OFFSET,
>>> +                                true);
>>> +       if (ret) {
>>
>>
>> Call hibmc_ttm_global_release here?
>
>
> agreed, thanks for pointing it out.
>
>>
>>> +               DRM_ERROR("Error initialising bo driver; %d\n", ret);
>>> +               return ret;
>>> +       }
>>> +
>>> +       ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
>>> +                            hibmc->fb_size >> PAGE_SHIFT);
>>> +       if (ret) {
>>
>>
>> Clean up here as well?
>
>
> ditto
>
>
>>
>>> +               DRM_ERROR("Failed ttm VRAM init: %d\n", ret);
>>> +               return ret;
>>> +       }
>>> +
>>> +       hibmc->mm_inited = true;
>>> +       return 0;
>>> +}
>>> +
>>> +void hibmc_mm_fini(struct hibmc_drm_device *hibmc)
>>> +{
>>> +       if (!hibmc->mm_inited)
>>> +               return;
>>> +
>>> +       ttm_bo_device_release(&hibmc->ttm.bdev);
>>> +       hibmc_ttm_global_release(hibmc);
>>> +       hibmc->mm_inited = false;
>>> +}
>>> +
>>> +int hibmc_bo_create(struct drm_device *dev, int size, int align,
>>> +                   u32 flags, struct hibmc_bo **phibmcbo)
>>> +{
>>> +       struct hibmc_drm_device *hibmc = dev->dev_private;
>>> +       struct hibmc_bo *hibmcbo;
>>> +       size_t acc_size;
>>> +       int ret;
>>> +
>>> +       hibmcbo = kzalloc(sizeof(*hibmcbo), GFP_KERNEL);
>>> +       if (!hibmcbo)
>>> +               return -ENOMEM;
>>> +
>>> +       ret = drm_gem_object_init(dev, &hibmcbo->gem, size);
>>> +       if (ret) {
>>> +               kfree(hibmcbo);
>>> +               return ret;
>>> +       }
>>> +
>>> +       hibmcbo->bo.bdev = &hibmc->ttm.bdev;
>>> +
>>> +       hibmc_ttm_placement(hibmcbo, TTM_PL_FLAG_VRAM |
>>> TTM_PL_FLAG_SYSTEM);
>>> +
>>> +       acc_size = ttm_bo_dma_acc_size(&hibmc->ttm.bdev, size,
>>> +                                      sizeof(struct hibmc_bo));
>>> +
>>> +       ret = ttm_bo_init(&hibmc->ttm.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)
>>
>>
>> Missing hibmcbo clean up here
>
>
> i looked at all other ttm drivers and all of them return directly when
> ttm_bo_init
> failed, however, i think it is better to clean up here, should i call
> hibmc_bo_unref(&hibmc_bo) here ?
>

Yeah, that should work (might want to test it, though ;)


>>
>>> +               return ret;
>>> +
>>> +       *phibmcbo = hibmcbo;
>>> +       return 0;
>>> +}
>>> +
>>> +static inline u64 hibmc_bo_gpu_offset(struct hibmc_bo *bo)
>>> +{
>>> +       return bo->bo.offset;
>>> +}
>>
>>
>> I don't think this function provides any value
>
>
> do you nean i use bo->bo.offset instead of calling hibmc_bo_gpu_offset()?
>

yes

>>
>>> +
>>> +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 = hibmc_bo_gpu_offset(bo);
>>
>>
>> Are you missing a return here?
>
>
> Thanks for pointing it out!
>
>
>>
>>> +       }
>>> +
>>> +       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 = hibmc_bo_gpu_offset(bo);
>>> +       return 0;
>>> +}
>>> +
>>> +int hibmc_bo_push_sysram(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;
>>> +
>>> +       if (bo->kmap.virtual)
>>
>>
>> ttm_bo_kunmap already does this check so you don't have to
>
>
> agreed. will remove this condition.
>
>>
>>> +               ttm_bo_kunmap(&bo->kmap);
>>> +
>>> +       hibmc_ttm_placement(bo, TTM_PL_FLAG_SYSTEM);
>>> +       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("pushing to VRAM failed\n");
>>
>>
>> Print ret
>
>
> ok, thanks.
>
>
>>
>>> +               return ret;
>>> +       }
>>> +       return 0;
>>> +}
>>> +
>>> +int hibmc_mmap(struct file *filp, struct vm_area_struct *vma)
>>> +{
>>> +       struct drm_file *file_priv;
>>> +       struct hibmc_drm_device *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->ttm.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)
>>
>>
>> Print error
>
>
> ditto
>
>>
>>> +               return -EINVAL;
>>> +
>>> +       ret = hibmc_bo_create(dev, size, 0, 0, &hibmcbo);
>>> +       if (ret) {
>>> +               if (ret != -ERESTARTSYS)
>>> +                       DRM_ERROR("failed to allocate GEM object\n");
>>
>>
>> Print ret
>
>
> ditto
>
>>
>>> +               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 * ((args->bpp + 7) / 8), 16);
>>
>>
>> What's up with the bpp + 7 here? Perhaps you're looking for DIV_ROUND_UP?
>
>
> Yes, that sounds sane.
>

sane is what i usually aim for :)

Sean


>>
>>
>>> +       args->size = args->pitch * args->height;
>>> +
>>> +       ret = hibmc_gem_create(dev, args->size, false,
>>> +                              &gobj);
>>> +       if (ret)
>>> +               return ret;
>>> +
>>> +       ret = drm_gem_handle_create(file, gobj, &handle);
>>> +       drm_gem_object_unreference_unlocked(gobj);
>>> +       if (ret)
>>
>>
>> Print error here
>
>
> agreed.
>
>
>>
>>> +               return ret;
>>> +
>>> +       args->handle = handle;
>>> +       return 0;
>>> +}
>>> +
>>> +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;
>>> +}
>>> +
>>> +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;
>>> +}
>
>
> Regards,
> Rongrong.
>
>>> --
>>> 1.9.1
>>>
>>>
>>> _______________________________________________
>>> linux-arm-kernel mailing list
>>> linux-arm-kernel at lists.infradead.org
>>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>
>> _______________________________________________
>> linuxarm mailing list
>> linuxarm at huawei.com
>> http://rnd-openeuler.huawei.com/mailman/listinfo/linuxarm
>>
>> .
>>
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v6 2/9] drm/hisilicon/hibmc: Add video memory management
@ 2016-11-11 13:25         ` Sean Paul
  0 siblings, 0 replies; 64+ messages in thread
From: Sean Paul @ 2016-11-11 13:25 UTC (permalink / raw)
  To: Rongrong Zou
  Cc: Mark Rutland, lijianhua, Will Deacon, Tomeu Vizoso,
	Jonathan Corbet, catalin.marinas, Emil Velikov, linuxarm,
	dri-devel, james.xiong, shenhui, Rongrong Zou, Linux ARM Kernel

On Fri, Nov 11, 2016 at 6:16 AM, Rongrong Zou <zourongrong@huawei.com> wrote:
> 在 2016/11/11 1:35, Sean Paul 写道:
>>
>> On Fri, Oct 28, 2016 at 3:27 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>
>>> ---
>>>   drivers/gpu/drm/hisilicon/hibmc/Kconfig         |   1 +
>>>   drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  12 +
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |  46 +++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     | 490
>>> ++++++++++++++++++++++++
>>>   5 files changed, 550 insertions(+), 1 deletion(-)
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>>
>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>> b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>> index a9af90d..bcb8c18 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>> @@ -1,6 +1,7 @@
>>>   config DRM_HISI_HIBMC
>>>          tristate "DRM Support for Hisilicon Hibmc"
>>>          depends on DRM && PCI
>>> +       select DRM_TTM
>>>
>>>          help
>>>            Choose this option if you have a Hisilicon Hibmc soc chipset.
>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>> b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>> index 97cf4a0..d5c40b8 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>> @@ -1,5 +1,5 @@
>>>   ccflags-y := -Iinclude/drm
>>> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o
>>> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o hibmc_ttm.o
>>>
>>>   obj-$(CONFIG_DRM_HISI_HIBMC)   +=hibmc-drm.o
>>>   #obj-y += 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 4669d42..81f4301 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>> @@ -31,6 +31,7 @@
>>>   #ifdef CONFIG_COMPAT
>>>          .compat_ioctl   = drm_compat_ioctl,
>>>   #endif
>>> +       .mmap           = hibmc_mmap,
>>>          .poll           = drm_poll,
>>>          .read           = drm_read,
>>>          .llseek         = no_llseek,
>>> @@ -46,6 +47,8 @@ static void hibmc_disable_vblank(struct drm_device
>>> *dev, unsigned int pipe)
>>>   }
>>>
>>>   static struct drm_driver hibmc_driver = {
>>> +       .driver_features        = DRIVER_GEM,
>>> +
>>
>>
>> nit: extra space
>>
>>>          .fops                   = &hibmc_fops,
>>>          .name                   = "hibmc",
>>>          .date                   = "20160828",
>>> @@ -55,6 +58,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)
>>> @@ -163,6 +170,7 @@ static int hibmc_unload(struct drm_device *dev)
>>>   {
>>>          struct hibmc_drm_device *hidev = dev->dev_private;
>>>
>>> +       hibmc_mm_fini(hidev);
>>>          hibmc_hw_fini(hidev);
>>>          dev->dev_private = NULL;
>>>          return 0;
>>> @@ -183,6 +191,10 @@ static int hibmc_load(struct drm_device *dev,
>>> unsigned long flags)
>>>          if (ret)
>>>                  goto err;
>>>
>>> +       ret = hibmc_mm_init(hidev);
>>> +       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 0037341..db8d80e 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/ttm/ttm_bo_driver.h>
>>> +#include <drm/drm_gem.h>
>>
>>
>> nit: alphabetize
>
>
> will fix it, thanks.
>
>>
>>>
>>>   struct hibmc_drm_device {
>>>          /* hw */
>>> @@ -30,6 +32,50 @@ struct hibmc_drm_device {
>>>
>>>          /* drm */
>>>          struct drm_device  *dev;
>>> +
>>> +       /* ttm */
>>> +       struct {
>>> +               struct drm_global_reference mem_global_ref;
>>> +               struct ttm_bo_global_ref bo_global_ref;
>>> +               struct ttm_bo_device bdev;
>>> +               bool initialized;
>>> +       } ttm;
>>
>>
>> I don't think you gain anything other than keystrokes from the substruct
>
>
> I'm sorry i didn't catch you, i looked at the all drivers used ttm such
> as ast/bochs/cirrus/mgag200/qxl/virtio_gpu, they all embedded the ttm
> substruct
> into the driver-private struct.
>
> so do you mean
> struct hibmc_drm_device {
>         /* hw */
>         void __iomem   *mmio;
>         void __iomem   *fb_map;
>         unsigned long  fb_base;
>         unsigned long  fb_size;
>
>         /* drm */
>         struct drm_device  *dev;
>         struct drm_plane plane;
>         struct drm_crtc crtc;
>         struct drm_encoder encoder;
>         struct drm_connector connector;
>         bool mode_config_initialized;
>
>         /* ttm */
>         struct drm_global_reference mem_global_ref;
>         struct ttm_bo_global_ref bo_global_ref;
>         struct ttm_bo_device bdev;
>         bool initialized;
>         ...
>         };
> ?

Yeah, that's what I was thinking

>
>>
>>> +
>>> +       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);
>>> +}
>>> +
>>> +#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
>>
>>
>> Hide this in ttm.c
>
>
> ok, will do that.
> thanks for pointing it out.
>
>
>>
>>> +
>>> +int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
>>> +                    struct drm_gem_object **obj);
>>> +
>>> +int hibmc_mm_init(struct hibmc_drm_device *hibmc);
>>> +void hibmc_mm_fini(struct hibmc_drm_device *hibmc);
>>> +int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr);
>>> +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..0802ebd
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>> @@ -0,0 +1,490 @@
>>> +/* 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 "hibmc_drm_drv.h"
>>> +#include <ttm/ttm_page_alloc.h>
>>> +#include <drm/drm_crtc_helper.h>
>>> +#include <drm/drm_atomic_helper.h>
>>> +
>>> +static inline struct hibmc_drm_device *
>>> +hibmc_bdev(struct ttm_bo_device *bd)
>>> +{
>>> +       return container_of(bd, struct hibmc_drm_device, ttm.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_device *hibmc)
>>> +{
>>> +       struct drm_global_reference *global_ref;
>>> +       int r;
>>
>>
>> nit: try not to use one character variable names unless it's for the
>> purpose of a loop (ie: i,j). You also use ret elsewhere in the driver,
>> so it'd be nice to remain consistent
>
>
> the whole file is delivered from bochs ttm, i didn't modify anything except
> some checkpatch warnings and the 'hibmc_' prefix. Unfortunately, some
> problems were delivered too.

Yeah, seems like it. Perhaps you can post patches to fix these issues
in the other drivers too :)

>
>>
>>> +
>>> +       global_ref = &hibmc->ttm.mem_global_ref;
>>
>>
>> I think using the global_ref local obfuscates what you're doing here.
>> It saves you 6 characters while typing, but adds a layer of
>> indirection for all future readers.
>>
>>> +       global_ref->global_type = DRM_GLOBAL_TTM_MEM;
>>> +       global_ref->size = sizeof(struct ttm_mem_global);
>>> +       global_ref->init = &hibmc_ttm_mem_global_init;
>>> +       global_ref->release = &hibmc_ttm_mem_global_release;
>>> +       r = drm_global_item_ref(global_ref);
>>> +       if (r != 0) {
>>
>>
>> nit: if (r)
>
>
> will fix it,
> thanks.
> BTW, i wonder why checkpatch.pl didn't report it.
>
>
>>
>>> +               DRM_ERROR("Failed setting up TTM memory accounting
>>> subsystem.\n"
>>> +                        );
>>
>>
>> Breaking up the line for one character is probably not worthwhile, and
>> you should really print the error. How about:
>>
>> DRM_ERROR("Could not get ref on ttm global ret=%d.\n", ret);
>
>
> i like your solution, thanks.
>
>
>>
>>
>>> +               return r;
>>> +       }
>>> +
>>> +       hibmc->ttm.bo_global_ref.mem_glob =
>>> +               hibmc->ttm.mem_global_ref.object;
>>> +       global_ref = &hibmc->ttm.bo_global_ref.ref;
>>> +       global_ref->global_type = DRM_GLOBAL_TTM_BO;
>>> +       global_ref->size = sizeof(struct ttm_bo_global);
>>> +       global_ref->init = &ttm_bo_global_init;
>>> +       global_ref->release = &ttm_bo_global_release;
>>> +       r = drm_global_item_ref(global_ref);
>>> +       if (r != 0) {
>>> +               DRM_ERROR("Failed setting up TTM BO subsystem.\n");
>>> +               drm_global_item_unref(&hibmc->ttm.mem_global_ref);
>>> +               return r;
>>> +       }
>>> +       return 0;
>>> +}
>>> +
>>> +static void
>>> +hibmc_ttm_global_release(struct hibmc_drm_device *hibmc)
>>> +{
>>> +       if (!hibmc->ttm.mem_global_ref.release)
>>
>>
>> Are you actually hitting this condition? This seems like it's papering
>> over something else.
>
>
> it was also delivered from others, i looked at the xxx_ttm_global_init
> function, 'mem_global_ref.release' is assigned unconditionally, so i
> think this condition never be hit, it may be hit when release twice,
> but this won't take place in my driver.
>

Yeah, that's what I was hoping for. So perhaps we can remove this?

>>
>>> +               return;
>>> +
>>> +       drm_global_item_unref(&hibmc->ttm.bo_global_ref.ref);
>>> +       drm_global_item_unref(&hibmc->ttm.mem_global_ref);
>>> +       hibmc->ttm.mem_global_ref.release = NULL;
>>> +}
>>> +
>>> +static void hibmc_bo_ttm_destroy(struct ttm_buffer_object *tbo)
>>> +{
>>> +       struct hibmc_bo *bo;
>>> +
>>> +       bo = container_of(tbo, struct hibmc_bo, bo);
>>
>>
>> nit: No need to split this into a separate line.
>
>
> agreed, thanks.
>
>>
>>> +
>>> +       drm_gem_object_release(&bo->gem);
>>> +       kfree(bo);
>>> +}
>>> +
>>> +static bool hibmc_ttm_bo_is_hibmc_bo(struct ttm_buffer_object *bo)
>>> +{
>>> +       if (bo->destroy == &hibmc_bo_ttm_destroy)
>>> +               return true;
>>> +       return false;
>>
>>
>> return bo->destroy == &hibmc_bo_ttm_destroy;
>
>
> looks better to me.
>
>
>>
>>> +}
>>> +
>>> +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 c = 0;
>>
>>
>> Can you please use a more descriptive name than 'c'?
>
>
> ok, will do that.
>
>>
>>> +       u32 i;
>>> +
>>> +       bo->placement.placement = bo->placements;
>>> +       bo->placement.busy_placement = bo->placements;
>>> +       if (domain & TTM_PL_FLAG_VRAM)
>>> +               bo->placements[c++].flags = TTM_PL_FLAG_WC |
>>> +               TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
>>
>>
>> nit: you're alignment is off here and below
>
>
> is it correct?
>
>         if (domain & TTM_PL_FLAG_VRAM)
>                 bo->placements[c++].flags = TTM_PL_FLAG_WC |
>                         TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
>         if (domain & TTM_PL_FLAG_SYSTEM)
>                 bo->placements[c++].flags = TTM_PL_MASK_CACHING |
>                         TTM_PL_FLAG_SYSTEM;
>         if (!c)
>                 bo->placements[c++].flags = TTM_PL_MASK_CACHING |
>                         TTM_PL_FLAG_SYSTEM;
>

Pretty much anything other than lining them up one under the other is better

>>
>>> +       if (domain & TTM_PL_FLAG_SYSTEM)
>>> +               bo->placements[c++].flags = TTM_PL_MASK_CACHING |
>>> +               TTM_PL_FLAG_SYSTEM;
>>> +       if (!c)
>>> +               bo->placements[c++].flags = TTM_PL_MASK_CACHING |
>>> +               TTM_PL_FLAG_SYSTEM;
>>> +
>>> +       bo->placement.num_placement = c;
>>> +       bo->placement.num_busy_placement = c;
>>> +       for (i = 0; i < c; ++i) {
>>
>>
>> nit: we tend towards post-increment in kernel
>
>
> agreed, thanks.
>
>
>>
>>> +               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_device *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_io_mem_free(struct ttm_bo_device *bdev,
>>> +                                 struct ttm_mem_reg *mem)
>>> +{
>>> +}
>>
>>
>> No need to stub this, the caller does a NULL-check before invoking
>
>
> will delete it, thanks.
>
>>
>>> +
>>> +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;
>>> +
>>> +       tt = kzalloc(sizeof(*tt), GFP_KERNEL);
>>> +       if (!tt)
>>
>>
>> Print error
>
>
> ok, will do that, thanks.
>
>>
>>> +               return NULL;
>>> +       tt->func = &hibmc_tt_backend_func;
>>> +       if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) {
>>
>>
>> Here too?
>
>
> ditto
>
>
>>
>>> +               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            = &hibmc_ttm_io_mem_free,
>>> +       .lru_tail               = &ttm_bo_default_lru_tail,
>>> +       .swap_lru_tail          = &ttm_bo_default_swap_lru_tail,
>>> +};
>>> +
>>> +int hibmc_mm_init(struct hibmc_drm_device *hibmc)
>>> +{
>>> +       int ret;
>>> +       struct drm_device *dev = hibmc->dev;
>>> +       struct ttm_bo_device *bdev = &hibmc->ttm.bdev;
>>> +
>>> +       ret = hibmc_ttm_global_init(hibmc);
>>> +       if (ret)
>>> +               return ret;
>>> +
>>> +       ret = ttm_bo_device_init(&hibmc->ttm.bdev,
>>> +                                hibmc->ttm.bo_global_ref.ref.object,
>>> +                                &hibmc_bo_driver,
>>> +                                dev->anon_inode->i_mapping,
>>> +                                DRM_FILE_PAGE_OFFSET,
>>> +                                true);
>>> +       if (ret) {
>>
>>
>> Call hibmc_ttm_global_release here?
>
>
> agreed, thanks for pointing it out.
>
>>
>>> +               DRM_ERROR("Error initialising bo driver; %d\n", ret);
>>> +               return ret;
>>> +       }
>>> +
>>> +       ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
>>> +                            hibmc->fb_size >> PAGE_SHIFT);
>>> +       if (ret) {
>>
>>
>> Clean up here as well?
>
>
> ditto
>
>
>>
>>> +               DRM_ERROR("Failed ttm VRAM init: %d\n", ret);
>>> +               return ret;
>>> +       }
>>> +
>>> +       hibmc->mm_inited = true;
>>> +       return 0;
>>> +}
>>> +
>>> +void hibmc_mm_fini(struct hibmc_drm_device *hibmc)
>>> +{
>>> +       if (!hibmc->mm_inited)
>>> +               return;
>>> +
>>> +       ttm_bo_device_release(&hibmc->ttm.bdev);
>>> +       hibmc_ttm_global_release(hibmc);
>>> +       hibmc->mm_inited = false;
>>> +}
>>> +
>>> +int hibmc_bo_create(struct drm_device *dev, int size, int align,
>>> +                   u32 flags, struct hibmc_bo **phibmcbo)
>>> +{
>>> +       struct hibmc_drm_device *hibmc = dev->dev_private;
>>> +       struct hibmc_bo *hibmcbo;
>>> +       size_t acc_size;
>>> +       int ret;
>>> +
>>> +       hibmcbo = kzalloc(sizeof(*hibmcbo), GFP_KERNEL);
>>> +       if (!hibmcbo)
>>> +               return -ENOMEM;
>>> +
>>> +       ret = drm_gem_object_init(dev, &hibmcbo->gem, size);
>>> +       if (ret) {
>>> +               kfree(hibmcbo);
>>> +               return ret;
>>> +       }
>>> +
>>> +       hibmcbo->bo.bdev = &hibmc->ttm.bdev;
>>> +
>>> +       hibmc_ttm_placement(hibmcbo, TTM_PL_FLAG_VRAM |
>>> TTM_PL_FLAG_SYSTEM);
>>> +
>>> +       acc_size = ttm_bo_dma_acc_size(&hibmc->ttm.bdev, size,
>>> +                                      sizeof(struct hibmc_bo));
>>> +
>>> +       ret = ttm_bo_init(&hibmc->ttm.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)
>>
>>
>> Missing hibmcbo clean up here
>
>
> i looked at all other ttm drivers and all of them return directly when
> ttm_bo_init
> failed, however, i think it is better to clean up here, should i call
> hibmc_bo_unref(&hibmc_bo) here ?
>

Yeah, that should work (might want to test it, though ;)


>>
>>> +               return ret;
>>> +
>>> +       *phibmcbo = hibmcbo;
>>> +       return 0;
>>> +}
>>> +
>>> +static inline u64 hibmc_bo_gpu_offset(struct hibmc_bo *bo)
>>> +{
>>> +       return bo->bo.offset;
>>> +}
>>
>>
>> I don't think this function provides any value
>
>
> do you nean i use bo->bo.offset instead of calling hibmc_bo_gpu_offset()?
>

yes

>>
>>> +
>>> +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 = hibmc_bo_gpu_offset(bo);
>>
>>
>> Are you missing a return here?
>
>
> Thanks for pointing it out!
>
>
>>
>>> +       }
>>> +
>>> +       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 = hibmc_bo_gpu_offset(bo);
>>> +       return 0;
>>> +}
>>> +
>>> +int hibmc_bo_push_sysram(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;
>>> +
>>> +       if (bo->kmap.virtual)
>>
>>
>> ttm_bo_kunmap already does this check so you don't have to
>
>
> agreed. will remove this condition.
>
>>
>>> +               ttm_bo_kunmap(&bo->kmap);
>>> +
>>> +       hibmc_ttm_placement(bo, TTM_PL_FLAG_SYSTEM);
>>> +       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("pushing to VRAM failed\n");
>>
>>
>> Print ret
>
>
> ok, thanks.
>
>
>>
>>> +               return ret;
>>> +       }
>>> +       return 0;
>>> +}
>>> +
>>> +int hibmc_mmap(struct file *filp, struct vm_area_struct *vma)
>>> +{
>>> +       struct drm_file *file_priv;
>>> +       struct hibmc_drm_device *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->ttm.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)
>>
>>
>> Print error
>
>
> ditto
>
>>
>>> +               return -EINVAL;
>>> +
>>> +       ret = hibmc_bo_create(dev, size, 0, 0, &hibmcbo);
>>> +       if (ret) {
>>> +               if (ret != -ERESTARTSYS)
>>> +                       DRM_ERROR("failed to allocate GEM object\n");
>>
>>
>> Print ret
>
>
> ditto
>
>>
>>> +               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 * ((args->bpp + 7) / 8), 16);
>>
>>
>> What's up with the bpp + 7 here? Perhaps you're looking for DIV_ROUND_UP?
>
>
> Yes, that sounds sane.
>

sane is what i usually aim for :)

Sean


>>
>>
>>> +       args->size = args->pitch * args->height;
>>> +
>>> +       ret = hibmc_gem_create(dev, args->size, false,
>>> +                              &gobj);
>>> +       if (ret)
>>> +               return ret;
>>> +
>>> +       ret = drm_gem_handle_create(file, gobj, &handle);
>>> +       drm_gem_object_unreference_unlocked(gobj);
>>> +       if (ret)
>>
>>
>> Print error here
>
>
> agreed.
>
>
>>
>>> +               return ret;
>>> +
>>> +       args->handle = handle;
>>> +       return 0;
>>> +}
>>> +
>>> +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;
>>> +}
>>> +
>>> +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;
>>> +}
>
>
> Regards,
> Rongrong.
>
>>> --
>>> 1.9.1
>>>
>>>
>>> _______________________________________________
>>> linux-arm-kernel mailing list
>>> linux-arm-kernel@lists.infradead.org
>>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>
>> _______________________________________________
>> 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
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

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

On Fri, Nov 11, 2016 at 8:16 AM, Rongrong Zou <zourongrong@huawei.com> wrote:
> ? 2016/11/11 2:30, Sean Paul ??:
>>
>> On Fri, Oct 28, 2016 at 3:27 AM, Rongrong Zou <zourongrong@gmail.com>
>> wrote:
>>>
>>> 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   |  17 ++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   |  24 ++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 255
>>> ++++++++++++++++++++++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       |  66 ++++++
>>>   5 files changed, 363 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 d5c40b8..810a37e 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>> @@ -1,5 +1,5 @@
>>>   ccflags-y := -Iinclude/drm
>>> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o hibmc_ttm.o
>>> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_drm_power.o
>>> hibmc_ttm.o
>>>
>>>   obj-$(CONFIG_DRM_HISI_HIBMC)   +=hibmc-drm.o
>>>   #obj-y += 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 81f4301..5ac7a7e 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>> @@ -66,11 +66,23 @@ 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_device *hidev = drm_dev->dev_private;
>>> +
>>> +       drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 1);
>>> +
>>
>>
>> We have atomic helpers for suspend/resume now. Please use those.
>
>
> drm_atomic_helper_suspend/resume()?
>

Correct

>
>>
>>>          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_device *hidev = drm_dev->dev_private;
>>> +
>>> +       drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 0);
>>> +
>>>          return 0;
>>>   }
>>>
>>> @@ -170,6 +182,7 @@ static int hibmc_unload(struct drm_device *dev)
>>>   {
>>>          struct hibmc_drm_device *hidev = dev->dev_private;
>>>
>>> +       hibmc_fbdev_fini(hidev);
>>>          hibmc_mm_fini(hidev);
>>>          hibmc_hw_fini(hidev);
>>>          dev->dev_private = NULL;
>>> @@ -195,6 +208,10 @@ static int hibmc_load(struct drm_device *dev,
>>> unsigned long flags)
>>>          if (ret)
>>>                  goto err;
>>>
>>> +       ret = hibmc_fbdev_init(hidev);
>>> +       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 db8d80e..a40e9a7 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>>> @@ -20,9 +20,22 @@
>>>   #define HIBMC_DRM_DRV_H
>>>
>>>   #include <drm/drmP.h>
>>> +#include <drm/drm_fb_helper.h>
>>>   #include <drm/ttm/ttm_bo_driver.h>
>>>   #include <drm/drm_gem.h>
>>>
>>> +struct hibmc_framebuffer {
>>> +       struct drm_framebuffer fb;
>>> +       struct drm_gem_object *obj;
>>> +       bool is_fbdev_fb;
>>> +};
>>> +
>>> +struct hibmc_fbdev {
>>> +       struct drm_fb_helper helper;
>>> +       struct hibmc_framebuffer *fb;
>>> +       int size;
>>> +};
>>> +
>>>   struct hibmc_drm_device {
>>>          /* hw */
>>>          void __iomem   *mmio;
>>> @@ -41,9 +54,13 @@ struct hibmc_drm_device {
>>>                  bool initialized;
>>>          } ttm;
>>>
>>> +       /* 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;
>>> @@ -65,8 +82,15 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct
>>> drm_gem_object *gem)
>>>
>>>   #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
>>>
>>> +int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
>>> +void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
>>> +
>>>   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_device *hibmc);
>>>   void hibmc_mm_fini(struct hibmc_drm_device *hibmc);
>>> 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..630124b
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
>>> @@ -0,0 +1,255 @@
>>> +/* 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"
>>> +
>>> +/*
>>> ---------------------------------------------------------------------- */
>>
>>
>> Please remove
>
>
> will do that, thanks.
>
>
>>
>>> +
>>> +static int hibmcfb_create_object(
>>> +                               struct hibmc_drm_device *hidev,
>>> +                               const struct drm_mode_fb_cmd2 *mode_cmd,
>>> +                               struct drm_gem_object **gobj_p)
>>> +{
>>> +       struct drm_gem_object *gobj;
>>> +       struct drm_device *dev = hidev->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_device *hidev =
>>> +               (struct hibmc_drm_device *)helper->dev->dev_private;
>>> +       struct fb_info *info;
>>> +       struct hibmc_framebuffer *hibmc_fb;
>>> +       struct drm_framebuffer *fb;
>>> +       struct drm_mode_fb_cmd2 mode_cmd;
>>> +       struct drm_gem_object *gobj = NULL;
>>> +       int ret = 0;
>>> +       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 = roundup(mode_cmd.pitches[0] * mode_cmd.height, PAGE_SIZE);
>>
>>
>> It's somewhat curious that you used ALIGN in the previous patch and
>> roundup here. But anyways, I think PAGE_ALIGN would be the most
>> appropriate thing to do here.
>
>
> agreed, thanks.
>
>>
>>> +
>>> +       ret = hibmcfb_create_object(hidev, &mode_cmd, &gobj);
>>> +       if (ret) {
>>> +               DRM_ERROR("failed to create fbcon backing object %d\r\n",
>>
>> ret);
>>
>> \r, yikes!!!
>
>
> will delete it, thanks.
>
>>
>>> +               return -ENOMEM;
>>> +       }
>>> +
>>> +       bo = gem_to_hibmc_bo(gobj);
>>> +
>>> +       ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
>>> +       if (ret)
>>
>>
>> Print error here?
>
>
> will do.
>
>>
>> How about cleaning up gobj?
>
>
> you are right,
>
>>
>>> +               return ret;
>>> +
>>> +       ret = hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL);
>>> +       if (ret) {
>>> +               DRM_ERROR("failed to pin fbcon\n");
>>
>>
>> Print ret
>>
>> ttm_bo_unreserve? It seems like you're missing clean-up in all of the
>> error paths in this function. Can you please make sure everything is
>> tidied up?
>
>
> ok, thanks.
>
>>
>>> +               return ret;
>>> +       }
>>> +
>>> +       ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
>>> +
>>
>>
>> nit: extra space
>
>
> do you mean extra line?
>

yes, apologies.

>>
>>> +       if (ret) {
>>> +               DRM_ERROR("failed to kmap fbcon\n");
>>
>>
>> Print ret
>
>
> ok, thanks.
>
>>
>>> +               ttm_bo_unreserve(&bo->bo);
>>> +               return ret;
>>> +       }
>>> +
>>> +       ttm_bo_unreserve(&bo->bo);
>>
>>
>> Move this between ttm_bo_kmap and if (ret), then remove it from inside
>> the conditional.
>
>
> This is fine with me, thanks.
>
>>
>>> +
>>> +       info = drm_fb_helper_alloc_fbi(helper);
>>> +       if (IS_ERR(info))
>>
>>
>> Print error
>
>
> ok, thanks.
>
>>
>>> +               return PTR_ERR(info);
>>> +
>>> +       info->par = hi_fbdev;
>>> +
>>> +       hibmc_fb = hibmc_framebuffer_init(hidev->dev, &mode_cmd, gobj);
>>> +       if (IS_ERR(hibmc_fb)) {
>>> +               drm_fb_helper_release_fbi(helper);
>>> +               return PTR_ERR(hibmc_fb);
>>> +       }
>>> +
>>> +       hi_fbdev->fb = hibmc_fb;
>>> +       hidev->fbdev->size = size;
>>> +       fb = &hibmc_fb->fb;
>>
>>
>> The fb variable isn't necessary, and really, the hibmc_fb doesn't
>> really help either, it just masks what's actually happening IMO.
>
>
> i will clean the two variables.
>
>
>>
>>> +       if (!fb) {
>>> +               DRM_INFO("fb is NULL\n");
>>> +               return -EINVAL;
>>> +       }
>>> +
>>> +       hi_fbdev->helper.fb = fb;
>>> +
>>> +       strcpy(info->fix.id, "hibmcdrmfb");
>>> +
>>> +       info->flags = FBINFO_DEFAULT;
>>> +       info->fbops = &hibmc_drm_fb_ops;
>>> +
>>> +       drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
>>> +       drm_fb_helper_fill_var(info, &hidev->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;
>>> +}
>>> +
>>> +static void hibmc_fbdev_destroy(struct hibmc_fbdev *fbdev)
>>> +{
>>> +       struct hibmc_framebuffer *gfb = fbdev->fb;
>>> +       struct drm_fb_helper *fbh = &fbdev->helper;
>>> +
>>> +       DRM_DEBUG_DRIVER("hibmc_fbdev_destroy\n");
>>
>>
>> Not useful
>
>
> ok, will remove.
>
>
>>
>>> +
>>> +       drm_fb_helper_unregister_fbi(fbh);
>>> +       drm_fb_helper_release_fbi(fbh);
>>> +
>>> +       drm_fb_helper_fini(fbh);
>>> +
>>> +       if (gfb)
>>> +               drm_framebuffer_unreference(&gfb->fb);
>>> +
>>> +       kfree(fbdev);
>>> +}
>>> +
>>> +static const struct drm_fb_helper_funcs hibmc_fbdev_helper_funcs = {
>>> +       .fb_probe = hibmc_drm_fb_create,
>>> +};
>>> +
>>> +int hibmc_fbdev_init(struct hibmc_drm_device *hidev)
>>> +{
>>> +       int ret;
>>> +       struct fb_var_screeninfo *var;
>>> +       struct fb_fix_screeninfo *fix;
>>> +       struct hibmc_fbdev *hifbdev;
>>> +
>>> +       hifbdev = kzalloc(sizeof(*hifbdev), GFP_KERNEL);
>>
>>
>> devm_kzalloc?
>
>
> sounds good, so there need no kfree at hibmc_fbdev_destroy(),
> thanks.
>

yep, exactly

>>
>>> +       if (!hifbdev)
>>> +               return -ENOMEM;
>>> +
>>> +       hidev->fbdev = hifbdev;
>>> +       drm_fb_helper_prepare(hidev->dev, &hifbdev->helper,
>>> +                             &hibmc_fbdev_helper_funcs);
>>> +
>>> +       /* Now just one crtc and one channel */
>>> +       ret = drm_fb_helper_init(hidev->dev,
>>> +                                &hifbdev->helper, 1, 1);
>>> +
>>
>>
>> nit: extra line
>
>
> ok, thanks.
>
>
>>
>>> +       if (ret)
>>> +               return ret;
>>> +
>>> +       ret = drm_fb_helper_single_add_all_connectors(&hifbdev->helper);
>>> +       if (ret)
>>> +               goto fini;
>>> +
>>> +       ret = drm_fb_helper_initial_config(&hifbdev->helper, 16);
>>> +       if (ret)
>>> +               goto fini;
>>> +
>>> +       var = &hifbdev->helper.fbdev->var;
>>> +       fix = &hifbdev->helper.fbdev->fix;
>>> +
>>> +       DRM_DEBUG("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("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);
>>
>>
>> You've been using DRM_DEBUG_DRIVER elsewhere, you should probably use
>> it here, too.
>
>
> ok, thanks.
>
>
>>
>>> +
>>> +       return 0;
>>> +
>>> +fini:
>>> +       drm_fb_helper_fini(&hifbdev->helper);
>>> +       return ret;
>>> +}
>>> +
>>> +void hibmc_fbdev_fini(struct hibmc_drm_device *hidev)
>>> +{
>>> +       if (!hidev->fbdev)
>>> +               return;
>>> +
>>> +       hibmc_fbdev_destroy(hidev->fbdev);
>>> +       hidev->fbdev = NULL;
>>> +}
>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>> b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>> index 0802ebd..9822f62 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>> @@ -488,3 +488,69 @@ int hibmc_dumb_mmap_offset(struct drm_file *file,
>>> struct drm_device *dev,
>>>          drm_gem_object_unreference_unlocked(obj);
>>>          return 0;
>>>   }
>>> +
>>> +/*
>>> ---------------------------------------------------------------------- */
>>> +
>>
>>
>> Please remove
>
>
> will do.
>
>>
>>> +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)
>>
>>
>> Print error
>
>
> ok, thanks.
>
> Regards,
> Rongrong.
>
>>
>>> +               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
>>>
>>>
>>> _______________________________________________
>>> linux-arm-kernel mailing list
>>> linux-arm-kernel at lists.infradead.org
>>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>
>> _______________________________________________
>> linuxarm mailing list
>> linuxarm at huawei.com
>> http://rnd-openeuler.huawei.com/mailman/listinfo/linuxarm
>>
>> .
>>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v6 3/9] drm/hisilicon/hibmc: Add support for frame buffer
@ 2016-11-11 13:27         ` Sean Paul
  0 siblings, 0 replies; 64+ messages in thread
From: Sean Paul @ 2016-11-11 13:27 UTC (permalink / raw)
  To: Rongrong Zou
  Cc: Mark Rutland, lijianhua, Will Deacon, Tomeu Vizoso,
	Jonathan Corbet, catalin.marinas, Emil Velikov, linuxarm,
	dri-devel, james.xiong, shenhui, Rongrong Zou, Linux ARM Kernel

On Fri, Nov 11, 2016 at 8:16 AM, Rongrong Zou <zourongrong@huawei.com> wrote:
> 在 2016/11/11 2:30, Sean Paul 写道:
>>
>> On Fri, Oct 28, 2016 at 3:27 AM, Rongrong Zou <zourongrong@gmail.com>
>> wrote:
>>>
>>> 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   |  17 ++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   |  24 ++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 255
>>> ++++++++++++++++++++++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       |  66 ++++++
>>>   5 files changed, 363 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 d5c40b8..810a37e 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>> @@ -1,5 +1,5 @@
>>>   ccflags-y := -Iinclude/drm
>>> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o hibmc_ttm.o
>>> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_drm_power.o
>>> hibmc_ttm.o
>>>
>>>   obj-$(CONFIG_DRM_HISI_HIBMC)   +=hibmc-drm.o
>>>   #obj-y += 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 81f4301..5ac7a7e 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>> @@ -66,11 +66,23 @@ 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_device *hidev = drm_dev->dev_private;
>>> +
>>> +       drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 1);
>>> +
>>
>>
>> We have atomic helpers for suspend/resume now. Please use those.
>
>
> drm_atomic_helper_suspend/resume()?
>

Correct

>
>>
>>>          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_device *hidev = drm_dev->dev_private;
>>> +
>>> +       drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 0);
>>> +
>>>          return 0;
>>>   }
>>>
>>> @@ -170,6 +182,7 @@ static int hibmc_unload(struct drm_device *dev)
>>>   {
>>>          struct hibmc_drm_device *hidev = dev->dev_private;
>>>
>>> +       hibmc_fbdev_fini(hidev);
>>>          hibmc_mm_fini(hidev);
>>>          hibmc_hw_fini(hidev);
>>>          dev->dev_private = NULL;
>>> @@ -195,6 +208,10 @@ static int hibmc_load(struct drm_device *dev,
>>> unsigned long flags)
>>>          if (ret)
>>>                  goto err;
>>>
>>> +       ret = hibmc_fbdev_init(hidev);
>>> +       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 db8d80e..a40e9a7 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>>> @@ -20,9 +20,22 @@
>>>   #define HIBMC_DRM_DRV_H
>>>
>>>   #include <drm/drmP.h>
>>> +#include <drm/drm_fb_helper.h>
>>>   #include <drm/ttm/ttm_bo_driver.h>
>>>   #include <drm/drm_gem.h>
>>>
>>> +struct hibmc_framebuffer {
>>> +       struct drm_framebuffer fb;
>>> +       struct drm_gem_object *obj;
>>> +       bool is_fbdev_fb;
>>> +};
>>> +
>>> +struct hibmc_fbdev {
>>> +       struct drm_fb_helper helper;
>>> +       struct hibmc_framebuffer *fb;
>>> +       int size;
>>> +};
>>> +
>>>   struct hibmc_drm_device {
>>>          /* hw */
>>>          void __iomem   *mmio;
>>> @@ -41,9 +54,13 @@ struct hibmc_drm_device {
>>>                  bool initialized;
>>>          } ttm;
>>>
>>> +       /* 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;
>>> @@ -65,8 +82,15 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct
>>> drm_gem_object *gem)
>>>
>>>   #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
>>>
>>> +int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
>>> +void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
>>> +
>>>   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_device *hibmc);
>>>   void hibmc_mm_fini(struct hibmc_drm_device *hibmc);
>>> 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..630124b
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
>>> @@ -0,0 +1,255 @@
>>> +/* 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"
>>> +
>>> +/*
>>> ---------------------------------------------------------------------- */
>>
>>
>> Please remove
>
>
> will do that, thanks.
>
>
>>
>>> +
>>> +static int hibmcfb_create_object(
>>> +                               struct hibmc_drm_device *hidev,
>>> +                               const struct drm_mode_fb_cmd2 *mode_cmd,
>>> +                               struct drm_gem_object **gobj_p)
>>> +{
>>> +       struct drm_gem_object *gobj;
>>> +       struct drm_device *dev = hidev->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_device *hidev =
>>> +               (struct hibmc_drm_device *)helper->dev->dev_private;
>>> +       struct fb_info *info;
>>> +       struct hibmc_framebuffer *hibmc_fb;
>>> +       struct drm_framebuffer *fb;
>>> +       struct drm_mode_fb_cmd2 mode_cmd;
>>> +       struct drm_gem_object *gobj = NULL;
>>> +       int ret = 0;
>>> +       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 = roundup(mode_cmd.pitches[0] * mode_cmd.height, PAGE_SIZE);
>>
>>
>> It's somewhat curious that you used ALIGN in the previous patch and
>> roundup here. But anyways, I think PAGE_ALIGN would be the most
>> appropriate thing to do here.
>
>
> agreed, thanks.
>
>>
>>> +
>>> +       ret = hibmcfb_create_object(hidev, &mode_cmd, &gobj);
>>> +       if (ret) {
>>> +               DRM_ERROR("failed to create fbcon backing object %d\r\n",
>>
>> ret);
>>
>> \r, yikes!!!
>
>
> will delete it, thanks.
>
>>
>>> +               return -ENOMEM;
>>> +       }
>>> +
>>> +       bo = gem_to_hibmc_bo(gobj);
>>> +
>>> +       ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
>>> +       if (ret)
>>
>>
>> Print error here?
>
>
> will do.
>
>>
>> How about cleaning up gobj?
>
>
> you are right,
>
>>
>>> +               return ret;
>>> +
>>> +       ret = hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL);
>>> +       if (ret) {
>>> +               DRM_ERROR("failed to pin fbcon\n");
>>
>>
>> Print ret
>>
>> ttm_bo_unreserve? It seems like you're missing clean-up in all of the
>> error paths in this function. Can you please make sure everything is
>> tidied up?
>
>
> ok, thanks.
>
>>
>>> +               return ret;
>>> +       }
>>> +
>>> +       ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
>>> +
>>
>>
>> nit: extra space
>
>
> do you mean extra line?
>

yes, apologies.

>>
>>> +       if (ret) {
>>> +               DRM_ERROR("failed to kmap fbcon\n");
>>
>>
>> Print ret
>
>
> ok, thanks.
>
>>
>>> +               ttm_bo_unreserve(&bo->bo);
>>> +               return ret;
>>> +       }
>>> +
>>> +       ttm_bo_unreserve(&bo->bo);
>>
>>
>> Move this between ttm_bo_kmap and if (ret), then remove it from inside
>> the conditional.
>
>
> This is fine with me, thanks.
>
>>
>>> +
>>> +       info = drm_fb_helper_alloc_fbi(helper);
>>> +       if (IS_ERR(info))
>>
>>
>> Print error
>
>
> ok, thanks.
>
>>
>>> +               return PTR_ERR(info);
>>> +
>>> +       info->par = hi_fbdev;
>>> +
>>> +       hibmc_fb = hibmc_framebuffer_init(hidev->dev, &mode_cmd, gobj);
>>> +       if (IS_ERR(hibmc_fb)) {
>>> +               drm_fb_helper_release_fbi(helper);
>>> +               return PTR_ERR(hibmc_fb);
>>> +       }
>>> +
>>> +       hi_fbdev->fb = hibmc_fb;
>>> +       hidev->fbdev->size = size;
>>> +       fb = &hibmc_fb->fb;
>>
>>
>> The fb variable isn't necessary, and really, the hibmc_fb doesn't
>> really help either, it just masks what's actually happening IMO.
>
>
> i will clean the two variables.
>
>
>>
>>> +       if (!fb) {
>>> +               DRM_INFO("fb is NULL\n");
>>> +               return -EINVAL;
>>> +       }
>>> +
>>> +       hi_fbdev->helper.fb = fb;
>>> +
>>> +       strcpy(info->fix.id, "hibmcdrmfb");
>>> +
>>> +       info->flags = FBINFO_DEFAULT;
>>> +       info->fbops = &hibmc_drm_fb_ops;
>>> +
>>> +       drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
>>> +       drm_fb_helper_fill_var(info, &hidev->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;
>>> +}
>>> +
>>> +static void hibmc_fbdev_destroy(struct hibmc_fbdev *fbdev)
>>> +{
>>> +       struct hibmc_framebuffer *gfb = fbdev->fb;
>>> +       struct drm_fb_helper *fbh = &fbdev->helper;
>>> +
>>> +       DRM_DEBUG_DRIVER("hibmc_fbdev_destroy\n");
>>
>>
>> Not useful
>
>
> ok, will remove.
>
>
>>
>>> +
>>> +       drm_fb_helper_unregister_fbi(fbh);
>>> +       drm_fb_helper_release_fbi(fbh);
>>> +
>>> +       drm_fb_helper_fini(fbh);
>>> +
>>> +       if (gfb)
>>> +               drm_framebuffer_unreference(&gfb->fb);
>>> +
>>> +       kfree(fbdev);
>>> +}
>>> +
>>> +static const struct drm_fb_helper_funcs hibmc_fbdev_helper_funcs = {
>>> +       .fb_probe = hibmc_drm_fb_create,
>>> +};
>>> +
>>> +int hibmc_fbdev_init(struct hibmc_drm_device *hidev)
>>> +{
>>> +       int ret;
>>> +       struct fb_var_screeninfo *var;
>>> +       struct fb_fix_screeninfo *fix;
>>> +       struct hibmc_fbdev *hifbdev;
>>> +
>>> +       hifbdev = kzalloc(sizeof(*hifbdev), GFP_KERNEL);
>>
>>
>> devm_kzalloc?
>
>
> sounds good, so there need no kfree at hibmc_fbdev_destroy(),
> thanks.
>

yep, exactly

>>
>>> +       if (!hifbdev)
>>> +               return -ENOMEM;
>>> +
>>> +       hidev->fbdev = hifbdev;
>>> +       drm_fb_helper_prepare(hidev->dev, &hifbdev->helper,
>>> +                             &hibmc_fbdev_helper_funcs);
>>> +
>>> +       /* Now just one crtc and one channel */
>>> +       ret = drm_fb_helper_init(hidev->dev,
>>> +                                &hifbdev->helper, 1, 1);
>>> +
>>
>>
>> nit: extra line
>
>
> ok, thanks.
>
>
>>
>>> +       if (ret)
>>> +               return ret;
>>> +
>>> +       ret = drm_fb_helper_single_add_all_connectors(&hifbdev->helper);
>>> +       if (ret)
>>> +               goto fini;
>>> +
>>> +       ret = drm_fb_helper_initial_config(&hifbdev->helper, 16);
>>> +       if (ret)
>>> +               goto fini;
>>> +
>>> +       var = &hifbdev->helper.fbdev->var;
>>> +       fix = &hifbdev->helper.fbdev->fix;
>>> +
>>> +       DRM_DEBUG("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("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);
>>
>>
>> You've been using DRM_DEBUG_DRIVER elsewhere, you should probably use
>> it here, too.
>
>
> ok, thanks.
>
>
>>
>>> +
>>> +       return 0;
>>> +
>>> +fini:
>>> +       drm_fb_helper_fini(&hifbdev->helper);
>>> +       return ret;
>>> +}
>>> +
>>> +void hibmc_fbdev_fini(struct hibmc_drm_device *hidev)
>>> +{
>>> +       if (!hidev->fbdev)
>>> +               return;
>>> +
>>> +       hibmc_fbdev_destroy(hidev->fbdev);
>>> +       hidev->fbdev = NULL;
>>> +}
>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>> b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>> index 0802ebd..9822f62 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>> @@ -488,3 +488,69 @@ int hibmc_dumb_mmap_offset(struct drm_file *file,
>>> struct drm_device *dev,
>>>          drm_gem_object_unreference_unlocked(obj);
>>>          return 0;
>>>   }
>>> +
>>> +/*
>>> ---------------------------------------------------------------------- */
>>> +
>>
>>
>> Please remove
>
>
> will do.
>
>>
>>> +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)
>>
>>
>> Print error
>
>
> ok, thanks.
>
> Regards,
> Rongrong.
>
>>
>>> +               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
>>>
>>>
>>> _______________________________________________
>>> linux-arm-kernel mailing list
>>> linux-arm-kernel@lists.infradead.org
>>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>
>> _______________________________________________
>> 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
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v6 2/9] drm/hisilicon/hibmc: Add video memory management
  2016-11-11 13:25         ` Sean Paul
@ 2016-11-11 13:57           ` Rongrong Zou
  -1 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-11-11 13:57 UTC (permalink / raw)
  To: linux-arm-kernel

? 2016/11/11 21:25, Sean Paul ??:
> On Fri, Nov 11, 2016 at 6:16 AM, Rongrong Zou <zourongrong@huawei.com> wrote:
>> ? 2016/11/11 1:35, Sean Paul ??:
>>>
>>> On Fri, Oct 28, 2016 at 3:27 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>
>>>> ---
>>>>    drivers/gpu/drm/hisilicon/hibmc/Kconfig         |   1 +
>>>>    drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
>>>>    drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  12 +
>>>>    drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |  46 +++
>>>>    drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     | 490
>>>> ++++++++++++++++++++++++
>>>>    5 files changed, 550 insertions(+), 1 deletion(-)
>>>>    create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>>>
>>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>>> b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>>> index a9af90d..bcb8c18 100644
>>>> --- a/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>>> @@ -1,6 +1,7 @@
>>>>    config DRM_HISI_HIBMC
>>>>           tristate "DRM Support for Hisilicon Hibmc"
>>>>           depends on DRM && PCI
>>>> +       select DRM_TTM
>>>>
>>>>           help
>>>>             Choose this option if you have a Hisilicon Hibmc soc chipset.
>>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>>> b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>>> index 97cf4a0..d5c40b8 100644
>>>> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>>> @@ -1,5 +1,5 @@
>>>>    ccflags-y := -Iinclude/drm
>>>> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o
>>>> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o hibmc_ttm.o
>>>>
>>>>    obj-$(CONFIG_DRM_HISI_HIBMC)   +=hibmc-drm.o
>>>>    #obj-y += 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 4669d42..81f4301 100644
>>>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>>> @@ -31,6 +31,7 @@
>>>>    #ifdef CONFIG_COMPAT
>>>>           .compat_ioctl   = drm_compat_ioctl,
>>>>    #endif
>>>> +       .mmap           = hibmc_mmap,
>>>>           .poll           = drm_poll,
>>>>           .read           = drm_read,
>>>>           .llseek         = no_llseek,
>>>> @@ -46,6 +47,8 @@ static void hibmc_disable_vblank(struct drm_device
>>>> *dev, unsigned int pipe)
>>>>    }
>>>>
>>>>    static struct drm_driver hibmc_driver = {
>>>> +       .driver_features        = DRIVER_GEM,
>>>> +
>>>
>>>
>>> nit: extra space
>>>
>>>>           .fops                   = &hibmc_fops,
>>>>           .name                   = "hibmc",
>>>>           .date                   = "20160828",
>>>> @@ -55,6 +58,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)
>>>> @@ -163,6 +170,7 @@ static int hibmc_unload(struct drm_device *dev)
>>>>    {
>>>>           struct hibmc_drm_device *hidev = dev->dev_private;
>>>>
>>>> +       hibmc_mm_fini(hidev);
>>>>           hibmc_hw_fini(hidev);
>>>>           dev->dev_private = NULL;
>>>>           return 0;
>>>> @@ -183,6 +191,10 @@ static int hibmc_load(struct drm_device *dev,
>>>> unsigned long flags)
>>>>           if (ret)
>>>>                   goto err;
>>>>
>>>> +       ret = hibmc_mm_init(hidev);
>>>> +       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 0037341..db8d80e 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/ttm/ttm_bo_driver.h>
>>>> +#include <drm/drm_gem.h>
>>>
>>>
>>> nit: alphabetize
>>
>>
>> will fix it, thanks.
>>
>>>
>>>>
>>>>    struct hibmc_drm_device {
>>>>           /* hw */
>>>> @@ -30,6 +32,50 @@ struct hibmc_drm_device {
>>>>
>>>>           /* drm */
>>>>           struct drm_device  *dev;
>>>> +
>>>> +       /* ttm */
>>>> +       struct {
>>>> +               struct drm_global_reference mem_global_ref;
>>>> +               struct ttm_bo_global_ref bo_global_ref;
>>>> +               struct ttm_bo_device bdev;
>>>> +               bool initialized;
>>>> +       } ttm;
>>>
>>>
>>> I don't think you gain anything other than keystrokes from the substruct
>>
>>
>> I'm sorry i didn't catch you, i looked at the all drivers used ttm such
>> as ast/bochs/cirrus/mgag200/qxl/virtio_gpu, they all embedded the ttm
>> substruct
>> into the driver-private struct.
>>
>> so do you mean
>> struct hibmc_drm_device {
>>          /* hw */
>>          void __iomem   *mmio;
>>          void __iomem   *fb_map;
>>          unsigned long  fb_base;
>>          unsigned long  fb_size;
>>
>>          /* drm */
>>          struct drm_device  *dev;
>>          struct drm_plane plane;
>>          struct drm_crtc crtc;
>>          struct drm_encoder encoder;
>>          struct drm_connector connector;
>>          bool mode_config_initialized;
>>
>>          /* ttm */
>>          struct drm_global_reference mem_global_ref;
>>          struct ttm_bo_global_ref bo_global_ref;
>>          struct ttm_bo_device bdev;
>>          bool initialized;
>>          ...
>>          };
>> ?
>
> Yeah, that's what I was thinking
>
>>
>>>
>>>> +
>>>> +       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);
>>>> +}
>>>> +
>>>> +#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
>>>
>>>
>>> Hide this in ttm.c
>>
>>
>> ok, will do that.
>> thanks for pointing it out.
>>
>>
>>>
>>>> +
>>>> +int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
>>>> +                    struct drm_gem_object **obj);
>>>> +
>>>> +int hibmc_mm_init(struct hibmc_drm_device *hibmc);
>>>> +void hibmc_mm_fini(struct hibmc_drm_device *hibmc);
>>>> +int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr);
>>>> +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..0802ebd
>>>> --- /dev/null
>>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>>> @@ -0,0 +1,490 @@
>>>> +/* 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 "hibmc_drm_drv.h"
>>>> +#include <ttm/ttm_page_alloc.h>
>>>> +#include <drm/drm_crtc_helper.h>
>>>> +#include <drm/drm_atomic_helper.h>
>>>> +
>>>> +static inline struct hibmc_drm_device *
>>>> +hibmc_bdev(struct ttm_bo_device *bd)
>>>> +{
>>>> +       return container_of(bd, struct hibmc_drm_device, ttm.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_device *hibmc)
>>>> +{
>>>> +       struct drm_global_reference *global_ref;
>>>> +       int r;
>>>
>>>
>>> nit: try not to use one character variable names unless it's for the
>>> purpose of a loop (ie: i,j). You also use ret elsewhere in the driver,
>>> so it'd be nice to remain consistent
>>
>>
>> the whole file is delivered from bochs ttm, i didn't modify anything except
>> some checkpatch warnings and the 'hibmc_' prefix. Unfortunately, some
>> problems were delivered too.
>
> Yeah, seems like it. Perhaps you can post patches to fix these issues
> in the other drivers too :)

i will do after the this one get merged :)

>
>>
>>>
>>>> +
>>>> +       global_ref = &hibmc->ttm.mem_global_ref;
>>>
>>>
>>> I think using the global_ref local obfuscates what you're doing here.
>>> It saves you 6 characters while typing, but adds a layer of
>>> indirection for all future readers.
>>>
>>>> +       global_ref->global_type = DRM_GLOBAL_TTM_MEM;
>>>> +       global_ref->size = sizeof(struct ttm_mem_global);
>>>> +       global_ref->init = &hibmc_ttm_mem_global_init;
>>>> +       global_ref->release = &hibmc_ttm_mem_global_release;
>>>> +       r = drm_global_item_ref(global_ref);
>>>> +       if (r != 0) {
>>>
>>>
>>> nit: if (r)
>>
>>
>> will fix it,
>> thanks.
>> BTW, i wonder why checkpatch.pl didn't report it.
>>
>>
>>>
>>>> +               DRM_ERROR("Failed setting up TTM memory accounting
>>>> subsystem.\n"
>>>> +                        );
>>>
>>>
>>> Breaking up the line for one character is probably not worthwhile, and
>>> you should really print the error. How about:
>>>
>>> DRM_ERROR("Could not get ref on ttm global ret=%d.\n", ret);
>>
>>
>> i like your solution, thanks.
>>
>>
>>>
>>>
>>>> +               return r;
>>>> +       }
>>>> +
>>>> +       hibmc->ttm.bo_global_ref.mem_glob =
>>>> +               hibmc->ttm.mem_global_ref.object;
>>>> +       global_ref = &hibmc->ttm.bo_global_ref.ref;
>>>> +       global_ref->global_type = DRM_GLOBAL_TTM_BO;
>>>> +       global_ref->size = sizeof(struct ttm_bo_global);
>>>> +       global_ref->init = &ttm_bo_global_init;
>>>> +       global_ref->release = &ttm_bo_global_release;
>>>> +       r = drm_global_item_ref(global_ref);
>>>> +       if (r != 0) {
>>>> +               DRM_ERROR("Failed setting up TTM BO subsystem.\n");
>>>> +               drm_global_item_unref(&hibmc->ttm.mem_global_ref);
>>>> +               return r;
>>>> +       }
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +static void
>>>> +hibmc_ttm_global_release(struct hibmc_drm_device *hibmc)
>>>> +{
>>>> +       if (!hibmc->ttm.mem_global_ref.release)
>>>
>>>
>>> Are you actually hitting this condition? This seems like it's papering
>>> over something else.
>>
>>
>> it was also delivered from others, i looked at the xxx_ttm_global_init
>> function, 'mem_global_ref.release' is assigned unconditionally, so i
>> think this condition never be hit, it may be hit when release twice,
>> but this won't take place in my driver.
>>
>
> Yeah, that's what I was hoping for. So perhaps we can remove this?

yes, we can.

Regards,
Rongrong.

>
>>>
>>>> +               return;
>>>> +
>>>> +       drm_global_item_unref(&hibmc->ttm.bo_global_ref.ref);
>>>> +       drm_global_item_unref(&hibmc->ttm.mem_global_ref);
>>>> +       hibmc->ttm.mem_global_ref.release = NULL;
>>>> +}
>>>> +
>>>> +static void hibmc_bo_ttm_destroy(struct ttm_buffer_object *tbo)
>>>> +{
>>>> +       struct hibmc_bo *bo;
>>>> +
>>>> +       bo = container_of(tbo, struct hibmc_bo, bo);
>>>
>>>
>>> nit: No need to split this into a separate line.
>>
>>
>> agreed, thanks.
>>
>>>
>>>> +
>>>> +       drm_gem_object_release(&bo->gem);
>>>> +       kfree(bo);
>>>> +}
>>>> +
>>>> +static bool hibmc_ttm_bo_is_hibmc_bo(struct ttm_buffer_object *bo)
>>>> +{
>>>> +       if (bo->destroy == &hibmc_bo_ttm_destroy)
>>>> +               return true;
>>>> +       return false;
>>>
>>>
>>> return bo->destroy == &hibmc_bo_ttm_destroy;
>>
>>
>> looks better to me.
>>
>>
>>>
>>>> +}
>>>> +
>>>> +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 c = 0;
>>>
>>>
>>> Can you please use a more descriptive name than 'c'?
>>
>>
>> ok, will do that.
>>
>>>
>>>> +       u32 i;
>>>> +
>>>> +       bo->placement.placement = bo->placements;
>>>> +       bo->placement.busy_placement = bo->placements;
>>>> +       if (domain & TTM_PL_FLAG_VRAM)
>>>> +               bo->placements[c++].flags = TTM_PL_FLAG_WC |
>>>> +               TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
>>>
>>>
>>> nit: you're alignment is off here and below
>>
>>
>> is it correct?
>>
>>          if (domain & TTM_PL_FLAG_VRAM)
>>                  bo->placements[c++].flags = TTM_PL_FLAG_WC |
>>                          TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
>>          if (domain & TTM_PL_FLAG_SYSTEM)
>>                  bo->placements[c++].flags = TTM_PL_MASK_CACHING |
>>                          TTM_PL_FLAG_SYSTEM;
>>          if (!c)
>>                  bo->placements[c++].flags = TTM_PL_MASK_CACHING |
>>                          TTM_PL_FLAG_SYSTEM;
>>
>
> Pretty much anything other than lining them up one under the other is better
>
>>>
>>>> +       if (domain & TTM_PL_FLAG_SYSTEM)
>>>> +               bo->placements[c++].flags = TTM_PL_MASK_CACHING |
>>>> +               TTM_PL_FLAG_SYSTEM;
>>>> +       if (!c)
>>>> +               bo->placements[c++].flags = TTM_PL_MASK_CACHING |
>>>> +               TTM_PL_FLAG_SYSTEM;
>>>> +
>>>> +       bo->placement.num_placement = c;
>>>> +       bo->placement.num_busy_placement = c;
>>>> +       for (i = 0; i < c; ++i) {
>>>
>>>
>>> nit: we tend towards post-increment in kernel
>>
>>
>> agreed, thanks.
>>
>>
>>>
>>>> +               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_device *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_io_mem_free(struct ttm_bo_device *bdev,
>>>> +                                 struct ttm_mem_reg *mem)
>>>> +{
>>>> +}
>>>
>>>
>>> No need to stub this, the caller does a NULL-check before invoking
>>
>>
>> will delete it, thanks.
>>
>>>
>>>> +
>>>> +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;
>>>> +
>>>> +       tt = kzalloc(sizeof(*tt), GFP_KERNEL);
>>>> +       if (!tt)
>>>
>>>
>>> Print error
>>
>>
>> ok, will do that, thanks.
>>
>>>
>>>> +               return NULL;
>>>> +       tt->func = &hibmc_tt_backend_func;
>>>> +       if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) {
>>>
>>>
>>> Here too?
>>
>>
>> ditto
>>
>>
>>>
>>>> +               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            = &hibmc_ttm_io_mem_free,
>>>> +       .lru_tail               = &ttm_bo_default_lru_tail,
>>>> +       .swap_lru_tail          = &ttm_bo_default_swap_lru_tail,
>>>> +};
>>>> +
>>>> +int hibmc_mm_init(struct hibmc_drm_device *hibmc)
>>>> +{
>>>> +       int ret;
>>>> +       struct drm_device *dev = hibmc->dev;
>>>> +       struct ttm_bo_device *bdev = &hibmc->ttm.bdev;
>>>> +
>>>> +       ret = hibmc_ttm_global_init(hibmc);
>>>> +       if (ret)
>>>> +               return ret;
>>>> +
>>>> +       ret = ttm_bo_device_init(&hibmc->ttm.bdev,
>>>> +                                hibmc->ttm.bo_global_ref.ref.object,
>>>> +                                &hibmc_bo_driver,
>>>> +                                dev->anon_inode->i_mapping,
>>>> +                                DRM_FILE_PAGE_OFFSET,
>>>> +                                true);
>>>> +       if (ret) {
>>>
>>>
>>> Call hibmc_ttm_global_release here?
>>
>>
>> agreed, thanks for pointing it out.
>>
>>>
>>>> +               DRM_ERROR("Error initialising bo driver; %d\n", ret);
>>>> +               return ret;
>>>> +       }
>>>> +
>>>> +       ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
>>>> +                            hibmc->fb_size >> PAGE_SHIFT);
>>>> +       if (ret) {
>>>
>>>
>>> Clean up here as well?
>>
>>
>> ditto
>>
>>
>>>
>>>> +               DRM_ERROR("Failed ttm VRAM init: %d\n", ret);
>>>> +               return ret;
>>>> +       }
>>>> +
>>>> +       hibmc->mm_inited = true;
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +void hibmc_mm_fini(struct hibmc_drm_device *hibmc)
>>>> +{
>>>> +       if (!hibmc->mm_inited)
>>>> +               return;
>>>> +
>>>> +       ttm_bo_device_release(&hibmc->ttm.bdev);
>>>> +       hibmc_ttm_global_release(hibmc);
>>>> +       hibmc->mm_inited = false;
>>>> +}
>>>> +
>>>> +int hibmc_bo_create(struct drm_device *dev, int size, int align,
>>>> +                   u32 flags, struct hibmc_bo **phibmcbo)
>>>> +{
>>>> +       struct hibmc_drm_device *hibmc = dev->dev_private;
>>>> +       struct hibmc_bo *hibmcbo;
>>>> +       size_t acc_size;
>>>> +       int ret;
>>>> +
>>>> +       hibmcbo = kzalloc(sizeof(*hibmcbo), GFP_KERNEL);
>>>> +       if (!hibmcbo)
>>>> +               return -ENOMEM;
>>>> +
>>>> +       ret = drm_gem_object_init(dev, &hibmcbo->gem, size);
>>>> +       if (ret) {
>>>> +               kfree(hibmcbo);
>>>> +               return ret;
>>>> +       }
>>>> +
>>>> +       hibmcbo->bo.bdev = &hibmc->ttm.bdev;
>>>> +
>>>> +       hibmc_ttm_placement(hibmcbo, TTM_PL_FLAG_VRAM |
>>>> TTM_PL_FLAG_SYSTEM);
>>>> +
>>>> +       acc_size = ttm_bo_dma_acc_size(&hibmc->ttm.bdev, size,
>>>> +                                      sizeof(struct hibmc_bo));
>>>> +
>>>> +       ret = ttm_bo_init(&hibmc->ttm.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)
>>>
>>>
>>> Missing hibmcbo clean up here
>>
>>
>> i looked at all other ttm drivers and all of them return directly when
>> ttm_bo_init
>> failed, however, i think it is better to clean up here, should i call
>> hibmc_bo_unref(&hibmc_bo) here ?
>>
>
> Yeah, that should work (might want to test it, though ;)
>
>
>>>
>>>> +               return ret;
>>>> +
>>>> +       *phibmcbo = hibmcbo;
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +static inline u64 hibmc_bo_gpu_offset(struct hibmc_bo *bo)
>>>> +{
>>>> +       return bo->bo.offset;
>>>> +}
>>>
>>>
>>> I don't think this function provides any value
>>
>>
>> do you nean i use bo->bo.offset instead of calling hibmc_bo_gpu_offset()?
>>
>
> yes
>
>>>
>>>> +
>>>> +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 = hibmc_bo_gpu_offset(bo);
>>>
>>>
>>> Are you missing a return here?
>>
>>
>> Thanks for pointing it out!
>>
>>
>>>
>>>> +       }
>>>> +
>>>> +       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 = hibmc_bo_gpu_offset(bo);
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +int hibmc_bo_push_sysram(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;
>>>> +
>>>> +       if (bo->kmap.virtual)
>>>
>>>
>>> ttm_bo_kunmap already does this check so you don't have to
>>
>>
>> agreed. will remove this condition.
>>
>>>
>>>> +               ttm_bo_kunmap(&bo->kmap);
>>>> +
>>>> +       hibmc_ttm_placement(bo, TTM_PL_FLAG_SYSTEM);
>>>> +       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("pushing to VRAM failed\n");
>>>
>>>
>>> Print ret
>>
>>
>> ok, thanks.
>>
>>
>>>
>>>> +               return ret;
>>>> +       }
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +int hibmc_mmap(struct file *filp, struct vm_area_struct *vma)
>>>> +{
>>>> +       struct drm_file *file_priv;
>>>> +       struct hibmc_drm_device *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->ttm.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)
>>>
>>>
>>> Print error
>>
>>
>> ditto
>>
>>>
>>>> +               return -EINVAL;
>>>> +
>>>> +       ret = hibmc_bo_create(dev, size, 0, 0, &hibmcbo);
>>>> +       if (ret) {
>>>> +               if (ret != -ERESTARTSYS)
>>>> +                       DRM_ERROR("failed to allocate GEM object\n");
>>>
>>>
>>> Print ret
>>
>>
>> ditto
>>
>>>
>>>> +               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 * ((args->bpp + 7) / 8), 16);
>>>
>>>
>>> What's up with the bpp + 7 here? Perhaps you're looking for DIV_ROUND_UP?
>>
>>
>> Yes, that sounds sane.
>>
>
> sane is what i usually aim for :)
>
> Sean
>
>
>>>
>>>
>>>> +       args->size = args->pitch * args->height;
>>>> +
>>>> +       ret = hibmc_gem_create(dev, args->size, false,
>>>> +                              &gobj);
>>>> +       if (ret)
>>>> +               return ret;
>>>> +
>>>> +       ret = drm_gem_handle_create(file, gobj, &handle);
>>>> +       drm_gem_object_unreference_unlocked(gobj);
>>>> +       if (ret)
>>>
>>>
>>> Print error here
>>
>>
>> agreed.
>>
>>
>>>
>>>> +               return ret;
>>>> +
>>>> +       args->handle = handle;
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +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;
>>>> +}
>>>> +
>>>> +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;
>>>> +}
>>
>>
>> Regards,
>> Rongrong.
>>
>>>> --
>>>> 1.9.1
>>>>
>>>>
>>>> _______________________________________________
>>>> linux-arm-kernel mailing list
>>>> linux-arm-kernel at lists.infradead.org
>>>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>>
>>> _______________________________________________
>>> linuxarm mailing list
>>> linuxarm at huawei.com
>>> http://rnd-openeuler.huawei.com/mailman/listinfo/linuxarm
>>>
>>> .
>>>
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
> .
>


-- 
Regards, Rongrong

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

* Re: [PATCH v6 2/9] drm/hisilicon/hibmc: Add video memory management
@ 2016-11-11 13:57           ` Rongrong Zou
  0 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-11-11 13:57 UTC (permalink / raw)
  To: Sean Paul
  Cc: Mark Rutland, Archit, lijianhua, Daniel Vetter, Tomeu Vizoso,
	Jonathan Corbet, Dave Airlie, catalin.marinas, Emil Velikov,
	linuxarm, dri-devel, Xinliang Liu, james.xiong, shenhui,
	Rongrong Zou, Daniel Stone, Will Deacon, Linux ARM Kernel,
	Benjamin Gaignard

在 2016/11/11 21:25, Sean Paul 写道:
> On Fri, Nov 11, 2016 at 6:16 AM, Rongrong Zou <zourongrong@huawei.com> wrote:
>> 在 2016/11/11 1:35, Sean Paul 写道:
>>>
>>> On Fri, Oct 28, 2016 at 3:27 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>
>>>> ---
>>>>    drivers/gpu/drm/hisilicon/hibmc/Kconfig         |   1 +
>>>>    drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
>>>>    drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  12 +
>>>>    drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |  46 +++
>>>>    drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     | 490
>>>> ++++++++++++++++++++++++
>>>>    5 files changed, 550 insertions(+), 1 deletion(-)
>>>>    create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>>>
>>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>>> b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>>> index a9af90d..bcb8c18 100644
>>>> --- a/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>>> @@ -1,6 +1,7 @@
>>>>    config DRM_HISI_HIBMC
>>>>           tristate "DRM Support for Hisilicon Hibmc"
>>>>           depends on DRM && PCI
>>>> +       select DRM_TTM
>>>>
>>>>           help
>>>>             Choose this option if you have a Hisilicon Hibmc soc chipset.
>>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>>> b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>>> index 97cf4a0..d5c40b8 100644
>>>> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>>> @@ -1,5 +1,5 @@
>>>>    ccflags-y := -Iinclude/drm
>>>> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o
>>>> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o hibmc_ttm.o
>>>>
>>>>    obj-$(CONFIG_DRM_HISI_HIBMC)   +=hibmc-drm.o
>>>>    #obj-y += 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 4669d42..81f4301 100644
>>>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>>> @@ -31,6 +31,7 @@
>>>>    #ifdef CONFIG_COMPAT
>>>>           .compat_ioctl   = drm_compat_ioctl,
>>>>    #endif
>>>> +       .mmap           = hibmc_mmap,
>>>>           .poll           = drm_poll,
>>>>           .read           = drm_read,
>>>>           .llseek         = no_llseek,
>>>> @@ -46,6 +47,8 @@ static void hibmc_disable_vblank(struct drm_device
>>>> *dev, unsigned int pipe)
>>>>    }
>>>>
>>>>    static struct drm_driver hibmc_driver = {
>>>> +       .driver_features        = DRIVER_GEM,
>>>> +
>>>
>>>
>>> nit: extra space
>>>
>>>>           .fops                   = &hibmc_fops,
>>>>           .name                   = "hibmc",
>>>>           .date                   = "20160828",
>>>> @@ -55,6 +58,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)
>>>> @@ -163,6 +170,7 @@ static int hibmc_unload(struct drm_device *dev)
>>>>    {
>>>>           struct hibmc_drm_device *hidev = dev->dev_private;
>>>>
>>>> +       hibmc_mm_fini(hidev);
>>>>           hibmc_hw_fini(hidev);
>>>>           dev->dev_private = NULL;
>>>>           return 0;
>>>> @@ -183,6 +191,10 @@ static int hibmc_load(struct drm_device *dev,
>>>> unsigned long flags)
>>>>           if (ret)
>>>>                   goto err;
>>>>
>>>> +       ret = hibmc_mm_init(hidev);
>>>> +       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 0037341..db8d80e 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/ttm/ttm_bo_driver.h>
>>>> +#include <drm/drm_gem.h>
>>>
>>>
>>> nit: alphabetize
>>
>>
>> will fix it, thanks.
>>
>>>
>>>>
>>>>    struct hibmc_drm_device {
>>>>           /* hw */
>>>> @@ -30,6 +32,50 @@ struct hibmc_drm_device {
>>>>
>>>>           /* drm */
>>>>           struct drm_device  *dev;
>>>> +
>>>> +       /* ttm */
>>>> +       struct {
>>>> +               struct drm_global_reference mem_global_ref;
>>>> +               struct ttm_bo_global_ref bo_global_ref;
>>>> +               struct ttm_bo_device bdev;
>>>> +               bool initialized;
>>>> +       } ttm;
>>>
>>>
>>> I don't think you gain anything other than keystrokes from the substruct
>>
>>
>> I'm sorry i didn't catch you, i looked at the all drivers used ttm such
>> as ast/bochs/cirrus/mgag200/qxl/virtio_gpu, they all embedded the ttm
>> substruct
>> into the driver-private struct.
>>
>> so do you mean
>> struct hibmc_drm_device {
>>          /* hw */
>>          void __iomem   *mmio;
>>          void __iomem   *fb_map;
>>          unsigned long  fb_base;
>>          unsigned long  fb_size;
>>
>>          /* drm */
>>          struct drm_device  *dev;
>>          struct drm_plane plane;
>>          struct drm_crtc crtc;
>>          struct drm_encoder encoder;
>>          struct drm_connector connector;
>>          bool mode_config_initialized;
>>
>>          /* ttm */
>>          struct drm_global_reference mem_global_ref;
>>          struct ttm_bo_global_ref bo_global_ref;
>>          struct ttm_bo_device bdev;
>>          bool initialized;
>>          ...
>>          };
>> ?
>
> Yeah, that's what I was thinking
>
>>
>>>
>>>> +
>>>> +       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);
>>>> +}
>>>> +
>>>> +#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
>>>
>>>
>>> Hide this in ttm.c
>>
>>
>> ok, will do that.
>> thanks for pointing it out.
>>
>>
>>>
>>>> +
>>>> +int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
>>>> +                    struct drm_gem_object **obj);
>>>> +
>>>> +int hibmc_mm_init(struct hibmc_drm_device *hibmc);
>>>> +void hibmc_mm_fini(struct hibmc_drm_device *hibmc);
>>>> +int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr);
>>>> +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..0802ebd
>>>> --- /dev/null
>>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>>> @@ -0,0 +1,490 @@
>>>> +/* 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 "hibmc_drm_drv.h"
>>>> +#include <ttm/ttm_page_alloc.h>
>>>> +#include <drm/drm_crtc_helper.h>
>>>> +#include <drm/drm_atomic_helper.h>
>>>> +
>>>> +static inline struct hibmc_drm_device *
>>>> +hibmc_bdev(struct ttm_bo_device *bd)
>>>> +{
>>>> +       return container_of(bd, struct hibmc_drm_device, ttm.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_device *hibmc)
>>>> +{
>>>> +       struct drm_global_reference *global_ref;
>>>> +       int r;
>>>
>>>
>>> nit: try not to use one character variable names unless it's for the
>>> purpose of a loop (ie: i,j). You also use ret elsewhere in the driver,
>>> so it'd be nice to remain consistent
>>
>>
>> the whole file is delivered from bochs ttm, i didn't modify anything except
>> some checkpatch warnings and the 'hibmc_' prefix. Unfortunately, some
>> problems were delivered too.
>
> Yeah, seems like it. Perhaps you can post patches to fix these issues
> in the other drivers too :)

i will do after the this one get merged :)

>
>>
>>>
>>>> +
>>>> +       global_ref = &hibmc->ttm.mem_global_ref;
>>>
>>>
>>> I think using the global_ref local obfuscates what you're doing here.
>>> It saves you 6 characters while typing, but adds a layer of
>>> indirection for all future readers.
>>>
>>>> +       global_ref->global_type = DRM_GLOBAL_TTM_MEM;
>>>> +       global_ref->size = sizeof(struct ttm_mem_global);
>>>> +       global_ref->init = &hibmc_ttm_mem_global_init;
>>>> +       global_ref->release = &hibmc_ttm_mem_global_release;
>>>> +       r = drm_global_item_ref(global_ref);
>>>> +       if (r != 0) {
>>>
>>>
>>> nit: if (r)
>>
>>
>> will fix it,
>> thanks.
>> BTW, i wonder why checkpatch.pl didn't report it.
>>
>>
>>>
>>>> +               DRM_ERROR("Failed setting up TTM memory accounting
>>>> subsystem.\n"
>>>> +                        );
>>>
>>>
>>> Breaking up the line for one character is probably not worthwhile, and
>>> you should really print the error. How about:
>>>
>>> DRM_ERROR("Could not get ref on ttm global ret=%d.\n", ret);
>>
>>
>> i like your solution, thanks.
>>
>>
>>>
>>>
>>>> +               return r;
>>>> +       }
>>>> +
>>>> +       hibmc->ttm.bo_global_ref.mem_glob =
>>>> +               hibmc->ttm.mem_global_ref.object;
>>>> +       global_ref = &hibmc->ttm.bo_global_ref.ref;
>>>> +       global_ref->global_type = DRM_GLOBAL_TTM_BO;
>>>> +       global_ref->size = sizeof(struct ttm_bo_global);
>>>> +       global_ref->init = &ttm_bo_global_init;
>>>> +       global_ref->release = &ttm_bo_global_release;
>>>> +       r = drm_global_item_ref(global_ref);
>>>> +       if (r != 0) {
>>>> +               DRM_ERROR("Failed setting up TTM BO subsystem.\n");
>>>> +               drm_global_item_unref(&hibmc->ttm.mem_global_ref);
>>>> +               return r;
>>>> +       }
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +static void
>>>> +hibmc_ttm_global_release(struct hibmc_drm_device *hibmc)
>>>> +{
>>>> +       if (!hibmc->ttm.mem_global_ref.release)
>>>
>>>
>>> Are you actually hitting this condition? This seems like it's papering
>>> over something else.
>>
>>
>> it was also delivered from others, i looked at the xxx_ttm_global_init
>> function, 'mem_global_ref.release' is assigned unconditionally, so i
>> think this condition never be hit, it may be hit when release twice,
>> but this won't take place in my driver.
>>
>
> Yeah, that's what I was hoping for. So perhaps we can remove this?

yes, we can.

Regards,
Rongrong.

>
>>>
>>>> +               return;
>>>> +
>>>> +       drm_global_item_unref(&hibmc->ttm.bo_global_ref.ref);
>>>> +       drm_global_item_unref(&hibmc->ttm.mem_global_ref);
>>>> +       hibmc->ttm.mem_global_ref.release = NULL;
>>>> +}
>>>> +
>>>> +static void hibmc_bo_ttm_destroy(struct ttm_buffer_object *tbo)
>>>> +{
>>>> +       struct hibmc_bo *bo;
>>>> +
>>>> +       bo = container_of(tbo, struct hibmc_bo, bo);
>>>
>>>
>>> nit: No need to split this into a separate line.
>>
>>
>> agreed, thanks.
>>
>>>
>>>> +
>>>> +       drm_gem_object_release(&bo->gem);
>>>> +       kfree(bo);
>>>> +}
>>>> +
>>>> +static bool hibmc_ttm_bo_is_hibmc_bo(struct ttm_buffer_object *bo)
>>>> +{
>>>> +       if (bo->destroy == &hibmc_bo_ttm_destroy)
>>>> +               return true;
>>>> +       return false;
>>>
>>>
>>> return bo->destroy == &hibmc_bo_ttm_destroy;
>>
>>
>> looks better to me.
>>
>>
>>>
>>>> +}
>>>> +
>>>> +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 c = 0;
>>>
>>>
>>> Can you please use a more descriptive name than 'c'?
>>
>>
>> ok, will do that.
>>
>>>
>>>> +       u32 i;
>>>> +
>>>> +       bo->placement.placement = bo->placements;
>>>> +       bo->placement.busy_placement = bo->placements;
>>>> +       if (domain & TTM_PL_FLAG_VRAM)
>>>> +               bo->placements[c++].flags = TTM_PL_FLAG_WC |
>>>> +               TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
>>>
>>>
>>> nit: you're alignment is off here and below
>>
>>
>> is it correct?
>>
>>          if (domain & TTM_PL_FLAG_VRAM)
>>                  bo->placements[c++].flags = TTM_PL_FLAG_WC |
>>                          TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
>>          if (domain & TTM_PL_FLAG_SYSTEM)
>>                  bo->placements[c++].flags = TTM_PL_MASK_CACHING |
>>                          TTM_PL_FLAG_SYSTEM;
>>          if (!c)
>>                  bo->placements[c++].flags = TTM_PL_MASK_CACHING |
>>                          TTM_PL_FLAG_SYSTEM;
>>
>
> Pretty much anything other than lining them up one under the other is better
>
>>>
>>>> +       if (domain & TTM_PL_FLAG_SYSTEM)
>>>> +               bo->placements[c++].flags = TTM_PL_MASK_CACHING |
>>>> +               TTM_PL_FLAG_SYSTEM;
>>>> +       if (!c)
>>>> +               bo->placements[c++].flags = TTM_PL_MASK_CACHING |
>>>> +               TTM_PL_FLAG_SYSTEM;
>>>> +
>>>> +       bo->placement.num_placement = c;
>>>> +       bo->placement.num_busy_placement = c;
>>>> +       for (i = 0; i < c; ++i) {
>>>
>>>
>>> nit: we tend towards post-increment in kernel
>>
>>
>> agreed, thanks.
>>
>>
>>>
>>>> +               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_device *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_io_mem_free(struct ttm_bo_device *bdev,
>>>> +                                 struct ttm_mem_reg *mem)
>>>> +{
>>>> +}
>>>
>>>
>>> No need to stub this, the caller does a NULL-check before invoking
>>
>>
>> will delete it, thanks.
>>
>>>
>>>> +
>>>> +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;
>>>> +
>>>> +       tt = kzalloc(sizeof(*tt), GFP_KERNEL);
>>>> +       if (!tt)
>>>
>>>
>>> Print error
>>
>>
>> ok, will do that, thanks.
>>
>>>
>>>> +               return NULL;
>>>> +       tt->func = &hibmc_tt_backend_func;
>>>> +       if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) {
>>>
>>>
>>> Here too?
>>
>>
>> ditto
>>
>>
>>>
>>>> +               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            = &hibmc_ttm_io_mem_free,
>>>> +       .lru_tail               = &ttm_bo_default_lru_tail,
>>>> +       .swap_lru_tail          = &ttm_bo_default_swap_lru_tail,
>>>> +};
>>>> +
>>>> +int hibmc_mm_init(struct hibmc_drm_device *hibmc)
>>>> +{
>>>> +       int ret;
>>>> +       struct drm_device *dev = hibmc->dev;
>>>> +       struct ttm_bo_device *bdev = &hibmc->ttm.bdev;
>>>> +
>>>> +       ret = hibmc_ttm_global_init(hibmc);
>>>> +       if (ret)
>>>> +               return ret;
>>>> +
>>>> +       ret = ttm_bo_device_init(&hibmc->ttm.bdev,
>>>> +                                hibmc->ttm.bo_global_ref.ref.object,
>>>> +                                &hibmc_bo_driver,
>>>> +                                dev->anon_inode->i_mapping,
>>>> +                                DRM_FILE_PAGE_OFFSET,
>>>> +                                true);
>>>> +       if (ret) {
>>>
>>>
>>> Call hibmc_ttm_global_release here?
>>
>>
>> agreed, thanks for pointing it out.
>>
>>>
>>>> +               DRM_ERROR("Error initialising bo driver; %d\n", ret);
>>>> +               return ret;
>>>> +       }
>>>> +
>>>> +       ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
>>>> +                            hibmc->fb_size >> PAGE_SHIFT);
>>>> +       if (ret) {
>>>
>>>
>>> Clean up here as well?
>>
>>
>> ditto
>>
>>
>>>
>>>> +               DRM_ERROR("Failed ttm VRAM init: %d\n", ret);
>>>> +               return ret;
>>>> +       }
>>>> +
>>>> +       hibmc->mm_inited = true;
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +void hibmc_mm_fini(struct hibmc_drm_device *hibmc)
>>>> +{
>>>> +       if (!hibmc->mm_inited)
>>>> +               return;
>>>> +
>>>> +       ttm_bo_device_release(&hibmc->ttm.bdev);
>>>> +       hibmc_ttm_global_release(hibmc);
>>>> +       hibmc->mm_inited = false;
>>>> +}
>>>> +
>>>> +int hibmc_bo_create(struct drm_device *dev, int size, int align,
>>>> +                   u32 flags, struct hibmc_bo **phibmcbo)
>>>> +{
>>>> +       struct hibmc_drm_device *hibmc = dev->dev_private;
>>>> +       struct hibmc_bo *hibmcbo;
>>>> +       size_t acc_size;
>>>> +       int ret;
>>>> +
>>>> +       hibmcbo = kzalloc(sizeof(*hibmcbo), GFP_KERNEL);
>>>> +       if (!hibmcbo)
>>>> +               return -ENOMEM;
>>>> +
>>>> +       ret = drm_gem_object_init(dev, &hibmcbo->gem, size);
>>>> +       if (ret) {
>>>> +               kfree(hibmcbo);
>>>> +               return ret;
>>>> +       }
>>>> +
>>>> +       hibmcbo->bo.bdev = &hibmc->ttm.bdev;
>>>> +
>>>> +       hibmc_ttm_placement(hibmcbo, TTM_PL_FLAG_VRAM |
>>>> TTM_PL_FLAG_SYSTEM);
>>>> +
>>>> +       acc_size = ttm_bo_dma_acc_size(&hibmc->ttm.bdev, size,
>>>> +                                      sizeof(struct hibmc_bo));
>>>> +
>>>> +       ret = ttm_bo_init(&hibmc->ttm.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)
>>>
>>>
>>> Missing hibmcbo clean up here
>>
>>
>> i looked at all other ttm drivers and all of them return directly when
>> ttm_bo_init
>> failed, however, i think it is better to clean up here, should i call
>> hibmc_bo_unref(&hibmc_bo) here ?
>>
>
> Yeah, that should work (might want to test it, though ;)
>
>
>>>
>>>> +               return ret;
>>>> +
>>>> +       *phibmcbo = hibmcbo;
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +static inline u64 hibmc_bo_gpu_offset(struct hibmc_bo *bo)
>>>> +{
>>>> +       return bo->bo.offset;
>>>> +}
>>>
>>>
>>> I don't think this function provides any value
>>
>>
>> do you nean i use bo->bo.offset instead of calling hibmc_bo_gpu_offset()?
>>
>
> yes
>
>>>
>>>> +
>>>> +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 = hibmc_bo_gpu_offset(bo);
>>>
>>>
>>> Are you missing a return here?
>>
>>
>> Thanks for pointing it out!
>>
>>
>>>
>>>> +       }
>>>> +
>>>> +       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 = hibmc_bo_gpu_offset(bo);
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +int hibmc_bo_push_sysram(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;
>>>> +
>>>> +       if (bo->kmap.virtual)
>>>
>>>
>>> ttm_bo_kunmap already does this check so you don't have to
>>
>>
>> agreed. will remove this condition.
>>
>>>
>>>> +               ttm_bo_kunmap(&bo->kmap);
>>>> +
>>>> +       hibmc_ttm_placement(bo, TTM_PL_FLAG_SYSTEM);
>>>> +       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("pushing to VRAM failed\n");
>>>
>>>
>>> Print ret
>>
>>
>> ok, thanks.
>>
>>
>>>
>>>> +               return ret;
>>>> +       }
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +int hibmc_mmap(struct file *filp, struct vm_area_struct *vma)
>>>> +{
>>>> +       struct drm_file *file_priv;
>>>> +       struct hibmc_drm_device *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->ttm.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)
>>>
>>>
>>> Print error
>>
>>
>> ditto
>>
>>>
>>>> +               return -EINVAL;
>>>> +
>>>> +       ret = hibmc_bo_create(dev, size, 0, 0, &hibmcbo);
>>>> +       if (ret) {
>>>> +               if (ret != -ERESTARTSYS)
>>>> +                       DRM_ERROR("failed to allocate GEM object\n");
>>>
>>>
>>> Print ret
>>
>>
>> ditto
>>
>>>
>>>> +               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 * ((args->bpp + 7) / 8), 16);
>>>
>>>
>>> What's up with the bpp + 7 here? Perhaps you're looking for DIV_ROUND_UP?
>>
>>
>> Yes, that sounds sane.
>>
>
> sane is what i usually aim for :)
>
> Sean
>
>
>>>
>>>
>>>> +       args->size = args->pitch * args->height;
>>>> +
>>>> +       ret = hibmc_gem_create(dev, args->size, false,
>>>> +                              &gobj);
>>>> +       if (ret)
>>>> +               return ret;
>>>> +
>>>> +       ret = drm_gem_handle_create(file, gobj, &handle);
>>>> +       drm_gem_object_unreference_unlocked(gobj);
>>>> +       if (ret)
>>>
>>>
>>> Print error here
>>
>>
>> agreed.
>>
>>
>>>
>>>> +               return ret;
>>>> +
>>>> +       args->handle = handle;
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +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;
>>>> +}
>>>> +
>>>> +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;
>>>> +}
>>
>>
>> Regards,
>> Rongrong.
>>
>>>> --
>>>> 1.9.1
>>>>
>>>>
>>>> _______________________________________________
>>>> linux-arm-kernel mailing list
>>>> linux-arm-kernel@lists.infradead.org
>>>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>>
>>> _______________________________________________
>>> 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
>
> .
>


-- 
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] 64+ messages in thread

* [PATCH v6 4/9] drm/hisilicon/hibmc: Add plane for DE
  2016-11-10 21:53     ` Sean Paul
@ 2016-11-12  5:11       ` Rongrong Zou
  -1 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-11-12  5:11 UTC (permalink / raw)
  To: linux-arm-kernel

? 2016/11/11 5:53, Sean Paul ??:
> On Fri, Oct 28, 2016 at 3:27 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
>> Add plane funcs and helper funcs for DE.
>>
>> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
>> ---
>>   drivers/gpu/drm/hisilicon/hibmc/Kconfig         |   1 +
>>   drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c  | 170 ++++++++++++++++++++++++
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h  |  29 ++++
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  51 ++++++-
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |   5 +
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     |   6 +
>>   7 files changed, 261 insertions(+), 3 deletions(-)
>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
>>
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>> index bcb8c18..380622a 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>> @@ -1,6 +1,7 @@
>>   config DRM_HISI_HIBMC
>>          tristate "DRM Support for Hisilicon Hibmc"
>>          depends on DRM && PCI
>> +       select DRM_KMS_HELPER
>>          select DRM_TTM
>>
>>          help
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>> index 810a37e..72e107e 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>> @@ -1,5 +1,5 @@
>>   ccflags-y := -Iinclude/drm
>> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
>> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
>>
>>   obj-$(CONFIG_DRM_HISI_HIBMC)   +=hibmc-drm.o
>>   #obj-y += 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..9c1a68c
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>> @@ -0,0 +1,170 @@
>> +/* 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"
>> +#include "hibmc_drm_power.h"
>> +
>> +/* ---------------------------------------------------------------------- */
>
> Remove

ok, will do, thanks.

>
>> +
>> +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_x = state->src_x >> 16;
>> +       u32 src_y = state->src_y >> 16;
>> +       u32 src_w = state->src_w >> 16;
>> +       u32 src_h = state->src_h >> 16;
>> +       int crtc_x = state->crtc_x;
>> +       int crtc_y = state->crtc_y;
>> +       u32 crtc_w = state->crtc_w;
>> +       u32 crtc_h = state->crtc_h;
>
> I don't think you gain anything with the crtc_* vars

It would work well, but looks redundant and not simple enough,
will delete them, thanks.

>
>> +
>> +       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 != crtc_w || src_h != crtc_h) {
>> +               DRM_ERROR("Scale not support!!!\n");
>
> I like the enthusiasm, but I think DRM_DEBUG_ATOMIC would be better

I'm sorry, can you explain why here should be an DRM_DEBUG_ATOMIC,
when this condition is hit, it is really an error and atomic_commit will
abort with failure.

>
>> +               return -EINVAL;
>> +       }
>> +
>> +       if (src_x + src_w > fb->width ||
>> +           src_y + src_h > fb->height)
>
> These should be already covered in drm_atomic_plane_check

understood, thanks.

>
>> +               return -EINVAL;
>> +
>> +       if (crtc_x < 0 || crtc_y < 0)
>
> Print DRM_DEBUG_ATOMIC message here

agreed. thanks.

>
>> +               return -EINVAL;
>> +
>> +       if (crtc_x + crtc_w > crtc_state->adjusted_mode.hdisplay ||
>> +           crtc_y + crtc_h > crtc_state->adjusted_mode.vdisplay)
>
> DRM_DEBUG_ATOMIC here too

ditto.

>
>> +               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_device *hidev =
>> +               (struct hibmc_drm_device *)plane->dev->dev_private;
>> +
>
> nit: extra line

will delete, thanks.

>> +       struct hibmc_framebuffer *hibmc_fb;
>> +       struct hibmc_bo *bo;
>> +
>> +       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)
>
> Print error

agreed, thanks.

>
>> +               return;
>> +
>> +       hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
>
> Check return value

ok, thanks.

>
>> +       if (ret) {
>> +               ttm_bo_unreserve(&bo->bo);
>> +               return;
>> +       }
>> +
>> +       ttm_bo_unreserve(&bo->bo);
>
> Move this up before the conditional so you don't have to call it in
> both branches

understood, thanks.

>
>> +
>> +       writel(gpu_addr, hidev->mmio + HIBMC_CRT_FB_ADDRESS);
>> +
>> +       reg = state->fb->width * (state->fb->bits_per_pixel >> 3);
>> +       /* now line_pad is 16 */
>> +       reg = PADDING(16, reg);
>> +
>> +       line_l = state->fb->width * state->fb->bits_per_pixel / 8;
>
> above, you >> 3. here you / 8, pick one?

i prefer /8 because it is more readable to human, although it is less effective
in executing.

>
>> +       line_l = PADDING(16, line_l);
>> +       writel((HIBMC_CRT_FB_WIDTH_WIDTH(reg) & HIBMC_CRT_FB_WIDTH_WIDTH_MASK) |
>> +              (HIBMC_CRT_FB_WIDTH_OFFS(line_l) & HIBMC_CRT_FB_WIDTH_OFFS_MASK),
>> +              hidev->mmio + HIBMC_CRT_FB_WIDTH);
>> +
>> +       /* SET PIXEL FORMAT */
>> +       reg = readl(hidev->mmio + HIBMC_CRT_DISP_CTL);
>> +       reg = reg & ~HIBMC_CRT_DISP_CTL_FORMAT_MASK;
>> +       reg = reg | (HIBMC_CRT_DISP_CTL_FORMAT(state->fb->bits_per_pixel >> 4) &
>> +                    HIBMC_CRT_DISP_CTL_FORMAT_MASK);
>> +       writel(reg, hidev->mmio + HIBMC_CRT_DISP_CTL);
>> +}
>> +
>> +static void hibmc_plane_atomic_disable(struct drm_plane *plane,
>> +                                      struct drm_plane_state *old_state)
>> +{
>> +}
>
> The caller checks for NULL, no need to stub

thanks for pointing it out,
will remove.

Regards,
Rongrong.

>
>> +
>> +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,
>> +       .atomic_disable = hibmc_plane_atomic_disable,
>> +};
>> +
>> +int hibmc_plane_init(struct hibmc_drm_device *hidev)
>> +{
>> +       struct drm_device *dev = hidev->dev;
>> +       struct drm_plane *plane = &hidev->plane;
>> +       int ret = 0;
>> +
>> +       /*
>> +        * 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("fail to init plane!!!\n");
>> +               return ret;
>> +       }
>> +
>> +       drm_plane_helper_add(plane, &hibmc_plane_helper_funcs);
>> +       return 0;
>> +}
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
>> new file mode 100644
>> index 0000000..4ce0d7b
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
>> @@ -0,0 +1,29 @@
>> +/* 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_DE_H
>> +#define HIBMC_DRM_DE_H
>> +
>> +struct panel_pll {
>> +       unsigned long M;
>> +       unsigned long N;
>> +       unsigned long OD;
>> +       unsigned long POD;
>> +};
>> +
>> +#endif
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> index 5ac7a7e..7d96583 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> @@ -18,6 +18,7 @@
>>
>>   #include <linux/module.h>
>>   #include <linux/console.h>
>> +#include <drm/drm_crtc_helper.h>
>>
>>   #include "hibmc_drm_drv.h"
>>   #include "hibmc_drm_regs.h"
>> @@ -47,8 +48,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",
>> @@ -70,6 +71,7 @@ static int hibmc_pm_suspend(struct device *dev)
>>          struct drm_device *drm_dev = pci_get_drvdata(pdev);
>>          struct hibmc_drm_device *hidev = drm_dev->dev_private;
>>
>> +       drm_kms_helper_poll_disable(drm_dev);
>>          drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 1);
>>
>>          return 0;
>> @@ -81,7 +83,9 @@ static int hibmc_pm_resume(struct device *dev)
>>          struct drm_device *drm_dev = pci_get_drvdata(pdev);
>>          struct hibmc_drm_device *hidev = drm_dev->dev_private;
>>
>> +       drm_helper_resume_force_mode(drm_dev);
>>          drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 0);
>> +       drm_kms_helper_poll_enable(drm_dev);
>>
>>          return 0;
>>   }
>> @@ -91,6 +95,41 @@ static int hibmc_pm_resume(struct device *dev)
>>                                  hibmc_pm_resume)
>>   };
>>
>> +static int hibmc_kms_init(struct hibmc_drm_device *hidev)
>> +{
>> +       int ret;
>> +
>> +       drm_mode_config_init(hidev->dev);
>> +       hidev->mode_config_initialized = true;
>> +
>> +       hidev->dev->mode_config.min_width = 0;
>> +       hidev->dev->mode_config.min_height = 0;
>> +       hidev->dev->mode_config.max_width = 1920;
>> +       hidev->dev->mode_config.max_height = 1440;
>> +
>> +       hidev->dev->mode_config.fb_base = hidev->fb_base;
>> +       hidev->dev->mode_config.preferred_depth = 24;
>> +       hidev->dev->mode_config.prefer_shadow = 0;
>> +
>> +       hidev->dev->mode_config.funcs = (void *)&hibmc_mode_funcs;
>> +
>> +       ret = hibmc_plane_init(hidev);
>> +       if (ret) {
>> +               DRM_ERROR("fail to init plane!!!\n");
>> +               return ret;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static void hibmc_kms_fini(struct hibmc_drm_device *hidev)
>> +{
>> +       if (hidev->mode_config_initialized) {
>> +               drm_mode_config_cleanup(hidev->dev);
>> +               hidev->mode_config_initialized = false;
>> +       }
>> +}
>> +
>>   static int hibmc_hw_config(struct hibmc_drm_device *hidev)
>>   {
>>          unsigned int reg;
>> @@ -183,6 +222,7 @@ static int hibmc_unload(struct drm_device *dev)
>>          struct hibmc_drm_device *hidev = dev->dev_private;
>>
>>          hibmc_fbdev_fini(hidev);
>> +       hibmc_kms_fini(hidev);
>>          hibmc_mm_fini(hidev);
>>          hibmc_hw_fini(hidev);
>>          dev->dev_private = NULL;
>> @@ -208,6 +248,13 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
>>          if (ret)
>>                  goto err;
>>
>> +       ret = hibmc_kms_init(hidev);
>> +       if (ret)
>> +               goto err;
>> +
>> +       /* reset all the states of crtc/plane/encoder/connector */
>> +       drm_mode_config_reset(dev);
>> +
>>          ret = hibmc_fbdev_init(hidev);
>>          if (ret)
>>                  goto err;
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> index a40e9a7..49e39d2 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> @@ -45,6 +45,8 @@ struct hibmc_drm_device {
>>
>>          /* drm */
>>          struct drm_device  *dev;
>> +       struct drm_plane plane;
>> +       bool mode_config_initialized;
>>
>>          /* ttm */
>>          struct {
>> @@ -82,6 +84,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
>>
>>   #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
>>
>> +int hibmc_plane_init(struct hibmc_drm_device *hidev);
>>   int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
>>   void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
>>
>> @@ -102,4 +105,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 9822f62..beb4d76 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>> @@ -554,3 +554,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
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> _______________________________________________
> linuxarm mailing list
> linuxarm at huawei.com
> http://rnd-openeuler.huawei.com/mailman/listinfo/linuxarm
>
> .
>

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

* Re: [PATCH v6 4/9] drm/hisilicon/hibmc: Add plane for DE
@ 2016-11-12  5:11       ` Rongrong Zou
  0 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-11-12  5:11 UTC (permalink / raw)
  To: Sean Paul, Rongrong Zou
  Cc: Mark Rutland, Archit, shenhui, Tomeu Vizoso, Jonathan Corbet,
	Dave Airlie, catalin.marinas, Emil Velikov, linuxarm, dri-devel,
	Xinliang Liu, james.xiong, Daniel Stone, Daniel Vetter,
	Will Deacon, lijianhua, Linux ARM Kernel, Benjamin Gaignard

在 2016/11/11 5:53, Sean Paul 写道:
> On Fri, Oct 28, 2016 at 3:27 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
>> Add plane funcs and helper funcs for DE.
>>
>> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
>> ---
>>   drivers/gpu/drm/hisilicon/hibmc/Kconfig         |   1 +
>>   drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c  | 170 ++++++++++++++++++++++++
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h  |  29 ++++
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  51 ++++++-
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |   5 +
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     |   6 +
>>   7 files changed, 261 insertions(+), 3 deletions(-)
>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
>>
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>> index bcb8c18..380622a 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>> @@ -1,6 +1,7 @@
>>   config DRM_HISI_HIBMC
>>          tristate "DRM Support for Hisilicon Hibmc"
>>          depends on DRM && PCI
>> +       select DRM_KMS_HELPER
>>          select DRM_TTM
>>
>>          help
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>> index 810a37e..72e107e 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>> @@ -1,5 +1,5 @@
>>   ccflags-y := -Iinclude/drm
>> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
>> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
>>
>>   obj-$(CONFIG_DRM_HISI_HIBMC)   +=hibmc-drm.o
>>   #obj-y += 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..9c1a68c
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>> @@ -0,0 +1,170 @@
>> +/* 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"
>> +#include "hibmc_drm_power.h"
>> +
>> +/* ---------------------------------------------------------------------- */
>
> Remove

ok, will do, thanks.

>
>> +
>> +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_x = state->src_x >> 16;
>> +       u32 src_y = state->src_y >> 16;
>> +       u32 src_w = state->src_w >> 16;
>> +       u32 src_h = state->src_h >> 16;
>> +       int crtc_x = state->crtc_x;
>> +       int crtc_y = state->crtc_y;
>> +       u32 crtc_w = state->crtc_w;
>> +       u32 crtc_h = state->crtc_h;
>
> I don't think you gain anything with the crtc_* vars

It would work well, but looks redundant and not simple enough,
will delete them, thanks.

>
>> +
>> +       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 != crtc_w || src_h != crtc_h) {
>> +               DRM_ERROR("Scale not support!!!\n");
>
> I like the enthusiasm, but I think DRM_DEBUG_ATOMIC would be better

I'm sorry, can you explain why here should be an DRM_DEBUG_ATOMIC,
when this condition is hit, it is really an error and atomic_commit will
abort with failure.

>
>> +               return -EINVAL;
>> +       }
>> +
>> +       if (src_x + src_w > fb->width ||
>> +           src_y + src_h > fb->height)
>
> These should be already covered in drm_atomic_plane_check

understood, thanks.

>
>> +               return -EINVAL;
>> +
>> +       if (crtc_x < 0 || crtc_y < 0)
>
> Print DRM_DEBUG_ATOMIC message here

agreed. thanks.

>
>> +               return -EINVAL;
>> +
>> +       if (crtc_x + crtc_w > crtc_state->adjusted_mode.hdisplay ||
>> +           crtc_y + crtc_h > crtc_state->adjusted_mode.vdisplay)
>
> DRM_DEBUG_ATOMIC here too

ditto.

>
>> +               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_device *hidev =
>> +               (struct hibmc_drm_device *)plane->dev->dev_private;
>> +
>
> nit: extra line

will delete, thanks.

>> +       struct hibmc_framebuffer *hibmc_fb;
>> +       struct hibmc_bo *bo;
>> +
>> +       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)
>
> Print error

agreed, thanks.

>
>> +               return;
>> +
>> +       hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
>
> Check return value

ok, thanks.

>
>> +       if (ret) {
>> +               ttm_bo_unreserve(&bo->bo);
>> +               return;
>> +       }
>> +
>> +       ttm_bo_unreserve(&bo->bo);
>
> Move this up before the conditional so you don't have to call it in
> both branches

understood, thanks.

>
>> +
>> +       writel(gpu_addr, hidev->mmio + HIBMC_CRT_FB_ADDRESS);
>> +
>> +       reg = state->fb->width * (state->fb->bits_per_pixel >> 3);
>> +       /* now line_pad is 16 */
>> +       reg = PADDING(16, reg);
>> +
>> +       line_l = state->fb->width * state->fb->bits_per_pixel / 8;
>
> above, you >> 3. here you / 8, pick one?

i prefer /8 because it is more readable to human, although it is less effective
in executing.

>
>> +       line_l = PADDING(16, line_l);
>> +       writel((HIBMC_CRT_FB_WIDTH_WIDTH(reg) & HIBMC_CRT_FB_WIDTH_WIDTH_MASK) |
>> +              (HIBMC_CRT_FB_WIDTH_OFFS(line_l) & HIBMC_CRT_FB_WIDTH_OFFS_MASK),
>> +              hidev->mmio + HIBMC_CRT_FB_WIDTH);
>> +
>> +       /* SET PIXEL FORMAT */
>> +       reg = readl(hidev->mmio + HIBMC_CRT_DISP_CTL);
>> +       reg = reg & ~HIBMC_CRT_DISP_CTL_FORMAT_MASK;
>> +       reg = reg | (HIBMC_CRT_DISP_CTL_FORMAT(state->fb->bits_per_pixel >> 4) &
>> +                    HIBMC_CRT_DISP_CTL_FORMAT_MASK);
>> +       writel(reg, hidev->mmio + HIBMC_CRT_DISP_CTL);
>> +}
>> +
>> +static void hibmc_plane_atomic_disable(struct drm_plane *plane,
>> +                                      struct drm_plane_state *old_state)
>> +{
>> +}
>
> The caller checks for NULL, no need to stub

thanks for pointing it out,
will remove.

Regards,
Rongrong.

>
>> +
>> +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,
>> +       .atomic_disable = hibmc_plane_atomic_disable,
>> +};
>> +
>> +int hibmc_plane_init(struct hibmc_drm_device *hidev)
>> +{
>> +       struct drm_device *dev = hidev->dev;
>> +       struct drm_plane *plane = &hidev->plane;
>> +       int ret = 0;
>> +
>> +       /*
>> +        * 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("fail to init plane!!!\n");
>> +               return ret;
>> +       }
>> +
>> +       drm_plane_helper_add(plane, &hibmc_plane_helper_funcs);
>> +       return 0;
>> +}
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
>> new file mode 100644
>> index 0000000..4ce0d7b
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
>> @@ -0,0 +1,29 @@
>> +/* 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_DE_H
>> +#define HIBMC_DRM_DE_H
>> +
>> +struct panel_pll {
>> +       unsigned long M;
>> +       unsigned long N;
>> +       unsigned long OD;
>> +       unsigned long POD;
>> +};
>> +
>> +#endif
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> index 5ac7a7e..7d96583 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> @@ -18,6 +18,7 @@
>>
>>   #include <linux/module.h>
>>   #include <linux/console.h>
>> +#include <drm/drm_crtc_helper.h>
>>
>>   #include "hibmc_drm_drv.h"
>>   #include "hibmc_drm_regs.h"
>> @@ -47,8 +48,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",
>> @@ -70,6 +71,7 @@ static int hibmc_pm_suspend(struct device *dev)
>>          struct drm_device *drm_dev = pci_get_drvdata(pdev);
>>          struct hibmc_drm_device *hidev = drm_dev->dev_private;
>>
>> +       drm_kms_helper_poll_disable(drm_dev);
>>          drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 1);
>>
>>          return 0;
>> @@ -81,7 +83,9 @@ static int hibmc_pm_resume(struct device *dev)
>>          struct drm_device *drm_dev = pci_get_drvdata(pdev);
>>          struct hibmc_drm_device *hidev = drm_dev->dev_private;
>>
>> +       drm_helper_resume_force_mode(drm_dev);
>>          drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 0);
>> +       drm_kms_helper_poll_enable(drm_dev);
>>
>>          return 0;
>>   }
>> @@ -91,6 +95,41 @@ static int hibmc_pm_resume(struct device *dev)
>>                                  hibmc_pm_resume)
>>   };
>>
>> +static int hibmc_kms_init(struct hibmc_drm_device *hidev)
>> +{
>> +       int ret;
>> +
>> +       drm_mode_config_init(hidev->dev);
>> +       hidev->mode_config_initialized = true;
>> +
>> +       hidev->dev->mode_config.min_width = 0;
>> +       hidev->dev->mode_config.min_height = 0;
>> +       hidev->dev->mode_config.max_width = 1920;
>> +       hidev->dev->mode_config.max_height = 1440;
>> +
>> +       hidev->dev->mode_config.fb_base = hidev->fb_base;
>> +       hidev->dev->mode_config.preferred_depth = 24;
>> +       hidev->dev->mode_config.prefer_shadow = 0;
>> +
>> +       hidev->dev->mode_config.funcs = (void *)&hibmc_mode_funcs;
>> +
>> +       ret = hibmc_plane_init(hidev);
>> +       if (ret) {
>> +               DRM_ERROR("fail to init plane!!!\n");
>> +               return ret;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static void hibmc_kms_fini(struct hibmc_drm_device *hidev)
>> +{
>> +       if (hidev->mode_config_initialized) {
>> +               drm_mode_config_cleanup(hidev->dev);
>> +               hidev->mode_config_initialized = false;
>> +       }
>> +}
>> +
>>   static int hibmc_hw_config(struct hibmc_drm_device *hidev)
>>   {
>>          unsigned int reg;
>> @@ -183,6 +222,7 @@ static int hibmc_unload(struct drm_device *dev)
>>          struct hibmc_drm_device *hidev = dev->dev_private;
>>
>>          hibmc_fbdev_fini(hidev);
>> +       hibmc_kms_fini(hidev);
>>          hibmc_mm_fini(hidev);
>>          hibmc_hw_fini(hidev);
>>          dev->dev_private = NULL;
>> @@ -208,6 +248,13 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
>>          if (ret)
>>                  goto err;
>>
>> +       ret = hibmc_kms_init(hidev);
>> +       if (ret)
>> +               goto err;
>> +
>> +       /* reset all the states of crtc/plane/encoder/connector */
>> +       drm_mode_config_reset(dev);
>> +
>>          ret = hibmc_fbdev_init(hidev);
>>          if (ret)
>>                  goto err;
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> index a40e9a7..49e39d2 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> @@ -45,6 +45,8 @@ struct hibmc_drm_device {
>>
>>          /* drm */
>>          struct drm_device  *dev;
>> +       struct drm_plane plane;
>> +       bool mode_config_initialized;
>>
>>          /* ttm */
>>          struct {
>> @@ -82,6 +84,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
>>
>>   #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
>>
>> +int hibmc_plane_init(struct hibmc_drm_device *hidev);
>>   int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
>>   void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
>>
>> @@ -102,4 +105,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 9822f62..beb4d76 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>> @@ -554,3 +554,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
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> _______________________________________________
> 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] 64+ messages in thread

* [PATCH v6 5/9] drm/hisilicon/hibmc: Add crtc for DE
  2016-11-10 22:14     ` Sean Paul
@ 2016-11-12 10:19       ` Rongrong Zou
  -1 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-11-12 10:19 UTC (permalink / raw)
  To: linux-arm-kernel

? 2016/11/11 6:14, Sean Paul ??:
> On Fri, Oct 28, 2016 at 3:27 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
>> Add crtc funcs and helper funcs for DE.
>>
>> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
>> ---
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c  | 318 ++++++++++++++++++++++++
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |   6 +
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |   2 +
>>   3 files changed, 326 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>> index 9c1a68c..9b5d0d0 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>> @@ -23,6 +23,7 @@
>>
>>   #include "hibmc_drm_drv.h"
>>   #include "hibmc_drm_regs.h"
>> +#include "hibmc_drm_de.h"
>>   #include "hibmc_drm_power.h"
>
> nit: alphabetize

ok, thanks.

>
>>
>>   /* ---------------------------------------------------------------------- */
>
> Remove

will do, thanks.

>
>> @@ -168,3 +169,320 @@ int hibmc_plane_init(struct hibmc_drm_device *hidev)
>>          drm_plane_helper_add(plane, &hibmc_plane_helper_funcs);
>>          return 0;
>>   }
>> +
>> +static void hibmc_crtc_enable(struct drm_crtc *crtc)
>> +{
>> +       unsigned int reg;
>> +       /* power mode 0 is default. */
>
> This comment seems to be in the wrong place

will remove it, thanks.

>
>> +       struct hibmc_drm_device *hidev = crtc->dev->dev_private;
>> +
>> +       hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_MODE0);
>> +
>> +       /* Enable display power gate & LOCALMEM power gate*/
>> +       reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
>> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
>> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
>> +       reg |= HIBMC_CURR_GATE_LOCALMEM(ON);
>> +       reg |= HIBMC_CURR_GATE_DISPLAY(ON);
>> +       hibmc_set_current_gate(hidev, reg);
>> +       drm_crtc_vblank_on(crtc);
>> +}
>> +
>> +static void hibmc_crtc_disable(struct drm_crtc *crtc)
>> +{
>> +       unsigned int reg;
>> +       struct hibmc_drm_device *hidev = crtc->dev->dev_private;
>> +
>> +       drm_crtc_vblank_off(crtc);
>> +
>> +       hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_SLEEP);
>> +
>> +       /* Enable display power gate & LOCALMEM power gate*/
>> +       reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
>> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
>> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
>> +       reg |= HIBMC_CURR_GATE_LOCALMEM(OFF);
>> +       reg |= HIBMC_CURR_GATE_DISPLAY(OFF);
>> +       hibmc_set_current_gate(hidev, reg);
>> +}
>> +
>> +static int hibmc_crtc_atomic_check(struct drm_crtc *crtc,
>> +                                  struct drm_crtc_state *state)
>> +{
>> +       return 0;
>> +}
>
> Caller NULL-checks, no need for stub

thanks for pointing it out.

>
>> +
>> +static unsigned int format_pll_reg(void)
>> +{
>> +       unsigned int pllreg = 0;
>> +       struct 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_PLL_CTRL_BYPASS(OFF) & HIBMC_PLL_CTRL_BYPASS_MASK;
>> +       pllreg |= HIBMC_PLL_CTRL_POWER(ON) & HIBMC_PLL_CTRL_POWER_MASK;
>> +       pllreg |= HIBMC_PLL_CTRL_INPUT(OSC) & HIBMC_PLL_CTRL_INPUT_MASK;
>> +       pllreg |= HIBMC_PLL_CTRL_POD(pll.POD) & HIBMC_PLL_CTRL_POD_MASK;
>> +       pllreg |= HIBMC_PLL_CTRL_OD(pll.OD) & HIBMC_PLL_CTRL_OD_MASK;
>> +       pllreg |= HIBMC_PLL_CTRL_N(pll.N) & HIBMC_PLL_CTRL_N_MASK;
>> +       pllreg |= HIBMC_PLL_CTRL_M(pll.M) & HIBMC_PLL_CTRL_M_MASK;
>> +
>> +       return pllreg;
>> +}
>> +
>> +static void set_vclock_hisilicon(struct drm_device *dev, unsigned long pll)
>> +{
>> +       unsigned long tmp0, tmp1;
>> +       struct hibmc_drm_device *hidev = dev->dev_private;
>> +
>> +       /* 1. outer_bypass_n=0 */
>> +       tmp0 = readl(hidev->mmio + CRT_PLL1_HS);
>> +       tmp0 &= 0xBFFFFFFF;
>> +       writel(tmp0, hidev->mmio + CRT_PLL1_HS);
>> +
>> +       /* 2. pll_pd=1?inter_bypass=1 */
>> +       writel(0x21000000, hidev->mmio + CRT_PLL1_HS);
>> +
>> +       /* 3. config pll */
>> +       writel(pll, hidev->mmio + CRT_PLL1_HS);
>> +
>> +       /* 4. delay  */
>> +       mdelay(1);
>
> These should be usleep_range() see
> https://www.kernel.org/doc/Documentation/timers/timers-howto.txt

This looks better to me. i think a 'usleep_range(1000, 2000)' is ok.

>
>> +
>> +       /* 5. pll_pd =0 */
>> +       tmp1 = pll & ~0x01000000;
>> +       writel(tmp1, hidev->mmio + CRT_PLL1_HS);
>> +
>> +       /* 6. delay  */
>> +       mdelay(1);
>> +
>> +       /* 7. inter_bypass=0 */
>> +       tmp1 &= ~0x20000000;
>> +       writel(tmp1, hidev->mmio + CRT_PLL1_HS);
>> +
>> +       /* 8. delay  */
>> +       mdelay(1);
>> +
>> +       /* 9. outer_bypass_n=1 */
>> +       tmp1 |= 0x40000000;
>> +       writel(tmp1, hidev->mmio + CRT_PLL1_HS);
>
> This function is a whole lot of magic. Any chance you can pull the
> values out into #defines?

will do. thanks.

>
>> +}
>> +
>> +/* This function takes care the extra registers and bit fields required to
>
> nit: multi-line comments have a leading /* line with the comment
> starting on the following line

thanks for pointing it out.

>
> applies below as well
>
>
>> + *setup a mode in board.
>
> nit: space between * and comment, ie: * setup a mode in board

understood, thanks.

>
> applies to the rest of the comment too
>
>
>> + *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;
>> +       unsigned long pll1; /* bit[31:0] of PLL */
>> +       unsigned long pll2; /* bit[63:32] of PLL */
>> +       struct hibmc_drm_device *hidev = dev->dev_private;
>> +
>> +       x = mode->hdisplay;
>> +       y = mode->vdisplay;
>> +
>> +       /* Hisilicon has to set up a new register for PLL control
>> +        *(CRT_PLL1_HS & CRT_PLL2_HS).
>> +        */
>> +       if (x == 800 && y == 600) {
>> +               pll1 = CRT_PLL1_HS_40MHZ;
>> +               pll2 = CRT_PLL2_HS_40MHZ;
>> +       } else if (x == 1024 && y == 768) {
>> +               pll1 = CRT_PLL1_HS_65MHZ;
>> +               pll2 = CRT_PLL2_HS_65MHZ;
>> +       } else if (x == 1152 && y == 864) {
>> +               pll1 = CRT_PLL1_HS_80MHZ_1152;
>> +               pll2 = CRT_PLL2_HS_80MHZ;
>> +       } else if (x == 1280 && y == 768) {
>> +               pll1 = CRT_PLL1_HS_80MHZ;
>> +               pll2 = CRT_PLL2_HS_80MHZ;
>> +       } else if (x == 1280 && y == 720) {
>> +               pll1 = CRT_PLL1_HS_74MHZ;
>> +               pll2 = CRT_PLL2_HS_74MHZ;
>> +       } else if (x == 1280 && y == 960) {
>> +               pll1 = CRT_PLL1_HS_108MHZ;
>> +               pll2 = CRT_PLL2_HS_108MHZ;
>> +       } else if (x == 1280 && y == 1024) {
>> +               pll1 = CRT_PLL1_HS_108MHZ;
>> +               pll2 = CRT_PLL2_HS_108MHZ;
>> +       } else if (x == 1600 && y == 1200) {
>> +               pll1 = CRT_PLL1_HS_162MHZ;
>> +               pll2 = CRT_PLL2_HS_162MHZ;
>> +       } else if (x == 1920 && y == 1080) {
>> +               pll1 = CRT_PLL1_HS_148MHZ;
>> +               pll2 = CRT_PLL2_HS_148MHZ;
>> +       } else if (x == 1920 && y == 1200) {
>> +               pll1 = CRT_PLL1_HS_193MHZ;
>> +               pll2 = CRT_PLL2_HS_193MHZ;
>> +       } else /* default to VGA clock */ {
>> +               pll1 = CRT_PLL1_HS_25MHZ;
>> +               pll2 = CRT_PLL2_HS_25MHZ;
>> +       }
>
> This seems like something that should be checked in atomic_check so
> you can be sure the mode is supported.
>
> It would also be nice to pull this out into a separate function (and a
> lookup table if you're feeling adventurous)

a lookup table seems good, thanks.

>
>> +
>> +       writel(pll2, hidev->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_CRT_AUTO_CENTERING_TL_TOP(0) &
>> +               HIBMC_CRT_AUTO_CENTERING_TL_TOP_MSK) |
>> +              (HIBMC_CRT_AUTO_CENTERING_TL_LEFT(0) &
>> +               HIBMC_CRT_AUTO_CENTERING_TL_LEFT_MSK),
>> +              hidev->mmio + HIBMC_CRT_AUTO_CENTERING_TL);
>> +
>> +       writel((HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM(y - 1) &
>> +               HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM_MASK) |
>> +              (HIBMC_CRT_AUTO_CENTERING_BR_RIGHT(x - 1) &
>> +               HIBMC_CRT_AUTO_CENTERING_BR_RIGHT_MASK),
>> +               hidev->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(CRTSELECT_CRT);
>> +
>> +       /*ctrl = FIELD_SET(ctrl, HIBMC_CRT_DISP_CTL, CRTSELECT, CRT);*/
>
> What's the deal with this commented code?

sorry, will clean up.

>
>> +
>> +       /* Set bit 14 of display controller */
>> +       /*ctrl &= FIELD_CLEAR(HIBMC_CRT_DISP_CTL, CLOCK_PHASE);*/
>> +
>> +       /* clock_phase_polarity is 0 */
>> +       ctrl |= HIBMC_CRT_DISP_CTL_CLOCK_PHASE(PHASE_ACTIVE_HIGH);
>> +       /*ctrl = FIELD_SET(ctrl, HIBMC_CRT_DISP_CTL,*/
>> +       /*CLOCK_PHASE, ACTIVE_HIGH);*/
>
> Here too...

ditto.

>
>> +
>> +       writel(ctrl, hidev->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_device *hidev = dev->dev_private;
>> +
>> +       writel(format_pll_reg(), hidev->mmio + HIBMC_CRT_PLL_CTRL);
>> +       writel((HIBMC_CRT_HORZ_TOTAL_TOTAL(mode->htotal - 1) &
>> +               HIBMC_CRT_HORZ_TOTAL_TOTAL_MASK) |
>> +               (HIBMC_CRT_HORZ_TOTAL_DISPLAY_END(mode->hdisplay - 1) &
>> +               HIBMC_CRT_HORZ_TOTAL_DISPLAY_END_MASK),
>
> You could probably macroize this code to make it more readable


	#define HIBMC_FIELD(field, value) (field(value) & filed##_MASK)

	writel(HIBMC_FIELD(HIBMC_CRT_HORZ_TOTAL_TOTAL, mode->htotal - 1) |
	       HIBMC_FIELD(HIBMC_CRT_HORZ_TOTAL_DISPLAY_END, mode->hdisplay - 1),
	       hidev->mmio + HIBMC_CRT_HORZ_TOTAL);

Is above ok?
	


>
>> +               hidev->mmio + HIBMC_CRT_HORZ_TOTAL);
>> +
>> +       writel((HIBMC_CRT_HORZ_SYNC_WIDTH(mode->hsync_end - mode->hsync_start)
>> +               & HIBMC_CRT_HORZ_SYNC_WIDTH_MASK) |
>> +               (HIBMC_CRT_HORZ_SYNC_START(mode->hsync_start - 1)
>> +               & HIBMC_CRT_HORZ_SYNC_START_MASK),
>> +               hidev->mmio + HIBMC_CRT_HORZ_SYNC);
>> +
>> +       writel((HIBMC_CRT_VERT_TOTAL_TOTAL(mode->vtotal - 1) &
>> +               HIBMC_CRT_VERT_TOTAL_TOTAL_MASK) |
>> +               (HIBMC_CRT_VERT_TOTAL_DISPLAY_END(mode->vdisplay - 1) &
>> +               HIBMC_CRT_VERT_TOTAL_DISPLAY_END_MASK),
>> +               hidev->mmio + HIBMC_CRT_VERT_TOTAL);
>> +
>> +       writel((HIBMC_CRT_VERT_SYNC_HEIGHT(mode->vsync_end - mode->vsync_start)
>> +               & HIBMC_CRT_VERT_SYNC_HEIGHT_MASK) |
>> +              (HIBMC_CRT_VERT_SYNC_START(mode->vsync_start - 1) &
>> +               HIBMC_CRT_VERT_SYNC_START_MASK),
>> +               hidev->mmio + HIBMC_CRT_VERT_SYNC);
>> +
>> +       val = HIBMC_CRT_DISP_CTL_VSYNC_PHASE(0) &
>> +             HIBMC_CRT_DISP_CTL_VSYNC_PHASE_MASK;
>> +       val |= HIBMC_CRT_DISP_CTL_HSYNC_PHASE(0) &
>> +              HIBMC_CRT_DISP_CTL_HSYNC_PHASE_MASK;
>> +       val |= HIBMC_CRT_DISP_CTL_TIMING(ENABLE);
>> +       val |= HIBMC_CRT_DISP_CTL_PLANE(ENABLE);
>> +
>> +       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_device *hidev = dev->dev_private;
>> +
>> +       hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_MODE0);
>> +
>> +       /* Enable display power gate & LOCALMEM power gate*/
>> +       reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
>> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
>> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
>> +       reg |= HIBMC_CURR_GATE_DISPLAY(ON);
>> +       reg |= HIBMC_CURR_GATE_LOCALMEM(ON);
>> +       hibmc_set_current_gate(hidev, 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);
>> +}
>> +
>> +/* These provide the minimum set of functions required to handle a CRTC */
>
> nit: don't need this comment

will delete, thanks.

>
>> +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_check   = hibmc_crtc_atomic_check,
>> +       .atomic_begin   = hibmc_crtc_atomic_begin,
>> +       .atomic_flush   = hibmc_crtc_atomic_flush,
>> +};
>> +
>> +int hibmc_crtc_init(struct hibmc_drm_device *hidev)
>> +{
>> +       struct drm_device *dev = hidev->dev;
>> +       struct drm_crtc *crtc = &hidev->crtc;
>> +       struct drm_plane *plane = &hidev->plane;
>> +       int ret;
>> +
>> +       ret = drm_crtc_init_with_planes(dev, crtc, plane,
>> +                                       NULL, &hibmc_crtc_funcs, NULL);
>> +       if (ret) {
>> +               DRM_ERROR("failed to init crtc.\n");
>
> print return code

agreed, thanks.

>
>> +               return ret;
>> +       }
>> +
>> +       drm_mode_crtc_set_gamma_size(crtc, 256);
>
> check return code

agreed though none of other drivers has done this,
thanks.

>
>> +       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 7d96583..303cd36 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> @@ -119,6 +119,12 @@ static int hibmc_kms_init(struct hibmc_drm_device *hidev)
>>                  return ret;
>>          }
>>
>> +       ret = hibmc_crtc_init(hidev);
>> +       if (ret) {
>> +               DRM_ERROR("failed to init crtc.\n");
>> +               return ret;
>> +       }
>
> Typically the plane is initialized internally in the crtc driver. I
> think this is a good design pattern, and you should probably use it.
>
> So how about squashing this down with the plane patch and keeping the
> plane inside hibmc_drm_de.c?

understood after i looked at intel_display.c, this file will be merged
with patch 4/9, and the tile will be: 'drm/hisilicon/hibmc: Add display
engine'.

>
>> +
>>          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 49e39d2..5731ec2 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> @@ -46,6 +46,7 @@ struct hibmc_drm_device {
>>          /* drm */
>>          struct drm_device  *dev;
>>          struct drm_plane plane;
>
> I don't think you should be keeping track of plane here. plane is only
> used in the crtc init, which should be addressed by the previous
> comment.

so allocate with devm_kzalloc(sizeof(*plane)) and remove it from
hibmc_drm_device?

>
>
>> +       struct drm_crtc crtc;
>
> crtc is only used in the irq handler, so you could remove this here
> and just call drm_handle_vblank(dev, 0) in the handler.

so allocate with devm_kzalloc(sizeof(*crtc)) and remove it from
hibmc_drm_device, when driver unload drm_crtc_cleanup() will be
called and finally memory will be freed before quit.

>
>
>>          bool mode_config_initialized;
>>
>>          /* ttm */
>> @@ -85,6 +86,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
>>   #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
>>
>>   int hibmc_plane_init(struct hibmc_drm_device *hidev);
>> +int hibmc_crtc_init(struct hibmc_drm_device *hidev);
>>   int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
>>   void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
>>
>> --
>> 1.9.1
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> _______________________________________________
> linuxarm mailing list
> linuxarm at huawei.com
> http://rnd-openeuler.huawei.com/mailman/listinfo/linuxarm
>
> .
>


-- 
Regards, Rongrong

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

* Re: [PATCH v6 5/9] drm/hisilicon/hibmc: Add crtc for DE
@ 2016-11-12 10:19       ` Rongrong Zou
  0 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-11-12 10:19 UTC (permalink / raw)
  To: Sean Paul, Rongrong Zou
  Cc: Mark Rutland, Archit, shenhui, Tomeu Vizoso, Jonathan Corbet,
	Dave Airlie, catalin.marinas, Emil Velikov, linuxarm, dri-devel,
	Xinliang Liu, james.xiong, Daniel Stone, Daniel Vetter,
	Will Deacon, lijianhua, Linux ARM Kernel, Benjamin Gaignard

在 2016/11/11 6:14, Sean Paul 写道:
> On Fri, Oct 28, 2016 at 3:27 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
>> Add crtc funcs and helper funcs for DE.
>>
>> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
>> ---
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c  | 318 ++++++++++++++++++++++++
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |   6 +
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |   2 +
>>   3 files changed, 326 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>> index 9c1a68c..9b5d0d0 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>> @@ -23,6 +23,7 @@
>>
>>   #include "hibmc_drm_drv.h"
>>   #include "hibmc_drm_regs.h"
>> +#include "hibmc_drm_de.h"
>>   #include "hibmc_drm_power.h"
>
> nit: alphabetize

ok, thanks.

>
>>
>>   /* ---------------------------------------------------------------------- */
>
> Remove

will do, thanks.

>
>> @@ -168,3 +169,320 @@ int hibmc_plane_init(struct hibmc_drm_device *hidev)
>>          drm_plane_helper_add(plane, &hibmc_plane_helper_funcs);
>>          return 0;
>>   }
>> +
>> +static void hibmc_crtc_enable(struct drm_crtc *crtc)
>> +{
>> +       unsigned int reg;
>> +       /* power mode 0 is default. */
>
> This comment seems to be in the wrong place

will remove it, thanks.

>
>> +       struct hibmc_drm_device *hidev = crtc->dev->dev_private;
>> +
>> +       hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_MODE0);
>> +
>> +       /* Enable display power gate & LOCALMEM power gate*/
>> +       reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
>> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
>> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
>> +       reg |= HIBMC_CURR_GATE_LOCALMEM(ON);
>> +       reg |= HIBMC_CURR_GATE_DISPLAY(ON);
>> +       hibmc_set_current_gate(hidev, reg);
>> +       drm_crtc_vblank_on(crtc);
>> +}
>> +
>> +static void hibmc_crtc_disable(struct drm_crtc *crtc)
>> +{
>> +       unsigned int reg;
>> +       struct hibmc_drm_device *hidev = crtc->dev->dev_private;
>> +
>> +       drm_crtc_vblank_off(crtc);
>> +
>> +       hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_SLEEP);
>> +
>> +       /* Enable display power gate & LOCALMEM power gate*/
>> +       reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
>> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
>> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
>> +       reg |= HIBMC_CURR_GATE_LOCALMEM(OFF);
>> +       reg |= HIBMC_CURR_GATE_DISPLAY(OFF);
>> +       hibmc_set_current_gate(hidev, reg);
>> +}
>> +
>> +static int hibmc_crtc_atomic_check(struct drm_crtc *crtc,
>> +                                  struct drm_crtc_state *state)
>> +{
>> +       return 0;
>> +}
>
> Caller NULL-checks, no need for stub

thanks for pointing it out.

>
>> +
>> +static unsigned int format_pll_reg(void)
>> +{
>> +       unsigned int pllreg = 0;
>> +       struct 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_PLL_CTRL_BYPASS(OFF) & HIBMC_PLL_CTRL_BYPASS_MASK;
>> +       pllreg |= HIBMC_PLL_CTRL_POWER(ON) & HIBMC_PLL_CTRL_POWER_MASK;
>> +       pllreg |= HIBMC_PLL_CTRL_INPUT(OSC) & HIBMC_PLL_CTRL_INPUT_MASK;
>> +       pllreg |= HIBMC_PLL_CTRL_POD(pll.POD) & HIBMC_PLL_CTRL_POD_MASK;
>> +       pllreg |= HIBMC_PLL_CTRL_OD(pll.OD) & HIBMC_PLL_CTRL_OD_MASK;
>> +       pllreg |= HIBMC_PLL_CTRL_N(pll.N) & HIBMC_PLL_CTRL_N_MASK;
>> +       pllreg |= HIBMC_PLL_CTRL_M(pll.M) & HIBMC_PLL_CTRL_M_MASK;
>> +
>> +       return pllreg;
>> +}
>> +
>> +static void set_vclock_hisilicon(struct drm_device *dev, unsigned long pll)
>> +{
>> +       unsigned long tmp0, tmp1;
>> +       struct hibmc_drm_device *hidev = dev->dev_private;
>> +
>> +       /* 1. outer_bypass_n=0 */
>> +       tmp0 = readl(hidev->mmio + CRT_PLL1_HS);
>> +       tmp0 &= 0xBFFFFFFF;
>> +       writel(tmp0, hidev->mmio + CRT_PLL1_HS);
>> +
>> +       /* 2. pll_pd=1?inter_bypass=1 */
>> +       writel(0x21000000, hidev->mmio + CRT_PLL1_HS);
>> +
>> +       /* 3. config pll */
>> +       writel(pll, hidev->mmio + CRT_PLL1_HS);
>> +
>> +       /* 4. delay  */
>> +       mdelay(1);
>
> These should be usleep_range() see
> https://www.kernel.org/doc/Documentation/timers/timers-howto.txt

This looks better to me. i think a 'usleep_range(1000, 2000)' is ok.

>
>> +
>> +       /* 5. pll_pd =0 */
>> +       tmp1 = pll & ~0x01000000;
>> +       writel(tmp1, hidev->mmio + CRT_PLL1_HS);
>> +
>> +       /* 6. delay  */
>> +       mdelay(1);
>> +
>> +       /* 7. inter_bypass=0 */
>> +       tmp1 &= ~0x20000000;
>> +       writel(tmp1, hidev->mmio + CRT_PLL1_HS);
>> +
>> +       /* 8. delay  */
>> +       mdelay(1);
>> +
>> +       /* 9. outer_bypass_n=1 */
>> +       tmp1 |= 0x40000000;
>> +       writel(tmp1, hidev->mmio + CRT_PLL1_HS);
>
> This function is a whole lot of magic. Any chance you can pull the
> values out into #defines?

will do. thanks.

>
>> +}
>> +
>> +/* This function takes care the extra registers and bit fields required to
>
> nit: multi-line comments have a leading /* line with the comment
> starting on the following line

thanks for pointing it out.

>
> applies below as well
>
>
>> + *setup a mode in board.
>
> nit: space between * and comment, ie: * setup a mode in board

understood, thanks.

>
> applies to the rest of the comment too
>
>
>> + *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;
>> +       unsigned long pll1; /* bit[31:0] of PLL */
>> +       unsigned long pll2; /* bit[63:32] of PLL */
>> +       struct hibmc_drm_device *hidev = dev->dev_private;
>> +
>> +       x = mode->hdisplay;
>> +       y = mode->vdisplay;
>> +
>> +       /* Hisilicon has to set up a new register for PLL control
>> +        *(CRT_PLL1_HS & CRT_PLL2_HS).
>> +        */
>> +       if (x == 800 && y == 600) {
>> +               pll1 = CRT_PLL1_HS_40MHZ;
>> +               pll2 = CRT_PLL2_HS_40MHZ;
>> +       } else if (x == 1024 && y == 768) {
>> +               pll1 = CRT_PLL1_HS_65MHZ;
>> +               pll2 = CRT_PLL2_HS_65MHZ;
>> +       } else if (x == 1152 && y == 864) {
>> +               pll1 = CRT_PLL1_HS_80MHZ_1152;
>> +               pll2 = CRT_PLL2_HS_80MHZ;
>> +       } else if (x == 1280 && y == 768) {
>> +               pll1 = CRT_PLL1_HS_80MHZ;
>> +               pll2 = CRT_PLL2_HS_80MHZ;
>> +       } else if (x == 1280 && y == 720) {
>> +               pll1 = CRT_PLL1_HS_74MHZ;
>> +               pll2 = CRT_PLL2_HS_74MHZ;
>> +       } else if (x == 1280 && y == 960) {
>> +               pll1 = CRT_PLL1_HS_108MHZ;
>> +               pll2 = CRT_PLL2_HS_108MHZ;
>> +       } else if (x == 1280 && y == 1024) {
>> +               pll1 = CRT_PLL1_HS_108MHZ;
>> +               pll2 = CRT_PLL2_HS_108MHZ;
>> +       } else if (x == 1600 && y == 1200) {
>> +               pll1 = CRT_PLL1_HS_162MHZ;
>> +               pll2 = CRT_PLL2_HS_162MHZ;
>> +       } else if (x == 1920 && y == 1080) {
>> +               pll1 = CRT_PLL1_HS_148MHZ;
>> +               pll2 = CRT_PLL2_HS_148MHZ;
>> +       } else if (x == 1920 && y == 1200) {
>> +               pll1 = CRT_PLL1_HS_193MHZ;
>> +               pll2 = CRT_PLL2_HS_193MHZ;
>> +       } else /* default to VGA clock */ {
>> +               pll1 = CRT_PLL1_HS_25MHZ;
>> +               pll2 = CRT_PLL2_HS_25MHZ;
>> +       }
>
> This seems like something that should be checked in atomic_check so
> you can be sure the mode is supported.
>
> It would also be nice to pull this out into a separate function (and a
> lookup table if you're feeling adventurous)

a lookup table seems good, thanks.

>
>> +
>> +       writel(pll2, hidev->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_CRT_AUTO_CENTERING_TL_TOP(0) &
>> +               HIBMC_CRT_AUTO_CENTERING_TL_TOP_MSK) |
>> +              (HIBMC_CRT_AUTO_CENTERING_TL_LEFT(0) &
>> +               HIBMC_CRT_AUTO_CENTERING_TL_LEFT_MSK),
>> +              hidev->mmio + HIBMC_CRT_AUTO_CENTERING_TL);
>> +
>> +       writel((HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM(y - 1) &
>> +               HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM_MASK) |
>> +              (HIBMC_CRT_AUTO_CENTERING_BR_RIGHT(x - 1) &
>> +               HIBMC_CRT_AUTO_CENTERING_BR_RIGHT_MASK),
>> +               hidev->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(CRTSELECT_CRT);
>> +
>> +       /*ctrl = FIELD_SET(ctrl, HIBMC_CRT_DISP_CTL, CRTSELECT, CRT);*/
>
> What's the deal with this commented code?

sorry, will clean up.

>
>> +
>> +       /* Set bit 14 of display controller */
>> +       /*ctrl &= FIELD_CLEAR(HIBMC_CRT_DISP_CTL, CLOCK_PHASE);*/
>> +
>> +       /* clock_phase_polarity is 0 */
>> +       ctrl |= HIBMC_CRT_DISP_CTL_CLOCK_PHASE(PHASE_ACTIVE_HIGH);
>> +       /*ctrl = FIELD_SET(ctrl, HIBMC_CRT_DISP_CTL,*/
>> +       /*CLOCK_PHASE, ACTIVE_HIGH);*/
>
> Here too...

ditto.

>
>> +
>> +       writel(ctrl, hidev->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_device *hidev = dev->dev_private;
>> +
>> +       writel(format_pll_reg(), hidev->mmio + HIBMC_CRT_PLL_CTRL);
>> +       writel((HIBMC_CRT_HORZ_TOTAL_TOTAL(mode->htotal - 1) &
>> +               HIBMC_CRT_HORZ_TOTAL_TOTAL_MASK) |
>> +               (HIBMC_CRT_HORZ_TOTAL_DISPLAY_END(mode->hdisplay - 1) &
>> +               HIBMC_CRT_HORZ_TOTAL_DISPLAY_END_MASK),
>
> You could probably macroize this code to make it more readable


	#define HIBMC_FIELD(field, value) (field(value) & filed##_MASK)

	writel(HIBMC_FIELD(HIBMC_CRT_HORZ_TOTAL_TOTAL, mode->htotal - 1) |
	       HIBMC_FIELD(HIBMC_CRT_HORZ_TOTAL_DISPLAY_END, mode->hdisplay - 1),
	       hidev->mmio + HIBMC_CRT_HORZ_TOTAL);

Is above ok?
	


>
>> +               hidev->mmio + HIBMC_CRT_HORZ_TOTAL);
>> +
>> +       writel((HIBMC_CRT_HORZ_SYNC_WIDTH(mode->hsync_end - mode->hsync_start)
>> +               & HIBMC_CRT_HORZ_SYNC_WIDTH_MASK) |
>> +               (HIBMC_CRT_HORZ_SYNC_START(mode->hsync_start - 1)
>> +               & HIBMC_CRT_HORZ_SYNC_START_MASK),
>> +               hidev->mmio + HIBMC_CRT_HORZ_SYNC);
>> +
>> +       writel((HIBMC_CRT_VERT_TOTAL_TOTAL(mode->vtotal - 1) &
>> +               HIBMC_CRT_VERT_TOTAL_TOTAL_MASK) |
>> +               (HIBMC_CRT_VERT_TOTAL_DISPLAY_END(mode->vdisplay - 1) &
>> +               HIBMC_CRT_VERT_TOTAL_DISPLAY_END_MASK),
>> +               hidev->mmio + HIBMC_CRT_VERT_TOTAL);
>> +
>> +       writel((HIBMC_CRT_VERT_SYNC_HEIGHT(mode->vsync_end - mode->vsync_start)
>> +               & HIBMC_CRT_VERT_SYNC_HEIGHT_MASK) |
>> +              (HIBMC_CRT_VERT_SYNC_START(mode->vsync_start - 1) &
>> +               HIBMC_CRT_VERT_SYNC_START_MASK),
>> +               hidev->mmio + HIBMC_CRT_VERT_SYNC);
>> +
>> +       val = HIBMC_CRT_DISP_CTL_VSYNC_PHASE(0) &
>> +             HIBMC_CRT_DISP_CTL_VSYNC_PHASE_MASK;
>> +       val |= HIBMC_CRT_DISP_CTL_HSYNC_PHASE(0) &
>> +              HIBMC_CRT_DISP_CTL_HSYNC_PHASE_MASK;
>> +       val |= HIBMC_CRT_DISP_CTL_TIMING(ENABLE);
>> +       val |= HIBMC_CRT_DISP_CTL_PLANE(ENABLE);
>> +
>> +       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_device *hidev = dev->dev_private;
>> +
>> +       hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_MODE0);
>> +
>> +       /* Enable display power gate & LOCALMEM power gate*/
>> +       reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
>> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
>> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
>> +       reg |= HIBMC_CURR_GATE_DISPLAY(ON);
>> +       reg |= HIBMC_CURR_GATE_LOCALMEM(ON);
>> +       hibmc_set_current_gate(hidev, 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);
>> +}
>> +
>> +/* These provide the minimum set of functions required to handle a CRTC */
>
> nit: don't need this comment

will delete, thanks.

>
>> +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_check   = hibmc_crtc_atomic_check,
>> +       .atomic_begin   = hibmc_crtc_atomic_begin,
>> +       .atomic_flush   = hibmc_crtc_atomic_flush,
>> +};
>> +
>> +int hibmc_crtc_init(struct hibmc_drm_device *hidev)
>> +{
>> +       struct drm_device *dev = hidev->dev;
>> +       struct drm_crtc *crtc = &hidev->crtc;
>> +       struct drm_plane *plane = &hidev->plane;
>> +       int ret;
>> +
>> +       ret = drm_crtc_init_with_planes(dev, crtc, plane,
>> +                                       NULL, &hibmc_crtc_funcs, NULL);
>> +       if (ret) {
>> +               DRM_ERROR("failed to init crtc.\n");
>
> print return code

agreed, thanks.

>
>> +               return ret;
>> +       }
>> +
>> +       drm_mode_crtc_set_gamma_size(crtc, 256);
>
> check return code

agreed though none of other drivers has done this,
thanks.

>
>> +       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 7d96583..303cd36 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> @@ -119,6 +119,12 @@ static int hibmc_kms_init(struct hibmc_drm_device *hidev)
>>                  return ret;
>>          }
>>
>> +       ret = hibmc_crtc_init(hidev);
>> +       if (ret) {
>> +               DRM_ERROR("failed to init crtc.\n");
>> +               return ret;
>> +       }
>
> Typically the plane is initialized internally in the crtc driver. I
> think this is a good design pattern, and you should probably use it.
>
> So how about squashing this down with the plane patch and keeping the
> plane inside hibmc_drm_de.c?

understood after i looked at intel_display.c, this file will be merged
with patch 4/9, and the tile will be: 'drm/hisilicon/hibmc: Add display
engine'.

>
>> +
>>          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 49e39d2..5731ec2 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> @@ -46,6 +46,7 @@ struct hibmc_drm_device {
>>          /* drm */
>>          struct drm_device  *dev;
>>          struct drm_plane plane;
>
> I don't think you should be keeping track of plane here. plane is only
> used in the crtc init, which should be addressed by the previous
> comment.

so allocate with devm_kzalloc(sizeof(*plane)) and remove it from
hibmc_drm_device?

>
>
>> +       struct drm_crtc crtc;
>
> crtc is only used in the irq handler, so you could remove this here
> and just call drm_handle_vblank(dev, 0) in the handler.

so allocate with devm_kzalloc(sizeof(*crtc)) and remove it from
hibmc_drm_device, when driver unload drm_crtc_cleanup() will be
called and finally memory will be freed before quit.

>
>
>>          bool mode_config_initialized;
>>
>>          /* ttm */
>> @@ -85,6 +86,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
>>   #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
>>
>>   int hibmc_plane_init(struct hibmc_drm_device *hidev);
>> +int hibmc_crtc_init(struct hibmc_drm_device *hidev);
>>   int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
>>   void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
>>
>> --
>> 1.9.1
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> _______________________________________________
> 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] 64+ messages in thread

* [PATCH v6 6/9] drm/hisilicon/hibmc: Add encoder for VDAC
  2016-11-10 22:20     ` Sean Paul
@ 2016-11-12 10:36       ` Rongrong Zou
  -1 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-11-12 10:36 UTC (permalink / raw)
  To: linux-arm-kernel

? 2016/11/11 6:20, Sean Paul ??:
> On Fri, Oct 28, 2016 at 3:27 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
>> Add encoder funcs and helpers for VDAC.
>>
>> 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  |  2 +
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c | 89 ++++++++++++++++++++++++
>>   4 files changed, 98 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 72e107e..e04f114 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>> @@ -1,5 +1,5 @@
>>   ccflags-y := -Iinclude/drm
>> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
>> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
>>
>>   obj-$(CONFIG_DRM_HISI_HIBMC)   +=hibmc-drm.o
>>   #obj-y += 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 303cd36..ba191e1 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> @@ -125,6 +125,12 @@ static int hibmc_kms_init(struct hibmc_drm_device *hidev)
>>                  return ret;
>>          }
>>
>> +       ret = hibmc_encoder_init(hidev);
>> +       if (ret) {
>> +               DRM_ERROR("failed to init encoder\n");
>> +               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 5731ec2..401cea4 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> @@ -47,6 +47,7 @@ struct hibmc_drm_device {
>>          struct drm_device  *dev;
>>          struct drm_plane plane;
>>          struct drm_crtc crtc;
>> +       struct drm_encoder encoder;
>
> Same comment here, you don't need to keep track of this

ok, it can be dealt with like crtc.

>
>>          bool mode_config_initialized;
>>
>>          /* ttm */
>> @@ -87,6 +88,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
>>
>>   int hibmc_plane_init(struct hibmc_drm_device *hidev);
>>   int hibmc_crtc_init(struct hibmc_drm_device *hidev);
>> +int hibmc_encoder_init(struct hibmc_drm_device *hidev);
>>   int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
>>   void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
>>
>> 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..953f659
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
>> @@ -0,0 +1,89 @@
>> +/* 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 defx = 800;
>> +static int defy = 600;
>> +
>> +module_param(defx, int, 0444);
>> +module_param(defy, int, 0444);
>> +MODULE_PARM_DESC(defx, "default x resolution");
>> +MODULE_PARM_DESC(defy, "default y resolution");
>
> Not used, and I'm not sure these are a good idea

it is used in following patch, i think it is put in wrong place.

>
>> +
>> +static void hibmc_encoder_disable(struct drm_encoder *encoder)
>> +{
>> +}
>> +
>> +static void hibmc_encoder_enable(struct drm_encoder *encoder)
>> +{
>> +}
>
> Null-checked, no need to stub

thanks for pointing it out.

>
>> +
>> +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_device *hidev = dev->dev_private;
>> +
>> +       /* just open DISPLAY_CONTROL_HISILE register bit 3:0*/
>> +       reg = readl(hidev->mmio + DISPLAY_CONTROL_HISILE);
>> +       reg |= 0xf;
>
> Can you just pull this into a #define instead of explaining in the comment?

ok, thanks.

>
>> +       writel(reg, hidev->mmio + DISPLAY_CONTROL_HISILE);
>> +}
>> +
>> +static int hibmc_encoder_atomic_check(struct drm_encoder *encoder,
>> +                                     struct drm_crtc_state *crtc_state,
>> +                                     struct drm_connector_state *conn_state)
>> +{
>> +       return 0;
>> +}
>
> null-checked, remove stub

ok, will do.

>
>> +
>> +static const struct drm_encoder_helper_funcs hibmc_encoder_helper_funcs = {
>> +       .mode_set = hibmc_encoder_mode_set,
>> +       .disable = hibmc_encoder_disable,
>> +       .enable = hibmc_encoder_enable,
>> +       .atomic_check = hibmc_encoder_atomic_check,
>> +};
>> +
>> +static const struct drm_encoder_funcs hibmc_encoder_encoder_funcs = {
>> +       .destroy = drm_encoder_cleanup,
>> +};
>> +
>> +int hibmc_encoder_init(struct hibmc_drm_device *hidev)
>> +{
>> +       struct drm_device *dev = hidev->dev;
>> +       struct drm_encoder *encoder = &hidev->encoder;
>> +       int ret;
>> +
>> +       encoder->possible_crtcs = 0x1;
>> +       ret = drm_encoder_init(dev, encoder, &hibmc_encoder_encoder_funcs,
>> +                              DRM_MODE_ENCODER_DAC, NULL);
>> +       if (ret) {
>> +               DRM_ERROR("failed to init encoder\n");
>
> print ret

will do, thanks.

>
>> +               return ret;
>> +       }
>> +
>> +       drm_encoder_helper_add(encoder, &hibmc_encoder_helper_funcs);
>> +       return 0;
>> +}
>> --
>> 1.9.1
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> _______________________________________________
> linuxarm mailing list
> linuxarm at huawei.com
> http://rnd-openeuler.huawei.com/mailman/listinfo/linuxarm
>
> .
>


-- 
Regards, Rongrong

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

* Re: [PATCH v6 6/9] drm/hisilicon/hibmc: Add encoder for VDAC
@ 2016-11-12 10:36       ` Rongrong Zou
  0 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-11-12 10:36 UTC (permalink / raw)
  To: Sean Paul, Rongrong Zou
  Cc: Mark Rutland, Archit, shenhui, Tomeu Vizoso, Jonathan Corbet,
	Dave Airlie, catalin.marinas, Emil Velikov, linuxarm, dri-devel,
	Xinliang Liu, james.xiong, Daniel Stone, Daniel Vetter,
	Will Deacon, lijianhua, Linux ARM Kernel, Benjamin Gaignard

在 2016/11/11 6:20, Sean Paul 写道:
> On Fri, Oct 28, 2016 at 3:27 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
>> Add encoder funcs and helpers for VDAC.
>>
>> 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  |  2 +
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c | 89 ++++++++++++++++++++++++
>>   4 files changed, 98 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 72e107e..e04f114 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>> @@ -1,5 +1,5 @@
>>   ccflags-y := -Iinclude/drm
>> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
>> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
>>
>>   obj-$(CONFIG_DRM_HISI_HIBMC)   +=hibmc-drm.o
>>   #obj-y += 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 303cd36..ba191e1 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> @@ -125,6 +125,12 @@ static int hibmc_kms_init(struct hibmc_drm_device *hidev)
>>                  return ret;
>>          }
>>
>> +       ret = hibmc_encoder_init(hidev);
>> +       if (ret) {
>> +               DRM_ERROR("failed to init encoder\n");
>> +               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 5731ec2..401cea4 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> @@ -47,6 +47,7 @@ struct hibmc_drm_device {
>>          struct drm_device  *dev;
>>          struct drm_plane plane;
>>          struct drm_crtc crtc;
>> +       struct drm_encoder encoder;
>
> Same comment here, you don't need to keep track of this

ok, it can be dealt with like crtc.

>
>>          bool mode_config_initialized;
>>
>>          /* ttm */
>> @@ -87,6 +88,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
>>
>>   int hibmc_plane_init(struct hibmc_drm_device *hidev);
>>   int hibmc_crtc_init(struct hibmc_drm_device *hidev);
>> +int hibmc_encoder_init(struct hibmc_drm_device *hidev);
>>   int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
>>   void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
>>
>> 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..953f659
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
>> @@ -0,0 +1,89 @@
>> +/* 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 defx = 800;
>> +static int defy = 600;
>> +
>> +module_param(defx, int, 0444);
>> +module_param(defy, int, 0444);
>> +MODULE_PARM_DESC(defx, "default x resolution");
>> +MODULE_PARM_DESC(defy, "default y resolution");
>
> Not used, and I'm not sure these are a good idea

it is used in following patch, i think it is put in wrong place.

>
>> +
>> +static void hibmc_encoder_disable(struct drm_encoder *encoder)
>> +{
>> +}
>> +
>> +static void hibmc_encoder_enable(struct drm_encoder *encoder)
>> +{
>> +}
>
> Null-checked, no need to stub

thanks for pointing it out.

>
>> +
>> +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_device *hidev = dev->dev_private;
>> +
>> +       /* just open DISPLAY_CONTROL_HISILE register bit 3:0*/
>> +       reg = readl(hidev->mmio + DISPLAY_CONTROL_HISILE);
>> +       reg |= 0xf;
>
> Can you just pull this into a #define instead of explaining in the comment?

ok, thanks.

>
>> +       writel(reg, hidev->mmio + DISPLAY_CONTROL_HISILE);
>> +}
>> +
>> +static int hibmc_encoder_atomic_check(struct drm_encoder *encoder,
>> +                                     struct drm_crtc_state *crtc_state,
>> +                                     struct drm_connector_state *conn_state)
>> +{
>> +       return 0;
>> +}
>
> null-checked, remove stub

ok, will do.

>
>> +
>> +static const struct drm_encoder_helper_funcs hibmc_encoder_helper_funcs = {
>> +       .mode_set = hibmc_encoder_mode_set,
>> +       .disable = hibmc_encoder_disable,
>> +       .enable = hibmc_encoder_enable,
>> +       .atomic_check = hibmc_encoder_atomic_check,
>> +};
>> +
>> +static const struct drm_encoder_funcs hibmc_encoder_encoder_funcs = {
>> +       .destroy = drm_encoder_cleanup,
>> +};
>> +
>> +int hibmc_encoder_init(struct hibmc_drm_device *hidev)
>> +{
>> +       struct drm_device *dev = hidev->dev;
>> +       struct drm_encoder *encoder = &hidev->encoder;
>> +       int ret;
>> +
>> +       encoder->possible_crtcs = 0x1;
>> +       ret = drm_encoder_init(dev, encoder, &hibmc_encoder_encoder_funcs,
>> +                              DRM_MODE_ENCODER_DAC, NULL);
>> +       if (ret) {
>> +               DRM_ERROR("failed to init encoder\n");
>
> print ret

will do, thanks.

>
>> +               return ret;
>> +       }
>> +
>> +       drm_encoder_helper_add(encoder, &hibmc_encoder_helper_funcs);
>> +       return 0;
>> +}
>> --
>> 1.9.1
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> _______________________________________________
> 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] 64+ messages in thread

* [PATCH v6 7/9] drm/hisilicon/hibmc: Add connector for VDAC
  2016-11-11  1:45     ` Sean Paul
@ 2016-11-14 14:07       ` Rongrong Zou
  -1 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-11-14 14:07 UTC (permalink / raw)
  To: linux-arm-kernel

? 2016/11/11 9:45, Sean Paul ??:
> On Fri, Oct 28, 2016 at 3:28 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
>> Add connector funcs and helper funcs for VDAC.
>>
>> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
>> ---
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c  |  8 +++
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h  |  2 +
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c | 76 ++++++++++++++++++++++++
>>   3 files changed, 86 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> index ba191e1..4253603 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> @@ -131,6 +131,14 @@ static int hibmc_kms_init(struct hibmc_drm_device *hidev)
>>                  return ret;
>>          }
>>
>> +       ret = hibmc_connector_init(hidev);
>> +       if (ret) {
>> +               DRM_ERROR("failed to init connector\n");
>> +               return ret;
>> +       }
>> +
>> +       drm_mode_connector_attach_encoder(&hidev->connector,
>> +                                         &hidev->encoder);
>
> The connector should be initialized in the vdac driver with the
> encoder, not in the drv file (same as plane/crtc)

applied, thanks.

>
>>          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 401cea4..450247d 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> @@ -48,6 +48,7 @@ struct hibmc_drm_device {
>>          struct drm_plane plane;
>>          struct drm_crtc crtc;
>>          struct drm_encoder encoder;
>> +       struct drm_connector connector;
>
> No need to keep track here

will allocate with devm_kzalloc(), thanks.

>
>>          bool mode_config_initialized;
>>
>>          /* ttm */
>> @@ -89,6 +90,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
>>   int hibmc_plane_init(struct hibmc_drm_device *hidev);
>>   int hibmc_crtc_init(struct hibmc_drm_device *hidev);
>>   int hibmc_encoder_init(struct hibmc_drm_device *hidev);
>> +int hibmc_connector_init(struct hibmc_drm_device *hidev);
>>   int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
>>   void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
>>
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
>> index 953f659..ebefcd1 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
>> @@ -87,3 +87,79 @@ int hibmc_encoder_init(struct hibmc_drm_device *hidev)
>>          drm_encoder_helper_add(encoder, &hibmc_encoder_helper_funcs);
>>          return 0;
>>   }
>> +
>> +static int hibmc_connector_get_modes(struct drm_connector *connector)
>> +{
>> +       int count;
>> +
>> +       count = drm_add_modes_noedid(connector, 800, 600);
>> +       drm_set_preferred_mode(connector, defx, defy);
>
> So you have defx/defy as module parameters, but then hardcode the
> 800x600 mode. If defx/defy is anything other than 800/600, this won't
> work. I think you should just remove the defx/defy module params and
> rely on userspace adding modes as appropriate.

will remove them, thanks.

>
>> +       return count;
>> +}
>> +
>> +static int hibmc_connector_mode_valid(struct drm_connector *connector,
>> +                                     struct drm_display_mode *mode)
>> +{
>> +       struct hibmc_drm_device *hiprivate =
>> +        container_of(connector, struct hibmc_drm_device, connector);
>> +       unsigned long size = mode->hdisplay * mode->vdisplay * 4;
>
> Why * 4 here and why * 2 below? You support formats less than 32 bpp,
> so the * 4 isn't necessarily correct for all formats. Is the * 2 to
> account for front & back buffer?
>

it is from bochs, the original comments below:
	/*
	 * Make sure we can fit two framebuffers into video memory.
	 * This allows up to 1600x1200 with 16 MB (default size).
	 * If you want more try this:
	 *     'qemu -vga std -global VGA.vgamem_mb=32 $otherargs'
	 */
i think it is not necessary for hibmc, so will remove it and return
MODE_OK, thanks.

>
>> +
>> +       if (size * 2 > hiprivate->fb_size)
>> +               return MODE_BAD;
>> +
>> +       return MODE_OK;
>> +}
>> +
>> +static struct drm_encoder *
>> +hibmc_connector_best_encoder(struct drm_connector *connector)
>> +{
>> +       int enc_id = connector->encoder_ids[0];
>> +
>> +       /* pick the encoder ids */
>> +       if (enc_id)
>> +               return drm_encoder_find(connector->dev, enc_id);
>
> Can't you just do return drm_encoder_find(connector->dev,
> connector->encoder_ids[0]); ?
>
> ie: won't drm_encoder_find do the right thing if you pass in id == 0?

hibmc_connector_best_encoder(struct drm_connector *connector)
{
	return drm_encoder_find(connector->dev, connector->encoder_ids[0]);
}
looks more simple, i like it, thanks:)

>
>> +
>> +       return NULL;
>> +}
>> +
>> +static enum drm_connector_status hibmc_connector_detect(struct drm_connector
>> +                                                *connector, bool force)
>> +{
>> +       return connector_status_connected;
>
> Perhaps this should be connector_status_unknown, since you don't
> necessarily know it's connected.

it is always connected in hibmc's scenario, usually it is used as a
management chip on server, we use KVM(keyboard, mouse, video) rather than
a directly connected monitor. I will modify if a phisical monitor
is connected later.

>
>> +}
>> +
>> +static const struct drm_connector_helper_funcs
>> +       hibmc_connector_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_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,
>> +};
>> +
>> +int hibmc_connector_init(struct hibmc_drm_device *hidev)
>> +{
>> +       struct drm_device *dev = hidev->dev;
>> +       struct drm_connector *connector = &hidev->connector;
>> +       int ret;
>> +
>> +       ret = drm_connector_init(dev, connector,
>> +                                &hibmc_connector_connector_funcs,
>> +                                DRM_MODE_CONNECTOR_VGA);
>> +       if (ret) {
>> +               DRM_ERROR("failed to init connector\n");
>> +               return ret;
>> +       }
>> +       drm_connector_helper_add(connector,
>> +                                &hibmc_connector_connector_helper_funcs);
>> +
>> +       return 0;
>> +}
>> --
>> 1.9.1
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> _______________________________________________
> linuxarm mailing list
> linuxarm at huawei.com
> http://rnd-openeuler.huawei.com/mailman/listinfo/linuxarm
>
> .
>


-- 
Regards, Rongrong

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

* Re: [PATCH v6 7/9] drm/hisilicon/hibmc: Add connector for VDAC
@ 2016-11-14 14:07       ` Rongrong Zou
  0 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-11-14 14:07 UTC (permalink / raw)
  To: Sean Paul, Rongrong Zou
  Cc: Mark Rutland, Archit, shenhui, Tomeu Vizoso, Jonathan Corbet,
	Dave Airlie, catalin.marinas, Emil Velikov, linuxarm, dri-devel,
	Xinliang Liu, james.xiong, Daniel Stone, Daniel Vetter,
	Will Deacon, lijianhua, Linux ARM Kernel, Benjamin Gaignard

在 2016/11/11 9:45, Sean Paul 写道:
> On Fri, Oct 28, 2016 at 3:28 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
>> Add connector funcs and helper funcs for VDAC.
>>
>> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
>> ---
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c  |  8 +++
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h  |  2 +
>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c | 76 ++++++++++++++++++++++++
>>   3 files changed, 86 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> index ba191e1..4253603 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> @@ -131,6 +131,14 @@ static int hibmc_kms_init(struct hibmc_drm_device *hidev)
>>                  return ret;
>>          }
>>
>> +       ret = hibmc_connector_init(hidev);
>> +       if (ret) {
>> +               DRM_ERROR("failed to init connector\n");
>> +               return ret;
>> +       }
>> +
>> +       drm_mode_connector_attach_encoder(&hidev->connector,
>> +                                         &hidev->encoder);
>
> The connector should be initialized in the vdac driver with the
> encoder, not in the drv file (same as plane/crtc)

applied, thanks.

>
>>          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 401cea4..450247d 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> @@ -48,6 +48,7 @@ struct hibmc_drm_device {
>>          struct drm_plane plane;
>>          struct drm_crtc crtc;
>>          struct drm_encoder encoder;
>> +       struct drm_connector connector;
>
> No need to keep track here

will allocate with devm_kzalloc(), thanks.

>
>>          bool mode_config_initialized;
>>
>>          /* ttm */
>> @@ -89,6 +90,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
>>   int hibmc_plane_init(struct hibmc_drm_device *hidev);
>>   int hibmc_crtc_init(struct hibmc_drm_device *hidev);
>>   int hibmc_encoder_init(struct hibmc_drm_device *hidev);
>> +int hibmc_connector_init(struct hibmc_drm_device *hidev);
>>   int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
>>   void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
>>
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
>> index 953f659..ebefcd1 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
>> @@ -87,3 +87,79 @@ int hibmc_encoder_init(struct hibmc_drm_device *hidev)
>>          drm_encoder_helper_add(encoder, &hibmc_encoder_helper_funcs);
>>          return 0;
>>   }
>> +
>> +static int hibmc_connector_get_modes(struct drm_connector *connector)
>> +{
>> +       int count;
>> +
>> +       count = drm_add_modes_noedid(connector, 800, 600);
>> +       drm_set_preferred_mode(connector, defx, defy);
>
> So you have defx/defy as module parameters, but then hardcode the
> 800x600 mode. If defx/defy is anything other than 800/600, this won't
> work. I think you should just remove the defx/defy module params and
> rely on userspace adding modes as appropriate.

will remove them, thanks.

>
>> +       return count;
>> +}
>> +
>> +static int hibmc_connector_mode_valid(struct drm_connector *connector,
>> +                                     struct drm_display_mode *mode)
>> +{
>> +       struct hibmc_drm_device *hiprivate =
>> +        container_of(connector, struct hibmc_drm_device, connector);
>> +       unsigned long size = mode->hdisplay * mode->vdisplay * 4;
>
> Why * 4 here and why * 2 below? You support formats less than 32 bpp,
> so the * 4 isn't necessarily correct for all formats. Is the * 2 to
> account for front & back buffer?
>

it is from bochs, the original comments below:
	/*
	 * Make sure we can fit two framebuffers into video memory.
	 * This allows up to 1600x1200 with 16 MB (default size).
	 * If you want more try this:
	 *     'qemu -vga std -global VGA.vgamem_mb=32 $otherargs'
	 */
i think it is not necessary for hibmc, so will remove it and return
MODE_OK, thanks.

>
>> +
>> +       if (size * 2 > hiprivate->fb_size)
>> +               return MODE_BAD;
>> +
>> +       return MODE_OK;
>> +}
>> +
>> +static struct drm_encoder *
>> +hibmc_connector_best_encoder(struct drm_connector *connector)
>> +{
>> +       int enc_id = connector->encoder_ids[0];
>> +
>> +       /* pick the encoder ids */
>> +       if (enc_id)
>> +               return drm_encoder_find(connector->dev, enc_id);
>
> Can't you just do return drm_encoder_find(connector->dev,
> connector->encoder_ids[0]); ?
>
> ie: won't drm_encoder_find do the right thing if you pass in id == 0?

hibmc_connector_best_encoder(struct drm_connector *connector)
{
	return drm_encoder_find(connector->dev, connector->encoder_ids[0]);
}
looks more simple, i like it, thanks:)

>
>> +
>> +       return NULL;
>> +}
>> +
>> +static enum drm_connector_status hibmc_connector_detect(struct drm_connector
>> +                                                *connector, bool force)
>> +{
>> +       return connector_status_connected;
>
> Perhaps this should be connector_status_unknown, since you don't
> necessarily know it's connected.

it is always connected in hibmc's scenario, usually it is used as a
management chip on server, we use KVM(keyboard, mouse, video) rather than
a directly connected monitor. I will modify if a phisical monitor
is connected later.

>
>> +}
>> +
>> +static const struct drm_connector_helper_funcs
>> +       hibmc_connector_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_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,
>> +};
>> +
>> +int hibmc_connector_init(struct hibmc_drm_device *hidev)
>> +{
>> +       struct drm_device *dev = hidev->dev;
>> +       struct drm_connector *connector = &hidev->connector;
>> +       int ret;
>> +
>> +       ret = drm_connector_init(dev, connector,
>> +                                &hibmc_connector_connector_funcs,
>> +                                DRM_MODE_CONNECTOR_VGA);
>> +       if (ret) {
>> +               DRM_ERROR("failed to init connector\n");
>> +               return ret;
>> +       }
>> +       drm_connector_helper_add(connector,
>> +                                &hibmc_connector_connector_helper_funcs);
>> +
>> +       return 0;
>> +}
>> --
>> 1.9.1
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> _______________________________________________
> 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] 64+ messages in thread

* [PATCH v6 8/9] drm/hisilicon/hibmc: Add vblank interruput
  2016-11-11  1:49     ` Sean Paul
@ 2016-11-14 14:10       ` Rongrong Zou
  -1 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-11-14 14:10 UTC (permalink / raw)
  To: linux-arm-kernel

? 2016/11/11 9:49, Sean Paul ??:
> On Fri, Oct 28, 2016 at 3:28 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
>> 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 4253603..b668e3e 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> @@ -40,16 +40,46 @@
>>
>>   static int hibmc_enable_vblank(struct drm_device *dev, unsigned int pipe)
>>   {
>> +       struct hibmc_drm_device *hidev =
>> +               (struct hibmc_drm_device *)dev->dev_private;
>> +
>> +       writel(HIBMC_RAW_INTERRUPT_EN_VBLANK(1),
>> +              hidev->mmio + HIBMC_RAW_INTERRUPT_EN);
>> +
>>          return 0;
>>   }
>>
>>   static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>>   {
>> +       struct hibmc_drm_device *hidev =
>> +               (struct hibmc_drm_device *)dev->dev_private;
>> +
>> +       writel(HIBMC_RAW_INTERRUPT_EN_VBLANK(0),
>> +              hidev->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_device *hidev =
>> +               (struct hibmc_drm_device *)dev->dev_private;
>> +       struct drm_crtc *crtc = &hidev->crtc;
>> +       u32 status;
>> +
>> +       status = readl(hidev->mmio + HIBMC_RAW_INTERRUPT);
>> +
>> +       if (status & HIBMC_RAW_INTERRUPT_VBLANK(1)) {
>> +               writel(HIBMC_RAW_INTERRUPT_VBLANK(1),
>> +                      hidev->mmio + HIBMC_RAW_INTERRUPT);
>> +               drm_crtc_handle_vblank(crtc);
>> +       }
>> +
>> +       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",
>> @@ -63,6 +93,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)
>> @@ -242,6 +273,13 @@ static int hibmc_unload(struct drm_device *dev)
>>          struct hibmc_drm_device *hidev = dev->dev_private;
>>
>>          hibmc_fbdev_fini(hidev);
>> +
>> +       if (dev->irq_enabled)
>> +               drm_irq_uninstall(dev);
>> +       if (hidev->msi_enabled)
>> +               pci_disable_msi(dev->pdev);
>> +       drm_vblank_cleanup(dev);
>> +
>>          hibmc_kms_fini(hidev);
>>          hibmc_mm_fini(hidev);
>>          hibmc_hw_fini(hidev);
>> @@ -272,6 +310,22 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
>>          if (ret)
>>                  goto err;
>>
>> +       ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
>> +       if (ret) {
>> +               DRM_ERROR("failed to initialize vblank.\n");
>> +               goto err;
>> +       }
>> +
>> +       hidev->msi_enabled = 0;
>> +       if (pci_enable_msi(dev->pdev)) {
>
> It would be useful to check and print the return value of this.

agreed, thanks.

>
>> +               DRM_ERROR("Enabling MSI failed!\n");
>> +       } else {
>> +               hidev->msi_enabled = 1;
>> +               ret = drm_irq_install(dev, dev->pdev->irq);
>> +               if (ret)
>> +                       DRM_ERROR("install irq failed , ret = %d\n", ret);
>
> DRM_WARN might be more appropriate, given that this isn't considered fatal.

agreed, thanks.

>
>> +       }
>> +
>>          /* 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 450247d..f1706fb 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_device {
>>          void __iomem   *fb_map;
>>          unsigned long  fb_base;
>>          unsigned long  fb_size;
>> +       int msi_enabled;
>
> Why not bool?

agreed, thanks.

Regards,
Rongrong.

>
>>
>>          /* drm */
>>          struct drm_device  *dev;
>> --
>> 1.9.1
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> _______________________________________________
> linuxarm mailing list
> linuxarm at huawei.com
> http://rnd-openeuler.huawei.com/mailman/listinfo/linuxarm
>
> .
>

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

* Re: [PATCH v6 8/9] drm/hisilicon/hibmc: Add vblank interruput
@ 2016-11-14 14:10       ` Rongrong Zou
  0 siblings, 0 replies; 64+ messages in thread
From: Rongrong Zou @ 2016-11-14 14:10 UTC (permalink / raw)
  To: Sean Paul, Rongrong Zou
  Cc: Mark Rutland, Archit, shenhui, Tomeu Vizoso, Jonathan Corbet,
	Dave Airlie, catalin.marinas, Emil Velikov, linuxarm, dri-devel,
	Xinliang Liu, james.xiong, Daniel Stone, Daniel Vetter,
	Will Deacon, lijianhua, Linux ARM Kernel, Benjamin Gaignard

在 2016/11/11 9:49, Sean Paul 写道:
> On Fri, Oct 28, 2016 at 3:28 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
>> 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 4253603..b668e3e 100644
>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> @@ -40,16 +40,46 @@
>>
>>   static int hibmc_enable_vblank(struct drm_device *dev, unsigned int pipe)
>>   {
>> +       struct hibmc_drm_device *hidev =
>> +               (struct hibmc_drm_device *)dev->dev_private;
>> +
>> +       writel(HIBMC_RAW_INTERRUPT_EN_VBLANK(1),
>> +              hidev->mmio + HIBMC_RAW_INTERRUPT_EN);
>> +
>>          return 0;
>>   }
>>
>>   static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>>   {
>> +       struct hibmc_drm_device *hidev =
>> +               (struct hibmc_drm_device *)dev->dev_private;
>> +
>> +       writel(HIBMC_RAW_INTERRUPT_EN_VBLANK(0),
>> +              hidev->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_device *hidev =
>> +               (struct hibmc_drm_device *)dev->dev_private;
>> +       struct drm_crtc *crtc = &hidev->crtc;
>> +       u32 status;
>> +
>> +       status = readl(hidev->mmio + HIBMC_RAW_INTERRUPT);
>> +
>> +       if (status & HIBMC_RAW_INTERRUPT_VBLANK(1)) {
>> +               writel(HIBMC_RAW_INTERRUPT_VBLANK(1),
>> +                      hidev->mmio + HIBMC_RAW_INTERRUPT);
>> +               drm_crtc_handle_vblank(crtc);
>> +       }
>> +
>> +       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",
>> @@ -63,6 +93,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)
>> @@ -242,6 +273,13 @@ static int hibmc_unload(struct drm_device *dev)
>>          struct hibmc_drm_device *hidev = dev->dev_private;
>>
>>          hibmc_fbdev_fini(hidev);
>> +
>> +       if (dev->irq_enabled)
>> +               drm_irq_uninstall(dev);
>> +       if (hidev->msi_enabled)
>> +               pci_disable_msi(dev->pdev);
>> +       drm_vblank_cleanup(dev);
>> +
>>          hibmc_kms_fini(hidev);
>>          hibmc_mm_fini(hidev);
>>          hibmc_hw_fini(hidev);
>> @@ -272,6 +310,22 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
>>          if (ret)
>>                  goto err;
>>
>> +       ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
>> +       if (ret) {
>> +               DRM_ERROR("failed to initialize vblank.\n");
>> +               goto err;
>> +       }
>> +
>> +       hidev->msi_enabled = 0;
>> +       if (pci_enable_msi(dev->pdev)) {
>
> It would be useful to check and print the return value of this.

agreed, thanks.

>
>> +               DRM_ERROR("Enabling MSI failed!\n");
>> +       } else {
>> +               hidev->msi_enabled = 1;
>> +               ret = drm_irq_install(dev, dev->pdev->irq);
>> +               if (ret)
>> +                       DRM_ERROR("install irq failed , ret = %d\n", ret);
>
> DRM_WARN might be more appropriate, given that this isn't considered fatal.

agreed, thanks.

>
>> +       }
>> +
>>          /* 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 450247d..f1706fb 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_device {
>>          void __iomem   *fb_map;
>>          unsigned long  fb_base;
>>          unsigned long  fb_size;
>> +       int msi_enabled;
>
> Why not bool?

agreed, thanks.

Regards,
Rongrong.

>
>>
>>          /* drm */
>>          struct drm_device  *dev;
>> --
>> 1.9.1
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> _______________________________________________
> 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] 64+ messages in thread

* [PATCH v6 4/9] drm/hisilicon/hibmc: Add plane for DE
  2016-11-12  5:11       ` Rongrong Zou
@ 2016-11-14 17:08         ` Sean Paul
  -1 siblings, 0 replies; 64+ messages in thread
From: Sean Paul @ 2016-11-14 17:08 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Nov 12, 2016 at 12:11 AM, Rongrong Zou <zourongrong@huawei.com> wrote:
> ? 2016/11/11 5:53, Sean Paul ??:
>>
>> On Fri, Oct 28, 2016 at 3:27 AM, Rongrong Zou <zourongrong@gmail.com>
>> wrote:
>>>
>>> Add plane funcs and helper funcs for DE.
>>>
>>> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
>>> ---
>>>   drivers/gpu/drm/hisilicon/hibmc/Kconfig         |   1 +
>>>   drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c  | 170
>>> ++++++++++++++++++++++++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h  |  29 ++++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  51 ++++++-
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |   5 +
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     |   6 +
>>>   7 files changed, 261 insertions(+), 3 deletions(-)
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
>>>
>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>> b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>> index bcb8c18..380622a 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>> @@ -1,6 +1,7 @@
>>>   config DRM_HISI_HIBMC
>>>          tristate "DRM Support for Hisilicon Hibmc"
>>>          depends on DRM && PCI
>>> +       select DRM_KMS_HELPER
>>>          select DRM_TTM
>>>
>>>          help
>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>> b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>> index 810a37e..72e107e 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>> @@ -1,5 +1,5 @@
>>>   ccflags-y := -Iinclude/drm
>>> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_drm_power.o
>>> hibmc_ttm.o
>>> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_fbdev.o
>>> hibmc_drm_power.o hibmc_ttm.o
>>>
>>>   obj-$(CONFIG_DRM_HISI_HIBMC)   +=hibmc-drm.o
>>>   #obj-y += 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..9c1a68c
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>>> @@ -0,0 +1,170 @@
>>> +/* 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"
>>> +#include "hibmc_drm_power.h"
>>> +
>>> +/*
>>> ---------------------------------------------------------------------- */
>>
>>
>> Remove
>
>
> ok, will do, thanks.
>
>>
>>> +
>>> +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_x = state->src_x >> 16;
>>> +       u32 src_y = state->src_y >> 16;
>>> +       u32 src_w = state->src_w >> 16;
>>> +       u32 src_h = state->src_h >> 16;
>>> +       int crtc_x = state->crtc_x;
>>> +       int crtc_y = state->crtc_y;
>>> +       u32 crtc_w = state->crtc_w;
>>> +       u32 crtc_h = state->crtc_h;
>>
>>
>> I don't think you gain anything with the crtc_* vars
>
>
> It would work well, but looks redundant and not simple enough,
> will delete them, thanks.
>
>>
>>> +
>>> +       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 != crtc_w || src_h != crtc_h) {
>>> +               DRM_ERROR("Scale not support!!!\n");
>>
>>
>> I like the enthusiasm, but I think DRM_DEBUG_ATOMIC would be better
>
>
> I'm sorry, can you explain why here should be an DRM_DEBUG_ATOMIC,
> when this condition is hit, it is really an error and atomic_commit will
> abort with failure.
>

I don't have strong opinions, but this class of failure isn't a driver
error, so much as invalid input from userspace. As such, I'd tend to
classify it as debug level.

At any rate, keep it ERROR if you really want.

Sean

>>
>>> +               return -EINVAL;
>>> +       }
>>> +
>>> +       if (src_x + src_w > fb->width ||
>>> +           src_y + src_h > fb->height)
>>
>>
>> These should be already covered in drm_atomic_plane_check
>
>
> understood, thanks.
>
>>
>>> +               return -EINVAL;
>>> +
>>> +       if (crtc_x < 0 || crtc_y < 0)
>>
>>
>> Print DRM_DEBUG_ATOMIC message here
>
>
> agreed. thanks.
>
>>
>>> +               return -EINVAL;
>>> +
>>> +       if (crtc_x + crtc_w > crtc_state->adjusted_mode.hdisplay ||
>>> +           crtc_y + crtc_h > crtc_state->adjusted_mode.vdisplay)
>>
>>
>> DRM_DEBUG_ATOMIC here too
>
>
> ditto.
>
>>
>>> +               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_device *hidev =
>>> +               (struct hibmc_drm_device *)plane->dev->dev_private;
>>> +
>>
>>
>> nit: extra line
>
>
> will delete, thanks.
>
>>> +       struct hibmc_framebuffer *hibmc_fb;
>>> +       struct hibmc_bo *bo;
>>> +
>>> +       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)
>>
>>
>> Print error
>
>
> agreed, thanks.
>
>>
>>> +               return;
>>> +
>>> +       hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
>>
>>
>> Check return value
>
>
> ok, thanks.
>
>>
>>> +       if (ret) {
>>> +               ttm_bo_unreserve(&bo->bo);
>>> +               return;
>>> +       }
>>> +
>>> +       ttm_bo_unreserve(&bo->bo);
>>
>>
>> Move this up before the conditional so you don't have to call it in
>> both branches
>
>
> understood, thanks.
>
>>
>>> +
>>> +       writel(gpu_addr, hidev->mmio + HIBMC_CRT_FB_ADDRESS);
>>> +
>>> +       reg = state->fb->width * (state->fb->bits_per_pixel >> 3);
>>> +       /* now line_pad is 16 */
>>> +       reg = PADDING(16, reg);
>>> +
>>> +       line_l = state->fb->width * state->fb->bits_per_pixel / 8;
>>
>>
>> above, you >> 3. here you / 8, pick one?
>
>
> i prefer /8 because it is more readable to human, although it is less
> effective
> in executing.
>

I think the compiler will optimize it, regardless.

Sean

>>
>>> +       line_l = PADDING(16, line_l);
>>> +       writel((HIBMC_CRT_FB_WIDTH_WIDTH(reg) &
>>> HIBMC_CRT_FB_WIDTH_WIDTH_MASK) |
>>> +              (HIBMC_CRT_FB_WIDTH_OFFS(line_l) &
>>> HIBMC_CRT_FB_WIDTH_OFFS_MASK),
>>> +              hidev->mmio + HIBMC_CRT_FB_WIDTH);
>>> +
>>> +       /* SET PIXEL FORMAT */
>>> +       reg = readl(hidev->mmio + HIBMC_CRT_DISP_CTL);
>>> +       reg = reg & ~HIBMC_CRT_DISP_CTL_FORMAT_MASK;
>>> +       reg = reg | (HIBMC_CRT_DISP_CTL_FORMAT(state->fb->bits_per_pixel
>>> >> 4) &
>>> +                    HIBMC_CRT_DISP_CTL_FORMAT_MASK);
>>> +       writel(reg, hidev->mmio + HIBMC_CRT_DISP_CTL);
>>> +}
>>> +
>>> +static void hibmc_plane_atomic_disable(struct drm_plane *plane,
>>> +                                      struct drm_plane_state *old_state)
>>> +{
>>> +}
>>
>>
>> The caller checks for NULL, no need to stub
>
>
> thanks for pointing it out,
> will remove.
>
> Regards,
> Rongrong.
>
>>
>>> +
>>> +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,
>>> +       .atomic_disable = hibmc_plane_atomic_disable,
>>> +};
>>> +
>>> +int hibmc_plane_init(struct hibmc_drm_device *hidev)
>>> +{
>>> +       struct drm_device *dev = hidev->dev;
>>> +       struct drm_plane *plane = &hidev->plane;
>>> +       int ret = 0;
>>> +
>>> +       /*
>>> +        * 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("fail to init plane!!!\n");
>>> +               return ret;
>>> +       }
>>> +
>>> +       drm_plane_helper_add(plane, &hibmc_plane_helper_funcs);
>>> +       return 0;
>>> +}
>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
>>> b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
>>> new file mode 100644
>>> index 0000000..4ce0d7b
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
>>> @@ -0,0 +1,29 @@
>>> +/* 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_DE_H
>>> +#define HIBMC_DRM_DE_H
>>> +
>>> +struct panel_pll {
>>> +       unsigned long M;
>>> +       unsigned long N;
>>> +       unsigned long OD;
>>> +       unsigned long POD;
>>> +};
>>> +
>>> +#endif
>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>> b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>> index 5ac7a7e..7d96583 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>> @@ -18,6 +18,7 @@
>>>
>>>   #include <linux/module.h>
>>>   #include <linux/console.h>
>>> +#include <drm/drm_crtc_helper.h>
>>>
>>>   #include "hibmc_drm_drv.h"
>>>   #include "hibmc_drm_regs.h"
>>> @@ -47,8 +48,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",
>>> @@ -70,6 +71,7 @@ static int hibmc_pm_suspend(struct device *dev)
>>>          struct drm_device *drm_dev = pci_get_drvdata(pdev);
>>>          struct hibmc_drm_device *hidev = drm_dev->dev_private;
>>>
>>> +       drm_kms_helper_poll_disable(drm_dev);
>>>          drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 1);
>>>
>>>          return 0;
>>> @@ -81,7 +83,9 @@ static int hibmc_pm_resume(struct device *dev)
>>>          struct drm_device *drm_dev = pci_get_drvdata(pdev);
>>>          struct hibmc_drm_device *hidev = drm_dev->dev_private;
>>>
>>> +       drm_helper_resume_force_mode(drm_dev);
>>>          drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 0);
>>> +       drm_kms_helper_poll_enable(drm_dev);
>>>
>>>          return 0;
>>>   }
>>> @@ -91,6 +95,41 @@ static int hibmc_pm_resume(struct device *dev)
>>>                                  hibmc_pm_resume)
>>>   };
>>>
>>> +static int hibmc_kms_init(struct hibmc_drm_device *hidev)
>>> +{
>>> +       int ret;
>>> +
>>> +       drm_mode_config_init(hidev->dev);
>>> +       hidev->mode_config_initialized = true;
>>> +
>>> +       hidev->dev->mode_config.min_width = 0;
>>> +       hidev->dev->mode_config.min_height = 0;
>>> +       hidev->dev->mode_config.max_width = 1920;
>>> +       hidev->dev->mode_config.max_height = 1440;
>>> +
>>> +       hidev->dev->mode_config.fb_base = hidev->fb_base;
>>> +       hidev->dev->mode_config.preferred_depth = 24;
>>> +       hidev->dev->mode_config.prefer_shadow = 0;
>>> +
>>> +       hidev->dev->mode_config.funcs = (void *)&hibmc_mode_funcs;
>>> +
>>> +       ret = hibmc_plane_init(hidev);
>>> +       if (ret) {
>>> +               DRM_ERROR("fail to init plane!!!\n");
>>> +               return ret;
>>> +       }
>>> +
>>> +       return 0;
>>> +}
>>> +
>>> +static void hibmc_kms_fini(struct hibmc_drm_device *hidev)
>>> +{
>>> +       if (hidev->mode_config_initialized) {
>>> +               drm_mode_config_cleanup(hidev->dev);
>>> +               hidev->mode_config_initialized = false;
>>> +       }
>>> +}
>>> +
>>>   static int hibmc_hw_config(struct hibmc_drm_device *hidev)
>>>   {
>>>          unsigned int reg;
>>> @@ -183,6 +222,7 @@ static int hibmc_unload(struct drm_device *dev)
>>>          struct hibmc_drm_device *hidev = dev->dev_private;
>>>
>>>          hibmc_fbdev_fini(hidev);
>>> +       hibmc_kms_fini(hidev);
>>>          hibmc_mm_fini(hidev);
>>>          hibmc_hw_fini(hidev);
>>>          dev->dev_private = NULL;
>>> @@ -208,6 +248,13 @@ static int hibmc_load(struct drm_device *dev,
>>> unsigned long flags)
>>>          if (ret)
>>>                  goto err;
>>>
>>> +       ret = hibmc_kms_init(hidev);
>>> +       if (ret)
>>> +               goto err;
>>> +
>>> +       /* reset all the states of crtc/plane/encoder/connector */
>>> +       drm_mode_config_reset(dev);
>>> +
>>>          ret = hibmc_fbdev_init(hidev);
>>>          if (ret)
>>>                  goto err;
>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>>> b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>>> index a40e9a7..49e39d2 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>>> @@ -45,6 +45,8 @@ struct hibmc_drm_device {
>>>
>>>          /* drm */
>>>          struct drm_device  *dev;
>>> +       struct drm_plane plane;
>>> +       bool mode_config_initialized;
>>>
>>>          /* ttm */
>>>          struct {
>>> @@ -82,6 +84,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct
>>> drm_gem_object *gem)
>>>
>>>   #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
>>>
>>> +int hibmc_plane_init(struct hibmc_drm_device *hidev);
>>>   int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
>>>   void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
>>>
>>> @@ -102,4 +105,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 9822f62..beb4d76 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>> @@ -554,3 +554,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
>>>
>>>
>>> _______________________________________________
>>> linux-arm-kernel mailing list
>>> linux-arm-kernel at lists.infradead.org
>>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>
>> _______________________________________________
>> linuxarm mailing list
>> linuxarm at huawei.com
>> http://rnd-openeuler.huawei.com/mailman/listinfo/linuxarm
>>
>> .
>>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v6 4/9] drm/hisilicon/hibmc: Add plane for DE
@ 2016-11-14 17:08         ` Sean Paul
  0 siblings, 0 replies; 64+ messages in thread
From: Sean Paul @ 2016-11-14 17:08 UTC (permalink / raw)
  To: Rongrong Zou
  Cc: Mark Rutland, lijianhua, Will Deacon, Tomeu Vizoso,
	Jonathan Corbet, catalin.marinas, Emil Velikov, linuxarm,
	dri-devel, james.xiong, shenhui, Rongrong Zou, Linux ARM Kernel

On Sat, Nov 12, 2016 at 12:11 AM, Rongrong Zou <zourongrong@huawei.com> wrote:
> 在 2016/11/11 5:53, Sean Paul 写道:
>>
>> On Fri, Oct 28, 2016 at 3:27 AM, Rongrong Zou <zourongrong@gmail.com>
>> wrote:
>>>
>>> Add plane funcs and helper funcs for DE.
>>>
>>> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
>>> ---
>>>   drivers/gpu/drm/hisilicon/hibmc/Kconfig         |   1 +
>>>   drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c  | 170
>>> ++++++++++++++++++++++++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h  |  29 ++++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  51 ++++++-
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |   5 +
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     |   6 +
>>>   7 files changed, 261 insertions(+), 3 deletions(-)
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>>>   create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
>>>
>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>> b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>> index bcb8c18..380622a 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>> @@ -1,6 +1,7 @@
>>>   config DRM_HISI_HIBMC
>>>          tristate "DRM Support for Hisilicon Hibmc"
>>>          depends on DRM && PCI
>>> +       select DRM_KMS_HELPER
>>>          select DRM_TTM
>>>
>>>          help
>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>> b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>> index 810a37e..72e107e 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>>> @@ -1,5 +1,5 @@
>>>   ccflags-y := -Iinclude/drm
>>> -hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_drm_power.o
>>> hibmc_ttm.o
>>> +hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_fbdev.o
>>> hibmc_drm_power.o hibmc_ttm.o
>>>
>>>   obj-$(CONFIG_DRM_HISI_HIBMC)   +=hibmc-drm.o
>>>   #obj-y += 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..9c1a68c
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>>> @@ -0,0 +1,170 @@
>>> +/* 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"
>>> +#include "hibmc_drm_power.h"
>>> +
>>> +/*
>>> ---------------------------------------------------------------------- */
>>
>>
>> Remove
>
>
> ok, will do, thanks.
>
>>
>>> +
>>> +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_x = state->src_x >> 16;
>>> +       u32 src_y = state->src_y >> 16;
>>> +       u32 src_w = state->src_w >> 16;
>>> +       u32 src_h = state->src_h >> 16;
>>> +       int crtc_x = state->crtc_x;
>>> +       int crtc_y = state->crtc_y;
>>> +       u32 crtc_w = state->crtc_w;
>>> +       u32 crtc_h = state->crtc_h;
>>
>>
>> I don't think you gain anything with the crtc_* vars
>
>
> It would work well, but looks redundant and not simple enough,
> will delete them, thanks.
>
>>
>>> +
>>> +       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 != crtc_w || src_h != crtc_h) {
>>> +               DRM_ERROR("Scale not support!!!\n");
>>
>>
>> I like the enthusiasm, but I think DRM_DEBUG_ATOMIC would be better
>
>
> I'm sorry, can you explain why here should be an DRM_DEBUG_ATOMIC,
> when this condition is hit, it is really an error and atomic_commit will
> abort with failure.
>

I don't have strong opinions, but this class of failure isn't a driver
error, so much as invalid input from userspace. As such, I'd tend to
classify it as debug level.

At any rate, keep it ERROR if you really want.

Sean

>>
>>> +               return -EINVAL;
>>> +       }
>>> +
>>> +       if (src_x + src_w > fb->width ||
>>> +           src_y + src_h > fb->height)
>>
>>
>> These should be already covered in drm_atomic_plane_check
>
>
> understood, thanks.
>
>>
>>> +               return -EINVAL;
>>> +
>>> +       if (crtc_x < 0 || crtc_y < 0)
>>
>>
>> Print DRM_DEBUG_ATOMIC message here
>
>
> agreed. thanks.
>
>>
>>> +               return -EINVAL;
>>> +
>>> +       if (crtc_x + crtc_w > crtc_state->adjusted_mode.hdisplay ||
>>> +           crtc_y + crtc_h > crtc_state->adjusted_mode.vdisplay)
>>
>>
>> DRM_DEBUG_ATOMIC here too
>
>
> ditto.
>
>>
>>> +               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_device *hidev =
>>> +               (struct hibmc_drm_device *)plane->dev->dev_private;
>>> +
>>
>>
>> nit: extra line
>
>
> will delete, thanks.
>
>>> +       struct hibmc_framebuffer *hibmc_fb;
>>> +       struct hibmc_bo *bo;
>>> +
>>> +       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)
>>
>>
>> Print error
>
>
> agreed, thanks.
>
>>
>>> +               return;
>>> +
>>> +       hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
>>
>>
>> Check return value
>
>
> ok, thanks.
>
>>
>>> +       if (ret) {
>>> +               ttm_bo_unreserve(&bo->bo);
>>> +               return;
>>> +       }
>>> +
>>> +       ttm_bo_unreserve(&bo->bo);
>>
>>
>> Move this up before the conditional so you don't have to call it in
>> both branches
>
>
> understood, thanks.
>
>>
>>> +
>>> +       writel(gpu_addr, hidev->mmio + HIBMC_CRT_FB_ADDRESS);
>>> +
>>> +       reg = state->fb->width * (state->fb->bits_per_pixel >> 3);
>>> +       /* now line_pad is 16 */
>>> +       reg = PADDING(16, reg);
>>> +
>>> +       line_l = state->fb->width * state->fb->bits_per_pixel / 8;
>>
>>
>> above, you >> 3. here you / 8, pick one?
>
>
> i prefer /8 because it is more readable to human, although it is less
> effective
> in executing.
>

I think the compiler will optimize it, regardless.

Sean

>>
>>> +       line_l = PADDING(16, line_l);
>>> +       writel((HIBMC_CRT_FB_WIDTH_WIDTH(reg) &
>>> HIBMC_CRT_FB_WIDTH_WIDTH_MASK) |
>>> +              (HIBMC_CRT_FB_WIDTH_OFFS(line_l) &
>>> HIBMC_CRT_FB_WIDTH_OFFS_MASK),
>>> +              hidev->mmio + HIBMC_CRT_FB_WIDTH);
>>> +
>>> +       /* SET PIXEL FORMAT */
>>> +       reg = readl(hidev->mmio + HIBMC_CRT_DISP_CTL);
>>> +       reg = reg & ~HIBMC_CRT_DISP_CTL_FORMAT_MASK;
>>> +       reg = reg | (HIBMC_CRT_DISP_CTL_FORMAT(state->fb->bits_per_pixel
>>> >> 4) &
>>> +                    HIBMC_CRT_DISP_CTL_FORMAT_MASK);
>>> +       writel(reg, hidev->mmio + HIBMC_CRT_DISP_CTL);
>>> +}
>>> +
>>> +static void hibmc_plane_atomic_disable(struct drm_plane *plane,
>>> +                                      struct drm_plane_state *old_state)
>>> +{
>>> +}
>>
>>
>> The caller checks for NULL, no need to stub
>
>
> thanks for pointing it out,
> will remove.
>
> Regards,
> Rongrong.
>
>>
>>> +
>>> +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,
>>> +       .atomic_disable = hibmc_plane_atomic_disable,
>>> +};
>>> +
>>> +int hibmc_plane_init(struct hibmc_drm_device *hidev)
>>> +{
>>> +       struct drm_device *dev = hidev->dev;
>>> +       struct drm_plane *plane = &hidev->plane;
>>> +       int ret = 0;
>>> +
>>> +       /*
>>> +        * 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("fail to init plane!!!\n");
>>> +               return ret;
>>> +       }
>>> +
>>> +       drm_plane_helper_add(plane, &hibmc_plane_helper_funcs);
>>> +       return 0;
>>> +}
>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
>>> b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
>>> new file mode 100644
>>> index 0000000..4ce0d7b
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
>>> @@ -0,0 +1,29 @@
>>> +/* 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_DE_H
>>> +#define HIBMC_DRM_DE_H
>>> +
>>> +struct panel_pll {
>>> +       unsigned long M;
>>> +       unsigned long N;
>>> +       unsigned long OD;
>>> +       unsigned long POD;
>>> +};
>>> +
>>> +#endif
>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>> b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>> index 5ac7a7e..7d96583 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>> @@ -18,6 +18,7 @@
>>>
>>>   #include <linux/module.h>
>>>   #include <linux/console.h>
>>> +#include <drm/drm_crtc_helper.h>
>>>
>>>   #include "hibmc_drm_drv.h"
>>>   #include "hibmc_drm_regs.h"
>>> @@ -47,8 +48,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",
>>> @@ -70,6 +71,7 @@ static int hibmc_pm_suspend(struct device *dev)
>>>          struct drm_device *drm_dev = pci_get_drvdata(pdev);
>>>          struct hibmc_drm_device *hidev = drm_dev->dev_private;
>>>
>>> +       drm_kms_helper_poll_disable(drm_dev);
>>>          drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 1);
>>>
>>>          return 0;
>>> @@ -81,7 +83,9 @@ static int hibmc_pm_resume(struct device *dev)
>>>          struct drm_device *drm_dev = pci_get_drvdata(pdev);
>>>          struct hibmc_drm_device *hidev = drm_dev->dev_private;
>>>
>>> +       drm_helper_resume_force_mode(drm_dev);
>>>          drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 0);
>>> +       drm_kms_helper_poll_enable(drm_dev);
>>>
>>>          return 0;
>>>   }
>>> @@ -91,6 +95,41 @@ static int hibmc_pm_resume(struct device *dev)
>>>                                  hibmc_pm_resume)
>>>   };
>>>
>>> +static int hibmc_kms_init(struct hibmc_drm_device *hidev)
>>> +{
>>> +       int ret;
>>> +
>>> +       drm_mode_config_init(hidev->dev);
>>> +       hidev->mode_config_initialized = true;
>>> +
>>> +       hidev->dev->mode_config.min_width = 0;
>>> +       hidev->dev->mode_config.min_height = 0;
>>> +       hidev->dev->mode_config.max_width = 1920;
>>> +       hidev->dev->mode_config.max_height = 1440;
>>> +
>>> +       hidev->dev->mode_config.fb_base = hidev->fb_base;
>>> +       hidev->dev->mode_config.preferred_depth = 24;
>>> +       hidev->dev->mode_config.prefer_shadow = 0;
>>> +
>>> +       hidev->dev->mode_config.funcs = (void *)&hibmc_mode_funcs;
>>> +
>>> +       ret = hibmc_plane_init(hidev);
>>> +       if (ret) {
>>> +               DRM_ERROR("fail to init plane!!!\n");
>>> +               return ret;
>>> +       }
>>> +
>>> +       return 0;
>>> +}
>>> +
>>> +static void hibmc_kms_fini(struct hibmc_drm_device *hidev)
>>> +{
>>> +       if (hidev->mode_config_initialized) {
>>> +               drm_mode_config_cleanup(hidev->dev);
>>> +               hidev->mode_config_initialized = false;
>>> +       }
>>> +}
>>> +
>>>   static int hibmc_hw_config(struct hibmc_drm_device *hidev)
>>>   {
>>>          unsigned int reg;
>>> @@ -183,6 +222,7 @@ static int hibmc_unload(struct drm_device *dev)
>>>          struct hibmc_drm_device *hidev = dev->dev_private;
>>>
>>>          hibmc_fbdev_fini(hidev);
>>> +       hibmc_kms_fini(hidev);
>>>          hibmc_mm_fini(hidev);
>>>          hibmc_hw_fini(hidev);
>>>          dev->dev_private = NULL;
>>> @@ -208,6 +248,13 @@ static int hibmc_load(struct drm_device *dev,
>>> unsigned long flags)
>>>          if (ret)
>>>                  goto err;
>>>
>>> +       ret = hibmc_kms_init(hidev);
>>> +       if (ret)
>>> +               goto err;
>>> +
>>> +       /* reset all the states of crtc/plane/encoder/connector */
>>> +       drm_mode_config_reset(dev);
>>> +
>>>          ret = hibmc_fbdev_init(hidev);
>>>          if (ret)
>>>                  goto err;
>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>>> b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>>> index a40e9a7..49e39d2 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>>> @@ -45,6 +45,8 @@ struct hibmc_drm_device {
>>>
>>>          /* drm */
>>>          struct drm_device  *dev;
>>> +       struct drm_plane plane;
>>> +       bool mode_config_initialized;
>>>
>>>          /* ttm */
>>>          struct {
>>> @@ -82,6 +84,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct
>>> drm_gem_object *gem)
>>>
>>>   #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
>>>
>>> +int hibmc_plane_init(struct hibmc_drm_device *hidev);
>>>   int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
>>>   void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
>>>
>>> @@ -102,4 +105,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 9822f62..beb4d76 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>> @@ -554,3 +554,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
>>>
>>>
>>> _______________________________________________
>>> linux-arm-kernel mailing list
>>> linux-arm-kernel@lists.infradead.org
>>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>
>> _______________________________________________
>> 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
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v6 5/9] drm/hisilicon/hibmc: Add crtc for DE
  2016-11-12 10:19       ` Rongrong Zou
@ 2016-11-14 17:10         ` Sean Paul
  -1 siblings, 0 replies; 64+ messages in thread
From: Sean Paul @ 2016-11-14 17:10 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Nov 12, 2016 at 5:19 AM, Rongrong Zou <zourongrong@huawei.com> wrote:
> ? 2016/11/11 6:14, Sean Paul ??:
>>
>> On Fri, Oct 28, 2016 at 3:27 AM, Rongrong Zou <zourongrong@gmail.com>
>> wrote:
>>>
>>> Add crtc funcs and helper funcs for DE.
>>>
>>> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
>>> ---
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c  | 318
>>> ++++++++++++++++++++++++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |   6 +
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |   2 +
>>>   3 files changed, 326 insertions(+)
>>>
>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>>> b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>>> index 9c1a68c..9b5d0d0 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>>> @@ -23,6 +23,7 @@
>>>
>>>   #include "hibmc_drm_drv.h"
>>>   #include "hibmc_drm_regs.h"
>>> +#include "hibmc_drm_de.h"
>>>   #include "hibmc_drm_power.h"
>>
>>
>> nit: alphabetize
>
>
> ok, thanks.
>
>>
>>>
>>>   /*
>>> ---------------------------------------------------------------------- */
>>
>>
>> Remove
>
>
> will do, thanks.
>
>>
>>> @@ -168,3 +169,320 @@ int hibmc_plane_init(struct hibmc_drm_device
>>> *hidev)
>>>          drm_plane_helper_add(plane, &hibmc_plane_helper_funcs);
>>>          return 0;
>>>   }
>>> +
>>> +static void hibmc_crtc_enable(struct drm_crtc *crtc)
>>> +{
>>> +       unsigned int reg;
>>> +       /* power mode 0 is default. */
>>
>>
>> This comment seems to be in the wrong place
>
>
> will remove it, thanks.
>
>
>>
>>> +       struct hibmc_drm_device *hidev = crtc->dev->dev_private;
>>> +
>>> +       hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_MODE0);
>>> +
>>> +       /* Enable display power gate & LOCALMEM power gate*/
>>> +       reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
>>> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
>>> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
>>> +       reg |= HIBMC_CURR_GATE_LOCALMEM(ON);
>>> +       reg |= HIBMC_CURR_GATE_DISPLAY(ON);
>>> +       hibmc_set_current_gate(hidev, reg);
>>> +       drm_crtc_vblank_on(crtc);
>>> +}
>>> +
>>> +static void hibmc_crtc_disable(struct drm_crtc *crtc)
>>> +{
>>> +       unsigned int reg;
>>> +       struct hibmc_drm_device *hidev = crtc->dev->dev_private;
>>> +
>>> +       drm_crtc_vblank_off(crtc);
>>> +
>>> +       hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_SLEEP);
>>> +
>>> +       /* Enable display power gate & LOCALMEM power gate*/
>>> +       reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
>>> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
>>> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
>>> +       reg |= HIBMC_CURR_GATE_LOCALMEM(OFF);
>>> +       reg |= HIBMC_CURR_GATE_DISPLAY(OFF);
>>> +       hibmc_set_current_gate(hidev, reg);
>>> +}
>>> +
>>> +static int hibmc_crtc_atomic_check(struct drm_crtc *crtc,
>>> +                                  struct drm_crtc_state *state)
>>> +{
>>> +       return 0;
>>> +}
>>
>>
>> Caller NULL-checks, no need for stub
>
>
> thanks for pointing it out.
>
>
>>
>>> +
>>> +static unsigned int format_pll_reg(void)
>>> +{
>>> +       unsigned int pllreg = 0;
>>> +       struct 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_PLL_CTRL_BYPASS(OFF) &
>>> HIBMC_PLL_CTRL_BYPASS_MASK;
>>> +       pllreg |= HIBMC_PLL_CTRL_POWER(ON) & HIBMC_PLL_CTRL_POWER_MASK;
>>> +       pllreg |= HIBMC_PLL_CTRL_INPUT(OSC) & HIBMC_PLL_CTRL_INPUT_MASK;
>>> +       pllreg |= HIBMC_PLL_CTRL_POD(pll.POD) & HIBMC_PLL_CTRL_POD_MASK;
>>> +       pllreg |= HIBMC_PLL_CTRL_OD(pll.OD) & HIBMC_PLL_CTRL_OD_MASK;
>>> +       pllreg |= HIBMC_PLL_CTRL_N(pll.N) & HIBMC_PLL_CTRL_N_MASK;
>>> +       pllreg |= HIBMC_PLL_CTRL_M(pll.M) & HIBMC_PLL_CTRL_M_MASK;
>>> +
>>> +       return pllreg;
>>> +}
>>> +
>>> +static void set_vclock_hisilicon(struct drm_device *dev, unsigned long
>>> pll)
>>> +{
>>> +       unsigned long tmp0, tmp1;
>>> +       struct hibmc_drm_device *hidev = dev->dev_private;
>>> +
>>> +       /* 1. outer_bypass_n=0 */
>>> +       tmp0 = readl(hidev->mmio + CRT_PLL1_HS);
>>> +       tmp0 &= 0xBFFFFFFF;
>>> +       writel(tmp0, hidev->mmio + CRT_PLL1_HS);
>>> +
>>> +       /* 2. pll_pd=1?inter_bypass=1 */
>>> +       writel(0x21000000, hidev->mmio + CRT_PLL1_HS);
>>> +
>>> +       /* 3. config pll */
>>> +       writel(pll, hidev->mmio + CRT_PLL1_HS);
>>> +
>>> +       /* 4. delay  */
>>> +       mdelay(1);
>>
>>
>> These should be usleep_range() see
>> https://www.kernel.org/doc/Documentation/timers/timers-howto.txt
>
>
> This looks better to me. i think a 'usleep_range(1000, 2000)' is ok.
>
>>
>>> +
>>> +       /* 5. pll_pd =0 */
>>> +       tmp1 = pll & ~0x01000000;
>>> +       writel(tmp1, hidev->mmio + CRT_PLL1_HS);
>>> +
>>> +       /* 6. delay  */
>>> +       mdelay(1);
>>> +
>>> +       /* 7. inter_bypass=0 */
>>> +       tmp1 &= ~0x20000000;
>>> +       writel(tmp1, hidev->mmio + CRT_PLL1_HS);
>>> +
>>> +       /* 8. delay  */
>>> +       mdelay(1);
>>> +
>>> +       /* 9. outer_bypass_n=1 */
>>> +       tmp1 |= 0x40000000;
>>> +       writel(tmp1, hidev->mmio + CRT_PLL1_HS);
>>
>>
>> This function is a whole lot of magic. Any chance you can pull the
>> values out into #defines?
>
>
> will do. thanks.
>
>>
>>> +}
>>> +
>>> +/* This function takes care the extra registers and bit fields required
>>> to
>>
>>
>> nit: multi-line comments have a leading /* line with the comment
>> starting on the following line
>
>
> thanks for pointing it out.
>
>>
>> applies below as well
>>
>>
>>> + *setup a mode in board.
>>
>>
>> nit: space between * and comment, ie: * setup a mode in board
>
>
> understood, thanks.
>
>
>>
>> applies to the rest of the comment too
>>
>>
>>> + *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;
>>> +       unsigned long pll1; /* bit[31:0] of PLL */
>>> +       unsigned long pll2; /* bit[63:32] of PLL */
>>> +       struct hibmc_drm_device *hidev = dev->dev_private;
>>> +
>>> +       x = mode->hdisplay;
>>> +       y = mode->vdisplay;
>>> +
>>> +       /* Hisilicon has to set up a new register for PLL control
>>> +        *(CRT_PLL1_HS & CRT_PLL2_HS).
>>> +        */
>>> +       if (x == 800 && y == 600) {
>>> +               pll1 = CRT_PLL1_HS_40MHZ;
>>> +               pll2 = CRT_PLL2_HS_40MHZ;
>>> +       } else if (x == 1024 && y == 768) {
>>> +               pll1 = CRT_PLL1_HS_65MHZ;
>>> +               pll2 = CRT_PLL2_HS_65MHZ;
>>> +       } else if (x == 1152 && y == 864) {
>>> +               pll1 = CRT_PLL1_HS_80MHZ_1152;
>>> +               pll2 = CRT_PLL2_HS_80MHZ;
>>> +       } else if (x == 1280 && y == 768) {
>>> +               pll1 = CRT_PLL1_HS_80MHZ;
>>> +               pll2 = CRT_PLL2_HS_80MHZ;
>>> +       } else if (x == 1280 && y == 720) {
>>> +               pll1 = CRT_PLL1_HS_74MHZ;
>>> +               pll2 = CRT_PLL2_HS_74MHZ;
>>> +       } else if (x == 1280 && y == 960) {
>>> +               pll1 = CRT_PLL1_HS_108MHZ;
>>> +               pll2 = CRT_PLL2_HS_108MHZ;
>>> +       } else if (x == 1280 && y == 1024) {
>>> +               pll1 = CRT_PLL1_HS_108MHZ;
>>> +               pll2 = CRT_PLL2_HS_108MHZ;
>>> +       } else if (x == 1600 && y == 1200) {
>>> +               pll1 = CRT_PLL1_HS_162MHZ;
>>> +               pll2 = CRT_PLL2_HS_162MHZ;
>>> +       } else if (x == 1920 && y == 1080) {
>>> +               pll1 = CRT_PLL1_HS_148MHZ;
>>> +               pll2 = CRT_PLL2_HS_148MHZ;
>>> +       } else if (x == 1920 && y == 1200) {
>>> +               pll1 = CRT_PLL1_HS_193MHZ;
>>> +               pll2 = CRT_PLL2_HS_193MHZ;
>>> +       } else /* default to VGA clock */ {
>>> +               pll1 = CRT_PLL1_HS_25MHZ;
>>> +               pll2 = CRT_PLL2_HS_25MHZ;
>>> +       }
>>
>>
>> This seems like something that should be checked in atomic_check so
>> you can be sure the mode is supported.
>>
>> It would also be nice to pull this out into a separate function (and a
>> lookup table if you're feeling adventurous)
>
>
> a lookup table seems good, thanks.
>
>
>>
>>> +
>>> +       writel(pll2, hidev->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_CRT_AUTO_CENTERING_TL_TOP(0) &
>>> +               HIBMC_CRT_AUTO_CENTERING_TL_TOP_MSK) |
>>> +              (HIBMC_CRT_AUTO_CENTERING_TL_LEFT(0) &
>>> +               HIBMC_CRT_AUTO_CENTERING_TL_LEFT_MSK),
>>> +              hidev->mmio + HIBMC_CRT_AUTO_CENTERING_TL);
>>> +
>>> +       writel((HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM(y - 1) &
>>> +               HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM_MASK) |
>>> +              (HIBMC_CRT_AUTO_CENTERING_BR_RIGHT(x - 1) &
>>> +               HIBMC_CRT_AUTO_CENTERING_BR_RIGHT_MASK),
>>> +               hidev->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(CRTSELECT_CRT);
>>> +
>>> +       /*ctrl = FIELD_SET(ctrl, HIBMC_CRT_DISP_CTL, CRTSELECT, CRT);*/
>>
>>
>> What's the deal with this commented code?
>
>
> sorry, will clean up.
>
>>
>>> +
>>> +       /* Set bit 14 of display controller */
>>> +       /*ctrl &= FIELD_CLEAR(HIBMC_CRT_DISP_CTL, CLOCK_PHASE);*/
>>> +
>>> +       /* clock_phase_polarity is 0 */
>>> +       ctrl |= HIBMC_CRT_DISP_CTL_CLOCK_PHASE(PHASE_ACTIVE_HIGH);
>>> +       /*ctrl = FIELD_SET(ctrl, HIBMC_CRT_DISP_CTL,*/
>>> +       /*CLOCK_PHASE, ACTIVE_HIGH);*/
>>
>>
>> Here too...
>
>
> ditto.
>
>>
>>> +
>>> +       writel(ctrl, hidev->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_device *hidev = dev->dev_private;
>>> +
>>> +       writel(format_pll_reg(), hidev->mmio + HIBMC_CRT_PLL_CTRL);
>>> +       writel((HIBMC_CRT_HORZ_TOTAL_TOTAL(mode->htotal - 1) &
>>> +               HIBMC_CRT_HORZ_TOTAL_TOTAL_MASK) |
>>> +               (HIBMC_CRT_HORZ_TOTAL_DISPLAY_END(mode->hdisplay - 1) &
>>> +               HIBMC_CRT_HORZ_TOTAL_DISPLAY_END_MASK),
>>
>>
>> You could probably macroize this code to make it more readable
>
>
>
>         #define HIBMC_FIELD(field, value) (field(value) & filed##_MASK)
>
>         writel(HIBMC_FIELD(HIBMC_CRT_HORZ_TOTAL_TOTAL, mode->htotal - 1) |
>                HIBMC_FIELD(HIBMC_CRT_HORZ_TOTAL_DISPLAY_END, mode->hdisplay
> - 1),
>                hidev->mmio + HIBMC_CRT_HORZ_TOTAL);
>
> Is above ok?
>

Seems like an improvement.

>
>
>
>>
>>> +               hidev->mmio + HIBMC_CRT_HORZ_TOTAL);
>>> +
>>> +       writel((HIBMC_CRT_HORZ_SYNC_WIDTH(mode->hsync_end -
>>> mode->hsync_start)
>>> +               & HIBMC_CRT_HORZ_SYNC_WIDTH_MASK) |
>>> +               (HIBMC_CRT_HORZ_SYNC_START(mode->hsync_start - 1)
>>> +               & HIBMC_CRT_HORZ_SYNC_START_MASK),
>>> +               hidev->mmio + HIBMC_CRT_HORZ_SYNC);
>>> +
>>> +       writel((HIBMC_CRT_VERT_TOTAL_TOTAL(mode->vtotal - 1) &
>>> +               HIBMC_CRT_VERT_TOTAL_TOTAL_MASK) |
>>> +               (HIBMC_CRT_VERT_TOTAL_DISPLAY_END(mode->vdisplay - 1) &
>>> +               HIBMC_CRT_VERT_TOTAL_DISPLAY_END_MASK),
>>> +               hidev->mmio + HIBMC_CRT_VERT_TOTAL);
>>> +
>>> +       writel((HIBMC_CRT_VERT_SYNC_HEIGHT(mode->vsync_end -
>>> mode->vsync_start)
>>> +               & HIBMC_CRT_VERT_SYNC_HEIGHT_MASK) |
>>> +              (HIBMC_CRT_VERT_SYNC_START(mode->vsync_start - 1) &
>>> +               HIBMC_CRT_VERT_SYNC_START_MASK),
>>> +               hidev->mmio + HIBMC_CRT_VERT_SYNC);
>>> +
>>> +       val = HIBMC_CRT_DISP_CTL_VSYNC_PHASE(0) &
>>> +             HIBMC_CRT_DISP_CTL_VSYNC_PHASE_MASK;
>>> +       val |= HIBMC_CRT_DISP_CTL_HSYNC_PHASE(0) &
>>> +              HIBMC_CRT_DISP_CTL_HSYNC_PHASE_MASK;
>>> +       val |= HIBMC_CRT_DISP_CTL_TIMING(ENABLE);
>>> +       val |= HIBMC_CRT_DISP_CTL_PLANE(ENABLE);
>>> +
>>> +       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_device *hidev = dev->dev_private;
>>> +
>>> +       hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_MODE0);
>>> +
>>> +       /* Enable display power gate & LOCALMEM power gate*/
>>> +       reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
>>> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
>>> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
>>> +       reg |= HIBMC_CURR_GATE_DISPLAY(ON);
>>> +       reg |= HIBMC_CURR_GATE_LOCALMEM(ON);
>>> +       hibmc_set_current_gate(hidev, 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);
>>> +}
>>> +
>>> +/* These provide the minimum set of functions required to handle a CRTC
>>> */
>>
>>
>> nit: don't need this comment
>
>
> will delete, thanks.
>
>
>>
>>> +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_check   = hibmc_crtc_atomic_check,
>>> +       .atomic_begin   = hibmc_crtc_atomic_begin,
>>> +       .atomic_flush   = hibmc_crtc_atomic_flush,
>>> +};
>>> +
>>> +int hibmc_crtc_init(struct hibmc_drm_device *hidev)
>>> +{
>>> +       struct drm_device *dev = hidev->dev;
>>> +       struct drm_crtc *crtc = &hidev->crtc;
>>> +       struct drm_plane *plane = &hidev->plane;
>>> +       int ret;
>>> +
>>> +       ret = drm_crtc_init_with_planes(dev, crtc, plane,
>>> +                                       NULL, &hibmc_crtc_funcs, NULL);
>>> +       if (ret) {
>>> +               DRM_ERROR("failed to init crtc.\n");
>>
>>
>> print return code
>
>
> agreed, thanks.
>
>>
>>> +               return ret;
>>> +       }
>>> +
>>> +       drm_mode_crtc_set_gamma_size(crtc, 256);
>>
>>
>> check return code
>
>
> agreed though none of other drivers has done this,
> thanks.
>
>>
>>> +       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 7d96583..303cd36 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>> @@ -119,6 +119,12 @@ static int hibmc_kms_init(struct hibmc_drm_device
>>> *hidev)
>>>                  return ret;
>>>          }
>>>
>>> +       ret = hibmc_crtc_init(hidev);
>>> +       if (ret) {
>>> +               DRM_ERROR("failed to init crtc.\n");
>>> +               return ret;
>>> +       }
>>
>>
>> Typically the plane is initialized internally in the crtc driver. I
>> think this is a good design pattern, and you should probably use it.
>>
>> So how about squashing this down with the plane patch and keeping the
>> plane inside hibmc_drm_de.c?
>
>
> understood after i looked at intel_display.c, this file will be merged
> with patch 4/9, and the tile will be: 'drm/hisilicon/hibmc: Add display
> engine'.
>

Great, thanks.

>>
>>> +
>>>          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 49e39d2..5731ec2 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>>> @@ -46,6 +46,7 @@ struct hibmc_drm_device {
>>>          /* drm */
>>>          struct drm_device  *dev;
>>>          struct drm_plane plane;
>>
>>
>> I don't think you should be keeping track of plane here. plane is only
>> used in the crtc init, which should be addressed by the previous
>> comment.
>
>
> so allocate with devm_kzalloc(sizeof(*plane)) and remove it from
> hibmc_drm_device?
>
>>
>>
>>> +       struct drm_crtc crtc;
>>
>>
>> crtc is only used in the irq handler, so you could remove this here
>> and just call drm_handle_vblank(dev, 0) in the handler.
>
>
> so allocate with devm_kzalloc(sizeof(*crtc)) and remove it from
> hibmc_drm_device, when driver unload drm_crtc_cleanup() will be
> called and finally memory will be freed before quit.
>

Yep, precisely.

Sean

>>
>>
>>>          bool mode_config_initialized;
>>>
>>>          /* ttm */
>>> @@ -85,6 +86,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct
>>> drm_gem_object *gem)
>>>   #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
>>>
>>>   int hibmc_plane_init(struct hibmc_drm_device *hidev);
>>> +int hibmc_crtc_init(struct hibmc_drm_device *hidev);
>>>   int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
>>>   void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
>>>
>>> --
>>> 1.9.1
>>>
>>>
>>> _______________________________________________
>>> linux-arm-kernel mailing list
>>> linux-arm-kernel at lists.infradead.org
>>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>
>> _______________________________________________
>> linuxarm mailing list
>> linuxarm at huawei.com
>> http://rnd-openeuler.huawei.com/mailman/listinfo/linuxarm
>>
>> .
>>
>
>
> --
> Regards, Rongrong
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v6 5/9] drm/hisilicon/hibmc: Add crtc for DE
@ 2016-11-14 17:10         ` Sean Paul
  0 siblings, 0 replies; 64+ messages in thread
From: Sean Paul @ 2016-11-14 17:10 UTC (permalink / raw)
  To: Rongrong Zou
  Cc: Mark Rutland, lijianhua, Will Deacon, Tomeu Vizoso,
	Jonathan Corbet, catalin.marinas, Emil Velikov, linuxarm,
	dri-devel, james.xiong, shenhui, Rongrong Zou, Linux ARM Kernel

On Sat, Nov 12, 2016 at 5:19 AM, Rongrong Zou <zourongrong@huawei.com> wrote:
> 在 2016/11/11 6:14, Sean Paul 写道:
>>
>> On Fri, Oct 28, 2016 at 3:27 AM, Rongrong Zou <zourongrong@gmail.com>
>> wrote:
>>>
>>> Add crtc funcs and helper funcs for DE.
>>>
>>> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
>>> ---
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c  | 318
>>> ++++++++++++++++++++++++
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |   6 +
>>>   drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |   2 +
>>>   3 files changed, 326 insertions(+)
>>>
>>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>>> b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>>> index 9c1a68c..9b5d0d0 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>>> @@ -23,6 +23,7 @@
>>>
>>>   #include "hibmc_drm_drv.h"
>>>   #include "hibmc_drm_regs.h"
>>> +#include "hibmc_drm_de.h"
>>>   #include "hibmc_drm_power.h"
>>
>>
>> nit: alphabetize
>
>
> ok, thanks.
>
>>
>>>
>>>   /*
>>> ---------------------------------------------------------------------- */
>>
>>
>> Remove
>
>
> will do, thanks.
>
>>
>>> @@ -168,3 +169,320 @@ int hibmc_plane_init(struct hibmc_drm_device
>>> *hidev)
>>>          drm_plane_helper_add(plane, &hibmc_plane_helper_funcs);
>>>          return 0;
>>>   }
>>> +
>>> +static void hibmc_crtc_enable(struct drm_crtc *crtc)
>>> +{
>>> +       unsigned int reg;
>>> +       /* power mode 0 is default. */
>>
>>
>> This comment seems to be in the wrong place
>
>
> will remove it, thanks.
>
>
>>
>>> +       struct hibmc_drm_device *hidev = crtc->dev->dev_private;
>>> +
>>> +       hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_MODE0);
>>> +
>>> +       /* Enable display power gate & LOCALMEM power gate*/
>>> +       reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
>>> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
>>> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
>>> +       reg |= HIBMC_CURR_GATE_LOCALMEM(ON);
>>> +       reg |= HIBMC_CURR_GATE_DISPLAY(ON);
>>> +       hibmc_set_current_gate(hidev, reg);
>>> +       drm_crtc_vblank_on(crtc);
>>> +}
>>> +
>>> +static void hibmc_crtc_disable(struct drm_crtc *crtc)
>>> +{
>>> +       unsigned int reg;
>>> +       struct hibmc_drm_device *hidev = crtc->dev->dev_private;
>>> +
>>> +       drm_crtc_vblank_off(crtc);
>>> +
>>> +       hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_SLEEP);
>>> +
>>> +       /* Enable display power gate & LOCALMEM power gate*/
>>> +       reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
>>> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
>>> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
>>> +       reg |= HIBMC_CURR_GATE_LOCALMEM(OFF);
>>> +       reg |= HIBMC_CURR_GATE_DISPLAY(OFF);
>>> +       hibmc_set_current_gate(hidev, reg);
>>> +}
>>> +
>>> +static int hibmc_crtc_atomic_check(struct drm_crtc *crtc,
>>> +                                  struct drm_crtc_state *state)
>>> +{
>>> +       return 0;
>>> +}
>>
>>
>> Caller NULL-checks, no need for stub
>
>
> thanks for pointing it out.
>
>
>>
>>> +
>>> +static unsigned int format_pll_reg(void)
>>> +{
>>> +       unsigned int pllreg = 0;
>>> +       struct 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_PLL_CTRL_BYPASS(OFF) &
>>> HIBMC_PLL_CTRL_BYPASS_MASK;
>>> +       pllreg |= HIBMC_PLL_CTRL_POWER(ON) & HIBMC_PLL_CTRL_POWER_MASK;
>>> +       pllreg |= HIBMC_PLL_CTRL_INPUT(OSC) & HIBMC_PLL_CTRL_INPUT_MASK;
>>> +       pllreg |= HIBMC_PLL_CTRL_POD(pll.POD) & HIBMC_PLL_CTRL_POD_MASK;
>>> +       pllreg |= HIBMC_PLL_CTRL_OD(pll.OD) & HIBMC_PLL_CTRL_OD_MASK;
>>> +       pllreg |= HIBMC_PLL_CTRL_N(pll.N) & HIBMC_PLL_CTRL_N_MASK;
>>> +       pllreg |= HIBMC_PLL_CTRL_M(pll.M) & HIBMC_PLL_CTRL_M_MASK;
>>> +
>>> +       return pllreg;
>>> +}
>>> +
>>> +static void set_vclock_hisilicon(struct drm_device *dev, unsigned long
>>> pll)
>>> +{
>>> +       unsigned long tmp0, tmp1;
>>> +       struct hibmc_drm_device *hidev = dev->dev_private;
>>> +
>>> +       /* 1. outer_bypass_n=0 */
>>> +       tmp0 = readl(hidev->mmio + CRT_PLL1_HS);
>>> +       tmp0 &= 0xBFFFFFFF;
>>> +       writel(tmp0, hidev->mmio + CRT_PLL1_HS);
>>> +
>>> +       /* 2. pll_pd=1?inter_bypass=1 */
>>> +       writel(0x21000000, hidev->mmio + CRT_PLL1_HS);
>>> +
>>> +       /* 3. config pll */
>>> +       writel(pll, hidev->mmio + CRT_PLL1_HS);
>>> +
>>> +       /* 4. delay  */
>>> +       mdelay(1);
>>
>>
>> These should be usleep_range() see
>> https://www.kernel.org/doc/Documentation/timers/timers-howto.txt
>
>
> This looks better to me. i think a 'usleep_range(1000, 2000)' is ok.
>
>>
>>> +
>>> +       /* 5. pll_pd =0 */
>>> +       tmp1 = pll & ~0x01000000;
>>> +       writel(tmp1, hidev->mmio + CRT_PLL1_HS);
>>> +
>>> +       /* 6. delay  */
>>> +       mdelay(1);
>>> +
>>> +       /* 7. inter_bypass=0 */
>>> +       tmp1 &= ~0x20000000;
>>> +       writel(tmp1, hidev->mmio + CRT_PLL1_HS);
>>> +
>>> +       /* 8. delay  */
>>> +       mdelay(1);
>>> +
>>> +       /* 9. outer_bypass_n=1 */
>>> +       tmp1 |= 0x40000000;
>>> +       writel(tmp1, hidev->mmio + CRT_PLL1_HS);
>>
>>
>> This function is a whole lot of magic. Any chance you can pull the
>> values out into #defines?
>
>
> will do. thanks.
>
>>
>>> +}
>>> +
>>> +/* This function takes care the extra registers and bit fields required
>>> to
>>
>>
>> nit: multi-line comments have a leading /* line with the comment
>> starting on the following line
>
>
> thanks for pointing it out.
>
>>
>> applies below as well
>>
>>
>>> + *setup a mode in board.
>>
>>
>> nit: space between * and comment, ie: * setup a mode in board
>
>
> understood, thanks.
>
>
>>
>> applies to the rest of the comment too
>>
>>
>>> + *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;
>>> +       unsigned long pll1; /* bit[31:0] of PLL */
>>> +       unsigned long pll2; /* bit[63:32] of PLL */
>>> +       struct hibmc_drm_device *hidev = dev->dev_private;
>>> +
>>> +       x = mode->hdisplay;
>>> +       y = mode->vdisplay;
>>> +
>>> +       /* Hisilicon has to set up a new register for PLL control
>>> +        *(CRT_PLL1_HS & CRT_PLL2_HS).
>>> +        */
>>> +       if (x == 800 && y == 600) {
>>> +               pll1 = CRT_PLL1_HS_40MHZ;
>>> +               pll2 = CRT_PLL2_HS_40MHZ;
>>> +       } else if (x == 1024 && y == 768) {
>>> +               pll1 = CRT_PLL1_HS_65MHZ;
>>> +               pll2 = CRT_PLL2_HS_65MHZ;
>>> +       } else if (x == 1152 && y == 864) {
>>> +               pll1 = CRT_PLL1_HS_80MHZ_1152;
>>> +               pll2 = CRT_PLL2_HS_80MHZ;
>>> +       } else if (x == 1280 && y == 768) {
>>> +               pll1 = CRT_PLL1_HS_80MHZ;
>>> +               pll2 = CRT_PLL2_HS_80MHZ;
>>> +       } else if (x == 1280 && y == 720) {
>>> +               pll1 = CRT_PLL1_HS_74MHZ;
>>> +               pll2 = CRT_PLL2_HS_74MHZ;
>>> +       } else if (x == 1280 && y == 960) {
>>> +               pll1 = CRT_PLL1_HS_108MHZ;
>>> +               pll2 = CRT_PLL2_HS_108MHZ;
>>> +       } else if (x == 1280 && y == 1024) {
>>> +               pll1 = CRT_PLL1_HS_108MHZ;
>>> +               pll2 = CRT_PLL2_HS_108MHZ;
>>> +       } else if (x == 1600 && y == 1200) {
>>> +               pll1 = CRT_PLL1_HS_162MHZ;
>>> +               pll2 = CRT_PLL2_HS_162MHZ;
>>> +       } else if (x == 1920 && y == 1080) {
>>> +               pll1 = CRT_PLL1_HS_148MHZ;
>>> +               pll2 = CRT_PLL2_HS_148MHZ;
>>> +       } else if (x == 1920 && y == 1200) {
>>> +               pll1 = CRT_PLL1_HS_193MHZ;
>>> +               pll2 = CRT_PLL2_HS_193MHZ;
>>> +       } else /* default to VGA clock */ {
>>> +               pll1 = CRT_PLL1_HS_25MHZ;
>>> +               pll2 = CRT_PLL2_HS_25MHZ;
>>> +       }
>>
>>
>> This seems like something that should be checked in atomic_check so
>> you can be sure the mode is supported.
>>
>> It would also be nice to pull this out into a separate function (and a
>> lookup table if you're feeling adventurous)
>
>
> a lookup table seems good, thanks.
>
>
>>
>>> +
>>> +       writel(pll2, hidev->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_CRT_AUTO_CENTERING_TL_TOP(0) &
>>> +               HIBMC_CRT_AUTO_CENTERING_TL_TOP_MSK) |
>>> +              (HIBMC_CRT_AUTO_CENTERING_TL_LEFT(0) &
>>> +               HIBMC_CRT_AUTO_CENTERING_TL_LEFT_MSK),
>>> +              hidev->mmio + HIBMC_CRT_AUTO_CENTERING_TL);
>>> +
>>> +       writel((HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM(y - 1) &
>>> +               HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM_MASK) |
>>> +              (HIBMC_CRT_AUTO_CENTERING_BR_RIGHT(x - 1) &
>>> +               HIBMC_CRT_AUTO_CENTERING_BR_RIGHT_MASK),
>>> +               hidev->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(CRTSELECT_CRT);
>>> +
>>> +       /*ctrl = FIELD_SET(ctrl, HIBMC_CRT_DISP_CTL, CRTSELECT, CRT);*/
>>
>>
>> What's the deal with this commented code?
>
>
> sorry, will clean up.
>
>>
>>> +
>>> +       /* Set bit 14 of display controller */
>>> +       /*ctrl &= FIELD_CLEAR(HIBMC_CRT_DISP_CTL, CLOCK_PHASE);*/
>>> +
>>> +       /* clock_phase_polarity is 0 */
>>> +       ctrl |= HIBMC_CRT_DISP_CTL_CLOCK_PHASE(PHASE_ACTIVE_HIGH);
>>> +       /*ctrl = FIELD_SET(ctrl, HIBMC_CRT_DISP_CTL,*/
>>> +       /*CLOCK_PHASE, ACTIVE_HIGH);*/
>>
>>
>> Here too...
>
>
> ditto.
>
>>
>>> +
>>> +       writel(ctrl, hidev->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_device *hidev = dev->dev_private;
>>> +
>>> +       writel(format_pll_reg(), hidev->mmio + HIBMC_CRT_PLL_CTRL);
>>> +       writel((HIBMC_CRT_HORZ_TOTAL_TOTAL(mode->htotal - 1) &
>>> +               HIBMC_CRT_HORZ_TOTAL_TOTAL_MASK) |
>>> +               (HIBMC_CRT_HORZ_TOTAL_DISPLAY_END(mode->hdisplay - 1) &
>>> +               HIBMC_CRT_HORZ_TOTAL_DISPLAY_END_MASK),
>>
>>
>> You could probably macroize this code to make it more readable
>
>
>
>         #define HIBMC_FIELD(field, value) (field(value) & filed##_MASK)
>
>         writel(HIBMC_FIELD(HIBMC_CRT_HORZ_TOTAL_TOTAL, mode->htotal - 1) |
>                HIBMC_FIELD(HIBMC_CRT_HORZ_TOTAL_DISPLAY_END, mode->hdisplay
> - 1),
>                hidev->mmio + HIBMC_CRT_HORZ_TOTAL);
>
> Is above ok?
>

Seems like an improvement.

>
>
>
>>
>>> +               hidev->mmio + HIBMC_CRT_HORZ_TOTAL);
>>> +
>>> +       writel((HIBMC_CRT_HORZ_SYNC_WIDTH(mode->hsync_end -
>>> mode->hsync_start)
>>> +               & HIBMC_CRT_HORZ_SYNC_WIDTH_MASK) |
>>> +               (HIBMC_CRT_HORZ_SYNC_START(mode->hsync_start - 1)
>>> +               & HIBMC_CRT_HORZ_SYNC_START_MASK),
>>> +               hidev->mmio + HIBMC_CRT_HORZ_SYNC);
>>> +
>>> +       writel((HIBMC_CRT_VERT_TOTAL_TOTAL(mode->vtotal - 1) &
>>> +               HIBMC_CRT_VERT_TOTAL_TOTAL_MASK) |
>>> +               (HIBMC_CRT_VERT_TOTAL_DISPLAY_END(mode->vdisplay - 1) &
>>> +               HIBMC_CRT_VERT_TOTAL_DISPLAY_END_MASK),
>>> +               hidev->mmio + HIBMC_CRT_VERT_TOTAL);
>>> +
>>> +       writel((HIBMC_CRT_VERT_SYNC_HEIGHT(mode->vsync_end -
>>> mode->vsync_start)
>>> +               & HIBMC_CRT_VERT_SYNC_HEIGHT_MASK) |
>>> +              (HIBMC_CRT_VERT_SYNC_START(mode->vsync_start - 1) &
>>> +               HIBMC_CRT_VERT_SYNC_START_MASK),
>>> +               hidev->mmio + HIBMC_CRT_VERT_SYNC);
>>> +
>>> +       val = HIBMC_CRT_DISP_CTL_VSYNC_PHASE(0) &
>>> +             HIBMC_CRT_DISP_CTL_VSYNC_PHASE_MASK;
>>> +       val |= HIBMC_CRT_DISP_CTL_HSYNC_PHASE(0) &
>>> +              HIBMC_CRT_DISP_CTL_HSYNC_PHASE_MASK;
>>> +       val |= HIBMC_CRT_DISP_CTL_TIMING(ENABLE);
>>> +       val |= HIBMC_CRT_DISP_CTL_PLANE(ENABLE);
>>> +
>>> +       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_device *hidev = dev->dev_private;
>>> +
>>> +       hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_MODE0);
>>> +
>>> +       /* Enable display power gate & LOCALMEM power gate*/
>>> +       reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
>>> +       reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
>>> +       reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
>>> +       reg |= HIBMC_CURR_GATE_DISPLAY(ON);
>>> +       reg |= HIBMC_CURR_GATE_LOCALMEM(ON);
>>> +       hibmc_set_current_gate(hidev, 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);
>>> +}
>>> +
>>> +/* These provide the minimum set of functions required to handle a CRTC
>>> */
>>
>>
>> nit: don't need this comment
>
>
> will delete, thanks.
>
>
>>
>>> +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_check   = hibmc_crtc_atomic_check,
>>> +       .atomic_begin   = hibmc_crtc_atomic_begin,
>>> +       .atomic_flush   = hibmc_crtc_atomic_flush,
>>> +};
>>> +
>>> +int hibmc_crtc_init(struct hibmc_drm_device *hidev)
>>> +{
>>> +       struct drm_device *dev = hidev->dev;
>>> +       struct drm_crtc *crtc = &hidev->crtc;
>>> +       struct drm_plane *plane = &hidev->plane;
>>> +       int ret;
>>> +
>>> +       ret = drm_crtc_init_with_planes(dev, crtc, plane,
>>> +                                       NULL, &hibmc_crtc_funcs, NULL);
>>> +       if (ret) {
>>> +               DRM_ERROR("failed to init crtc.\n");
>>
>>
>> print return code
>
>
> agreed, thanks.
>
>>
>>> +               return ret;
>>> +       }
>>> +
>>> +       drm_mode_crtc_set_gamma_size(crtc, 256);
>>
>>
>> check return code
>
>
> agreed though none of other drivers has done this,
> thanks.
>
>>
>>> +       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 7d96583..303cd36 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>> @@ -119,6 +119,12 @@ static int hibmc_kms_init(struct hibmc_drm_device
>>> *hidev)
>>>                  return ret;
>>>          }
>>>
>>> +       ret = hibmc_crtc_init(hidev);
>>> +       if (ret) {
>>> +               DRM_ERROR("failed to init crtc.\n");
>>> +               return ret;
>>> +       }
>>
>>
>> Typically the plane is initialized internally in the crtc driver. I
>> think this is a good design pattern, and you should probably use it.
>>
>> So how about squashing this down with the plane patch and keeping the
>> plane inside hibmc_drm_de.c?
>
>
> understood after i looked at intel_display.c, this file will be merged
> with patch 4/9, and the tile will be: 'drm/hisilicon/hibmc: Add display
> engine'.
>

Great, thanks.

>>
>>> +
>>>          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 49e39d2..5731ec2 100644
>>> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>>> @@ -46,6 +46,7 @@ struct hibmc_drm_device {
>>>          /* drm */
>>>          struct drm_device  *dev;
>>>          struct drm_plane plane;
>>
>>
>> I don't think you should be keeping track of plane here. plane is only
>> used in the crtc init, which should be addressed by the previous
>> comment.
>
>
> so allocate with devm_kzalloc(sizeof(*plane)) and remove it from
> hibmc_drm_device?
>
>>
>>
>>> +       struct drm_crtc crtc;
>>
>>
>> crtc is only used in the irq handler, so you could remove this here
>> and just call drm_handle_vblank(dev, 0) in the handler.
>
>
> so allocate with devm_kzalloc(sizeof(*crtc)) and remove it from
> hibmc_drm_device, when driver unload drm_crtc_cleanup() will be
> called and finally memory will be freed before quit.
>

Yep, precisely.

Sean

>>
>>
>>>          bool mode_config_initialized;
>>>
>>>          /* ttm */
>>> @@ -85,6 +86,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct
>>> drm_gem_object *gem)
>>>   #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
>>>
>>>   int hibmc_plane_init(struct hibmc_drm_device *hidev);
>>> +int hibmc_crtc_init(struct hibmc_drm_device *hidev);
>>>   int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
>>>   void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
>>>
>>> --
>>> 1.9.1
>>>
>>>
>>> _______________________________________________
>>> linux-arm-kernel mailing list
>>> linux-arm-kernel@lists.infradead.org
>>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>
>> _______________________________________________
>> 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
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

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

Thread overview: 64+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-28  7:27 [PATCH v6 0/9] Add DRM driver for Hisilicon Hibmc Rongrong Zou
2016-10-28  7:27 ` Rongrong Zou
2016-10-28  7:27 ` [PATCH v6 1/9] drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver Rongrong Zou
2016-10-28  7:27   ` Rongrong Zou
2016-11-10 17:35   ` Sean Paul
2016-11-10 17:35     ` Sean Paul
2016-11-11  3:10     ` Rongrong Zou
2016-11-11  3:10       ` Rongrong Zou
2016-10-28  7:27 ` [PATCH v6 2/9] drm/hisilicon/hibmc: Add video memory management Rongrong Zou
2016-10-28  7:27   ` Rongrong Zou
2016-11-10 17:35   ` Sean Paul
2016-11-10 17:35     ` Sean Paul
2016-11-11 11:16     ` Rongrong Zou
2016-11-11 11:16       ` Rongrong Zou
2016-11-11 13:25       ` Sean Paul
2016-11-11 13:25         ` Sean Paul
2016-11-11 13:57         ` Rongrong Zou
2016-11-11 13:57           ` Rongrong Zou
2016-10-28  7:27 ` [PATCH v6 3/9] drm/hisilicon/hibmc: Add support for frame buffer Rongrong Zou
2016-10-28  7:27   ` Rongrong Zou
2016-11-10 18:30   ` Sean Paul
2016-11-10 18:30     ` Sean Paul
2016-11-11 13:16     ` Rongrong Zou
2016-11-11 13:16       ` Rongrong Zou
2016-11-11 13:27       ` Sean Paul
2016-11-11 13:27         ` Sean Paul
2016-10-28  7:27 ` [PATCH v6 4/9] drm/hisilicon/hibmc: Add plane for DE Rongrong Zou
2016-10-28  7:27   ` Rongrong Zou
2016-11-10 21:53   ` Sean Paul
2016-11-10 21:53     ` Sean Paul
2016-11-12  5:11     ` Rongrong Zou
2016-11-12  5:11       ` Rongrong Zou
2016-11-14 17:08       ` Sean Paul
2016-11-14 17:08         ` Sean Paul
2016-10-28  7:27 ` [PATCH v6 5/9] drm/hisilicon/hibmc: Add crtc " Rongrong Zou
2016-10-28  7:27   ` Rongrong Zou
2016-11-10 22:14   ` Sean Paul
2016-11-10 22:14     ` Sean Paul
2016-11-12 10:19     ` Rongrong Zou
2016-11-12 10:19       ` Rongrong Zou
2016-11-14 17:10       ` Sean Paul
2016-11-14 17:10         ` Sean Paul
2016-10-28  7:27 ` [PATCH v6 6/9] drm/hisilicon/hibmc: Add encoder for VDAC Rongrong Zou
2016-10-28  7:27   ` Rongrong Zou
2016-11-10 22:20   ` Sean Paul
2016-11-10 22:20     ` Sean Paul
2016-11-12 10:36     ` Rongrong Zou
2016-11-12 10:36       ` Rongrong Zou
2016-10-28  7:28 ` [PATCH v6 7/9] drm/hisilicon/hibmc: Add connector " Rongrong Zou
2016-10-28  7:28   ` Rongrong Zou
2016-11-11  1:45   ` Sean Paul
2016-11-11  1:45     ` Sean Paul
2016-11-14 14:07     ` Rongrong Zou
2016-11-14 14:07       ` Rongrong Zou
2016-10-28  7:28 ` [PATCH v6 8/9] drm/hisilicon/hibmc: Add vblank interruput Rongrong Zou
2016-10-28  7:28   ` Rongrong Zou
2016-11-11  1:49   ` Sean Paul
2016-11-11  1:49     ` Sean Paul
2016-11-14 14:10     ` Rongrong Zou
2016-11-14 14:10       ` Rongrong Zou
2016-10-28  7:28 ` [PATCH v6 9/9] MAINTAINERS: Update HISILICON DRM entries Rongrong Zou
2016-10-28  7:28   ` Rongrong Zou
2016-11-11  1:50   ` Sean Paul
2016-11-11  1:50     ` Sean Paul

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.