Commit d8c1abd9 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'zxdrm-4.10' of...

Merge tag 'zxdrm-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/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
parents c765102a dbb01037
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";
};
};
...@@ -4298,6 +4298,13 @@ S: Maintained ...@@ -4298,6 +4298,13 @@ S: Maintained
F: drivers/gpu/drm/tilcdc/ F: drivers/gpu/drm/tilcdc/
F: Documentation/devicetree/bindings/display/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 DSBR100 USB FM RADIO DRIVER
M: Alexey Klimov <klimov.linux@gmail.com> M: Alexey Klimov <klimov.linux@gmail.com>
L: linux-media@vger.kernel.org L: linux-media@vger.kernel.org
......
...@@ -237,6 +237,8 @@ source "drivers/gpu/drm/hisilicon/Kconfig" ...@@ -237,6 +237,8 @@ source "drivers/gpu/drm/hisilicon/Kconfig"
source "drivers/gpu/drm/mediatek/Kconfig" source "drivers/gpu/drm/mediatek/Kconfig"
source "drivers/gpu/drm/zte/Kconfig"
# Keep legacy drivers last # Keep legacy drivers last
menuconfig DRM_LEGACY menuconfig DRM_LEGACY
......
...@@ -87,3 +87,4 @@ obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/ ...@@ -87,3 +87,4 @@ obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/
obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/ obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/
obj-$(CONFIG_DRM_ARCPGU)+= arc/ obj-$(CONFIG_DRM_ARCPGU)+= arc/
obj-y += hisilicon/ obj-y += hisilicon/
obj-$(CONFIG_DRM_ZTE) += zte/
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.
zxdrm-y := \
zx_drm_drv.o \
zx_hdmi.o \
zx_plane.o \
zx_vou.o
obj-$(CONFIG_DRM_ZTE) += zxdrm.o
/*
* 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");
/*
* 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.
*
*/
#ifndef __ZX_DRM_DRV_H__
#define __ZX_DRM_DRV_H__
extern struct platform_driver zx_crtc_driver;
extern struct platform_driver zx_hdmi_driver;
static inline u32 zx_readl(void __iomem *reg)
{
return readl_relaxed(reg);
}
static inline void zx_writel(void __iomem *reg, u32 val)
{
writel_relaxed(val, reg);
}
static inline void zx_writel_mask(void __iomem *reg, u32 mask, u32 val)
{
u32 tmp;
tmp = zx_readl(reg);
tmp = (tmp & ~mask) | (val & mask);
zx_writel(reg, tmp);
}
#endif /* __ZX_DRM_DRV_H__ */
This diff is collapsed.
/*
* 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.
*
*/
#ifndef __ZX_HDMI_REGS_H__
#define __ZX_HDMI_REGS_H__
#define FUNC_SEL 0x000b
#define FUNC_HDMI_EN BIT(0)
#define CLKPWD 0x000d
#define CLKPWD_PDIDCK BIT(2)
#define P2T_CTRL 0x0066
#define P2T_DC_PKT_EN BIT(7)
#define L1_INTR_STAT 0x007e
#define L1_INTR_STAT_INTR1 BIT(0)
#define INTR1_STAT 0x008f
#define INTR1_MASK 0x0095
#define INTR1_MONITOR_DETECT (BIT(5) | BIT(6))
#define ZX_DDC_ADDR 0x00ed
#define ZX_DDC_SEGM 0x00ee
#define ZX_DDC_OFFSET 0x00ef
#define ZX_DDC_DIN_CNT1 0x00f0
#define ZX_DDC_DIN_CNT2 0x00f1
#define ZX_DDC_CMD 0x00f3
#define DDC_CMD_MASK 0xf
#define DDC_CMD_CLEAR_FIFO 0x9
#define DDC_CMD_SEQUENTIAL_READ 0x2
#define ZX_DDC_DATA 0x00f4
#define ZX_DDC_DOUT_CNT 0x00f5
#define DDC_DOUT_CNT_MASK 0x1f
#define TEST_TXCTRL 0x00f7
#define TEST_TXCTRL_HDMI_MODE BIT(1)
#define HDMICTL4 0x0235
#define TPI_HPD_RSEN 0x063b
#define TPI_HPD_CONNECTION (BIT(1) | BIT(2))
#define TPI_INFO_FSEL 0x06bf
#define FSEL_AVI 0
#define FSEL_GBD 1
#define FSEL_AUDIO 2
#define FSEL_SPD 3
#define FSEL_MPEG 4
#define FSEL_VSIF 5
#define TPI_INFO_B0 0x06c0
#define TPI_INFO_EN 0x06df
#define TPI_INFO_TRANS_EN BIT(7)
#define TPI_INFO_TRANS_RPT BIT(6)
#define TPI_DDC_MASTER_EN 0x06f8
#define HW_DDC_MASTER BIT(7)
#endif /* __ZX_HDMI_REGS_H__ */
/*
* 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 <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_plane_helper.h>
#include <drm/drmP.h>
#include "zx_drm_drv.h"
#include "zx_plane.h"
#include "zx_plane_regs.h"
#include "zx_vou.h"
struct zx_plane {
struct drm_plane plane;
void __iomem *layer;
void __iomem *csc;
void __iomem *hbsc;
void __iomem *rsz;
};
#define to_zx_plane(plane) container_of(plane, struct zx_plane, plane)
static const uint32_t gl_formats[] = {
DRM_FORMAT_ARGB8888,
DRM_FORMAT_XRGB8888,
DRM_FORMAT_RGB888,
DRM_FORMAT_RGB565,
DRM_FORMAT_ARGB1555,
DRM_FORMAT_ARGB4444,
};
static int zx_gl_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *plane_state)
{
struct drm_framebuffer *fb = plane_state->fb;
struct drm_crtc *crtc = plane_state->crtc;
struct drm_crtc_state *crtc_state;
struct drm_rect clip;
if (!crtc || !fb)
return 0;
crtc_state = drm_atomic_get_existing_crtc_state(plane_state->state,
crtc);
if (WARN_ON(!crtc_state))
return -EINVAL;
/* nothing to check when disabling or disabled */
if (!crtc_state->enable)
return 0;
/* plane must be enabled */
if (!plane_state->crtc)
return -EINVAL;
clip.x1 = 0;
clip.y1 = 0;
clip.x2 = crtc_state->adjusted_mode.hdisplay;
clip.y2 = crtc_state->adjusted_mode.vdisplay;
return drm_plane_helper_check_state(plane_state, &clip,
DRM_PLANE_HELPER_NO_SCALING,
DRM_PLANE_HELPER_NO_SCALING,
false, true);
}
static int zx_gl_get_fmt(uint32_t format)
{
switch (format) {
case DRM_FORMAT_ARGB8888:
case DRM_FORMAT_XRGB8888:
return GL_FMT_ARGB8888;
case DRM_FORMAT_RGB888:
return GL_FMT_RGB888;
case DRM_FORMAT_RGB565:
return GL_FMT_RGB565;
case DRM_FORMAT_ARGB1555:
return GL_FMT_ARGB1555;
case DRM_FORMAT_ARGB4444:
return GL_FMT_ARGB4444;
default:
WARN_ONCE(1, "invalid pixel format %d\n", format);
return -EINVAL;
}
}
static inline void zx_gl_set_update(struct zx_plane *zplane)
{
void __iomem *layer = zplane->layer;
zx_writel_mask(layer + GL_CTRL0, GL_UPDATE, GL_UPDATE);
}
static inline void zx_gl_rsz_set_update(struct zx_plane *zplane)
{
zx_writel(zplane->rsz + RSZ_ENABLE_CFG, 1);
}
void zx_plane_set_update(struct drm_plane *plane)
{
struct zx_plane *zplane = to_zx_plane(plane);
zx_gl_rsz_set_update(zplane);
zx_gl_set_update(zplane);
}
static void zx_gl_rsz_setup(struct zx_plane *zplane, u32 src_w, u32 src_h,
u32 dst_w, u32 dst_h)
{
void __iomem *rsz = zplane->rsz;
zx_writel(rsz + RSZ_SRC_CFG, RSZ_VER(src_h - 1) | RSZ_HOR(src_w - 1));
zx_writel(rsz + RSZ_DEST_CFG, RSZ_VER(dst_h - 1) | RSZ_HOR(dst_w - 1));
zx_gl_rsz_set_update(zplane);
}
static void zx_gl_plane_atomic_update(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
struct zx_plane *zplane = to_zx_plane(plane);
struct drm_framebuffer *fb = plane->state->fb;
struct drm_gem_cma_object *cma_obj;
void __iomem *layer = zplane->layer;
void __iomem *csc = zplane->csc;
void __iomem *hbsc = zplane->hbsc;
u32 src_x, src_y, src_w, src_h;
u32 dst_x, dst_y, dst_w, dst_h;
unsigned int bpp;
uint32_t format;
dma_addr_t paddr;
u32 stride;
int fmt;
if (!fb)
return;
format = fb->pixel_format;
stride = fb->pitches[0];
src_x = plane->state->src_x >> 16;
src_y = plane->state->src_y >> 16;
src_w = plane->state->src_w >> 16;
src_h = plane->state->src_h >> 16;
dst_x = plane->state->crtc_x;
dst_y = plane->state->crtc_y;
dst_w = plane->state->crtc_w;
dst_h = plane->state->crtc_h;
bpp = drm_format_plane_cpp(format, 0);
cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
paddr = cma_obj->paddr + fb->offsets[0];
paddr += src_y * stride + src_x * bpp / 8;
zx_writel(layer + GL_ADDR, paddr);
/* Set up source height/width register */
zx_writel(layer + GL_SRC_SIZE, GL_SRC_W(src_w) | GL_SRC_H(src_h));
/* Set up start position register */
zx_writel(layer + GL_POS_START, GL_POS_X(dst_x) | GL_POS_Y(dst_y));
/* Set up end position register */
zx_writel(layer + GL_POS_END,
GL_POS_X(dst_x + dst_w) | GL_POS_Y(dst_y + dst_h));
/* Set up stride register */
zx_writel(layer + GL_STRIDE, stride & 0xffff);
/* Set up graphic layer data format */
fmt = zx_gl_get_fmt(format);
if (fmt >= 0)
zx_writel_mask(layer + GL_CTRL1, GL_DATA_FMT_MASK,
fmt << GL_DATA_FMT_SHIFT);
/* Initialize global alpha with a sane value */
zx_writel_mask(layer + GL_CTRL2, GL_GLOBAL_ALPHA_MASK,
0xff << GL_GLOBAL_ALPHA_SHIFT);
/* Setup CSC for the GL */
if (dst_h > 720)
zx_writel_mask(csc + CSC_CTRL0, CSC_COV_MODE_MASK,
CSC_BT709_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT);
else
zx_writel_mask(csc + CSC_CTRL0, CSC_COV_MODE_MASK,
CSC_BT601_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT);
zx_writel_mask(csc + CSC_CTRL0, CSC_WORK_ENABLE, CSC_WORK_ENABLE);
/* Always use scaler since it exists (set for not bypass) */
zx_writel_mask(layer + GL_CTRL3, GL_SCALER_BYPASS_MODE,
GL_SCALER_BYPASS_MODE);
zx_gl_rsz_setup(zplane, src_w, src_h, dst_w, dst_h);
/* Enable HBSC block */
zx_writel_mask(hbsc + HBSC_CTRL0, HBSC_CTRL_EN, HBSC_CTRL_EN);
zx_gl_set_update(zplane);
}
static const struct drm_plane_helper_funcs zx_gl_plane_helper_funcs = {
.atomic_check = zx_gl_plane_atomic_check,
.atomic_update = zx_gl_plane_atomic_update,
};
static void zx_plane_destroy(struct drm_plane *plane)
{
drm_plane_helper_disable(plane);
drm_plane_cleanup(plane);
}
static const struct drm_plane_funcs zx_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane,
.destroy = zx_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 zx_plane_hbsc_init(struct zx_plane *zplane)
{
void __iomem *hbsc = zplane->hbsc;
/*
* Initialize HBSC block with a sane configuration per recommedation
* from ZTE BSP code.
*/
zx_writel(hbsc + HBSC_SATURATION, 0x200);
zx_writel(hbsc + HBSC_HUE, 0x0);
zx_writel(hbsc + HBSC_BRIGHT, 0x0);
zx_writel(hbsc + HBSC_CONTRAST, 0x200);
zx_writel(hbsc + HBSC_THRESHOLD_COL1, (0x3ac << 16) | 0x40);
zx_writel(hbsc + HBSC_THRESHOLD_COL2, (0x3c0 << 16) | 0x40);
zx_writel(hbsc + HBSC_THRESHOLD_COL3, (0x3c0 << 16) | 0x40);
}
struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev,
struct zx_layer_data *data,
enum drm_plane_type type)
{
const struct drm_plane_helper_funcs *helper;
struct zx_plane *zplane;
struct drm_plane *plane;
const uint32_t *formats;
unsigned int format_count;
int ret;
zplane = devm_kzalloc(dev, sizeof(*zplane), GFP_KERNEL);
if (!zplane)
return ERR_PTR(-ENOMEM);
plane = &zplane->plane;
zplane->layer = data->layer;
zplane->hbsc = data->hbsc;
zplane->csc = data->csc;
zplane->rsz = data->rsz;
zx_plane_hbsc_init(zplane);
switch (type) {
case DRM_PLANE_TYPE_PRIMARY:
helper = &zx_gl_plane_helper_funcs;
formats = gl_formats;
format_count = ARRAY_SIZE(gl_formats);
break;
case DRM_PLANE_TYPE_OVERLAY:
/* TODO: add video layer (vl) support */
break;
default:
return ERR_PTR(-ENODEV);
}
ret = drm_universal_plane_init(drm, plane, VOU_CRTC_MASK,
&zx_plane_funcs, formats, format_count,
type, NULL);
if (ret) {
DRM_DEV_ERROR(dev, "failed to init universal plane: %d\n", ret);
return ERR_PTR(ret);
}
drm_plane_helper_add(plane, helper);
return plane;
}
/*
* 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.
*
*/
#ifndef __ZX_PLANE_H__
#define __ZX_PLANE_H__
struct zx_layer_data {
void __iomem *layer;
void __iomem *csc;
void __iomem *hbsc;
void __iomem *rsz;
};
struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev,
struct zx_layer_data *data,
enum drm_plane_type type);
void zx_plane_set_update(struct drm_plane *plane);
#endif /* __ZX_PLANE_H__ */
/*
* 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.
*
*/
#ifndef __ZX_PLANE_REGS_H__
#define __ZX_PLANE_REGS_H__
/* GL registers */
#define GL_CTRL0 0x00
#define GL_UPDATE BIT(5)
#define GL_CTRL1 0x04
#define GL_DATA_FMT_SHIFT 0
#define GL_DATA_FMT_MASK (0xf << GL_DATA_FMT_SHIFT)
#define GL_FMT_ARGB8888 0
#define GL_FMT_RGB888 1
#define GL_FMT_RGB565 2
#define GL_FMT_ARGB1555 3
#define GL_FMT_ARGB4444 4
#define GL_CTRL2 0x08
#define GL_GLOBAL_ALPHA_SHIFT 8
#define GL_GLOBAL_ALPHA_MASK (0xff << GL_GLOBAL_ALPHA_SHIFT)
#define GL_CTRL3 0x0c
#define GL_SCALER_BYPASS_MODE BIT(0)
#define GL_STRIDE 0x18
#define GL_ADDR 0x1c
#define GL_SRC_SIZE 0x38
#define GL_SRC_W_SHIFT 16
#define GL_SRC_W_MASK (0x3fff << GL_SRC_W_SHIFT)
#define GL_SRC_H_SHIFT 0
#define GL_SRC_H_MASK (0x3fff << GL_SRC_H_SHIFT)
#define GL_POS_START 0x9c
#define GL_POS_END 0xa0
#define GL_POS_X_SHIFT 16
#define GL_POS_X_MASK (0x1fff << GL_POS_X_SHIFT)
#define GL_POS_Y_SHIFT 0
#define GL_POS_Y_MASK (0x1fff << GL_POS_Y_SHIFT)
#define GL_SRC_W(x) (((x) << GL_SRC_W_SHIFT) & GL_SRC_W_MASK)
#define GL_SRC_H(x) (((x) << GL_SRC_H_SHIFT) & GL_SRC_H_MASK)
#define GL_POS_X(x) (((x) << GL_POS_X_SHIFT) & GL_POS_X_MASK)
#define GL_POS_Y(x) (((x) << GL_POS_Y_SHIFT) & GL_POS_Y_MASK)
/* CSC registers */
#define CSC_CTRL0 0x30
#define CSC_COV_MODE_SHIFT 16
#define CSC_COV_MODE_MASK (0xffff << CSC_COV_MODE_SHIFT)
#define CSC_BT601_IMAGE_RGB2YCBCR 0
#define CSC_BT601_IMAGE_YCBCR2RGB 1
#define CSC_BT601_VIDEO_RGB2YCBCR 2
#define CSC_BT601_VIDEO_YCBCR2RGB 3
#define CSC_BT709_IMAGE_RGB2YCBCR 4
#define CSC_BT709_IMAGE_YCBCR2RGB 5
#define CSC_BT709_VIDEO_RGB2YCBCR 6
#define CSC_BT709_VIDEO_YCBCR2RGB 7
#define CSC_BT2020_IMAGE_RGB2YCBCR 8
#define CSC_BT2020_IMAGE_YCBCR2RGB 9
#define CSC_BT2020_VIDEO_RGB2YCBCR 10
#define CSC_BT2020_VIDEO_YCBCR2RGB 11
#define CSC_WORK_ENABLE BIT(0)
/* RSZ registers */
#define RSZ_SRC_CFG 0x00
#define RSZ_DEST_CFG 0x04
#define RSZ_ENABLE_CFG 0x14
#define RSZ_VER_SHIFT 16
#define RSZ_VER_MASK (0xffff << RSZ_VER_SHIFT)
#define RSZ_HOR_SHIFT 0
#define RSZ_HOR_MASK (0xffff << RSZ_HOR_SHIFT)
#define RSZ_VER(x) (((x) << RSZ_VER_SHIFT) & RSZ_VER_MASK)
#define RSZ_HOR(x) (((x) << RSZ_HOR_SHIFT) & RSZ_HOR_MASK)
/* HBSC registers */
#define HBSC_SATURATION 0x00
#define HBSC_HUE 0x04
#define HBSC_BRIGHT 0x08
#define HBSC_CONTRAST 0x0c
#define HBSC_THRESHOLD_COL1 0x10
#define HBSC_THRESHOLD_COL2 0x14
#define HBSC_THRESHOLD_COL3 0x18
#define HBSC_CTRL0 0x28
#define HBSC_CTRL_EN BIT(2)
#endif /* __ZX_PLANE_REGS_H__ */
This diff is collapsed.
/*
* 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.
*
*/
#ifndef __ZX_VOU_H__
#define __ZX_VOU_H__
#define VOU_CRTC_MASK 0x3
/* VOU output interfaces */
enum vou_inf_id {
VOU_HDMI = 0,
VOU_RGB_LCD = 1,
VOU_TV_ENC = 2,
VOU_MIPI_DSI = 3,
VOU_LVDS = 4,
VOU_VGA = 5,
};
enum vou_inf_data_sel {
VOU_YUV444 = 0,
VOU_RGB_101010 = 1,
VOU_RGB_888 = 2,
VOU_RGB_666 = 3,
};
struct vou_inf {
enum vou_inf_id id;
enum vou_inf_data_sel data_sel;
u32 clocks_en_bits;
u32 clocks_sel_bits;
};
void vou_inf_enable(const struct vou_inf *inf, struct drm_crtc *crtc);
void vou_inf_disable(const struct vou_inf *inf, struct drm_crtc *crtc);
int zx_vou_enable_vblank(struct drm_device *drm, unsigned int pipe);
void zx_vou_disable_vblank(struct drm_device *drm, unsigned int pipe);
#endif /* __ZX_VOU_H__ */
/*
* 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.
*
*/
#ifndef __ZX_VOU_REGS_H__
#define __ZX_VOU_REGS_H__
/* Sub-module offset */
#define MAIN_GL_OFFSET 0x130
#define MAIN_CSC_OFFSET 0x580
#define MAIN_HBSC_OFFSET 0x820
#define MAIN_RSZ_OFFSET 0x600 /* OTFPPU sub-module */
#define AUX_GL_OFFSET 0x200
#define AUX_CSC_OFFSET 0x5d0
#define AUX_HBSC_OFFSET 0x860
#define AUX_RSZ_OFFSET 0x800
/* OSD (GPC_GLOBAL) registers */
#define OSD_INT_STA 0x04
#define OSD_INT_CLRSTA 0x08
#define OSD_INT_MSK 0x0c
#define OSD_INT_AUX_UPT BIT(14)
#define OSD_INT_MAIN_UPT BIT(13)
#define OSD_INT_GL1_LBW BIT(10)
#define OSD_INT_GL0_LBW BIT(9)
#define OSD_INT_VL2_LBW BIT(8)
#define OSD_INT_VL1_LBW BIT(7)
#define OSD_INT_VL0_LBW BIT(6)
#define OSD_INT_BUS_ERR BIT(3)
#define OSD_INT_CFG_ERR BIT(2)
#define OSD_INT_ERROR (\
OSD_INT_GL1_LBW | OSD_INT_GL0_LBW | \
OSD_INT_VL2_LBW | OSD_INT_VL1_LBW | OSD_INT_VL0_LBW | \
OSD_INT_BUS_ERR | OSD_INT_CFG_ERR \
)
#define OSD_INT_ENABLE (OSD_INT_ERROR | OSD_INT_AUX_UPT | OSD_INT_MAIN_UPT)
#define OSD_CTRL0 0x10
#define OSD_CTRL0_GL0_EN BIT(7)
#define OSD_CTRL0_GL0_SEL BIT(6)
#define OSD_CTRL0_GL1_EN BIT(5)
#define OSD_CTRL0_GL1_SEL BIT(4)
#define OSD_RST_CLR 0x1c
#define RST_PER_FRAME BIT(19)
/* Main/Aux channel registers */
#define OSD_MAIN_CHN 0x470
#define OSD_AUX_CHN 0x4d0
#define CHN_CTRL0 0x00
#define CHN_ENABLE BIT(0)
#define CHN_CTRL1 0x04
#define CHN_SCREEN_W_SHIFT 18
#define CHN_SCREEN_W_MASK (0x1fff << CHN_SCREEN_W_SHIFT)
#define CHN_SCREEN_H_SHIFT 5
#define CHN_SCREEN_H_MASK (0x1fff << CHN_SCREEN_H_SHIFT)
#define CHN_UPDATE 0x08
/* TIMING_CTRL registers */
#define TIMING_TC_ENABLE 0x04
#define AUX_TC_EN BIT(1)
#define MAIN_TC_EN BIT(0)
#define FIR_MAIN_ACTIVE 0x08
#define FIR_AUX_ACTIVE 0x0c
#define V_ACTIVE_SHIFT 16
#define V_ACTIVE_MASK (0xffff << V_ACTIVE_SHIFT)
#define H_ACTIVE_SHIFT 0
#define H_ACTIVE_MASK (0xffff << H_ACTIVE_SHIFT)
#define FIR_MAIN_H_TIMING 0x10
#define FIR_MAIN_V_TIMING 0x14
#define FIR_AUX_H_TIMING 0x18
#define FIR_AUX_V_TIMING 0x1c
#define SYNC_WIDE_SHIFT 22
#define SYNC_WIDE_MASK (0x3ff << SYNC_WIDE_SHIFT)
#define BACK_PORCH_SHIFT 11
#define BACK_PORCH_MASK (0x7ff << BACK_PORCH_SHIFT)
#define FRONT_PORCH_SHIFT 0
#define FRONT_PORCH_MASK (0x7ff << FRONT_PORCH_SHIFT)
#define TIMING_CTRL 0x20
#define AUX_POL_SHIFT 3
#define AUX_POL_MASK (0x7 << AUX_POL_SHIFT)
#define MAIN_POL_SHIFT 0
#define MAIN_POL_MASK (0x7 << MAIN_POL_SHIFT)
#define POL_DE_SHIFT 2
#define POL_VSYNC_SHIFT 1
#define POL_HSYNC_SHIFT 0
#define TIMING_INT_CTRL 0x24
#define TIMING_INT_STATE 0x28
#define TIMING_INT_AUX_FRAME BIT(3)
#define TIMING_INT_MAIN_FRAME BIT(1)
#define TIMING_INT_AUX_FRAME_SEL_VSW (0x2 << 10)
#define TIMING_INT_MAIN_FRAME_SEL_VSW (0x2 << 6)
#define TIMING_INT_ENABLE (\
TIMING_INT_MAIN_FRAME_SEL_VSW | TIMING_INT_AUX_FRAME_SEL_VSW | \
TIMING_INT_MAIN_FRAME | TIMING_INT_AUX_FRAME \
)
#define TIMING_MAIN_SHIFT 0x2c
#define TIMING_AUX_SHIFT 0x30
#define H_SHIFT_VAL 0x0048
#define TIMING_MAIN_PI_SHIFT 0x68
#define TIMING_AUX_PI_SHIFT 0x6c
#define H_PI_SHIFT_VAL 0x000f
#define V_ACTIVE(x) (((x) << V_ACTIVE_SHIFT) & V_ACTIVE_MASK)
#define H_ACTIVE(x) (((x) << H_ACTIVE_SHIFT) & H_ACTIVE_MASK)
#define SYNC_WIDE(x) (((x) << SYNC_WIDE_SHIFT) & SYNC_WIDE_MASK)
#define BACK_PORCH(x) (((x) << BACK_PORCH_SHIFT) & BACK_PORCH_MASK)
#define FRONT_PORCH(x) (((x) << FRONT_PORCH_SHIFT) & FRONT_PORCH_MASK)
/* DTRC registers */
#define DTRC_F0_CTRL 0x2c
#define DTRC_F1_CTRL 0x5c
#define DTRC_DECOMPRESS_BYPASS BIT(17)
#define DTRC_DETILE_CTRL 0x68
#define TILE2RASTESCAN_BYPASS_MODE BIT(30)
#define DETILE_ARIDR_MODE_MASK (0x3 << 0)
#define DETILE_ARID_ALL 0
#define DETILE_ARID_IN_ARIDR 1
#define DETILE_ARID_BYP_BUT_ARIDR 2
#define DETILE_ARID_IN_ARIDR2 3
#define DTRC_ARID 0x6c
#define DTRC_ARID3_SHIFT 24
#define DTRC_ARID3_MASK (0xff << DTRC_ARID3_SHIFT)
#define DTRC_ARID2_SHIFT 16
#define DTRC_ARID2_MASK (0xff << DTRC_ARID2_SHIFT)
#define DTRC_ARID1_SHIFT 8
#define DTRC_ARID1_MASK (0xff << DTRC_ARID1_SHIFT)
#define DTRC_ARID0_SHIFT 0
#define DTRC_ARID0_MASK (0xff << DTRC_ARID0_SHIFT)
#define DTRC_DEC2DDR_ARID 0x70
#define DTRC_ARID3(x) (((x) << DTRC_ARID3_SHIFT) & DTRC_ARID3_MASK)
#define DTRC_ARID2(x) (((x) << DTRC_ARID2_SHIFT) & DTRC_ARID2_MASK)
#define DTRC_ARID1(x) (((x) << DTRC_ARID1_SHIFT) & DTRC_ARID1_MASK)
#define DTRC_ARID0(x) (((x) << DTRC_ARID0_SHIFT) & DTRC_ARID0_MASK)
/* VOU_CTRL registers */
#define VOU_INF_EN 0x00
#define VOU_INF_CH_SEL 0x04
#define VOU_INF_DATA_SEL 0x08
#define VOU_SOFT_RST 0x14
#define VOU_CLK_SEL 0x18
#define VOU_CLK_GL1_SEL BIT(5)
#define VOU_CLK_GL0_SEL BIT(4)
#define VOU_CLK_REQEN 0x20
#define VOU_CLK_EN 0x24
/* OTFPPU_CTRL registers */
#define OTFPPU_RSZ_DATA_SOURCE 0x04
#endif /* __ZX_VOU_REGS_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment