Skip to content

Commit

Permalink
Merge tag 'zxdrm-4.10' of git://git.kernel.org/pub/scm/linux/kernel/g…
Browse files Browse the repository at this point in the history
…it/shawnguo/linux into drm-next

ZTE zxdrm driver support for 4.10:

This is the initial ZTE VOU display controller DRM/KMS driver.  There
are still some features to be added, like overlay plane, scaling, and
more output devices support.  But it's already useful with dual CRTCs
and HDMI display working.

[airlied: use drm_format_plane_cpp instead of legacy api]
* tag 'zxdrm-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux:
  MAINTAINERS: add an entry for ZTE ZX DRM driver
  drm: zte: add initial vou drm driver
  dt-bindings: add bindings doc for ZTE VOU display controller
  • Loading branch information
Dave Airlie committed Nov 11, 2016
2 parents c765102 + dbb0103 commit d8c1abd
Show file tree
Hide file tree
Showing 16 changed files with 2,372 additions and 0 deletions.
84 changes: 84 additions & 0 deletions Documentation/devicetree/bindings/display/zte,vou.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
ZTE VOU Display Controller

This is a display controller found on ZTE ZX296718 SoC. It includes multiple
Graphic Layer (GL) and Video Layer (VL), two Mixers/Channels, and a few blocks
handling scaling, color space conversion etc. VOU also integrates the support
for typical output devices, like HDMI, TV Encoder, VGA, and RGB LCD.

* Master VOU node

It must be the parent node of all the sub-device nodes.

Required properties:
- compatible: should be "zte,zx296718-vou"
- #address-cells: should be <1>
- #size-cells: should be <1>
- ranges: list of address translations between VOU and sub-devices

* VOU DPC device

Required properties:
- compatible: should be "zte,zx296718-dpc"
- reg: Physical base address and length of DPC register regions, one for each
entry in 'reg-names'
- reg-names: The names of register regions. The following regions are required:
"osd"
"timing_ctrl"
"dtrc"
"vou_ctrl"
"otfppu"
- interrupts: VOU DPC interrupt number to CPU
- clocks: A list of phandle + clock-specifier pairs, one for each entry
in 'clock-names'
- clock-names: A list of clock names. The following clocks are required:
"aclk"
"ppu_wclk"
"main_wclk"
"aux_wclk"

* HDMI output device

Required properties:
- compatible: should be "zte,zx296718-hdmi"
- reg: Physical base address and length of the HDMI device IO region
- interrupts : HDMI interrupt number to CPU
- clocks: A list of phandle + clock-specifier pairs, one for each entry
in 'clock-names'
- clock-names: A list of clock names. The following clocks are required:
"osc_cec"
"osc_clk"
"xclk"

Example:

vou: vou@1440000 {
compatible = "zte,zx296718-vou";
#address-cells = <1>;
#size-cells = <1>;
ranges = <0 0x1440000 0x10000>;

dpc: dpc@0 {
compatible = "zte,zx296718-dpc";
reg = <0x0000 0x1000>, <0x1000 0x1000>,
<0x5000 0x1000>, <0x6000 0x1000>,
<0xa000 0x1000>;
reg-names = "osd", "timing_ctrl",
"dtrc", "vou_ctrl",
"otfppu";
interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&topcrm VOU_ACLK>, <&topcrm VOU_PPU_WCLK>,
<&topcrm VOU_MAIN_WCLK>, <&topcrm VOU_AUX_WCLK>;
clock-names = "aclk", "ppu_wclk",
"main_wclk", "aux_wclk";
};

hdmi: hdmi@c000 {
compatible = "zte,zx296718-hdmi";
reg = <0xc000 0x4000>;
interrupts = <GIC_SPI 82 IRQ_TYPE_EDGE_RISING>;
clocks = <&topcrm HDMI_OSC_CEC>,
<&topcrm HDMI_OSC_CLK>,
<&topcrm HDMI_XCLK>;
clock-names = "osc_cec", "osc_clk", "xclk";
};
};
7 changes: 7 additions & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -4298,6 +4298,13 @@ S: Maintained
F: drivers/gpu/drm/tilcdc/
F: Documentation/devicetree/bindings/display/tilcdc/

