DRM Display driver for Intel FPGA Video and Image Processing Suite

Daniel Vetter daniel at ffwll.ch
Sun Apr 2 12:42:44 UTC 2017


On Fri, Mar 31, 2017 at 09:08:37AM +0000, Ong, Hean Loong wrote:
> Hi,
> 
> I would like to upstream the attached Intel FPGA Video and Image
> Processing Suite. The attached patch supports the Intel Arria10 devkit
> and its variants. The purpose of the patch is to enable the FPGA driven
> display designed from the Intel Quartus FPGA design suite.

For my understanding of the hw: Does this fpga thing have a real output,
or is it a virtual thing? It kinda looks very much like a virtual output
...

> The driver is required as part of the Intel Arria10 devkit reference
> design. The driver was tested on:
> - The Open Embedded Angstrom Distro. 
> - The matchbox-terminal and window-manager was used for functional
> testing

Please use igt to validate your driver, running a desktop isn't really a
full work-out. See https://dri.freedesktop.org/docs/drm/gpu/drm-uapi.html#testing-and-validation
> 
> Current the intention of the driver is meant to validate the FPGA
> designs on the Arria10 devkit for Display Port connecter. We have not
> verified its performance of or stability in 3D acceleration or other
> non Intel FPGA hardware

For next time around, pls submit is plain patch, not attached. You might
need to ask intel IT to adjust your outlook setttings to make sure it goes
through. Bunch of comments below.

Also, do you want to maintain this as part of the "small drivers in
drm-misc" effort? See:

https://01.org/linuxgraphics/gfx-docs/maintainer-tools/drm-misc.html#small-drivers

Note that it's no longer an expirement, we're accepting new drivers (but
the patch to change that hasn't gone through the autobuilders yet, hence
docs are a bit stale).

Bunch of comments below. Overall looks like a nice simple&clean driver.

Cheers, Daniel

> 
> BR
> 
> Hean Loong

> From 0de293e3646a1780ed603cf8e1f2a19d9aebbe83 Mon Sep 17 00:00:00 2001
> From: Ong, Hean Loong <hean.loong.ong at intel.com>
> Date: Thu, 30 Mar 2017 18:02:22 +0800
> Subject: [PATCHv0] Intel FPGA Video and Image Processing Suite Frame Buffer II driver
> 
> Signed-off-by: Ong, Hean Loong <hean.loong.ong at intel.com>
> ---
>  drivers/gpu/drm/Kconfig               |    2 +
>  drivers/gpu/drm/Makefile              |    1 +
>  drivers/gpu/drm/ivip/Kconfig          |   22 ++++
>  drivers/gpu/drm/ivip/Makefile         |    9 ++
>  drivers/gpu/drm/ivip/intel_vip_conn.c |  145 ++++++++++++++++++++++
>  drivers/gpu/drm/ivip/intel_vip_core.c |  215 +++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/ivip/intel_vip_crtc.c |  161 ++++++++++++++++++++++++
>  drivers/gpu/drm/ivip/intel_vip_drv.h  |   55 +++++++++
>  drivers/gpu/drm/ivip/intel_vip_of.c   |  146 ++++++++++++++++++++++
>  9 files changed, 756 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/gpu/drm/ivip/Kconfig
>  create mode 100644 drivers/gpu/drm/ivip/Makefile
>  create mode 100644 drivers/gpu/drm/ivip/intel_vip_conn.c
>  create mode 100644 drivers/gpu/drm/ivip/intel_vip_core.c
>  create mode 100644 drivers/gpu/drm/ivip/intel_vip_crtc.c
>  create mode 100644 drivers/gpu/drm/ivip/intel_vip_drv.h
>  create mode 100644 drivers/gpu/drm/ivip/intel_vip_of.c
> 
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index ebfe840..c487507 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -167,6 +167,8 @@ source "drivers/gpu/drm/nouveau/Kconfig"
>  
>  source "drivers/gpu/drm/i915/Kconfig"
>  
> +source "drivers/gpu/drm/ivip/Kconfig"
> +
>  config DRM_VGEM
>  	tristate "Virtual GEM provider"
>  	depends on DRM
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index b9ae428..945cf53 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -52,6 +52,7 @@ obj-$(CONFIG_DRM_AMDGPU)+= amd/amdgpu/
>  obj-$(CONFIG_DRM_MGA)	+= mga/
>  obj-$(CONFIG_DRM_I810)	+= i810/
>  obj-$(CONFIG_DRM_I915)	+= i915/
> +obj-$(CONFIG_DRM_IVIP)	+= ivip/
>  obj-$(CONFIG_DRM_MGAG200) += mgag200/
>  obj-$(CONFIG_DRM_VC4)  += vc4/
>  obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus/
> diff --git a/drivers/gpu/drm/ivip/Kconfig b/drivers/gpu/drm/ivip/Kconfig
> new file mode 100644
> index 0000000..ddf3cb5
> --- /dev/null
> +++ b/drivers/gpu/drm/ivip/Kconfig
> @@ -0,0 +1,22 @@
> +config DRM_IVIP
> +        tristate "Intel FGPA Video and Image Processing"
> +        depends on DRM
> +        select DRM_GEM_CMA_HELPER
> +        select DRM_KMS_HELPER
> +        select DRM_KMS_FB_HELPER
> +        select DRM_KMS_CMA_HELPER
> +        help
> +                Choose this option if you have a Intel FPGA Arria 10 system
> +                and above with a Display Port IP. This does not support legacy
> +                Intel FPGA Cyclone V display port. Currently only single frame
> +                buffer is supported. Note that ACPI and X_86 architecture is yet
> +                to be supported.

This config option seems defunct, only IVIP_OF seems to do anything.
Please merge.

> +
> +config DRM_IVIP_OF
> +        tristate "Intel FGPA Video and Image Processing Open Firmware Systems"
> +        depends on DRM_IVIP && OF
> +        help
> +                Choose this option if the Intel FPGA system is using Open
> +                Firmware systems (Arria 10). If M is selected the module would
> +                be called ivip.
> +
> diff --git a/drivers/gpu/drm/ivip/Makefile b/drivers/gpu/drm/ivip/Makefile
> new file mode 100644
> index 0000000..7be1e99
> --- /dev/null
> +++ b/drivers/gpu/drm/ivip/Makefile
> @@ -0,0 +1,9 @@
> +#
> +# Makefile for the drm device driver.  This driver provides support for the
> +# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
> +
> +ccflags-y := -Iinclude/drm
> +
> +obj-$(CONFIG_DRM_IVIP_OF) += ivip.o
> +ivip-objs := intel_vip_of.o intel_vip_core.o \
> +intel_vip_conn.o intel_vip_crtc.o
> diff --git a/drivers/gpu/drm/ivip/intel_vip_conn.c b/drivers/gpu/drm/ivip/intel_vip_conn.c
> new file mode 100644
> index 0000000..89ab587
> --- /dev/null
> +++ b/drivers/gpu/drm/ivip/intel_vip_conn.c
> @@ -0,0 +1,145 @@
> +/*
> + * intel_vip_conn.c -- Intel Video and Image Processing(VIP)
> + * Frame Buffer II driver
> + *
> + * This driver supports the Intel VIP Frame Reader component.
> + * More info on the hardware can be found in the Intel Video
> + * and Image Processing Suite User Guide at this address
> + * http://www.altera.com/literature/ug/ug_vip.pdf.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * Authors:
> + * Ong, Hean-Loong <hean.loong.ong at intel.com>
> + *
> + */
> +
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_encoder_slave.h>
> +#include <drm/drm_plane_helper.h>
> +
> +static enum drm_connector_status
> +intelvipfb_drm_connector_detect(struct drm_connector *connector, bool force)
> +{
> +	return connector_status_connected;
> +}
> +
> +static void intelvipfb_drm_connector_destroy(struct drm_connector *connector)
> +{
> +	drm_connector_unregister(connector);
> +	drm_connector_cleanup(connector);
> +}
> +
> +static const struct drm_connector_funcs intelvipfb_drm_connector_funcs = {
> +	.dpms = drm_helper_connector_dpms,
> +	.reset = drm_atomic_helper_connector_reset,
> +	.detect = intelvipfb_drm_connector_detect,
> +	.fill_modes = drm_helper_probe_single_connector_modes,
> +	.destroy = intelvipfb_drm_connector_destroy,
> +	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> +	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> +};
> +
> +static int intelvipfb_drm_connector_get_modes(struct drm_connector *connector)
> +{
> +	struct drm_device *drm = connector->dev;
> +	int count;
> +
> +	count = drm_add_modes_noedid(connector, drm->mode_config.max_width,
> +				     drm->mode_config.max_height);
> +	drm_set_preferred_mode(connector, drm->mode_config.max_width,
> +			       drm->mode_config.max_height);
> +	return count;
> +}
> +
> +static const struct drm_connector_helper_funcs
> +intelvipfb_drm_connector_helper_funcs = {
> +	.get_modes = intelvipfb_drm_connector_get_modes,
> +};
> +
> +static const struct drm_encoder_funcs
> +intelvipfb_drm_encoder_funcs = {
> +	.destroy = drm_encoder_cleanup,
> +};

