* [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.