DRM DRIVERS FOR ZTE ZX
M: Shawn Guo <shawnguo@kernel.org>
L: dri-devel@lists.freedesktop.org
S: Maintained
F: drivers/gpu/drm/zte/
F: Documentation/devicetree/bindings/display/zte,vou.txt

DSBR100 USB FM RADIO DRIVER
M: Alexey Klimov <klimov.linux@gmail.com>
L: linux-media@vger.kernel.org
Expand Down
2 changes: 2 additions & 0 deletions drivers/gpu/drm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,8 @@ source "drivers/gpu/drm/hisilicon/Kconfig"

source "drivers/gpu/drm/mediatek/Kconfig"

source "drivers/gpu/drm/zte/Kconfig"

# Keep legacy drivers last

menuconfig DRM_LEGACY
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,4 @@ obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/
obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/
obj-$(CONFIG_DRM_ARCPGU)+= arc/
obj-y += hisilicon/
obj-$(CONFIG_DRM_ZTE) += zte/
8 changes: 8 additions & 0 deletions drivers/gpu/drm/zte/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
config DRM_ZTE
tristate "DRM Support for ZTE SoCs"
depends on DRM && ARCH_ZX
select DRM_KMS_CMA_HELPER
select DRM_KMS_FB_HELPER
select DRM_KMS_HELPER
help
Choose this option to enable DRM on ZTE ZX SoCs.
7 changes: 7 additions & 0 deletions drivers/gpu/drm/zte/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
zxdrm-y := \
zx_drm_drv.o \
zx_hdmi.o \
zx_plane.o \
zx_vou.o

obj-$(CONFIG_DRM_ZTE) += zxdrm.o
267 changes: 267 additions & 0 deletions drivers/gpu/drm/zte/zx_drm_drv.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
/*
* Copyright 2016 Linaro Ltd.
* Copyright 2016 ZTE Corporation.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/

#include <linux/clk.h>
#include <linux/component.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/of_graph.h>
#include <linux/of_platform.h>
#include <linux/spinlock.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_fb_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_of.h>
#include <drm/drmP.h>

#include "zx_drm_drv.h"
#include "zx_vou.h"

struct zx_drm_private {
struct drm_fbdev_cma *fbdev;
};

static void zx_drm_fb_output_poll_changed(struct drm_device *drm)
{
struct zx_drm_private *priv = drm->dev_private;

drm_fbdev_cma_hotplug_event(priv->fbdev);
}

static const struct drm_mode_config_funcs zx_drm_mode_config_funcs = {
.fb_create = drm_fb_cma_create,
.output_poll_changed = zx_drm_fb_output_poll_changed,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
};

static void zx_drm_lastclose(struct drm_device *drm)
{
struct zx_drm_private *priv = drm->dev_private;

drm_fbdev_cma_restore_mode(priv->fbdev);
}

static const struct file_operations zx_drm_fops = {
.owner = THIS_MODULE,
.open = drm_open,
.release = drm_release,
.unlocked_ioctl = drm_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = drm_compat_ioctl,
#endif
.poll = drm_poll,
.read = drm_read,
.llseek = noop_llseek,
.mmap = drm_gem_cma_mmap,
};

static struct drm_driver zx_drm_driver = {
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
DRIVER_ATOMIC,
.lastclose = zx_drm_lastclose,
.get_vblank_counter = drm_vblank_no_hw_counter,
.enable_vblank = zx_vou_enable_vblank,
.disable_vblank = zx_vou_disable_vblank,
.gem_free_object = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops,
.dumb_create = drm_gem_cma_dumb_create,
.dumb_map_offset = drm_gem_cma_dumb_map_offset,
.dumb_destroy = drm_gem_dumb_destroy,
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
.gem_prime_export = 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,
.fops = &zx_drm_fops,
.name = "zx-vou",
.desc = "ZTE VOU Controller DRM",
.date = "20160811",
.major = 1,
.minor = 0,
};

static int zx_drm_bind(struct device *dev)
{
struct drm_device *drm;
struct zx_drm_private *priv;
int ret;

priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;

drm = drm_dev_alloc(&zx_drm_driver, dev);
if (!drm)
return -ENOMEM;

drm->dev_private = priv;
dev_set_drvdata(dev, drm);

drm_mode_config_init(drm);
drm->mode_config.min_width = 16;
drm->mode_config.min_height = 16;
drm->mode_config.max_width = 4096;
drm->mode_config.max_height = 4096;
drm->mode_config.funcs = &zx_drm_mode_config_funcs;

ret = component_bind_all(dev, drm);
if (ret) {
DRM_DEV_ERROR(dev, "failed to bind all components: %d\n", ret);
goto out_unregister;
}

ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
if (ret < 0) {
DRM_DEV_ERROR(dev, "failed to init vblank: %d\n", ret);
goto out_unbind;
}

/*
* We will manage irq handler on our own. In this case, irq_enabled
* need to be true for using vblank core support.
*/
drm->irq_enabled = true;

drm_mode_config_reset(drm);
drm_kms_helper_poll_init(drm);

priv->fbdev = drm_fbdev_cma_init(drm, 32, drm->mode_config.num_crtc,
drm->mode_config.num_connector);
if (IS_ERR(priv->fbdev)) {
ret = PTR_ERR(priv->fbdev);
DRM_DEV_ERROR(dev, "failed to init cma fbdev: %d\n", ret);
priv->fbdev = NULL;
goto out_poll_fini;
}

ret = drm_dev_register(drm, 0);
if (ret)
goto out_fbdev_fini;

return 0;

out_fbdev_fini:
if (priv->fbdev) {
drm_fbdev_cma_fini(priv->fbdev);
priv->fbdev = NULL;
}
out_poll_fini:
drm_kms_helper_poll_fini(drm);
drm_mode_config_cleanup(drm);
drm_vblank_cleanup(drm);
out_unbind:
component_unbind_all(dev, drm);
out_unregister:
dev_set_drvdata(dev, NULL);
drm->dev_private = NULL;
drm_dev_unref(drm);
return ret;
}

static void zx_drm_unbind(struct device *dev)
{
struct drm_device *drm = dev_get_drvdata(dev);
struct zx_drm_private *priv = drm->dev_private;

drm_dev_unregister(drm);
if (priv->fbdev) {
drm_fbdev_cma_fini(priv->fbdev);
priv->fbdev = NULL;
}
drm_kms_helper_poll_fini(drm);
drm_mode_config_cleanup(drm);
drm_vblank_cleanup(drm);
component_unbind_all(dev, drm);
dev_set_drvdata(dev, NULL);
drm->dev_private = NULL;
drm_dev_unref(drm);
}

static const struct component_master_ops zx_drm_master_ops = {
.bind = zx_drm_bind,
.unbind = zx_drm_unbind,
};

static int compare_of(struct device *dev, void *data)
{
return dev->of_node == data;
}

static int zx_drm_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *parent = dev->of_node;
struct device_node *child;
struct component_match *match = NULL;
int ret;

ret = of_platform_populate(parent, NULL, NULL, dev);
if (ret)
return ret;

for_each_available_child_of_node(parent, child) {
component_match_add(dev, &match, compare_of, child);
of_node_put(child);
}

return component_master_add_with_match(dev, &zx_drm_master_ops, match);
}

static int zx_drm_remove(struct platform_device *pdev)
{
component_master_del(&pdev->dev, &zx_drm_master_ops);
return 0;
}

static const struct of_device_id zx_drm_of_match[] = {
{ .compatible = "zte,zx296718-vou", },
{ /* end */ },
};
MODULE_DEVICE_TABLE(of, zx_drm_of_match);

static struct platform_driver zx_drm_platform_driver = {
.probe = zx_drm_probe,
.remove = zx_drm_remove,
.driver = {
.name = "zx-drm",
.of_match_table = zx_drm_of_match,
},
};

static struct platform_driver *drivers[] = {
&zx_crtc_driver,
&zx_hdmi_driver,
&zx_drm_platform_driver,
};

static int zx_drm_init(void)
{
return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
}
module_init(zx_drm_init);

static void zx_drm_exit(void)
{
platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
}
module_exit(zx_drm_exit);

MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
MODULE_DESCRIPTION("ZTE ZX VOU DRM driver");
MODULE_LICENSE("GPL v2");
Loading

0 comments on commit d8c1abd

Please sign in to comment.