It'd be great to extract a virtual_connector helper which just provides
one default mode and could be used by all virtual drivers ... Just a
thought to look into, can of course be done as a follow-up.

> +
> +static void intelvipfb_mode_set(struct drm_encoder *encoder,
> +				struct drm_display_mode *mode,
> +				struct drm_display_mode *adjusted_mode)
> +{
> +	/* do nothing */
> +}
> +
> +static void intelvipfb_nop(struct drm_encoder *encoder)
> +{
> +	/* do nothing */
> +}

Please drop these dummy functions, they're not needed on latest kernels.

> +
> +static const struct drm_encoder_helper_funcs i
> +intelvipfb_drm_encoder_helper = {
> +	.mode_set = intelvipfb_mode_set,
> +	.enable = intelvipfb_nop,
> +	.disable = intelvipfb_nop,
> +};
> +
> +int intelvipfb_drm_conn_init(struct drm_device *drm)
> +{
> +	struct drm_encoder_slave *encoder;
> +	struct drm_connector *conn;
> +	int ret;
> +
> +	encoder = devm_kzalloc(drm->dev, sizeof(*encoder), GFP_KERNEL);
> +	if (!encoder)
> +		return -ENOMEM;
> +
> +	encoder->base.possible_crtcs = 1;
> +	encoder->base.possible_clones = 0;
> +
> +	ret = drm_encoder_init(drm, &encoder->base,
> +			       &intelvipfb_drm_encoder_funcs,
> +			       DRM_MODE_ENCODER_VIRTUAL, NULL);
> +	if (ret)
> +		return ret;
> +
> +	drm_encoder_helper_add(&encoder->base, &intelvipfb_drm_encoder_helper);
> +
> +	conn = devm_kzalloc(drm->dev, sizeof(*conn), GFP_KERNEL);
> +	if (IS_ERR(conn))
> +		return PTR_ERR(conn);
> +
> +	ret = drm_connector_init(drm, conn, &intelvipfb_drm_connector_funcs,
> +				 DRM_MODE_CONNECTOR_DisplayPort);
> +	if (ret < 0) {
> +		dev_err(drm->dev, "failed to initialize drm connector\n");
> +		ret = -ENOMEM;
> +		goto error_encoder_cleanup;
> +	}
> +
> +	drm_connector_helper_add(conn, &intelvipfb_drm_connector_helper_funcs);
> +
> +	ret = drm_mode_connector_attach_encoder(conn, &encoder->base);
> +	if (ret < 0) {
> +		dev_err(drm->dev, "could not attach connector to encoder\n");
> +		drm_connector_unregister(conn);
> +		goto error_connector_cleanup;
> +	}
> +
> +	return 0;
> +
> +error_connector_cleanup:
> +	drm_connector_cleanup(conn);
> +
> +error_encoder_cleanup:
> +	drm_encoder_cleanup(&encoder->base);
> +
> +	return ret;
> +}
> diff --git a/drivers/gpu/drm/ivip/intel_vip_core.c b/drivers/gpu/drm/ivip/intel_vip_core.c
> new file mode 100644
> index 0000000..3001ad0
> --- /dev/null
> +++ b/drivers/gpu/drm/ivip/intel_vip_core.c
> @@ -0,0 +1,215 @@
> +/*
> + * intel_vip_core.c -- Intel Video and Image Processing(VIP)
> + * Frame Buffer II driver
> + *
> + * This driver supports the Intel VIP Frame Reader component.
> + * More info on the hardware can be found in the Intel Video
> + * and Image Processing Suite User Guide at this address
> + * http://www.altera.com/literature/ug/ug_vip.pdf.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * Authors:
> + * Ong, Hean-Loong <hean.loong.ong at intel.com>
> + *
> + */
> +
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +
> +#include <drm/drmP.h>
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_fb_helper.h>
> +#include <drm/drm_fb_cma_helper.h>
> +#include <drm/drm_gem_cma_helper.h>
> +#include <drm/drm_of.h>
> +
> +#include "intel_vip_drv.h"
> +
> +static const struct file_operations intelvipfb_drm_fops = {
> +	.owner		= THIS_MODULE,
> +	.open		= drm_open,
> +	.release	= drm_release,
> +	.unlocked_ioctl	= drm_ioctl,
> +	.poll		= drm_poll,
> +	.read		= drm_read,
> +	.llseek		= no_llseek,
> +	.mmap		= drm_gem_cma_mmap,

Please use the shiny new DRM_GEM_CMA_FOPS macro merged into linux-next
just recently.

> +};
> +
> +static void intelvipfb_lastclose(struct drm_device *drm)
> +{
> +	struct intelvipfb_priv *fbpriv = drm->dev_private;
> +
> +	drm_fbdev_cma_restore_mode(fbpriv->fbcma);
> +}
> +
> +static struct drm_driver intelvipfb_drm = {
> +	.driver_features =
> +	    DRIVER_GEM | DRIVER_PRIME |
> +	    DRIVER_RENDER | DRIVER_MODESET | DRIVER_ATOMIC,
> +	.gem_free_object_unlocked = drm_gem_cma_free_object,
> +	.gem_vm_ops = &drm_gem_cma_vm_ops,
> +	.dumb_create = drm_gem_cma_dumb_create,
> +	.dumb_map_offset = drm_gem_cma_dumb_map_offset,
> +	.dumb_destroy = drm_gem_dumb_destroy,
> +	.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
> +	.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
> +	.gem_prime_export = drm_gem_prime_export,
> +	.gem_prime_import = drm_gem_prime_import,
> +	.gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
> +	.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
> +	.gem_prime_vmap = drm_gem_cma_prime_vmap,
> +	.gem_prime_vunmap = drm_gem_cma_prime_vunmap,
> +	.gem_prime_mmap = drm_gem_cma_prime_mmap,
> +	.name = DRIVER_NAME,
> +	.date = "20170329",
> +	.desc = "Intel FPGA VIP SUITE",
> +	.major = 1,
> +	.minor = 0,
> +	.patchlevel = 0,
> +	.lastclose = intelvipfb_lastclose,
> +	.fops = &intelvipfb_drm_fops,
> +};
> +
> +static void intelvipfb_start_hw(void __iomem *base, resource_size_t addr)
> +{
> +	/*
> +	 * The frameinfo variable has to correspond to the size of the VIP Suite
> +	 * Frame Reader register 7 which will determine the maximum size used
> +	 * in this frameinfo
> +	 */
> +
> +	u32 frameinfo;
> +
> +	frameinfo =
> +		readl(base + INTELVIPFB_FRAME_READER) & 0x00ffffff;
> +
> +	writel(frameinfo, base + INTELVIPFB_FRAME_INFO);
> +
> +	writel(addr, base + INTELVIPFB_FRAME_START);
> +	/* Finally set the control register to 1 to start streaming */
> +	writel(1, base + INTELVIPFB_CONTROL);
> +}
> +
> +static void intelvipfb_disable_hw(void __iomem *base)
> +{
> +	/* set the control register to 0 to stop streaming */
> +	writel(0, base + INTELVIPFB_CONTROL);
> +}
> +
> +static void intelvipfb_output_poll_changed(struct drm_device *drm)
> +{
> +	struct intelvipfb_priv *fbpriv = drm->dev_private;
> +
> +	drm_fbdev_cma_hotplug_event(fbpriv->fbcma);
> +}
> +
> +static const struct drm_mode_config_funcs intelvipfb_mode_config_funcs = {
> +	.fb_create = drm_fb_cma_create,
> +	.output_poll_changed = intelvipfb_output_poll_changed,
> +	.atomic_check = drm_atomic_helper_check,
> +	.atomic_commit = drm_atomic_helper_commit,
> +};
> +
> +static struct drm_mode_config_helper_funcs intelvipfb_mode_config_helpers = {
> +	.atomic_commit_tail = drm_atomic_helper_commit_tail,
> +};
> +
> +static void intelvipfb_setup_mode_config(struct drm_device *drm,
> +					 struct fb_info *info)
> +{
> +	drm_mode_config_init(drm);
> +	drm->mode_config.min_width = 0;
> +	drm->mode_config.min_height = 0;
> +	drm->mode_config.max_width = info->var.xres;
> +	drm->mode_config.max_height = info->var.yres;
> +	drm->mode_config.preferred_depth = 32;
> +	drm->mode_config.funcs = &intelvipfb_mode_config_funcs;
> +	drm->mode_config.helper_private = &intelvipfb_mode_config_helpers;
> +}
> +
> +int intelvipfb_probe(struct device *dev, void __iomem *base)
> +{
> +	int retval;
> +	struct drm_device *drm;
> +	struct intelvipfb_priv *fbpriv = dev_get_drvdata(dev);
> +	struct fb_info *info = &fbpriv->info;
> +
> +	/*setup DRM */
> +	drm = drm_dev_alloc(&intelvipfb_drm, dev);
> +	if (IS_ERR(drm))
> +		return PTR_ERR(drm);
> +
> +	drm->dev_private = fbpriv;
> +
> +	dev_set_drvdata(dev, drm);
> +
> +	intelvipfb_setup_mode_config(drm, info);
> +
> +	retval = dma_set_mask_and_coherent(drm->dev, DMA_BIT_MASK(32));
> +	if (retval)
> +		return -ENODEV;
> +
> +	retval = intelvipfb_setup_crtc(drm);
> +	if (retval < 0)
> +		return -ENODEV;
> +
> +	retval = intelvipfb_drm_conn_init(drm);
> +	if (retval)
> +		return -ENOMEM;
> +
> +	drm_mode_config_reset(drm);
> +
> +	fbpriv->fbcma = drm_fbdev_cma_init(drm, PREF_BPP,
> +							CRTC_NUM, CONN_NUM);
> +	if (!fbpriv->fbcma) {
> +		fbpriv->fbcma = NULL;
> +		return -ENODEV;
> +	}
> +
> +	intelvipfb_start_hw(base, drm->mode_config.fb_base);
> +
> +	drm_kms_helper_poll_init(drm);
> +
> +	drm_dev_register(drm, 0);
> +
> +	return retval;
> +}
> +EXPORT_SYMBOL_GPL(intelvipfb_probe);
> +
> +int intelvipfb_remove(struct device *dev)
> +{
> +	struct drm_device *drm = dev_get_drvdata(dev);
> +	struct intelvipfb_priv *fbpriv = drm->dev_private;
> +
> +	drm_dev_unregister(drm);
> +
> +	drm_kms_helper_poll_fini(drm);
> +	drm_fbdev_cma_fini(fbpriv->fbcma);
> +
> +	intelvipfb_disable_hw(fbpriv->base);
> +
> +drm_mode_config_cleanup(drm);
> +
> +drm_dev_unref(drm);
> +
> +devm_kfree(dev, fbpriv);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(intelvipfb_remove);
> +
> +MODULE_AUTHOR("Ong, Hean-Loong <hean.loong.ong at intel.com>");
> +MODULE_DESCRIPTION("Intel VIP Frame Buffer II driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/gpu/drm/ivip/intel_vip_crtc.c b/drivers/gpu/drm/ivip/intel_vip_crtc.c
> new file mode 100644
> index 0000000..97a3954
> --- /dev/null
> +++ b/drivers/gpu/drm/ivip/intel_vip_crtc.c
> @@ -0,0 +1,161 @@
> +/*
> + * intel_vip_crtc.c -- Intel Video and Image Processing(VIP)
> + * Frame Buffer II driver
> + *
> + * This driver supports the Intel VIP Frame Reader component.
> + * More info on the hardware can be found in the Intel Video
> + * and Image Processing Suite User Guide at this address
> + * http://www.altera.com/literature/ug/ug_vip.pdf.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * Authors:
> + * Ong, Hean-Loong <hean.loong.ong at intel.com>
> + *
> + */
> +
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/platform_data/simplefb.h>
> +
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_fb_cma_helper.h>
> +#include <drm/drm_gem_cma_helper.h>
> +#include <drm/drm_plane_helper.h>
> +
> +#include "intel_vip_drv.h"
> +
> +static struct simplefb_format intelvipfb_formats[] = SIMPLEFB_FORMATS;

This looks like copypasta from simplefb? Please remove.

> +
> +static void intelvipfb_crtc_destroy(struct drm_crtc *crtc)
> +{
> +	drm_crtc_cleanup(crtc);
> +	kfree(crtc);
> +}
> +
> +static const struct drm_crtc_funcs intelvipfb_crtc_funcs = {
> +	.destroy = intelvipfb_crtc_destroy,
> +	.set_config = drm_atomic_helper_set_config,
> +	.page_flip = drm_atomic_helper_page_flip,
> +	.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 void intelvipfb_crtc_atomic_begin(struct drm_crtc *crtc,
> +					 struct drm_crtc_state *state)
> +{
> +	struct drm_pending_vblank_event *event = crtc->state->event;
> +
> +	if (event) {
> +		crtc->state->event = NULL;
> +
> +		spin_lock_irq(&crtc->dev->event_lock);
> +		drm_crtc_send_vblank_event(crtc, event);
> +		spin_unlock_irq(&crtc->dev->event_lock);
> +	}
> +}
> +
> +static void intelvipfb_crtc_nop(struct drm_crtc *crtc)
> +{
> +	/* do nothing */;
> +}

Again, don't fill out no-ops.

> +
> +static const struct drm_crtc_helper_funcs intelvipfb_crtc_helper_funcs = {
> +	.atomic_begin	= intelvipfb_crtc_atomic_begin,
> +	.enable = intelvipfb_crtc_nop,
> +};
> +
> +static void intelvipfb_plane_destroy(struct drm_plane *plane)
> +{
> +	drm_plane_helper_disable(plane);
> +	drm_plane_cleanup(plane);
> +}
> +
> +static const struct drm_plane_funcs intelvipfb_plane_funcs = {
> +	.update_plane		= drm_atomic_helper_update_plane,
> +	.disable_plane		= drm_atomic_helper_disable_plane,
> +	.destroy		= intelvipfb_plane_destroy,
> +	.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 void intelvipfb_plane_atomic_update(struct drm_plane *plane,
> +					   struct drm_plane_state *state)
> +{
> +	struct intelvipfb_priv *fbpriv;
> +	struct drm_gem_cma_object *gem;
> +
> +	if (!plane->state->crtc || !plane->state->fb)
> +		return;
> +
> +	fbpriv = plane->dev->dev_private;
> +	gem = drm_fb_cma_get_gem_obj(plane->state->fb, 0);
> +	writel(gem->paddr, fbpriv->base + INTELVIPFB_FRAME_START);
> +}
> +
> +static const struct drm_plane_helper_funcs intelvipfb_plane_helper_funcs = {
> +	.atomic_update = intelvipfb_plane_atomic_update,
> +};
> +
> +static struct drm_plane *intelvipfb_plane_init(struct drm_device *drm)
> +{
> +	struct drm_plane *plane = NULL;
> +	u32 formats[ARRAY_SIZE(intelvipfb_formats)], i;
> +	int ret;
> +
> +	plane = devm_kzalloc(drm->dev, sizeof(*plane), GFP_KERNEL);
> +	if (!plane)
> +		return ERR_PTR(-ENOMEM);
> +
> +	for (i = 0; i < ARRAY_SIZE(intelvipfb_formats); i++)
> +		formats[i] = intelvipfb_formats[i].fourcc;
> +
> +	ret = drm_universal_plane_init(drm, plane, 0xff,
> +				       &intelvipfb_plane_funcs,
> +				       formats, ARRAY_SIZE(formats),
> +				       DRM_PLANE_TYPE_PRIMARY, NULL);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	drm_plane_helper_add(plane, &intelvipfb_plane_helper_funcs);
> +
> +	return plane;
> +}
> +
> +int intelvipfb_setup_crtc(struct drm_device *drm)
> +{
> +	struct drm_crtc *crtc;
> +	struct drm_plane *primary;
> +	int ret;
> +
> +	crtc = kzalloc(sizeof(*crtc), GFP_KERNEL);
> +	if (!crtc)
> +		return -ENOMEM;
> +
> +	primary = intelvipfb_plane_init(drm);
> +	if (IS_ERR(primary))
> +		return PTR_ERR(primary);
> +
> +	ret = drm_crtc_init_with_planes(drm, crtc, primary, NULL,
> +					&intelvipfb_crtc_funcs, NULL);
> +
> +	if (ret) {
> +		intelvipfb_plane_destroy(primary);
> +		return ret;
> +	}
> +
> +	drm_crtc_helper_add(crtc, &intelvipfb_crtc_helper_funcs);
> +	return 0;
> +}

Looking at your driver overall, you really want to switch over to the
simple display pipe helpers. See https://dri.freedesktop.org/docs/drm/gpu/drm-kms-helpers.html#simple-kms-helper-reference

There's a few nice examples using this merged now, and a few more floating
around on the m-l. That will simplify your driver a lot.

> diff --git a/drivers/gpu/drm/ivip/intel_vip_drv.h b/drivers/gpu/drm/ivip/intel_vip_drv.h
> new file mode 100644
> index 0000000..657f23c
> --- /dev/null
> +++ b/drivers/gpu/drm/ivip/intel_vip_drv.h
> @@ -0,0 +1,55 @@
> +/*
> + * Copyright (C) 2017 Intel Corporation.
> + *
> + * Intel Video and Image Processing(VIP) Frame Buffer II driver.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + *
> + * Authors:
> + * Ong, Hean-Loong <hean.loong.ong at intel.com>
> + *
> + */
> +#ifndef _INTEL_VIP_DRV_H
> +#define _INTEL_VIP_DRV_H
> +#include <linux/io.h>
> +#include <linux/fb.h>
> +
> +#define DRIVER_NAME	"intelvipfb"
> +#define BYTES_PER_PIXEL	4
> +#define PREF_BPP		32
> +#define CRTC_NUM		1
> +#define CONN_NUM		1
> +
> +/* control registers */
> +#define INTELVIPFB_CONTROL		0
> +#define INTELVIPFB_STATUS		0x4
> +#define INTELVIPFB_INTERRUPT		0x8
> +#define INTELVIPFB_FRAME_COUNTER	0xC
> +#define INTELVIPFB_FRAME_DROP		0x10
> +#define INTELVIPFB_FRAME_INFO		0x14
> +#define INTELVIPFB_FRAME_START		0x18
> +#define INTELVIPFB_FRAME_READER		0x1C
> +
> +int intelvipfb_probe(struct device *dev, void __iomem *base);
> +int intelvipfb_remove(struct device *dev);
> +int intelvipfb_setup_crtc(struct drm_device *drm);
> +int intelvipfb_drm_conn_init(struct drm_device *drm);
> +
> +struct intelvipfb_priv {
> +	struct drm_fbdev_cma *fbcma;
> +	struct drm_device *drm;
> +	struct fb_info info;
> +	void	__iomem		*base;
> +};
> +
> +#endif
> diff --git a/drivers/gpu/drm/ivip/intel_vip_of.c b/drivers/gpu/drm/ivip/intel_vip_of.c
> new file mode 100644
> index 0000000..17dff36
> --- /dev/null
> +++ b/drivers/gpu/drm/ivip/intel_vip_of.c
> @@ -0,0 +1,146 @@
> +/*
> + * intel_vip_of.c -- Intel Video and Image Processing(VIP)
> + * Frame Buffer II driver
> + *
> + * This driver supports the Intel VIP Frame Reader component.
> + * More info on the hardware can be found in the Intel Video
> + * and Image Processing Suite User Guide at this address
> + * http://www.altera.com/literature/ug/ug_vip.pdf.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * Authors:
> + * Ong, Hean-Loong <hean.loong.ong at intel.com>
> + *
> + */
> +
> +#include <linux/fb.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +
> +#include <drm/drm_fb_helper.h>
> +#include "intel_vip_drv.h"
> +
> +/*
> + * Setting up information derived from OF Device Tree Nodes
> + * max-width, max-height, bits per pixel, memory port width
> + */
> +
> +static int intelvipfb_of_setup(struct intelvipfb_priv *fbdata,
> +			       struct platform_device *pdev)
> +{
> +	int ret;
> +	int mem_word_width;
> +	u32 bits_per_color;
> +	struct device_node *np = pdev->dev.of_node;
> +
> +	ret = of_property_read_u32(np, "altr,max-width",
> +				   &fbdata->info.var.xres);
> +	if (ret) {
> +		dev_err(&pdev->dev,
> +			"Missing required parameter 'altr,max-width'");
> +		return ret;
> +	}
> +	fbdata->info.var.xres_virtual = fbdata->info.var.xres;
> +
> +	ret = of_property_read_u32(np, "altr,max-height",
> +				   &fbdata->info.var.yres);
> +	if (ret) {
> +		dev_err(&pdev->dev,
> +			"Missing required parameter 'altr,max-height'");
> +		return ret;
> +	}
> +	fbdata->info.var.yres_virtual = fbdata->info.var.yres;
> +
> +	ret = of_property_read_u32(np, "altr,bits-per-symbol", &bits_per_color);
> +	if (ret) {
> +		dev_err(&pdev->dev,
> +			"Missing required parameter 'altr,bits-per-symbol'");
> +		return ret;
> +	}
> +
> +	fbdata->info.var.bits_per_pixel = bits_per_color * BYTES_PER_PIXEL;
> +
> +	ret = of_property_read_u32(np, "altr,mem-port-width", &mem_word_width);
> +	if (ret) {
> +		dev_err(&pdev->dev,
> +			"Missing required parameter 'altr,mem-port-width '");
> +		return ret;
> +	}
> +
> +	if (!(mem_word_width >= 32 && mem_word_width % 32 == 0)) {
> +		dev_err(&pdev->dev,
> +			"mem-word-width is set to %i. must be >= 32 and multiple of 32.",
> +			 mem_word_width);
> +		return -ENODEV;
> +	}
> +
> +	return 0;
> +}

I think we want this as a generic helper in drm_of.c, and instead of going
through the fbdev/legacy struct fb_info, directly fill out
drm_device->mode_config.

This assumes ofc that this is a generic DT thing. If not, then please
remove the fb_info indirection, I guess this is porting leftovers from
this being an fb driver?

> +
> +static int intelvipfb_of_probe(struct platform_device *pdev)
> +{
> +	int retval;
> +	struct resource *reg_res;
> +	struct intelvipfb_priv *fbdata;
> +
> +	fbdata = devm_kzalloc(&pdev->dev, sizeof(*fbdata), GFP_KERNEL);
> +	if (!fbdata)
> +		return -ENOMEM;
> +
> +	reg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!reg_res)
> +		return -ENOMEM;
> +
> +	fbdata->base = devm_ioremap_resource(&pdev->dev, reg_res);
> +
> +	if (IS_ERR(fbdata->base)) {
> +		dev_err(&pdev->dev, "devm_ioremap_resource failed\n");
> +		retval = PTR_ERR(fbdata->base);
> +		return -ENOMEM;
> +	}
> +
> +	intelvipfb_of_setup(fbdata, pdev);
> +
> +	platform_set_drvdata(pdev, fbdata);
> +
> +	return intelvipfb_probe(&pdev->dev, fbdata->base);
> +}
> +
> +static int intelvipfb_of_remove(struct platform_device *pdev)
> +{
> +	return intelvipfb_remove(&pdev->dev);
> +}
> +
> +/*
> + * The name vip-frame-buffer-2.0 is derived from
> + * http://www.altera.com/literature/ug/ug_vip.pdf
> + * frame buffer IP cores section 14
> + */
> +
> +static const struct of_device_id intelvipfb_of_match[] = {
> +	{ .compatible = "altr,vip-frame-buffer-2.0" },
> +	{},
> +};
> +
> +MODULE_DEVICE_TABLE(of, intelvipfb_of_match);
> +
> +static struct platform_driver intelvipfb_driver = {
> +	.probe = intelvipfb_of_probe,
> +	.remove = intelvipfb_of_remove,
> +	.driver = {
> +		.name = DRIVER_NAME,
> +		.of_match_table = intelvipfb_of_match,
> +	},
> +};
> +
> +module_platform_driver(intelvipfb_driver);
> -- 
> 1.7.1
> 

> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel


-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch


More information about the dri-devel mailing list